mirror of
				https://github.com/BookStackApp/BookStack.git
				synced 2025-10-31 03:50:27 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			143 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			143 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import {Component} from './component';
 | |
| 
 | |
| export class MarkdownEditor extends Component {
 | |
| 
 | |
|     setup() {
 | |
|         this.elem = this.$el;
 | |
| 
 | |
|         this.pageId = this.$opts.pageId;
 | |
|         this.textDirection = this.$opts.textDirection;
 | |
|         this.imageUploadErrorText = this.$opts.imageUploadErrorText;
 | |
|         this.serverUploadLimitText = this.$opts.serverUploadLimitText;
 | |
| 
 | |
|         this.display = this.$refs.display;
 | |
|         this.input = this.$refs.input;
 | |
|         this.divider = this.$refs.divider;
 | |
|         this.displayWrap = this.$refs.displayWrap;
 | |
| 
 | |
|         const {settingContainer} = this.$refs;
 | |
|         const settingInputs = settingContainer.querySelectorAll('input[type="checkbox"]');
 | |
| 
 | |
|         this.editor = null;
 | |
|         window.importVersioned('markdown').then(markdown => {
 | |
|             return markdown.init({
 | |
|                 pageId: this.pageId,
 | |
|                 container: this.elem,
 | |
|                 displayEl: this.display,
 | |
|                 inputEl: this.input,
 | |
|                 drawioUrl: this.getDrawioUrl(),
 | |
|                 settingInputs: Array.from(settingInputs),
 | |
|                 text: {
 | |
|                     serverUploadLimit: this.serverUploadLimitText,
 | |
|                     imageUploadError: this.imageUploadErrorText,
 | |
|                 },
 | |
|             });
 | |
|         }).then(editor => {
 | |
|             this.editor = editor;
 | |
|             this.setupListeners();
 | |
|             this.emitEditorEvents();
 | |
|             this.scrollToTextIfNeeded();
 | |
|             this.editor.actions.updateAndRender();
 | |
|         });
 | |
|     }
 | |
| 
 | |
|     emitEditorEvents() {
 | |
|         window.$events.emitPublic(this.elem, 'editor-markdown::setup', {
 | |
|             markdownIt: this.editor.markdown.getRenderer(),
 | |
|             displayEl: this.display,
 | |
|             cmEditorView: this.editor.cm,
 | |
|         });
 | |
|     }
 | |
| 
 | |
|     setupListeners() {
 | |
|         // Button actions
 | |
|         this.elem.addEventListener('click', event => {
 | |
|             const button = event.target.closest('button[data-action]');
 | |
|             if (button === null) return;
 | |
| 
 | |
|             const action = button.getAttribute('data-action');
 | |
|             if (action === 'insertImage') this.editor.actions.showImageInsert();
 | |
|             if (action === 'insertLink') this.editor.actions.showLinkSelector();
 | |
|             if (action === 'insertDrawing' && (event.ctrlKey || event.metaKey)) {
 | |
|                 this.editor.actions.showImageManager();
 | |
|                 return;
 | |
|             }
 | |
|             if (action === 'insertDrawing') this.editor.actions.startDrawing();
 | |
|             if (action === 'fullscreen') this.editor.actions.fullScreen();
 | |
|         });
 | |
| 
 | |
|         // Mobile section toggling
 | |
|         this.elem.addEventListener('click', event => {
 | |
|             const toolbarLabel = event.target.closest('.editor-toolbar-label');
 | |
|             if (!toolbarLabel) return;
 | |
| 
 | |
|             const currentActiveSections = this.elem.querySelectorAll('.markdown-editor-wrap');
 | |
|             for (const activeElem of currentActiveSections) {
 | |
|                 activeElem.classList.remove('active');
 | |
|             }
 | |
| 
 | |
|             toolbarLabel.closest('.markdown-editor-wrap').classList.add('active');
 | |
|         });
 | |
| 
 | |
|         this.handleDividerDrag();
 | |
|     }
 | |
| 
 | |
|     handleDividerDrag() {
 | |
|         this.divider.addEventListener('pointerdown', () => {
 | |
|             const wrapRect = this.elem.getBoundingClientRect();
 | |
|             const moveListener = event => {
 | |
|                 const xRel = event.pageX - wrapRect.left;
 | |
|                 const xPct = Math.min(Math.max(20, Math.floor((xRel / wrapRect.width) * 100)), 80);
 | |
|                 this.displayWrap.style.flexBasis = `${100 - xPct}%`;
 | |
|                 this.editor.settings.set('editorWidth', xPct);
 | |
|             };
 | |
|             const upListener = () => {
 | |
|                 window.removeEventListener('pointermove', moveListener);
 | |
|                 window.removeEventListener('pointerup', upListener);
 | |
|                 this.display.style.pointerEvents = null;
 | |
|                 document.body.style.userSelect = null;
 | |
|             };
 | |
| 
 | |
|             this.display.style.pointerEvents = 'none';
 | |
|             document.body.style.userSelect = 'none';
 | |
|             window.addEventListener('pointermove', moveListener);
 | |
|             window.addEventListener('pointerup', upListener);
 | |
|         });
 | |
|         const widthSetting = this.editor.settings.get('editorWidth');
 | |
|         if (widthSetting) {
 | |
|             this.displayWrap.style.flexBasis = `${100 - widthSetting}%`;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     scrollToTextIfNeeded() {
 | |
|         const queryParams = (new URL(window.location)).searchParams;
 | |
|         const scrollText = queryParams.get('content-text');
 | |
|         if (scrollText) {
 | |
|             this.editor.actions.scrollToText(scrollText);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Get the URL for the configured drawio instance.
 | |
|      * @returns {String}
 | |
|      */
 | |
|     getDrawioUrl() {
 | |
|         const drawioAttrEl = document.querySelector('[drawio-url]');
 | |
|         if (!drawioAttrEl) {
 | |
|             return '';
 | |
|         }
 | |
| 
 | |
|         return drawioAttrEl.getAttribute('drawio-url') || '';
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Get the content of this editor.
 | |
|      * Used by the parent page editor component.
 | |
|      * @return {Promise<{html: String, markdown: String}>}
 | |
|      */
 | |
|     async getContent() {
 | |
|         return this.editor.actions.getContent();
 | |
|     }
 | |
| 
 | |
| }
 |