]> BookStack Code Mirror - bookstack/blob - resources/js/markdown/codemirror.ts
MD Editor: Started work on input interface
[bookstack] / resources / js / markdown / codemirror.ts
1 import {provideKeyBindings} from './shortcuts';
2 import {debounce} from '../services/util';
3 import {Clipboard} from '../services/clipboard';
4 import {EditorView, ViewUpdate} from "@codemirror/view";
5 import {MarkdownEditor} from "./index.mjs";
6 import {CodeModule} from "../global";
7
8 /**
9  * Initiate the codemirror instance for the MarkDown editor.
10  */
11 export function init(editor: MarkdownEditor, Code: CodeModule): EditorView {
12     function onViewUpdate(v: ViewUpdate) {
13         if (v.docChanged) {
14             editor.actions.updateAndRender();
15         }
16     }
17
18     const onScrollDebounced = debounce(editor.actions.syncDisplayPosition.bind(editor.actions), 100, false);
19     let syncActive = editor.settings.get('scrollSync');
20     editor.settings.onChange('scrollSync', val => {
21         syncActive = val;
22     });
23
24     const domEventHandlers = {
25         // Handle scroll to sync display view
26         scroll: (event: Event) => syncActive && onScrollDebounced(event),
27         // Handle image & content drag n drop
28         drop: (event: DragEvent) => {
29             if (!event.dataTransfer) {
30                 return;
31             }
32
33             const templateId = event.dataTransfer.getData('bookstack/template');
34             if (templateId) {
35                 event.preventDefault();
36                 editor.actions.insertTemplate(templateId, event.pageX, event.pageY);
37             }
38
39             const clipboard = new Clipboard(event.dataTransfer);
40             const clipboardImages = clipboard.getImages();
41             if (clipboardImages.length > 0) {
42                 event.stopPropagation();
43                 event.preventDefault();
44                 editor.actions.insertClipboardImages(clipboardImages, event.pageX, event.pageY);
45             }
46         },
47         // Handle dragover event to allow as drop-target in chrome
48         dragover: (event: DragEvent) => {
49             event.preventDefault();
50         },
51         // Handle image paste
52         paste: (event: ClipboardEvent) => {
53             if (!event.clipboardData) {
54                 return;
55             }
56
57             const clipboard = new Clipboard(event.clipboardData);
58
59             // Don't handle the event ourselves if no items exist of contains table-looking data
60             if (!clipboard.hasItems() || clipboard.containsTabularData()) {
61                 return;
62             }
63
64             const images = clipboard.getImages();
65             for (const image of images) {
66                 editor.actions.uploadImage(image);
67             }
68         },
69     };
70
71     const cm = Code.markdownEditor(
72         editor.config.inputEl,
73         onViewUpdate,
74         domEventHandlers,
75         provideKeyBindings(editor),
76     );
77
78     // Add editor view to the window for easy access/debugging.
79     // Not part of official API/Docs
80     // @ts-ignore
81     window.mdEditorView = cm;
82
83     return cm;
84 }