Permalink
Browse files

문서 편집 기능 추가

  • Loading branch information...
ipari committed Aug 20, 2018
1 parent 4be3c1e commit 8648b6aadbf05bdf55ea8b761fd3ba25b0d3e0dd
@@ -0,0 +1,59 @@
import re
from flask import Blueprint, redirect, request, render_template
from .config import config
from .note import file_path, menu_list, note_meta, process_page, raw_page, \
render_markdown
from .user import logged_in
blueprint = Blueprint('edit', __name__)
def save_note(page_path, content):
path = file_path(page_path)
with open(path, 'w') as f:
f.write(content)
def edit_page(page_path):
base_url = config('note')['base_url']
content = raw_page(page_path)
# ` 문자는 ES6에서 템플릿 문자로 사용되므로 escape 해줘야 한다.
content = content.replace('`', '\`')
return render_template('edit.html',
pagename=page_path,
meta=note_meta(),
base_url=base_url,
menu=menu_list(),
content=content)
@blueprint.route('/preview', methods=['POST'])
def preview():
html = render_markdown(request.get_json()['raw_md'])
# 이미지 주소가 /edit 기준으로 렌더링되어있어 base_url 기준으로 고친다.
page_root = request.referrer.split('/')[-2]
base_url = config('note')['base_url']
rel_url = '{}/{}'.format(base_url, page_root)
def replace_path(matchobj):
return '{}/{}/{}{}'.format(matchobj.group(1), rel_url,
matchobj.group(2), matchobj.group(3))
pattern = r'(src=\")([^\"]*)(\")'
html = re.sub(pattern, replace_path, html)
return html
@blueprint.route('/edit/<path:page_path>', methods=['GET', 'POST'])
def view_edit(page_path):
if not logged_in():
return redirect('/login')
else:
if request.method == 'GET':
return edit_page(page_path)
else:
save_note(page_path, request.form['md'])
return process_page(page_path)
@@ -40,17 +40,28 @@ def page_permission(page_path):
return page_permissions().get(page_path, 0)
def render_page(page_path, meta, menu):
def raw_page(page_path):
path = file_path(page_path)
try:
with open(path, 'r') as f:
return f.read()
except IOError:
return None
def render_markdown(raw_md):
extensions = md_extensions()
return markdown.markdown(raw_md, extensions=extensions)
with open(path, 'r') as f:
extensions = md_extensions()
content = markdown.markdown(f.read(), extensions=extensions)
return render_template('page.html',
meta=meta,
pagename=page_path,
menu=menu,
content=content)
def render_page(page_path, meta, menu):
raw_md = raw_page(page_path)
content = render_markdown(raw_md)
return render_template('page.html',
meta=meta,
pagename=page_path,
menu=menu,
content=content)
def error_page(page_path, meta, menu, message):
@@ -1,6 +1,6 @@
from flask import Flask, redirect, url_for
from features import archive, note, user
from features import archive, edit, note, user
from features.config import config
@@ -17,6 +17,7 @@
url_prefix = '/{}'.format(config('note')['base_url'])
app.register_blueprint(archive.blueprint)
app.register_blueprint(edit.blueprint)
app.register_blueprint(note.blueprint, url_prefix=url_prefix)
app.register_blueprint(user.blueprint)

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.
@@ -418,6 +418,22 @@ div.alert p.admonition-title {
}
/* Editor */
form.editor {
margin: 1.5em 0;
}
form div.buttons {
text-align: right;
}
form a.button {
display: inline-block;
margin-top: .4em;
padding: .5em .8em;
}
/* Footnotes */
div.footnote ol {
padding: 0 1em;
@@ -457,7 +473,7 @@ div.error {
margin-bottom: .6em;
}
form div {
div.login form div {
margin-bottom: .6em;
}
@@ -482,6 +498,10 @@ input[type=submit] {
cursor: pointer;
}
input[type=submit]:hover {
background-color: #6cb0bf;
}
/* Footer */
footer {
@@ -70,17 +70,31 @@ function selects(query) {
return document.querySelectorAll(query);
}
function getElementValue(query, property) {
let elem = select(query);
let style = window.getComputedStyle(elem, null);
return style.getPropertyValue(property);
}
function setElementValue(query, property, value) {
let elements = selects(query);
for (let element of elements) {
element.style[property] = value;
}
}
function previewMarkdown(preview, plainText) {
let ajax = new XMLHttpRequest();
let parameters = {
"raw_md": plainText
};
ajax.open("POST", "/preview", true);
ajax.setRequestHeader("Content-type", "application/json");
ajax.onreadystatechange = function() {
if (ajax.readyState === 4 && ajax.status === 200) {
preview.innerHTML = ajax.responseText;
}
};
ajax.send(JSON.stringify(parameters));
}

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -4,10 +4,12 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="{{ url_for('static', filename='js/script.js') }}"></script>
{% block script %}{% endblock %}
<title>{% block pagename %}{% endblock %} - {{ meta.note_name }}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/normalize.css') }}" />
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}" />
<link rel="stylesheet" href="{{ url_for('static', filename='css/pygments/arduino.css') }}" />
{% block css %}{% endblock %}
</head>
<body>
<header>
@@ -0,0 +1,53 @@
{% extends "_base.html" %}
{% block script %}
<script src="{{ url_for('static', filename='js/simplemde.min.js') }}"></script>
<script src="https://cdn.jsdelivr.net/highlight.js/latest/highlight.min.js"></script>
{% endblock %}
{% block css %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/simplemde.min.css') }}" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/highlight.js/latest/styles/github.min.css">
{% endblock %}
{% block pagename %}{{ pagename }}{% endblock %}
{% block content %}
<h1>{{ pagename }}</h1>
<form method="post" class="editor">
<textarea name="md" id="md"></textarea>
<div class="buttons">
<input type="submit" value="저장"/>
<a class="button" href="/{{ base_url }}/{{ pagename }}">취소</a>
</div>
</form>
{# https://github.com/sparksuite/simplemde-markdown-editor #}
<script>
let simplemde = new SimpleMDE({
autofocus: true,
autosave: {
enabled: true,
uniqueId: "{{ pagename }}",
delay: 10000
},
element: document.getElementById("md"),
indentWithTabs: false,
previewRender: function(plainText, preview) {
setTimeout(function() {
previewMarkdown(preview, plainText);
}, 250);
return "Loading...";
},
promptURLs: false,
renderingConfig: {
codeSyntaxHighlighting: true
},
spellChecker: false,
tabSize: 4
});
{# ES6 템플릿 문자열 ` 을 사용해야 한다. #}
simplemde.value(`{{ content|safe }}`);
</script>
{% endblock %}

0 comments on commit 8648b6a

Please sign in to comment.