mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-01 01:36:00 -04:00
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:
parent
3fe666f36a
commit
e00d88f45d
14
package-lock.json
generated
14
package-lock.json
generated
@ -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",
|
||||||
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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');
|
||||||
|
31
resources/js/services/vdom.js
Normal file
31
resources/js/services/vdom.js
Normal 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));
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user