From c6a3f4ac7b33724db4274b173b37a2eda3598f1d Mon Sep 17 00:00:00 2001 From: wanglin2 <1013335014@qq.com> Date: Fri, 11 Aug 2023 17:39:04 +0800 Subject: [PATCH] =?UTF-8?q?Feat=EF=BC=9A=E5=8E=BB=E9=99=A4=E5=88=9B?= =?UTF-8?q?=E5=BB=BA=E9=9A=90=E8=97=8F=E8=BE=93=E5=85=A5=E6=A1=86=EF=BC=8C?= =?UTF-8?q?=E9=80=9A=E8=BF=87navigator.clipboard=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E5=A4=8D=E5=88=B6=E7=B2=98=E8=B4=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/constants/defaultOptions.js | 3 - simple-mind-map/src/core/render/Render.js | 30 +++++-- simple-mind-map/src/core/render/TextEdit.js | 88 +++++-------------- simple-mind-map/src/plugins/RichText.js | 5 ++ web/src/pages/Edit/components/Outline.vue | 2 - 5 files changed, 48 insertions(+), 80 deletions(-) diff --git a/simple-mind-map/src/constants/defaultOptions.js b/simple-mind-map/src/constants/defaultOptions.js index dfd07c83..d144a5a2 100644 --- a/simple-mind-map/src/constants/defaultOptions.js +++ b/simple-mind-map/src/constants/defaultOptions.js @@ -127,10 +127,7 @@ export const defaultOpt = { customInnerElsAppendTo: null, // 拖拽元素时,指示元素新位置的块的最大高度 nodeDragPlaceholderMaxSize: 20, - // 是否允许创建一个隐藏的输入框,该输入框会在节点激活时聚焦,用于粘贴数据和自动进入文本编辑状态 - enableCreateHiddenInput: true, // 是否在存在一个激活节点时,当按下中文、英文、数字按键时自动进入文本编辑模式 - // 该配置在enableCreateHiddenInput设为true时生效 enableAutoEnterTextEditWhenKeydown: true, // 设置富文本节点编辑框和节点大小一致,形成伪原地编辑的效果 // 需要注意的是,只有当节点内只有文本、且形状是矩形才会有比较好的效果 diff --git a/simple-mind-map/src/core/render/Render.js b/simple-mind-map/src/core/render/Render.js index 8944dba9..b5294043 100644 --- a/simple-mind-map/src/core/render/Render.js +++ b/simple-mind-map/src/core/render/Render.js @@ -108,10 +108,6 @@ class Render { this.mindMap.execCommand('CLEAR_ACTIVE_NODE') } }) - // 粘贴事件 - this.mindMap.on('paste', data => { - this.onPaste(data) - }) // let timer = null // this.mindMap.on('view_data_change', () => { // clearTimeout(timer) @@ -273,8 +269,7 @@ class Render { this.copy = this.copy.bind(this) this.mindMap.keyCommand.addShortcut('Control+c', this.copy) this.mindMap.keyCommand.addShortcut('Control+v', () => { - // 隐藏输入框可能会失去焦点,所以要重新聚焦 - this.textEdit.focusHiddenInput() + this.onPaste() }) this.cut = this.cut.bind(this) this.mindMap.keyCommand.addShortcut('Control+x', this.cut) @@ -608,7 +603,28 @@ class Render { } // 粘贴事件 - async onPaste({ text, img }) { + async onPaste() { + // 读取剪贴板的文字和图片 + let text = null + let img = null + if (navigator.clipboard) { + try { + text = await navigator.clipboard.readText() + const items = await navigator.clipboard.read() + if (items && items.length > 0) { + for (const clipboardItem of items) { + for (const type of clipboardItem.types) { + if (/^image\//.test(type)) { + img = await clipboardItem.getType(type) + break + } + } + } + } + } catch (error) { + console.log(error) + } + } // 检查剪切板数据是否有变化 // 通过图片大小来判断图片是否发生变化,可能是不准确的,但是目前没有其他好方法 const imgSize = img ? img.size : 0 diff --git a/simple-mind-map/src/core/render/TextEdit.js b/simple-mind-map/src/core/render/TextEdit.js index 92499d98..0926d3e0 100644 --- a/simple-mind-map/src/core/render/TextEdit.js +++ b/simple-mind-map/src/core/render/TextEdit.js @@ -1,4 +1,4 @@ -import { getStrWithBrFromHtml, checkNodeOuter, isMobile } from '../../utils' +import { getStrWithBrFromHtml, checkNodeOuter } from '../../utils' // 节点文字编辑类 export default class TextEdit { @@ -10,16 +10,11 @@ export default class TextEdit { this.currentNode = null // 文本编辑框 this.textEditNode = null - // 隐藏的文本输入框 - this.hiddenInputEl = null - // 节点激活时默认聚焦到隐藏输入框 - this.enableFocus = true // 文本编辑框是否显示 this.showTextEdit = false // 如果编辑过程中缩放画布了,那么缓存当前编辑的内容 this.cacheEditingText = '' this.bindEvent() - this.createHiddenInput() } // 事件 @@ -51,10 +46,6 @@ export default class TextEdit { this.mindMap.on('before_node_active', () => { this.hideEditTextBox() }) - // 节点激活事件 - this.mindMap.on('node_active', () => { - this.focusHiddenInput() - }) // 注册编辑快捷键 this.mindMap.keyCommand.addShortcut('F2', () => { if (this.renderer.activeNodeList.length <= 0) { @@ -63,74 +54,29 @@ export default class TextEdit { this.show(this.renderer.activeNodeList[0]) }) this.mindMap.on('scale', this.onScale) - } - - // 创建一个隐藏的文本输入框 - createHiddenInput() { - const { enableCreateHiddenInput, enableAutoEnterTextEditWhenKeydown } = - this.mindMap.opt - if (this.hiddenInputEl || isMobile() || !enableCreateHiddenInput) return - this.hiddenInputEl = document.createElement('input') - this.hiddenInputEl.type = 'text' - this.hiddenInputEl.style.cssText = ` - position: fixed; - left: -99999px; - top: -99999px; - ` - // 监听按键事件 - if (enableAutoEnterTextEditWhenKeydown) { - this.hiddenInputEl.addEventListener('keydown', e => { + // // 监听按键事件,判断是否自动进入文本编辑模式 + if (this.mindMap.opt.enableAutoEnterTextEditWhenKeydown) { + window.addEventListener('keydown', e => { const activeNodeList = this.mindMap.renderer.activeNodeList if (activeNodeList.length <= 0 || activeNodeList.length > 1) return const node = activeNodeList[0] // 当正在输入中文或英文或数字时,如果没有按下组合键,那么自动进入文本编辑模式 - const keyCode = e.keyCode - if ( - node && - (keyCode === 229 || - (keyCode >= 65 && keyCode <= 90) || - (keyCode >= 48 && keyCode <= 57)) && - !this.mindMap.keyCommand.hasCombinationKey(e) - ) { + if (node && this.checkIsAutoEnterTextEditKey(e)) { this.show(node) } }) } - // 监听粘贴事件 - this.hiddenInputEl.addEventListener('paste', async event => { - event.preventDefault() - const text = (event.clipboardData || window.clipboardData).getData('text') - const files = event.clipboardData.files - let img = null - if (files.length > 0) { - for (let i = 0; i < files.length; i++) { - if (/^image\//.test(files[i].type)) { - img = files[i] - break - } - } - } - this.mindMap.emit('paste', { - text, - img - }) - }) - document.body.appendChild(this.hiddenInputEl) } - // 让隐藏的文本输入框聚焦 - focusHiddenInput() { - if (this.hiddenInputEl && this.enableFocus) this.hiddenInputEl.focus() - } - - // 关闭默认聚焦 - stopFocusOnNodeActive() { - this.enableFocus = false - } - - // 开启默认聚焦 - openFocusOnNodeActive() { - this.enableFocus = true + // 判断是否是自动进入文本编模式的按钮 + checkIsAutoEnterTextEditKey(e) { + const keyCode = e.keyCode + return ( + (keyCode === 229 || + (keyCode >= 65 && keyCode <= 90) || + (keyCode >= 48 && keyCode <= 57)) && + !this.mindMap.keyCommand.hasCombinationKey(e) + ) } // 注册临时快捷键 @@ -188,6 +134,7 @@ export default class TextEdit { // 显示文本编辑框 showEditTextBox(node, rect, isInserting) { + if (this.showTextEdit) return this.mindMap.emit('before_show_text_edit') this.registerTmpShortcut() if (!this.textEditNode) { @@ -203,6 +150,11 @@ export default class TextEdit { this.textEditNode.addEventListener('mousedown', e => { e.stopPropagation() }) + this.textEditNode.addEventListener('keydown', e => { + if (this.checkIsAutoEnterTextEditKey(e)) { + e.stopPropagation() + } + }) const targetNode = this.mindMap.opt.customInnerElsAppendTo || document.body targetNode.appendChild(this.textEditNode) diff --git a/simple-mind-map/src/plugins/RichText.js b/simple-mind-map/src/plugins/RichText.js index 7b818e4e..c5830b44 100644 --- a/simple-mind-map/src/plugins/RichText.js +++ b/simple-mind-map/src/plugins/RichText.js @@ -198,6 +198,11 @@ class RichText { this.textEditNode.addEventListener('mousedown', e => { e.stopPropagation() }) + this.textEditNode.addEventListener('keydown', e => { + if (this.mindMap.renderer.textEdit.checkIsAutoEnterTextEditKey(e)) { + e.stopPropagation() + } + }) const targetNode = customInnerElsAppendTo || document.body targetNode.appendChild(this.textEditNode) } diff --git a/web/src/pages/Edit/components/Outline.vue b/web/src/pages/Edit/components/Outline.vue index 87e2b9ca..fa1fe23b 100644 --- a/web/src/pages/Edit/components/Outline.vue +++ b/web/src/pages/Edit/components/Outline.vue @@ -258,9 +258,7 @@ export default { this.notHandleDataChange = true const targetNode = this.mindMap.renderer.findNodeByUid(data.uid) if (targetNode && targetNode.nodeData.data.isActive) return - this.mindMap.renderer.textEdit.stopFocusOnNodeActive() this.mindMap.execCommand('GO_TARGET_NODE', data.uid, () => { - this.mindMap.renderer.textEdit.openFocusOnNodeActive() this.notHandleDataChange = false }) },