Add framework for editor live preview warnings

This commit is contained in:
Tim Van Baak 2020-02-14 14:22:38 -08:00
parent 40e7a0c030
commit c0c69805e3
4 changed files with 91 additions and 30 deletions

View File

@ -45,6 +45,15 @@ div#editor-right {
div#editor-right div.contentblock { div#editor-right div.contentblock {
margin: 10px 5px 10px 10px; margin: 10px 5px 10px 10px;
} }
div#editor-right p#editor-warnings {
color: #808000;
}
div#editor-right p#editor-errors {
color: #ff0000;
}
span.new {
color: #008000;
}
@media only screen and (max-width: 816px) { @media only screen and (max-width: 816px) {
div#wrapper { div#wrapper {
max-width: 564px; max-width: 564px;

View File

@ -5,23 +5,9 @@ function onContentChange() {
// Pass the draft text to the parser to get the preview html and citations // Pass the draft text to the parser to get the preview html and citations
var parseResult = parseLexipythonMarkdown(articleBody); var parseResult = parseLexipythonMarkdown(articleBody);
// Build the citation block // Build the citation block
var citeTexts = [] var citeblockContent = makeCiteblock(parseResult);
for (var i = 0; i < parseResult.citations.length; i++) {
var cite = parseResult.citations[i];
citeTexts.push("[" + cite.id.toString() + "] " + cite.citeTitle);
}
var citeblockContent = citeTexts.join(" / ");
// Compute warnings and build the control block // Compute warnings and build the control block
var flagMissingSignature = !parseResult.hasSignature; var controlContent = checkWarnings(parseResult);
var wordCount = (parseResult.html
// Delete all HTML tags
.replace(/<[^>]+>/g, "")
.trim()
.split(/\s+/)
.length);
var controlContent = "";
controlContent += "<p>Signature: " + (!flagMissingSignature).toString() + "</p>";
controlContent += "<p>Word count: " + wordCount.toString() + "</p>";
// Fill in the content blocks // Fill in the content blocks
document.getElementById("preview").innerHTML = ( document.getElementById("preview").innerHTML = (
"<h1>" + articleTitle + "</h1>\n" "<h1>" + articleTitle + "</h1>\n"
@ -91,15 +77,73 @@ function parseLexipythonMarkdown(text) {
content += "<p>" + citationList[i] + "</p>\n"; content += "<p>" + citationList[i] + "</p>\n";
} }
} }
// Calculate approximate word count
// var wordCount = text.trim().split(/\s+/).length;
// if (text.trim().length < 1)
// wordCount = 0;
// content += "<p><i>Article length: approx. " + wordCount + " words</p>";
return result; return result;
} }
function makeCiteblock(parseResult) {
var citeTexts = []
for (var i = 0; i < parseResult.citations.length; i++) {
var cite = parseResult.citations[i];
citeTexts.push("[" + cite.id.toString() + "] " + cite.citeTitle);
}
return citeTexts.join(" / ");
}
function checkWarnings(parseResult) {
var result = {
errors: [],
warnings: [],
};
if (!parseResult.hasSignature) {
result.warnings.push("Article has no signature.");
}
// Self-citation
// TODO
// Citation targets
// TODO
if (params.citation.min_total != null &&
parseResult.citations.length < params.citation.min_total) {
result.errors.push("Article must have a minimum of " +
params.citation.min_total + " citations.");
}
if (params.citation.max_total != null &&
parseResult.citations.length > params.citation.max_total) {
result.errors.push("Article cannot have more than " +
params.citation.max_total + " citations.");
}
// TODO
// Word limits
var wordCount = (parseResult.html
// Delete all HTML tags
.replace(/<[^>]+>/g, "")
.trim()
.split(/\s+/)
.length);
if (params.wordLimit.hard != null && wordCount > params.wordLimit.hard) {
result.errors.push("Article must be shorter than " + params.wordLimit.hard + " words.");
} else if (params.wordLimit.soft != null && wordCount > params.wordLimit.soft) {
result.warnings.push("Article should be shorter than " + params.wordLimit.soft + " words.");
}
var controlContent = "";
controlContent += "<p>Word count: " + wordCount + "</p>";
if (result.errors.length > 0) {
controlContent += "<p id=\"editor-errors\">";
for (var i = 0; i < result.errors.length; i++) {
controlContent += result.errors[i] + "<br>";
}
controlContent += "</p>";
}
if (result.warnings.length > 0) {
controlContent += "<p id=\"editor-warnings\">";
for (var i = 0; i < result.warnings.length; i++) {
controlContent += result.warnings[i] + "<br>";
}
controlContent += "</p>";
}
return controlContent;
}
// Parse the article content and update the preview pane // Parse the article content and update the preview pane
@ -128,13 +172,13 @@ function parseLexipythonMarkdown(text) {
// } // }
window.onload = function() { window.onload = function() {
document.getElementById("editor-content").value = "\n\n" + params.defaultSignature; document.getElementById("editor-content").value = "\n\n" + params.default_signature;
this.onContentChange(); this.onContentChange();
}; };
window.addEventListener("beforeunload", function(e) { window.addEventListener("beforeunload", function(e) {
var content = document.getElementById("editor-content").value var content = document.getElementById("editor-content").value
var hasText = content.length > 0 && content != "\n\n" + params.defaultSignature; var hasText = content.length > 0 && content != "\n\n" + params.default_signature;
if (hasText) { if (hasText) {
e.returnValue = "Are you sure?"; e.returnValue = "Are you sure?";
} }

View File

@ -1,7 +1,7 @@
import json import json
from flask import ( from flask import (
Blueprint, render_template, url_for, redirect, g, flash, request) Blueprint, render_template, url_for, redirect, g, flash, request, Markup)
from flask_login import login_required, current_user from flask_login import login_required, current_user
from amanuensis.config import json_ro, open_ex from amanuensis.config import json_ro, open_ex
@ -138,6 +138,11 @@ def get_bp():
@lexicon_param @lexicon_param
@player_required @player_required
def editor(name): def editor(name):
return render_template('lexicon/editor.html') return render_template(
'lexicon/editor.html',
current_turn=Markup(json.dumps(g.lexicon.turn.current)),
citation=Markup(json.dumps(dict(g.lexicon.article.citation))),
word_limit=Markup(json.dumps(dict(g.lexicon.article.word_limit))),
addendum=Markup(json.dumps(dict(g.lexicon.article.citation))))
return bp return bp

View File

@ -7,14 +7,17 @@
<head> <head>
<meta charset="utf-8"/> <meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}{% endblock %}</title> <title>Editor</title>
<link rel="stylesheet" href="{{ url_for('static', filename='page.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='page.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='editor.css') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='editor.css') }}">
<script> <script>
params = { params = {
currentTurn: "{{ g.lexicon.turn.current }}", current_turn: {{ current_turn }},
defaultSignature: "{{ characters[0].signature }}", default_signature: "{{ characters[0].signature }}",
} citation: {{ citation }},
wordLimit: {{ word_limit }},
addendum: {{ addendum }},
};
</script> </script>
<script type="text/javascript" src="{{ url_for('static', filename='editor.js') }}"></script> <script type="text/javascript" src="{{ url_for('static', filename='editor.js') }}"></script>
</head> </head>