Feat:去除创建隐藏输入框,通过navigator.clipboard实现复制粘贴

This commit is contained in:
wanglin2 2023-08-11 17:39:04 +08:00
parent 4d69778a50
commit c6a3f4ac7b
5 changed files with 48 additions and 80 deletions

View File

@ -127,10 +127,7 @@ export const defaultOpt = {
customInnerElsAppendTo: null,
// 拖拽元素时,指示元素新位置的块的最大高度
nodeDragPlaceholderMaxSize: 20,
// 是否允许创建一个隐藏的输入框,该输入框会在节点激活时聚焦,用于粘贴数据和自动进入文本编辑状态
enableCreateHiddenInput: true,
// 是否在存在一个激活节点时,当按下中文、英文、数字按键时自动进入文本编辑模式
// 该配置在enableCreateHiddenInput设为true时生效
enableAutoEnterTextEditWhenKeydown: true,
// 设置富文本节点编辑框和节点大小一致,形成伪原地编辑的效果
// 需要注意的是,只有当节点内只有文本、且形状是矩形才会有比较好的效果

View File

@ -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

View File

@ -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)

View File

@ -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)
}

View File

@ -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
})
},