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.settingContainer = this.$refs.settingContainer;
23 displayEl: this.display,
25 drawioUrl: this.getDrawioUrl(),
27 serverUploadLimit: this.serverUploadLimitText,
28 imageUploadError: this.imageUploadErrorText,
30 settings: this.loadSettings(),
33 this.setupListeners();
34 this.emitEditorEvents();
35 this.scrollToTextIfNeeded();
36 this.editor.actions.updateAndRender();
41 window.$events.emitPublic(this.elem, 'editor-markdown::setup', {
42 markdownIt: this.editor.markdown.getRenderer(),
43 displayEl: this.display,
44 codeMirrorInstance: this.editor.cm,
51 this.elem.addEventListener('click', event => {
52 let button = event.target.closest('button[data-action]');
53 if (button === null) return;
55 const action = button.getAttribute('data-action');
56 if (action === 'insertImage') this.editor.actions.insertImage();
57 if (action === 'insertLink') this.editor.actions.showLinkSelector();
58 if (action === 'insertDrawing' && (event.ctrlKey || event.metaKey)) {
59 this.editor.actions.showImageManager();
62 if (action === 'insertDrawing') this.editor.actions.startDrawing();
63 if (action === 'fullscreen') this.editor.actions.fullScreen();
66 // Mobile section toggling
67 this.elem.addEventListener('click', event => {
68 const toolbarLabel = event.target.closest('.editor-toolbar-label');
69 if (!toolbarLabel) return;
71 const currentActiveSections = this.elem.querySelectorAll('.markdown-editor-wrap');
72 for (const activeElem of currentActiveSections) {
73 activeElem.classList.remove('active');
76 toolbarLabel.closest('.markdown-editor-wrap').classList.add('active');
80 this.settingContainer.addEventListener('change', e => {
81 const actualInput = e.target.parentNode.querySelector('input[type="hidden"]');
82 const name = actualInput.getAttribute('name');
83 const value = actualInput.getAttribute('value');
84 window.$http.patch('/preferences/update-boolean', {name, value});
85 this.editor.settings.set(name, value === 'true');
88 // Refresh CodeMirror on container resize
89 const resizeDebounced = debounce(() => this.editor.cm.refresh(), 100, false);
90 const observer = new ResizeObserver(resizeDebounced);
91 observer.observe(this.elem);
96 const inputs = this.settingContainer.querySelectorAll('input[type="hidden"]');
98 for (const input of inputs) {
99 settings[input.getAttribute('name')] = input.value === 'true';
105 scrollToTextIfNeeded() {
106 const queryParams = (new URL(window.location)).searchParams;
107 const scrollText = queryParams.get('content-text');
109 this.editor.actions.scrollToText(scrollText);
114 * Get the URL for the configured drawio instance.
118 const drawioAttrEl = document.querySelector('[drawio-url]');
123 return drawioAttrEl.getAttribute('drawio-url') || '';