diff --git a/package-lock.json b/package-lock.json index eea8b3cfa..1448d592f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "dropzone": "^5.9.3", "markdown-it": "^13.0.1", "markdown-it-task-lists": "^2.1.1", + "snabbdom": "^3.5.0", "sortablejs": "^1.15.0" }, "devDependencies": { @@ -1600,6 +1601,14 @@ "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": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.0.tgz", @@ -2972,6 +2981,11 @@ "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": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.0.tgz", diff --git a/package.json b/package.json index 539e05057..9a2f66448 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "dropzone": "^5.9.3", "markdown-it": "^13.0.1", "markdown-it-task-lists": "^2.1.1", + "snabbdom": "^3.5.0", "sortablejs": "^1.15.0" } } diff --git a/resources/js/components/markdown-editor.js b/resources/js/components/markdown-editor.js index 297d9c8ec..21cf37bb4 100644 --- a/resources/js/components/markdown-editor.js +++ b/resources/js/components/markdown-editor.js @@ -2,7 +2,7 @@ import MarkdownIt from "markdown-it"; import mdTasksLists from 'markdown-it-task-lists'; import Clipboard from "../services/clipboard"; import {debounce} from "../services/util"; - +import {patchDomFromHtmlString} from "../services/vdom"; import DrawIO from "../services/drawio"; class MarkdownEditor { @@ -127,18 +127,31 @@ class MarkdownEditor { updateAndRender() { const content = this.cm.getValue(); this.input.value = content; + const html = this.markdown.render(content); window.$events.emit('editor-html-change', html); window.$events.emit('editor-markdown-change', content); // Set body content + const target = this.getDisplayTarget(); 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 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() { if (this.displayStylesLoaded) return; this.displayDoc.documentElement.classList.add('markdown-editor-display'); diff --git a/resources/js/services/vdom.js b/resources/js/services/vdom.js new file mode 100644 index 000000000..89a809084 --- /dev/null +++ b/resources/js/services/vdom.js @@ -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)); +} \ No newline at end of file