UNPKG

@opentiny/fluent-editor

Version:

A rich text editor based on Quill 2.0, which extends rich modules and formats on the basis of Quill. It's powerful and out-of-the-box.

357 lines (356 loc) 12.5 kB
"use strict"; var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } }); const Quill = require("quill"); const configUtils = require("../config-utils.cjs.js"); const icons = require("../icons.cjs.js"); const contextMenu = require("../modules/context-menu.cjs.js"); const controlPanel = require("../modules/control-panel.cjs.js"); const customResizeAction = require("../modules/custom-resize-action.cjs.js"); ;/* empty css */ const BlockEmbed = Quill.import("blots/embed"); const _MindMapPlaceholderBlot = class _MindMapPlaceholderBlot extends BlockEmbed { constructor(scroll, domNode) { super(scroll, domNode); __publicField(this, "quill", null); __publicField(this, "mindMap", null); __publicField(this, "data"); __publicField(this, "zoomCount", 0); __publicField(this, "contextMenu", null); __publicField(this, "currentNode", null); __publicField(this, "width", 100); __publicField(this, "height", 500); __publicField(this, "parentObserver", null); __publicField(this, "nextPObserver", null); const data = _MindMapPlaceholderBlot.value(domNode); this.width = data.width || 100; this.height = data.height || 500; this.domNode.style.width = `${this.width}${data.width ? "px" : "%"}`; this.domNode.style.height = `${this.height}px`; this.domNode.style.maxWidth = "100%"; this.domNode.style.border = "1px solid #e8e8e8"; this.domNode.setAttribute("contenteditable", "false"); this.data = _MindMapPlaceholderBlot.value(domNode); this.initMindMap(); } static value(domNode) { const dataStr = JSON.parse(domNode.getAttribute("data-mind-map")); const value = dataStr; if (domNode.hasAttribute("width")) { value.width = Number.parseInt(domNode.getAttribute("width"), 10); } if (domNode.hasAttribute("height")) { value.height = Number.parseInt(domNode.getAttribute("height"), 10); } return dataStr; } static create(value) { const node = super.create(); if (value) { node.setAttribute("data-mind-map", JSON.stringify(value)); } if (value.width) { node.setAttribute("width", String(value.width)); node.style.width = `${value.width}%`; } if (value.height) { node.setAttribute("height", String(value.height)); node.style.height = `${value.height}px`; } node.setAttribute("contenteditable", "false"); return node; } static findQuill(el) { let cur = el; while (cur) { const q = cur.__quillInstance; if (q) return q; cur = cur.parentElement; } return null; } attach() { super.attach(); this.quill = _MindMapPlaceholderBlot.findQuill(this.domNode); } initMindMap() { if (this.domNode.isConnected) { this.insertMindMapEditor(); } else { const observer = new MutationObserver(() => { if (this.domNode.isConnected) { this.insertMindMapEditor(); observer.disconnect(); } }); observer.observe(document.body, { childList: true, subtree: true }); } } insertMindMapEditor() { this.domNode.style.width = `${this.width}${this.data.width ? "px" : "%"}`; this.domNode.style.height = `${this.height}px`; while (this.domNode.firstChild) { this.domNode.removeChild(this.domNode.firstChild); } this.updateAlignmentStyle(); this.observeParentAlignment(); const { backgroundConfig, resizeConfig, lineConfig, themeConfig, deps } = configUtils.getAllConfigs(this.quill); const { SimpleMindMap, Themes, Drag, Export } = deps || window; Themes.init(SimpleMindMap); SimpleMindMap.usePlugin(Drag).usePlugin(Export); this.mindMap = new SimpleMindMap({ el: this.domNode, mousewheelAction: "zoom", disableMouseWheelZoom: true, layout: this.data.layout, theme: themeConfig, data: this.data.root ? this.data.root : this.data }); const styleConfig = { ...backgroundConfig }; if (lineConfig && typeof lineConfig === "object") { Object.assign(styleConfig, lineConfig); } this.mindMap.setThemeConfig(styleConfig); const handleScroll = () => { if (this.mindMap && this.domNode && this.domNode.isConnected) { this.mindMap.getElRectInfo(); } }; window.addEventListener("scroll", handleScroll, { passive: true }); this.domNode.addEventListener("remove", () => { window.removeEventListener("scroll", handleScroll); }); if (resizeConfig) { new customResizeAction.MindMapResizeAction(this); } controlPanel.createControlPanel(this, this.quill); contextMenu.initContextMenu(this, this.quill); this.observeOwnParentChange(); this.observeNextPElement(); this.addMouseHoverEvents(); this.mindMap.on("node_tree_render_end", () => { this.data = this.mindMap.getData({}); this.domNode.setAttribute("data-mind-map", JSON.stringify(this.data)); }); this.mindMap.on("node_dblclick", this.handleNodeDblClick.bind(this)); this.domNode.addEventListener("click", (e) => { if (this.quill) { this.mindMap.getElRectInfo(); const mindMapBlot = Quill.find(this.domNode); const index = this.quill.getIndex(mindMapBlot); if (index && typeof index === "number") { this.quill.setSelection(index + 1, 0); } } }); } addMouseHoverEvents() { this.domNode.addEventListener("mouseenter", () => { this.showControlPanel(); }); this.domNode.addEventListener("mouseleave", () => { this.mindMap.execCommand("CLEAR_ACTIVE_NODE"); this.hideControlPanel(); }); } getControlElements() { const leftUpControl = this.domNode.querySelector(".ql-mind-map-left-up-control"); const control = this.domNode.querySelector(".ql-mind-map-control"); const panelStatusIcon = this.domNode.querySelector('[data-control-type="panel-status"]'); return { leftUpControl, control, panelStatusIcon }; } showControlPanel() { const { leftUpControl, control, panelStatusIcon } = this.getControlElements(); if (!leftUpControl || !control) return; leftUpControl.style.display = "inline-flex"; control.style.display = "flex"; if (panelStatusIcon) { const iconElement = panelStatusIcon.querySelector("i") || panelStatusIcon; iconElement.innerHTML = icons.expandIcon; } } hideControlPanel() { const { leftUpControl, control, panelStatusIcon } = this.getControlElements(); if (!leftUpControl || !control) return; leftUpControl.style.display = "none"; control.style.display = "none"; if (panelStatusIcon) { const iconElement = panelStatusIcon.querySelector("i") || panelStatusIcon; iconElement.innerHTML = icons.contractIcon; } } // 监听父元素变化 observeOwnParentChange() { let currentParent = this.domNode.parentElement; const observer = new MutationObserver(() => { if (this.domNode.parentElement !== currentParent) { currentParent = this.domNode.parentElement; this.observeParentAlignment(); } }); observer.observe(document.body, { attributes: false, childList: true, subtree: true }); } // 监听父元素对齐变化 observeParentAlignment() { if (this.parentObserver) { this.parentObserver.disconnect(); } const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if (mutation.attributeName === "class") { this.updateAlignmentStyle(); } }); }); this.parentObserver = observer; const parent = this.domNode.parentElement; if (parent) { observer.observe(parent, { attributes: true, attributeFilter: ["class"] }); this.updateAlignmentStyle(); } } // 更新对齐样式 updateAlignmentStyle() { const parent = this.domNode.parentElement; if (!parent) return; this.domNode.style.margin = ""; this.domNode.style.display = "block"; if (parent.classList.contains("ql-align-center")) { this.domNode.style.margin = "0 auto"; } else if (parent.classList.contains("ql-align-right")) { this.domNode.style.marginLeft = "auto"; this.domNode.style.marginRight = "0"; } else { this.domNode.style.marginLeft = "0"; this.domNode.style.marginRight = "auto"; } } observeNextPElement() { if (this.nextPObserver) { this.nextPObserver.disconnect(); } const parentElement = this.domNode.parentElement; if (!parentElement) { return; } const trackedParentElement = parentElement; const parentElementId = parentElement.getAttribute("id") || `mind-map-parent-${Date.now()}`; parentElement.setAttribute("id", parentElementId); const observer = new MutationObserver(() => { if (!document.contains(trackedParentElement)) { const elementById = document.getElementById(parentElementId); if (!elementById) { this.remove(); observer.disconnect(); } } }); observer.observe(document.body, { childList: true, subtree: true }); this.nextPObserver = observer; } handleNodeDblClick(node, e) { if (node && node.uid && e) { this.currentNode = node; this.createEditInput(node, e); } } // 创建编辑输入框 createEditInput(node, e) { const input = document.createElement("textarea"); input.className = "ql-mind-map-edit-input"; input.value = node.nodeData.data.text || ""; const autoResize = () => { input.style.height = "auto"; input.style.height = `${input.scrollHeight}px`; }; Object.assign(input.style, { position: "absolute", boxSizing: "border-box", width: "100px", height: "35px", padding: "5px", lineHeight: "1.2", fontFamily: "微软雅黑", fontSize: "16px", whiteSpace: "pre", textAlign: "center", background: "#fff", border: "1px solid #edefed", borderRadius: "3px", outline: "none", transform: "translate(-50%, -50%)", resize: "none", zIndex: "1000", left: `${e.pageX ? e.pageX : 100}px`, top: `${e.pageY ? e.pageY : 100}px`, overflow: "hidden" }); document.body.appendChild(input); autoResize(); input.addEventListener("keydown", (event) => { if (event.key === "Enter" && event.shiftKey) { autoResize(); } }); input.focus(); const currentNode = node; const handleDrawClick = () => { this.updateNodeText(input.value, currentNode); input.remove(); this.mindMap.off("draw_click", handleDrawClick); }; this.mindMap.on("draw_click", handleDrawClick); input.addEventListener("keydown", (event) => { if (event.key === "Enter" && !event.shiftKey) { event.preventDefault(); this.updateNodeText(input.value, currentNode); input.remove(); this.mindMap.off("draw_click", handleDrawClick); } }); } updateNodeText(text, node) { if (node && this.mindMap) { node.setText(text); const editWraps = document.querySelectorAll(".smm-node-edit-wrap"); editWraps.forEach((editWrap) => { const input = editWrap.querySelector("input, textarea"); if (input) { input.value = text; } else { editWrap.textContent = text; } }); this.data = this.mindMap.getData({}); this.domNode.setAttribute("data-mind-map", JSON.stringify(this.data)); } } format(name, value) { } remove() { this.mindMap.destroy(); if (this.nextPObserver) { this.nextPObserver.disconnect(); this.nextPObserver = null; } super.remove(); } }; __publicField(_MindMapPlaceholderBlot, "blotName", "mind-map"); __publicField(_MindMapPlaceholderBlot, "tagName", "div"); __publicField(_MindMapPlaceholderBlot, "className", "ql-mind-map-item"); let MindMapPlaceholderBlot = _MindMapPlaceholderBlot; exports.default = MindMapPlaceholderBlot; //# sourceMappingURL=mind-map-blot.cjs.js.map