fix markdown<=>html
This commit is contained in:
parent
ff78d55b8e
commit
1bcaff892b
|
|
@ -250,6 +250,7 @@ def bootstrap():
|
|||
groups = root.add_member(schema.Page(name="Group", body="# Groups\ngroups go here."))
|
||||
npcs = root.add_member(schema.Page(name="NPC", body="# NPCS!"))
|
||||
widgets = root.add_member(schema.Page(name="Widget", body="Widgets go here."))
|
||||
widgets.add_member(schema.Widget(name="hello", body=schema.Widget.default))
|
||||
|
||||
# create the NPCs
|
||||
npcs.add_member(schema.NPC(name="Sabetha", body=""))
|
||||
|
|
|
|||
|
|
@ -312,40 +312,39 @@ class Widget(Page):
|
|||
|
||||
default = dedent(
|
||||
"""
|
||||
# {name}
|
||||
# hello
|
||||
|
||||
Insert the current user's name.
|
||||
Insert the word "HELLO."
|
||||
|
||||
## Usage
|
||||
{{{
|
||||
<pre>\\{\\{widget hello [name="NAME"] \\}\\}</pre>
|
||||
}}}
|
||||
|
||||
## Example
|
||||
|
||||
***
|
||||
This example uses the current page's widget definition: {{widget hello world}} Nice, huh?
|
||||
|
||||
Hello, <macro name='user' />
|
||||
|
||||
***
|
||||
|
||||
## Template
|
||||
|
||||
```html
|
||||
|
||||
```
|
||||
HELLO${name ? ", " + name : ""}.
|
||||
```
|
||||
|
||||
## CSS
|
||||
```css
|
||||
.widget-user {{
|
||||
display: inline- block;
|
||||
border: 1px solid green;
|
||||
|
||||
```
|
||||
display: inline;
|
||||
background: green;
|
||||
padding: 3px;
|
||||
color: white;
|
||||
border-radius: 5px;
|
||||
padding: 2px;
|
||||
}}
|
||||
```
|
||||
|
||||
## Processor
|
||||
```javascript
|
||||
function(tag, template, css) {{
|
||||
// Return the HTML that should be inserted into the template div.
|
||||
return document.querySelector("nav li.user a:first-child").outerHTML;
|
||||
}};
|
||||
|
||||
```
|
||||
```
|
||||
"""
|
||||
)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
<script src="{{ url_for('static', filename='froghat-editor.js' ) }}"></script>
|
||||
{% endif %}
|
||||
<script>
|
||||
const wiki = new Froghat{% if user.can_write(page) %}Editor{% endif %}({plugins: [MacroPlugin, WidgetPlugin]});
|
||||
wiki.view();
|
||||
const wiki = new Froghat{% if user.can_write(page) %}Editor{% endif %}({plugins: [MacroPlugin]});
|
||||
wiki.run();
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,6 @@
|
|||
class FroghatEditor extends Froghat {
|
||||
|
||||
constructor(settings) {
|
||||
/*
|
||||
* Create a new Editor instance.
|
||||
*/
|
||||
super(settings);
|
||||
run() {
|
||||
this.states = {
|
||||
VIEW: 'view',
|
||||
EDIT: 'edit',
|
||||
|
|
@ -17,9 +13,11 @@ class FroghatEditor extends Froghat {
|
|||
});
|
||||
this.turndown.use([turndownPluginGfm.gfm, turndownPluginGfm.tables]);
|
||||
this.turndown.keep(['pre']);
|
||||
this.#bindEvents();
|
||||
//this.#bindEvents();
|
||||
|
||||
this.plugins().forEach(plugin => { plugin.setEditable() });
|
||||
this.element.classList.add("loaded");
|
||||
this.view();
|
||||
}
|
||||
|
||||
#bindEvents() {
|
||||
|
|
@ -30,8 +28,8 @@ class FroghatEditor extends Froghat {
|
|||
|
||||
/*
|
||||
if (event.key === 'Enter') {
|
||||
console.log(this.#state, this.#states.EDIT);
|
||||
if (this.#state === this.#states.EDIT) {
|
||||
console.log(this.state, this.states.EDIT);
|
||||
if (this.state === this.states.WYSIWYG) {
|
||||
evt.preventDefault();
|
||||
this.insertAtCursor(document.createTextNode("\n"));
|
||||
}
|
||||
|
|
@ -45,8 +43,8 @@ class FroghatEditor extends Froghat {
|
|||
});
|
||||
};
|
||||
|
||||
HtmlToMarkdown(html) {
|
||||
return this.turndown.turndown(html);
|
||||
htmlToMarkdown(html) {
|
||||
return this.turndown.turndown(html || this.element.innerHTML);
|
||||
}
|
||||
|
||||
getMarkdown() {
|
||||
|
|
@ -54,11 +52,14 @@ class FroghatEditor extends Froghat {
|
|||
* Return the current markdown.
|
||||
*/
|
||||
if (this.getState() === this.states.EDIT) {
|
||||
this.cachedMarkdown = this.element.innerHTML.replaceAll(/<\/?div>/g, "\n").replaceAll('<br>', "");
|
||||
var html = this.element.innerHTML;
|
||||
html = html.replaceAll(/<(?:div|br)>/ig, '');
|
||||
html = html.replaceAll(/<\/div>/ig, "\n");
|
||||
this.cachedMarkdown = decodeHtmlEntities(html);
|
||||
} else if (this.getState() === this.states.WYSIWYG) {
|
||||
this.cachedMarkdown = this.HtmlToMarkdown(this.element.innerHTML);
|
||||
} else if (!this.cachedMarkdown) {
|
||||
this.cachedMarkdown = this.source;
|
||||
this.cachedMarkdown = this.htmlToMarkdown(this.element.innerHTML);
|
||||
} if (!this.cachedMarkdown) {
|
||||
this.cachedMarkdown = this.element.textContent;
|
||||
}
|
||||
return this.cachedMarkdown;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,7 +65,6 @@ class Froghat {
|
|||
this.api = settings.api || FroghatAPIv1;
|
||||
|
||||
this.element = document.getElementById(settings.editorId || 'froghat');
|
||||
this.source = this.element.textContent;
|
||||
|
||||
this.marked = marked;
|
||||
this.marked.use({
|
||||
|
|
@ -82,10 +81,14 @@ class Froghat {
|
|||
this.enabledPlugins = {};
|
||||
|
||||
settings.plugins.forEach(plugin => {
|
||||
this.enabledPlugins[plugin.name] = new plugin({name: plugin.name, editor: this});
|
||||
this.enabledPlugins[plugin.name] = new plugin({name: plugin.name, wiki: this});
|
||||
});
|
||||
this.getHTML();
|
||||
|
||||
}
|
||||
|
||||
run() {
|
||||
this.element.classList.add("loaded");
|
||||
this.view();
|
||||
}
|
||||
|
||||
plugins() {
|
||||
|
|
@ -116,35 +119,29 @@ class Froghat {
|
|||
/*
|
||||
* Convert the markdown source to HTML.
|
||||
*/
|
||||
/*
|
||||
if (this.changed || !this.cachedHTML) {
|
||||
this.cachedHTML = this.markdownToHTML(this.getMarkdown());
|
||||
}
|
||||
*/
|
||||
var md = this.getMarkdown();
|
||||
this.cachedHTML = this.markdownToHTML(md);
|
||||
return this.cachedHTML;
|
||||
}
|
||||
|
||||
getMarkdown() {
|
||||
if (!this.cachedMarkdown) {
|
||||
this.cachedMarkdown = this.source;
|
||||
}
|
||||
return this.cachedMarkdown;
|
||||
}
|
||||
|
||||
reset() {
|
||||
/*
|
||||
* Discard any unsaved edits and reset the editor to its initial state.
|
||||
*/
|
||||
this.cachedHTML = null;
|
||||
this.cachedMarkdown = null;
|
||||
this.view();
|
||||
}
|
||||
|
||||
view() {
|
||||
/*
|
||||
* Convert the editor read-only mode and display the current HTML.
|
||||
* Convert the wiki read-only mode and display the current HTML.
|
||||
*/
|
||||
/*
|
||||
if (this.getState() === this.states.VIEW) {
|
||||
return;
|
||||
}
|
||||
*/
|
||||
this.element.innerHTML = this.getHTML();
|
||||
this.setState(this.states.VIEW);
|
||||
this.contentEditable = false;
|
||||
|
|
@ -156,7 +153,7 @@ class FroghatPlugin {
|
|||
|
||||
constructor(settings) {
|
||||
this.name = settings.name;
|
||||
this.editor = settings.editor;
|
||||
this.wiki = settings.wiki;
|
||||
this.precedence = 50;
|
||||
};
|
||||
|
||||
|
|
@ -173,76 +170,76 @@ class FroghatPlugin {
|
|||
};
|
||||
|
||||
|
||||
class WidgetPlugin extends FroghatPlugin {
|
||||
|
||||
setEditable() {
|
||||
};
|
||||
|
||||
toMarkdown(html) {
|
||||
return html;
|
||||
};
|
||||
|
||||
toHTML(md) {
|
||||
return md;
|
||||
};
|
||||
|
||||
parseWidgetSource(html) {
|
||||
WIDGETS = {};
|
||||
|
||||
function loadWidget(name, callback) {
|
||||
var widget = null;
|
||||
if (Object.values(WIDGETS).indexOf(name) == -1) {
|
||||
(async () => {
|
||||
await FroghatAPIv1.search("Widget", name, (res) => {
|
||||
if (res.code == 200) {
|
||||
function block(prefix) {
|
||||
return RegExp('##\\s*' + prefix + '.*?```\\w*(.+?)```', 'gims');
|
||||
};
|
||||
|
||||
const template = block("Template").exec(html)[1];
|
||||
const css = block("CSS").exec(html)[1];
|
||||
const processor = block("Processor").exec(html)[1];
|
||||
|
||||
var func;
|
||||
eval("func = " + processor);
|
||||
|
||||
return {
|
||||
template: template,
|
||||
css: css,
|
||||
processor: func
|
||||
};
|
||||
var html = res.response[0].body;
|
||||
var proc = block("Processor").exec(html)[1].trim();
|
||||
if (!proc) {
|
||||
proc = function(token, widget) {
|
||||
var name = token.keywords.split(" ").slice(1).join(" ");
|
||||
var ret = '';
|
||||
eval("ret = `" + widget.template + "`");
|
||||
return ret;
|
||||
}
|
||||
|
||||
async processWidgets(html, callback) {
|
||||
|
||||
var widgetPattern = /({{(.+)}})/gm;
|
||||
|
||||
if (!html.match(widgetPattern)) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
html.matchAll(widgetPattern).forEach(match => {
|
||||
var widgetTag = match[1];
|
||||
var widgetName = match[2];
|
||||
if (Object.values(WIDGETS).indexOf(widgetName) == -1) {
|
||||
APIv1.search("Widget", widgetName, (res) => {
|
||||
if (res.code == 200) {
|
||||
var parts = parseWidgetSource(res.response[0].body);
|
||||
WIDGETS[widgetName] = parts.processor;
|
||||
contents = WIDGETS[widgetName](widgetTag, parts.template, parts.css);
|
||||
} else {
|
||||
contents = `Invalid widget: ${widgetName}`;
|
||||
eval(`proc = ${proc}`);
|
||||
}
|
||||
var rep = `<span class="widget-${widgetName}" data-source="${widgetTag}">${contents}</span>`;
|
||||
html = html.replaceAll(widgetTag, rep);
|
||||
if (parts) {
|
||||
html = `<style type='text/css'>${parts.css}</style>${html}`;
|
||||
}
|
||||
callback(html);
|
||||
});
|
||||
}
|
||||
});
|
||||
WIDGETS[name] = {
|
||||
template: block("Template").exec(html)[1],
|
||||
css: block("CSS").exec(html)[1],
|
||||
processor: proc
|
||||
};
|
||||
} else {
|
||||
WIDGETS[name] = {
|
||||
template: "",
|
||||
css: "",
|
||||
processor: function() { return `Invalid Widget: "${name}"` },
|
||||
};
|
||||
}
|
||||
if (callback) {
|
||||
callback(WIDGETS[name]);
|
||||
}
|
||||
});
|
||||
})();
|
||||
} else {
|
||||
if (callback) {
|
||||
callback(WIDGETS[name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class MacroPlugin extends FroghatPlugin {
|
||||
|
||||
macros = {
|
||||
// image: {}
|
||||
|
||||
widget: {
|
||||
inline: true,
|
||||
toHTML: (token, node) => {
|
||||
var widgetName = token.keywords.split(" ")[0];
|
||||
var contents = '';
|
||||
loadWidget(widgetName, (widget) => {
|
||||
contents = widget.processor(token, widget);
|
||||
var targets = wiki.element.querySelectorAll(`[data-macro-name="widget"][data-keywords="${token.keywords}"]`);
|
||||
targets.forEach(widgetElement => {
|
||||
widgetElement.style = widget.css;
|
||||
widgetElement.innerHTML = contents;
|
||||
});
|
||||
});
|
||||
return node + "</span>";
|
||||
}
|
||||
},
|
||||
|
||||
style: {
|
||||
inline: false,
|
||||
toHTML: (token, node) => {
|
||||
|
|
@ -437,14 +434,24 @@ class MacroPlugin extends FroghatPlugin {
|
|||
|
||||
constructor(settings) {
|
||||
super(settings);
|
||||
this.pattern = /(?<!`)(?<wrap><[^>]+?>){{(?<name>\w+)(?<keywords>(?:\s*[\w-]+)*?)?(?<parameters>(?:\s+[\w-]+=\S+?)*)?\s*(?<closed>}})?(?<endwrap><\/[^>]+?>)/mg;
|
||||
|
||||
this.pattern = new RegExp(
|
||||
'(?<!`)(?<wrap><[^>]+?>)?' + // capture the enclosing HTML tag, if any
|
||||
'{{' + // start of the macro
|
||||
'(?<name>\\w+)' + // the macro name
|
||||
'(?<keywords>(?:\\s(?:\\s*(?:[\\w-](?![\\w-]+=))+))+)?' + // zero or more keywords separated by spaces
|
||||
'(?<parameters>[^}<]+)?' + // anything else before the closing
|
||||
'\\s*(?<closed>}})?' + // is the tag closed?
|
||||
'(?<endwrap>(?:>!\\<)*?<\\/[^>]+?>)?', // capture the enclosing HTML tag, if any
|
||||
'mg'
|
||||
);
|
||||
this.endPattern = /<p>}}\s*<\/p>/mg;
|
||||
this.paramPattern = /\s*(?<name>[^=]+)="(?<value>[^"]*)"/g;
|
||||
this.multilinePattern = /(?<!\{{3}[\s\n]*)\{{3}[\s\n]*(?<content>(.(?!\}{3})*)+?)[\s\n]*\}{3}/smg;
|
||||
|
||||
const plugin = this;
|
||||
|
||||
this.editor.marked.use({
|
||||
this.wiki.marked.use({
|
||||
extensions: [
|
||||
{
|
||||
name: 'heading',
|
||||
|
|
@ -493,7 +500,8 @@ class MacroPlugin extends FroghatPlugin {
|
|||
}
|
||||
|
||||
setEditable() {
|
||||
this.editor.turndown.addRule('macros', {
|
||||
const plugin = this;
|
||||
this.wiki.turndown.addRule('macros', {
|
||||
filter: function (node, options) {
|
||||
return ((node.nodeName === 'DIV' || node.nodeName === 'SPAN') && node.dataset.pluginName == 'macro')
|
||||
},
|
||||
|
|
@ -518,7 +526,7 @@ class MacroPlugin extends FroghatPlugin {
|
|||
|
||||
if (node.dataset.inline == "false") {
|
||||
md = `\n\n${md}\n\n`;
|
||||
md += plugin.editor.HtmlToMarkdown(node.innerHTML);
|
||||
md += plugin.wiki.htmlToMarkdown(node.innerHTML);
|
||||
md += "\n\n}}\n\n";
|
||||
} else {
|
||||
md += "}}";
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user