Finished update pass of all md editor actions to cm6
This commit is contained in:
		
							parent
							
								
									32c765d0c3
								
							
						
					
					
						commit
						6f45d34bf8
					
				| 
						 | 
				
			
			@ -296,10 +296,11 @@ export class Actions {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    replaceLineStartForOrderedList() {
 | 
			
		||||
        // TODO
 | 
			
		||||
        const cursor = this.editor.cm.getCursor();
 | 
			
		||||
        const prevLineContent = this.editor.cm.getLine(cursor.line - 1) || '';
 | 
			
		||||
        const listMatch = prevLineContent.match(/^(\s*)(\d)([).])\s/) || [];
 | 
			
		||||
        const selectionRange = this.#getSelectionRange();
 | 
			
		||||
        const line = this.editor.cm.state.doc.lineAt(selectionRange.from);
 | 
			
		||||
        const prevLine = this.editor.cm.state.doc.line(line.number - 1);
 | 
			
		||||
 | 
			
		||||
        const listMatch = prevLine.text.match(/^(\s*)(\d)([).])\s/) || [];
 | 
			
		||||
 | 
			
		||||
        const number = (Number(listMatch[2]) || 0) + 1;
 | 
			
		||||
        const whiteSpace = listMatch[1] || '';
 | 
			
		||||
| 
						 | 
				
			
			@ -314,37 +315,28 @@ export class Actions {
 | 
			
		|||
     * Creates a callout block if none existing, and removes it if cycling past the danger type.
 | 
			
		||||
     */
 | 
			
		||||
    cycleCalloutTypeAtSelection() {
 | 
			
		||||
        // TODO
 | 
			
		||||
        const selectionRange = this.editor.cm.listSelections()[0];
 | 
			
		||||
        const lineContent = this.editor.cm.getLine(selectionRange.anchor.line);
 | 
			
		||||
        const lineLength = lineContent.length;
 | 
			
		||||
        const contentRange = {
 | 
			
		||||
            anchor: {line: selectionRange.anchor.line, ch: 0},
 | 
			
		||||
            head: {line: selectionRange.anchor.line, ch: lineLength},
 | 
			
		||||
        };
 | 
			
		||||
        const selectionRange = this.#getSelectionRange();
 | 
			
		||||
        const line = this.editor.cm.state.doc.lineAt(selectionRange.from);
 | 
			
		||||
 | 
			
		||||
        const formats = ['info', 'success', 'warning', 'danger'];
 | 
			
		||||
        const joint = formats.join('|');
 | 
			
		||||
        const regex = new RegExp(`class="((${joint})\\s+callout|callout\\s+(${joint}))"`, 'i');
 | 
			
		||||
        const matches = regex.exec(lineContent);
 | 
			
		||||
        const matches = regex.exec(line.text);
 | 
			
		||||
        const format = (matches ? (matches[2] || matches[3]) : '').toLowerCase();
 | 
			
		||||
 | 
			
		||||
        if (format === formats[formats.length - 1]) {
 | 
			
		||||
            this.wrapLine(`<p class="callout ${formats[formats.length - 1]}">`, '</p>');
 | 
			
		||||
            this.#wrapLine(`<p class="callout ${formats[formats.length - 1]}">`, '</p>');
 | 
			
		||||
        } else if (format === '') {
 | 
			
		||||
            this.wrapLine('<p class="callout info">', '</p>');
 | 
			
		||||
            this.#wrapLine('<p class="callout info">', '</p>');
 | 
			
		||||
        } else {
 | 
			
		||||
            const newFormatIndex = formats.indexOf(format) + 1;
 | 
			
		||||
            const newFormat = formats[newFormatIndex];
 | 
			
		||||
            const newContent = lineContent.replace(matches[0], matches[0].replace(format, newFormat));
 | 
			
		||||
            this.editor.cm.replaceRange(newContent, contentRange.anchor, contentRange.head);
 | 
			
		||||
 | 
			
		||||
            const chDiff = newContent.length - lineContent.length;
 | 
			
		||||
            selectionRange.anchor.ch += chDiff;
 | 
			
		||||
            if (selectionRange.anchor !== selectionRange.head) {
 | 
			
		||||
                selectionRange.head.ch += chDiff;
 | 
			
		||||
            }
 | 
			
		||||
            this.editor.cm.setSelection(selectionRange.anchor, selectionRange.head);
 | 
			
		||||
            const newContent = line.text.replace(matches[0], matches[0].replace(format, newFormat));
 | 
			
		||||
            const lineDiff = newContent.length - line.text.length;
 | 
			
		||||
            this.editor.cm.dispatch({
 | 
			
		||||
                changes: {from: line.from, to: line.to, insert: newContent},
 | 
			
		||||
                selection: {anchor: selectionRange.anchor + lineDiff, head: selectionRange.head + lineDiff},
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -372,38 +364,43 @@ export class Actions {
 | 
			
		|||
     * @param {Number} posX
 | 
			
		||||
     * @param {Number} posY
 | 
			
		||||
     */
 | 
			
		||||
    insertTemplate(templateId, posX, posY) {
 | 
			
		||||
        // TODO
 | 
			
		||||
        const cursorPos = this.editor.cm.coordsChar({left: posX, top: posY});
 | 
			
		||||
        this.editor.cm.setCursor(cursorPos);
 | 
			
		||||
        window.$http.get(`/templates/${templateId}`).then(resp => {
 | 
			
		||||
            const content = resp.data.markdown || resp.data.html;
 | 
			
		||||
            this.editor.cm.replaceSelection(content);
 | 
			
		||||
    async insertTemplate(templateId, posX, posY) {
 | 
			
		||||
        const cursorPos = this.editor.cm.posAtCoords({x: posX, y: posY}, false);
 | 
			
		||||
        const {data} = await window.$http.get(`/templates/${templateId}`);
 | 
			
		||||
        const content = data.markdown || data.html;
 | 
			
		||||
        this.editor.cm.dispatch({
 | 
			
		||||
            changes: {from: cursorPos, to: cursorPos, insert: content},
 | 
			
		||||
            selection: {anchor: cursorPos},
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Insert multiple images from the clipboard.
 | 
			
		||||
     * Insert multiple images from the clipboard from an event at the provided
 | 
			
		||||
     * screen coordinates (Typically form a paste event).
 | 
			
		||||
     * @param {File[]} images
 | 
			
		||||
     * @param {Number} posX
 | 
			
		||||
     * @param {Number} posY
 | 
			
		||||
     */
 | 
			
		||||
    insertClipboardImages(images) {
 | 
			
		||||
        // TODO
 | 
			
		||||
        const cursorPos = this.editor.cm.coordsChar({left: event.pageX, top: event.pageY});
 | 
			
		||||
        this.editor.cm.setCursor(cursorPos);
 | 
			
		||||
    insertClipboardImages(images, posX, posY) {
 | 
			
		||||
        const cursorPos = this.editor.cm.posAtCoords({x: posX, y: posY}, false);
 | 
			
		||||
        for (const image of images) {
 | 
			
		||||
            this.#uploadImage(image);
 | 
			
		||||
            this.uploadImage(image, cursorPos);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Handle image upload and add image into markdown content
 | 
			
		||||
     * @param {File} file
 | 
			
		||||
     * @param {?Number} position
 | 
			
		||||
     */
 | 
			
		||||
    #uploadImage(file) {
 | 
			
		||||
        // TODO
 | 
			
		||||
    async uploadImage(file, position= null) {
 | 
			
		||||
        if (file === null || file.type.indexOf('image') !== 0) return;
 | 
			
		||||
        let ext = 'png';
 | 
			
		||||
 | 
			
		||||
        if (position === null) {
 | 
			
		||||
            position = this.#getSelectionRange().from;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (file.name) {
 | 
			
		||||
            let fileNameMatches = file.name.match(/\.(.+)$/);
 | 
			
		||||
            if (fileNameMatches.length > 1) ext = fileNameMatches[1];
 | 
			
		||||
| 
						 | 
				
			
			@ -412,25 +409,26 @@ export class Actions {
 | 
			
		|||
        // Insert image into markdown
 | 
			
		||||
        const id = "image-" + Math.random().toString(16).slice(2);
 | 
			
		||||
        const placeholderImage = window.baseUrl(`/loading.gif#upload${id}`);
 | 
			
		||||
        const selectedText = this.editor.cm.getSelection();
 | 
			
		||||
        const placeHolderText = ``;
 | 
			
		||||
        const cursor = this.editor.cm.getCursor();
 | 
			
		||||
        this.editor.cm.replaceSelection(placeHolderText);
 | 
			
		||||
        this.editor.cm.setCursor({line: cursor.line, ch: cursor.ch + selectedText.length + 3});
 | 
			
		||||
        const placeHolderText = ``;
 | 
			
		||||
        this.editor.cm.dispatch({
 | 
			
		||||
            changes: {from: position, to: position, insert: placeHolderText},
 | 
			
		||||
            selection: {anchor: position},
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        const remoteFilename = "image-" + Date.now() + "." + ext;
 | 
			
		||||
        const formData = new FormData();
 | 
			
		||||
        formData.append('file', file, remoteFilename);
 | 
			
		||||
        formData.append('uploaded_to', this.editor.config.pageId);
 | 
			
		||||
 | 
			
		||||
        window.$http.post('/images/gallery', formData).then(resp => {
 | 
			
		||||
            const newContent = `[](${resp.data.url})`;
 | 
			
		||||
        try {
 | 
			
		||||
            const {data} = await window.$http.post('/images/gallery', formData);
 | 
			
		||||
            const newContent = `[](${data.url})`;
 | 
			
		||||
            this.#findAndReplaceContent(placeHolderText, newContent);
 | 
			
		||||
        }).catch(err => {
 | 
			
		||||
        } catch (err) {
 | 
			
		||||
            window.$events.emit('error', this.editor.config.text.imageUploadError);
 | 
			
		||||
            this.#findAndReplaceContent(placeHolderText, selectedText);
 | 
			
		||||
            this.#findAndReplaceContent(placeHolderText, '');
 | 
			
		||||
            console.log(err);
 | 
			
		||||
        });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,7 +25,37 @@ export async function init(editor) {
 | 
			
		|||
 | 
			
		||||
    const domEventHandlers = {
 | 
			
		||||
        // Handle scroll to sync display view
 | 
			
		||||
        scroll: (event) => syncActive && onScrollDebounced(event)
 | 
			
		||||
        scroll: (event) => syncActive && onScrollDebounced(event),
 | 
			
		||||
        // Handle image & content drag n drop
 | 
			
		||||
        drop: (event) => {
 | 
			
		||||
            const templateId = event.dataTransfer.getData('bookstack/template');
 | 
			
		||||
            if (templateId) {
 | 
			
		||||
                event.preventDefault();
 | 
			
		||||
                editor.actions.insertTemplate(templateId, event.pageX, event.pageY);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const clipboard = new Clipboard(event.dataTransfer);
 | 
			
		||||
            const clipboardImages = clipboard.getImages();
 | 
			
		||||
            if (clipboardImages.length > 0) {
 | 
			
		||||
                event.stopPropagation();
 | 
			
		||||
                event.preventDefault();
 | 
			
		||||
                editor.actions.insertClipboardImages(clipboardImages, event.pageX, event.pageY);
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        // Handle image paste
 | 
			
		||||
        paste: (event) => {
 | 
			
		||||
            const clipboard = new Clipboard(event.clipboardData || event.dataTransfer);
 | 
			
		||||
 | 
			
		||||
            // Don't handle the event ourselves if no items exist of contains table-looking data
 | 
			
		||||
            if (!clipboard.hasItems() || clipboard.containsTabularData()) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const images = clipboard.getImages();
 | 
			
		||||
            for (const image of images) {
 | 
			
		||||
                editor.actions.uploadImage(image);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const cm = Code.markdownEditor(
 | 
			
		||||
| 
						 | 
				
			
			@ -40,42 +70,5 @@ export async function init(editor) {
 | 
			
		|||
    // TODO
 | 
			
		||||
    // cm.setOption('direction', 'ltr');
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // Handle image paste
 | 
			
		||||
    // TODO
 | 
			
		||||
    // cm.on('paste', (cm, event) => {
 | 
			
		||||
    //     const clipboard = new Clipboard(event.clipboardData || event.dataTransfer);
 | 
			
		||||
    //
 | 
			
		||||
    //     // Don't handle the event ourselves if no items exist of contains table-looking data
 | 
			
		||||
    //     if (!clipboard.hasItems() || clipboard.containsTabularData()) {
 | 
			
		||||
    //         return;
 | 
			
		||||
    //     }
 | 
			
		||||
    //
 | 
			
		||||
    //     const images = clipboard.getImages();
 | 
			
		||||
    //     for (const image of images) {
 | 
			
		||||
    //         editor.actions.uploadImage(image);
 | 
			
		||||
    //     }
 | 
			
		||||
    // });
 | 
			
		||||
 | 
			
		||||
    // Handle image & content drag n drop
 | 
			
		||||
    // TODO
 | 
			
		||||
    // cm.on('drop', (cm, event) => {
 | 
			
		||||
    //
 | 
			
		||||
    //     const templateId = event.dataTransfer.getData('bookstack/template');
 | 
			
		||||
    //     if (templateId) {
 | 
			
		||||
    //         event.preventDefault();
 | 
			
		||||
    //         editor.actions.insertTemplate(templateId, event.pageX, event.pageY);
 | 
			
		||||
    //     }
 | 
			
		||||
    //
 | 
			
		||||
    //     const clipboard = new Clipboard(event.dataTransfer);
 | 
			
		||||
    //     const clipboardImages = clipboard.getImages();
 | 
			
		||||
    //     if (clipboardImages.length > 0) {
 | 
			
		||||
    //         event.stopPropagation();
 | 
			
		||||
    //         event.preventDefault();
 | 
			
		||||
    //         editor.actions.insertClipboardImages(clipboardImages);
 | 
			
		||||
    //     }
 | 
			
		||||
    //
 | 
			
		||||
    // });
 | 
			
		||||
 | 
			
		||||
    return cm;
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue