diff options
author | 2018-04-06 11:12:08 +0100 | |
---|---|---|
committer | 2018-04-06 11:13:16 +0100 | |
commit | 02e40b76817b06816ae37510c2fde2a88aecea37 (patch) | |
tree | 1587ae82d2304efc4ce7fc01d6491266f2c9df4e | |
parent | 5XX error view non-werkzeug exception support (diff) |
Updated wiki editing system with live-previewing
-rw-r--r-- | pysite/views/wiki/edit.py | 9 | ||||
-rw-r--r-- | pysite/views/wiki/render.py | 33 | ||||
-rw-r--r-- | templates/wiki/page_edit.html | 55 |
3 files changed, 83 insertions, 14 deletions
diff --git a/pysite/views/wiki/edit.py b/pysite/views/wiki/edit.py index 483be046..d9ea692f 100644 --- a/pysite/views/wiki/edit.py +++ b/pysite/views/wiki/edit.py @@ -1,5 +1,5 @@ # coding=utf-8 -from flask import url_for +from flask import url_for, request from werkzeug.utils import redirect from pysite.base_route import RouteView @@ -32,4 +32,11 @@ class EditView(RouteView, DBMixin): @csrf def post(self, page): # rst = request.form["rst"] + obj = { + "slug": page, + "title": request.form["title"], + "rst": request.form["rst"], + "html": "" + } + return redirect(url_for("wiki.page", page=page), code=303) # Redirect, ensuring a GET diff --git a/pysite/views/wiki/render.py b/pysite/views/wiki/render.py index d177a8b3..73c38731 100644 --- a/pysite/views/wiki/render.py +++ b/pysite/views/wiki/render.py @@ -1,5 +1,8 @@ # coding=utf-8 +import re + from docutils.core import publish_parts +from docutils.utils import SystemMessage from flask import jsonify from schema import Schema @@ -11,6 +14,8 @@ SCHEMA = Schema([{ "data": str }]) +MESSAGE_REGEX = re.compile(r"<string>:(\d+): \([A-Z]+/\d\) (.*)") + class RenderView(APIView): path = "/render" # "path" means that it accepts slashes @@ -26,9 +31,35 @@ class RenderView(APIView): data = data[0]["data"] try: html = publish_parts( - source=data, writer_name="html5", settings_overrides={"traceback": True, "halt_level": 2} + source=data, writer_name="html5", settings_overrides={"halt_level": 2} )["html_body"] return jsonify({"data": html}) + except SystemMessage as e: + lines = str(e) + data = { + "error": lines, + "error_lines": [] + } + + if "\n" in lines: + lines = lines.split("\n") + else: + lines = [lines] + + for message in lines: + match = MESSAGE_REGEX.match(message) + + if match: + data["error_lines"].append( + { + "row": int(match.group(1)) - 1, + "column": 0, + "type": "error", + "text": match.group(2) + } + ) + + return jsonify(data) except Exception as e: return jsonify({"error": str(e)}) diff --git a/templates/wiki/page_edit.html b/templates/wiki/page_edit.html index 97a5161c..e83676fd 100644 --- a/templates/wiki/page_edit.html +++ b/templates/wiki/page_edit.html @@ -2,19 +2,32 @@ {% block title %}Wiki | Home{% endblock %} {% block og_title %}Wiki | Home{% endblock %} {% block og_description %}Landing page for the wiki{% endblock %} +{% block extra_head %} +<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.3.3/ace.js" type="application/javascript"></script> +{% endblock %} {% block content %} <div class="uk-container uk-section"> - <form action="{{ url_for("wiki.edit", page=page) }}" method="post"> - <label for="title">Title: </label> - <input name="title" id="title" value="{{ title }}" class="uk-input" /> - <label for="rst">Document: </label> - <textarea name="rst" id="rst" class="uk-textarea">{{ rst }}</textarea> - <button value="Preview" id="preview">Preview</button> - <button type="submit" value="Save">Save</button> + <form uk-grid class="uk-grid-small" action="{{ url_for("wiki.edit", page=page) }}" method="post"> + <div class="uk-width-expand"> + <input name="title" id="title" placeholder="Page Title" value="{{ title }}" class="uk-input" /> + </div> + <div class="uk-width-auto"> + <button class="uk-button uk-button-secondary" type="button" value="Preview" id="preview">Preview</button> + </div> + <div class="uk-width-auto"> + <button class="uk-button uk-button-primary" type="submit" value="Save">Save</button> + </div> + <div class="uk-width-1-1"> +{# <label for="rst">Document: </label>#} + <div id="rst" class="uk-textarea" style="resize: vertical; min-height: 10rem;">{{ rst }}</div> + </div> + <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/> </form> - <div id="preview-div" style="border: 1px solid grey;"> + <h2 class="uk-h2">Preview</h2> + + <div id="preview-div"> <p>Preview will appear here.</p> </div> </div> @@ -26,15 +39,21 @@ document.getElementById("preview").onclick = function(event) { let oReq = new XMLHttpRequest(); - let data = document.getElementById("rst").value; oReq.addEventListener("load", function() { let response = JSON.parse(this.responseText); if (response.error !== undefined) { - console.log("Error: " + response.error) + if (response.error_lines !== undefined) { + editor.session.setAnnotations(response.error_lines); + document.getElementById("preview-div").innerHTML ="<h3>Error - see editor margin</h3>"; + } else { + console.log("Error: " + response.error); + document.getElementById("preview-div").innerHTML ="<h3>Error</h3><p>" + response.error + "<p>"; + } } else { document.getElementById("preview-div").innerHTML = response.data; + editor.session.setAnnotations([]); } }); @@ -43,9 +62,21 @@ oReq.setRequestHeader("Content-type", "application/json"); oReq.setRequestHeader("X-CSRFToken", csrf_token); - oReq.send(JSON.stringify({"data": data})); + oReq.send(JSON.stringify({"data": editor.getValue()})); return false; - } + }; + + let editor = ace.edit("rst"); + let timer; + + editor.session.setMode("ace/mode/rst"); + editor.setTheme("ace/theme/iplastic"); + editor.on("input", function() { + if (timer !== undefined) { + clearTimeout(timer); + } + timer = setTimeout(function() {document.getElementById("preview").click()}, 1000); + }) </script> {% endblock %}
\ No newline at end of file |