]> BookStack Code Mirror - bookstack/blob - resources/js/markdown/display.js
Fixed md editor refactoring issues after manual test
[bookstack] / resources / js / markdown / display.js
1 import {patchDomFromHtmlString} from "../services/vdom";
2
3 export class Display {
4
5     /**
6      * @param {MarkdownEditor} editor
7      */
8     constructor(editor) {
9         this.editor = editor;
10         this.container = editor.config.displayEl;
11
12         this.doc = null;
13         this.lastDisplayClick = 0;
14
15         if (this.container.contentDocument.readyState === 'complete') {
16             this.onLoad();
17         } else {
18             this.container.addEventListener('load', this.onLoad.bind(this));
19         }
20     }
21
22     onLoad() {
23         this.doc = this.container.contentDocument;
24
25         this.loadStylesIntoDisplay();
26         this.doc.body.className = 'page-content';
27
28         // Prevent markdown display link click redirect
29         this.doc.addEventListener('click', this.onDisplayClick.bind(this));
30     }
31
32     /**
33      * @param {MouseEvent} event
34      */
35     onDisplayClick(event) {
36         const isDblClick = Date.now() - this.lastDisplayClick < 300;
37
38         const link = event.target.closest('a');
39         if (link !== null) {
40             event.preventDefault();
41             window.open(link.getAttribute('href'));
42             return;
43         }
44
45         const drawing = event.target.closest('[drawio-diagram]');
46         if (drawing !== null && isDblClick) {
47             this.editor.actions.editDrawing(drawing);
48             return;
49         }
50
51         this.lastDisplayClick = Date.now();
52     }
53
54     loadStylesIntoDisplay() {
55         this.doc.documentElement.classList.add('markdown-editor-display');
56
57         // Set display to be dark mode if parent is
58         if (document.documentElement.classList.contains('dark-mode')) {
59             this.doc.documentElement.style.backgroundColor = '#222';
60             this.doc.documentElement.classList.add('dark-mode');
61         }
62
63         this.doc.head.innerHTML = '';
64         const styles = document.head.querySelectorAll('style,link[rel=stylesheet]');
65         for (const style of styles) {
66             const copy = style.cloneNode(true);
67             this.doc.head.appendChild(copy);
68         }
69     }
70
71     /**
72      * Patch the display DOM with the given HTML content.
73      * @param {String} html
74      */
75     patchWithHtml(html) {
76         const body = this.doc.body;
77
78         if (body.children.length === 0) {
79             const wrap = document.createElement('div');
80             this.doc.body.append(wrap);
81         }
82
83         const target = body.children[0];
84
85         patchDomFromHtmlString(target, html);
86     }
87
88     /**
89      * Scroll to the given block index within the display content.
90      * Will scroll to the end if the index is -1.
91      * @param {Number} index
92      */
93     scrollToIndex(index) {
94         const elems = this.doc.body?.children[0]?.children;
95         if (elems && elems.length <= index) return;
96
97         const topElem = (index === -1) ? elems[elems.length-1] : elems[index];
98         topElem.scrollIntoView({ block: 'start', inline: 'nearest', behavior: 'smooth'});
99     }
100
101 }