UNPKG

vditor

Version:

♏ 易于使用的 Markdown 编辑器,为适配不同的应用场景而生

265 lines (246 loc) 11.4 kB
import {Constants} from "../constants"; import {processHeading} from "../ir/process"; import {processKeydown as irProcessKeydown} from "../ir/processKeydown"; import {getMarkdown} from "../markdown/getMarkdown"; import {previewImage} from "../preview/image"; import {processHeading as processHeadingSV} from "../sv/process"; import {processKeydown as mdProcessKeydown} from "../sv/processKeydown"; import {setEditMode} from "../toolbar/EditMode"; import {hidePanel} from "../toolbar/setToolbar"; import {afterRenderEvent} from "../wysiwyg/afterRenderEvent"; import {processKeydown} from "../wysiwyg/processKeydown"; import {removeHeading, setHeading} from "../wysiwyg/setHeading"; import {getEventName, isCtrl} from "./compatibility"; import {execAfterRender, paste} from "./fixBrowserBehavior"; import {getSelectText} from "./getSelectText"; import {hasClosestByAttribute, hasClosestByMatchTag} from "./hasClosest"; import {matchHotKey} from "./hotKey"; import {getCursorPosition, getEditorRange} from "./selection"; export const focusEvent = (vditor: IVditor, editorElement: HTMLElement) => { editorElement.addEventListener("focus", () => { if (vditor.options.focus) { vditor.options.focus(getMarkdown(vditor)); } hidePanel(vditor, ["subToolbar", "hint"]); }); }; export const dblclickEvent = (vditor: IVditor, editorElement: HTMLElement) => { editorElement.addEventListener("dblclick", (event: MouseEvent & { target: HTMLElement }) => { if (event.target.tagName === "IMG") { if (vditor.options.image.preview) { vditor.options.image.preview(event.target); } else if (vditor.options.image.isPreview) { previewImage(event.target as HTMLImageElement, vditor.options.lang, vditor.options.theme); } } }); }; export const blurEvent = (vditor: IVditor, editorElement: HTMLElement) => { editorElement.addEventListener("blur", (event) => { if (vditor.currentMode === "ir") { const expandElement = vditor.ir.element.querySelector(".vditor-ir__node--expand"); if (expandElement) { expandElement.classList.remove("vditor-ir__node--expand"); } } else if (vditor.currentMode === "wysiwyg" && !vditor.wysiwyg.selectPopover.contains(event.relatedTarget as HTMLElement)) { vditor.wysiwyg.hideComment(); } vditor[vditor.currentMode].range = getEditorRange(vditor); if (vditor.options.blur) { vditor.options.blur(getMarkdown(vditor)); } }); }; export const dropEvent = (vditor: IVditor, editorElement: HTMLElement) => { editorElement.addEventListener("dragstart", (event) => { // 选中编辑器中的文字进行拖拽 event.dataTransfer.setData(Constants.DROP_EDITOR, Constants.DROP_EDITOR); }); editorElement.addEventListener("drop", (event: ClipboardEvent & { dataTransfer?: DataTransfer, target: HTMLElement }) => { if (event.dataTransfer.getData(Constants.DROP_EDITOR)) { // 编辑器内选中文字拖拽 execAfterRender(vditor); } else if (event.dataTransfer.types.includes("Files") || event.dataTransfer.types.includes("text/html")) { // 外部文件拖入编辑器中或者编辑器内选中文字拖拽 paste(vditor, event, { pasteCode: (code: string) => { document.execCommand("insertHTML", false, code); }, }); } }); }; export const copyEvent = (vditor: IVditor, editorElement: HTMLElement, copy: (event: ClipboardEvent, vditor: IVditor) => void) => { editorElement.addEventListener("copy", (event: ClipboardEvent) => copy(event, vditor)); }; export const cutEvent = (vditor: IVditor, editorElement: HTMLElement, copy: (event: ClipboardEvent, vditor: IVditor) => void) => { editorElement.addEventListener("cut", (event: ClipboardEvent) => { copy(event, vditor); // 获取 comment if (vditor.options.comment.enable && vditor.currentMode === "wysiwyg") { vditor.wysiwyg.getComments(vditor); } document.execCommand("delete"); }); }; export const scrollCenter = (vditor: IVditor) => { if (vditor.currentMode === "wysiwyg" && vditor.options.comment.enable) { vditor.options.comment.adjustTop(vditor.wysiwyg.getComments(vditor, true)); } if (!vditor.options.typewriterMode) { return; } const editorElement = vditor[vditor.currentMode].element; const cursorTop = getCursorPosition(editorElement).top; if (vditor.options.height === "auto" && !vditor.element.classList.contains("vditor--fullscreen")) { window.scrollTo(window.scrollX, cursorTop + vditor.element.offsetTop + vditor.toolbar.element.offsetHeight - window.innerHeight / 2 + 10); } if (vditor.options.height !== "auto" || vditor.element.classList.contains("vditor--fullscreen")) { editorElement.scrollTop = cursorTop + editorElement.scrollTop - editorElement.clientHeight / 2 + 10; } }; export const hotkeyEvent = (vditor: IVditor, editorElement: HTMLElement) => { editorElement.addEventListener("keydown", (event: KeyboardEvent & { target: HTMLElement }) => { if (!event.isComposing && vditor.options.keydown) { vditor.options.keydown(event); } // hint: 上下选择 if ((vditor.options.hint.extend.length > 1 || vditor.toolbar.elements.emoji) && vditor.hint.select(event, vditor)) { return; } // 重置 comment if (vditor.options.comment.enable && vditor.currentMode === "wysiwyg" && (event.key === "Backspace" || matchHotKey("⌘X", event))) { vditor.wysiwyg.getComments(vditor); } if (vditor.currentMode === "sv") { if (mdProcessKeydown(vditor, event)) { return; } } else if (vditor.currentMode === "wysiwyg") { if (processKeydown(vditor, event)) { return; } } else if (vditor.currentMode === "ir") { if (irProcessKeydown(vditor, event)) { return; } } if (vditor.options.ctrlEnter && matchHotKey("⌘Enter", event)) { vditor.options.ctrlEnter(getMarkdown(vditor)); event.preventDefault(); return; } // undo if (matchHotKey("⌘Z", event) && !vditor.toolbar.elements.undo) { vditor.undo.undo(vditor); event.preventDefault(); return; } // redo if (matchHotKey("⌘Y", event) && !vditor.toolbar.elements.redo) { vditor.undo.redo(vditor); event.preventDefault(); return; } // esc if (event.key === "Escape") { if (vditor.hint.element.style.display === "block") { vditor.hint.element.style.display = "none"; } else if (vditor.options.esc && !event.isComposing) { vditor.options.esc(getMarkdown(vditor)); } event.preventDefault(); return; } // h1 - h6 hotkey if (isCtrl(event) && event.altKey && !event.shiftKey && /^Digit[1-6]$/.test(event.code)) { if (vditor.currentMode === "wysiwyg") { const tagName = event.code.replace("Digit", "H"); if (hasClosestByMatchTag(getSelection().getRangeAt(0).startContainer, tagName)) { removeHeading(vditor); } else { setHeading(vditor, tagName); } afterRenderEvent(vditor); } else if (vditor.currentMode === "sv") { processHeadingSV(vditor, "#".repeat(parseInt(event.code.replace("Digit", ""), 10)) + " "); } else if (vditor.currentMode === "ir") { processHeading(vditor, "#".repeat(parseInt(event.code.replace("Digit", ""), 10)) + " "); } event.preventDefault(); return true; } // toggle edit mode if (isCtrl(event) && event.altKey && !event.shiftKey && /^Digit[7-9]$/.test(event.code)) { if (event.code === "Digit7") { setEditMode(vditor, "wysiwyg", event); } else if (event.code === "Digit8") { setEditMode(vditor, "ir", event); } else if (event.code === "Digit9") { setEditMode(vditor, "sv", event); } return true; } // toolbar action vditor.options.toolbar.find((menuItem: IMenuItem) => { if (!menuItem.hotkey || menuItem.toolbar) { if (menuItem.toolbar) { const sub = menuItem.toolbar.find((subMenuItem: IMenuItem) => { if (!subMenuItem.hotkey) { return false; } if (matchHotKey(subMenuItem.hotkey, event)) { vditor.toolbar.elements[subMenuItem.name].children[0] .dispatchEvent(new CustomEvent(getEventName())); event.preventDefault(); return true; } }); return sub ? true : false; } return false; } if (matchHotKey(menuItem.hotkey, event)) { vditor.toolbar.elements[menuItem.name].children[0].dispatchEvent(new CustomEvent(getEventName())); event.preventDefault(); return true; } }); }); }; export const selectEvent = (vditor: IVditor, editorElement: HTMLElement) => { editorElement.addEventListener("selectstart", (event: Event & { target: HTMLElement }) => { editorElement.onmouseup = () => { setTimeout(() => { // 鼠标放开后 range 没有即时更新 const selectText = getSelectText(vditor[vditor.currentMode].element); if (selectText.trim()) { if (vditor.currentMode === "wysiwyg" && vditor.options.comment.enable) { if (!hasClosestByAttribute(event.target, "data-type", "footnotes-block") && !hasClosestByAttribute(event.target, "data-type", "link-ref-defs-block")) { vditor.wysiwyg.showComment(); } else { vditor.wysiwyg.hideComment(); } } if (vditor.options.select) { vditor.options.select(selectText); } } else { if (vditor.currentMode === "wysiwyg" && vditor.options.comment.enable) { vditor.wysiwyg.hideComment(); } if (typeof vditor.options.unSelect === 'function') { vditor.options.unSelect(); } } }); }; }); };