1 import {Component} from './component';
3 export class MarkdownEditor extends Component {
8 this.pageId = this.$opts.pageId;
9 this.textDirection = this.$opts.textDirection;
10 this.imageUploadErrorText = this.$opts.imageUploadErrorText;
11 this.serverUploadLimitText = this.$opts.serverUploadLimitText;
13 this.display = this.$refs.display;
14 this.input = this.$refs.input;
15 this.divider = this.$refs.divider;
16 this.displayWrap = this.$refs.displayWrap;
18 const {settingContainer} = this.$refs;
19 const settingInputs = settingContainer.querySelectorAll('input[type="checkbox"]');
22 window.importVersioned('markdown').then(markdown => {
23 return markdown.init({
26 displayEl: this.display,
28 drawioUrl: this.getDrawioUrl(),
29 settingInputs: Array.from(settingInputs),
31 serverUploadLimit: this.serverUploadLimitText,
32 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,
48 cmEditorView: this.editor.cm,
54 this.elem.addEventListener('click', event => {
55 const button = event.target.closest('button[data-action]');
56 if (button === null) return;
58 const action = button.getAttribute('data-action');
59 if (action === 'insertImage') this.editor.actions.showImageInsert();
60 if (action === 'insertLink') this.editor.actions.showLinkSelector();
61 if (action === 'insertDrawing' && (event.ctrlKey || event.metaKey)) {
62 this.editor.actions.showImageManager();
65 if (action === 'insertDrawing') this.editor.actions.startDrawing();
66 if (action === 'fullscreen') this.editor.actions.fullScreen();
69 // Mobile section toggling
70 this.elem.addEventListener('click', event => {
71 const toolbarLabel = event.target.closest('.editor-toolbar-label');
72 if (!toolbarLabel) return;
74 const currentActiveSections = this.elem.querySelectorAll('.markdown-editor-wrap');
75 for (const activeElem of currentActiveSections) {
76 activeElem.classList.remove('active');
79 toolbarLabel.closest('.markdown-editor-wrap').classList.add('active');
82 this.handleDividerDrag();
86 this.divider.addEventListener('pointerdown', () => {
87 const wrapRect = this.elem.getBoundingClientRect();
88 const moveListener = event => {
89 const xRel = event.pageX - wrapRect.left;
90 const xPct = Math.min(Math.max(20, Math.floor((xRel / wrapRect.width) * 100)), 80);
91 this.displayWrap.style.flexBasis = `${100 - xPct}%`;
92 this.editor.settings.set('editorWidth', xPct);
94 const upListener = () => {
95 window.removeEventListener('pointermove', moveListener);
96 window.removeEventListener('pointerup', upListener);
97 this.display.style.pointerEvents = null;
98 document.body.style.userSelect = null;
101 this.display.style.pointerEvents = 'none';
102 document.body.style.userSelect = 'none';
103 window.addEventListener('pointermove', moveListener);
104 window.addEventListener('pointerup', upListener);
106 const widthSetting = this.editor.settings.get('editorWidth');
108 this.displayWrap.style.flexBasis = `${100 - widthSetting}%`;
112 scrollToTextIfNeeded() {
113 const queryParams = (new URL(window.location)).searchParams;
114 const scrollText = queryParams.get('content-text');
116 this.editor.actions.scrollToText(scrollText);
121 * Get the URL for the configured drawio instance.
125 const drawioAttrEl = document.querySelector('[drawio-url]');
130 return drawioAttrEl.getAttribute('drawio-url') || '';
134 * Get the content of this editor.
135 * Used by the parent page editor component.
136 * @return {{html: String, markdown: String}}
139 return this.editor.actions.getContent();