Updated markdown preview to update on diff-basis

Uses vdom system to diff and update the current markdown preview view
instead of requiring a full HTML replace change.
This should provide better performance, expecially where dynamically
loaded content such as iframes were in use.

Closes #3454
This commit is contained in:
Dan Brown 2022-06-07 16:07:28 +01:00
parent 3fe666f36a
commit e00d88f45d
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9
4 changed files with 61 additions and 2 deletions

14
package-lock.json generated
View File

@ -10,6 +10,7 @@
"dropzone": "^5.9.3", "dropzone": "^5.9.3",
"markdown-it": "^13.0.1", "markdown-it": "^13.0.1",
"markdown-it-task-lists": "^2.1.1", "markdown-it-task-lists": "^2.1.1",
"snabbdom": "^3.5.0",
"sortablejs": "^1.15.0" "sortablejs": "^1.15.0"
}, },
"devDependencies": { "devDependencies": {
@ -1600,6 +1601,14 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/snabbdom": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/snabbdom/-/snabbdom-3.5.0.tgz",
"integrity": "sha512-Ff5BKG18KrrPuskHJlA9aujPHqEabItaDl96l7ZZndF4zt5AYSczz7ZjjgQAX5IBd5cd25lw9NfgX21yVUJ+9g==",
"engines": {
"node": ">=8.3.0"
}
},
"node_modules/sortablejs": { "node_modules/sortablejs": {
"version": "1.15.0", "version": "1.15.0",
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.0.tgz", "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.0.tgz",
@ -2972,6 +2981,11 @@
"object-inspect": "^1.9.0" "object-inspect": "^1.9.0"
} }
}, },
"snabbdom": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/snabbdom/-/snabbdom-3.5.0.tgz",
"integrity": "sha512-Ff5BKG18KrrPuskHJlA9aujPHqEabItaDl96l7ZZndF4zt5AYSczz7ZjjgQAX5IBd5cd25lw9NfgX21yVUJ+9g=="
},
"sortablejs": { "sortablejs": {
"version": "1.15.0", "version": "1.15.0",
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.0.tgz", "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.0.tgz",

View File

@ -28,6 +28,7 @@
"dropzone": "^5.9.3", "dropzone": "^5.9.3",
"markdown-it": "^13.0.1", "markdown-it": "^13.0.1",
"markdown-it-task-lists": "^2.1.1", "markdown-it-task-lists": "^2.1.1",
"snabbdom": "^3.5.0",
"sortablejs": "^1.15.0" "sortablejs": "^1.15.0"
} }
} }

View File

@ -2,7 +2,7 @@ import MarkdownIt from "markdown-it";
import mdTasksLists from 'markdown-it-task-lists'; import mdTasksLists from 'markdown-it-task-lists';
import Clipboard from "../services/clipboard"; import Clipboard from "../services/clipboard";
import {debounce} from "../services/util"; import {debounce} from "../services/util";
import {patchDomFromHtmlString} from "../services/vdom";
import DrawIO from "../services/drawio"; import DrawIO from "../services/drawio";
class MarkdownEditor { class MarkdownEditor {
@ -127,18 +127,31 @@ class MarkdownEditor {
updateAndRender() { updateAndRender() {
const content = this.cm.getValue(); const content = this.cm.getValue();
this.input.value = content; this.input.value = content;
const html = this.markdown.render(content); const html = this.markdown.render(content);
window.$events.emit('editor-html-change', html); window.$events.emit('editor-html-change', html);
window.$events.emit('editor-markdown-change', content); window.$events.emit('editor-markdown-change', content);
// Set body content // Set body content
const target = this.getDisplayTarget();
this.displayDoc.body.className = 'page-content'; this.displayDoc.body.className = 'page-content';
this.displayDoc.body.innerHTML = html; patchDomFromHtmlString(target, html);
// Copy styles from page head and set custom styles for editor // Copy styles from page head and set custom styles for editor
this.loadStylesIntoDisplay(); this.loadStylesIntoDisplay();
} }
getDisplayTarget() {
const body = this.displayDoc.body;
if (body.children.length === 0) {
const wrap = document.createElement('div');
this.displayDoc.body.append(wrap);
}
return body.children[0];
}
loadStylesIntoDisplay() { loadStylesIntoDisplay() {
if (this.displayStylesLoaded) return; if (this.displayStylesLoaded) return;
this.displayDoc.documentElement.classList.add('markdown-editor-display'); this.displayDoc.documentElement.classList.add('markdown-editor-display');

View File

@ -0,0 +1,31 @@
import {
init,
attributesModule,
toVNode
} from "snabbdom";
let patcher;
/**
* @returns {Function}
*/
function getPatcher() {
if (patcher) return patcher;
patcher = init([
attributesModule,
]);
return patcher;
}
/**
* @param {Element} domTarget
* @param {String} html
*/
export function patchDomFromHtmlString(domTarget, html) {
const contentDom = document.createElement('div');
contentDom.innerHTML = html;
getPatcher()(toVNode(domTarget), toVNode(contentDom));
}