1 import {debounce} from "../services/util";
2 import {Component} from "./component";
3 import {init as initEditor} from "../markdown/editor";
5 export class MarkdownEditor extends Component {
10 this.pageId = this.$opts.pageId;
11 this.textDirection = this.$opts.textDirection;
12 this.imageUploadErrorText = this.$opts.imageUploadErrorText;
13 this.serverUploadLimitText = this.$opts.serverUploadLimitText;
15 this.display = this.$refs.display;
16 this.input = this.$refs.input;
17 this.divider = this.$refs.divider;
18 this.displayWrap = this.$refs.displayWrap;
20 const settingContainer = this.$refs.settingContainer;
21 const settingInputs = settingContainer.querySelectorAll('input[type="checkbox"]');
27 displayEl: this.display,
29 drawioUrl: this.getDrawioUrl(),
30 settingInputs: Array.from(settingInputs),
32 serverUploadLimit: this.serverUploadLimitText,
33 imageUploadError: this.imageUploadErrorText,
37 this.setupListeners();
38 this.emitEditorEvents();
39 this.scrollToTextIfNeeded();
40 this.editor.actions.updateAndRender();
45 window.$events.emitPublic(this.elem, 'editor-markdown::setup', {
46 markdownIt: this.editor.markdown.getRenderer(),
47 displayEl: this.display,
49 // codeMirrorInstance: this.editor.cm,
56 this.elem.addEventListener('click', event => {
57 let button = event.target.closest('button[data-action]');
58 if (button === null) return;
60 const action = button.getAttribute('data-action');
61 if (action === 'insertImage') this.editor.actions.insertImage();
62 if (action === 'insertLink') this.editor.actions.showLinkSelector();
63 if (action === 'insertDrawing' && (event.ctrlKey || event.metaKey)) {
64 this.editor.actions.showImageManager();
67 if (action === 'insertDrawing') this.editor.actions.startDrawing();
68 if (action === 'fullscreen') this.editor.actions.fullScreen();
71 // Mobile section toggling
72 this.elem.addEventListener('click', event => {
73 const toolbarLabel = event.target.closest('.editor-toolbar-label');
74 if (!toolbarLabel) return;
76 const currentActiveSections = this.elem.querySelectorAll('.markdown-editor-wrap');
77 for (const activeElem of currentActiveSections) {
78 activeElem.classList.remove('active');
81 toolbarLabel.closest('.markdown-editor-wrap').classList.add('active');
84 // Refresh CodeMirror on container resize
86 // const resizeDebounced = debounce(() => this.editor.cm.refresh(), 100, false);
87 // const observer = new ResizeObserver(resizeDebounced);
88 // observer.observe(this.elem);
90 this.handleDividerDrag();
94 this.divider.addEventListener('pointerdown', event => {
95 const wrapRect = this.elem.getBoundingClientRect();
96 const moveListener = (event) => {
97 const xRel = event.pageX - wrapRect.left;
98 const xPct = Math.min(Math.max(20, Math.floor((xRel / wrapRect.width) * 100)), 80);
99 this.displayWrap.style.flexBasis = `${100-xPct}%`;
100 this.editor.settings.set('editorWidth', xPct);
102 const upListener = (event) => {
103 window.removeEventListener('pointermove', moveListener);
104 window.removeEventListener('pointerup', upListener);
105 this.display.style.pointerEvents = null;
106 document.body.style.userSelect = null;
108 // this.editor.cm.refresh();
111 this.display.style.pointerEvents = 'none';
112 document.body.style.userSelect = 'none';
113 window.addEventListener('pointermove', moveListener);
114 window.addEventListener('pointerup', upListener);
116 const widthSetting = this.editor.settings.get('editorWidth');
118 this.displayWrap.style.flexBasis = `${100-widthSetting}%`;
122 scrollToTextIfNeeded() {
123 const queryParams = (new URL(window.location)).searchParams;
124 const scrollText = queryParams.get('content-text');
126 this.editor.actions.scrollToText(scrollText);
131 * Get the URL for the configured drawio instance.
135 const drawioAttrEl = document.querySelector('[drawio-url]');
140 return drawioAttrEl.getAttribute('drawio-url') || '';
144 * Get the content of this editor.
145 * Used by the parent page editor component.
146 * @return {{html: String, markdown: String}}
149 return this.editor.actions.getContent();