1 import { patchDomFromHtmlString } from '../services/vdom';
2 import {MarkdownEditor} from "./index.mjs";
5 protected editor: MarkdownEditor;
6 protected container: HTMLIFrameElement;
7 protected doc: Document | null = null;
8 protected lastDisplayClick: number = 0;
10 constructor(editor: MarkdownEditor) {
12 this.container = editor.config.displayEl;
14 if (this.container.contentDocument?.readyState === 'complete') {
17 this.container.addEventListener('load', this.onLoad.bind(this));
20 this.updateVisibility(Boolean(editor.settings.get('showPreview')));
21 editor.settings.onChange('showPreview', (show) => this.updateVisibility(Boolean(show)));
24 protected updateVisibility(show: boolean): void {
25 const wrap = this.container.closest('.markdown-editor-wrap') as HTMLElement;
26 wrap.style.display = show ? '' : 'none';
29 protected onLoad(): void {
30 this.doc = this.container.contentDocument;
32 if (!this.doc) return;
34 this.loadStylesIntoDisplay();
35 this.doc.body.className = 'page-content';
37 // Prevent markdown display link click redirect
38 this.doc.addEventListener('click', this.onDisplayClick.bind(this));
41 protected onDisplayClick(event: MouseEvent): void {
42 const isDblClick = Date.now() - this.lastDisplayClick < 300;
44 const link = (event.target as Element).closest('a');
46 event.preventDefault();
47 const href = link.getAttribute('href');
54 const drawing = (event.target as Element).closest('[drawio-diagram]') as HTMLElement;
55 if (drawing !== null && isDblClick) {
56 this.editor.actions.editDrawing(drawing);
60 this.lastDisplayClick = Date.now();
63 protected loadStylesIntoDisplay(): void {
64 if (!this.doc) return;
66 this.doc.documentElement.classList.add('markdown-editor-display');
68 // Set display to be dark mode if the parent is
69 if (document.documentElement.classList.contains('dark-mode')) {
70 this.doc.documentElement.style.backgroundColor = '#222';
71 this.doc.documentElement.classList.add('dark-mode');
74 this.doc.head.innerHTML = '';
75 const styles = document.head.querySelectorAll('style,link[rel=stylesheet]');
76 for (const style of styles) {
77 const copy = style.cloneNode(true) as HTMLElement;
78 this.doc.head.appendChild(copy);
83 * Patch the display DOM with the given HTML content.
85 public patchWithHtml(html: string): void {
86 if (!this.doc) return;
88 const { body } = this.doc;
90 if (body.children.length === 0) {
91 const wrap = document.createElement('div');
92 this.doc.body.append(wrap);
95 const target = body.children[0] as HTMLElement;
97 patchDomFromHtmlString(target, html);
101 * Scroll to the given block index within the display content.
102 * Will scroll to the end if the index is -1.
104 public scrollToIndex(index: number): void {
105 const elems = this.doc?.body?.children[0]?.children;
106 if (!elems || elems.length <= index) return;
108 const topElem = (index === -1) ? elems[elems.length - 1] : elems[index];
109 (topElem as Element).scrollIntoView({