Merge branch 'main' into main
This commit is contained in:
commit
7e7b6fae9d
28
simple-mind-map/package-lock.json
generated
28
simple-mind-map/package-lock.json
generated
@ -1,17 +1,17 @@
|
|||||||
{
|
{
|
||||||
"name": "simple-mind-map",
|
"name": "simple-mind-map",
|
||||||
"version": "0.6.11-fix.1",
|
"version": "0.6.12",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"version": "0.6.11-fix.1",
|
"version": "0.6.12",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@svgdotjs/svg.js": "^3.0.16",
|
"@svgdotjs/svg.js": "^3.0.16",
|
||||||
"deepmerge": "^1.5.2",
|
"deepmerge": "^1.5.2",
|
||||||
|
"dom-to-image-more": "^3.1.6",
|
||||||
"eventemitter3": "^4.0.7",
|
"eventemitter3": "^4.0.7",
|
||||||
"html2canvas": "^1.4.1",
|
|
||||||
"jspdf": "^2.5.1",
|
"jspdf": "^2.5.1",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
"mdast-util-from-markdown": "^1.3.0",
|
"mdast-util-from-markdown": "^1.3.0",
|
||||||
@ -255,6 +255,7 @@
|
|||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
|
||||||
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
|
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
|
||||||
|
"optional": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.6.0"
|
"node": ">= 0.6.0"
|
||||||
}
|
}
|
||||||
@ -411,6 +412,7 @@
|
|||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
|
||||||
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
|
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
|
||||||
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"utrie": "^1.0.2"
|
"utrie": "^1.0.2"
|
||||||
}
|
}
|
||||||
@ -516,6 +518,11 @@
|
|||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dom-to-image-more": {
|
||||||
|
"version": "3.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/dom-to-image-more/-/dom-to-image-more-3.1.6.tgz",
|
||||||
|
"integrity": "sha512-VMO0jNme32T06mWtkOC9QXfj+1npoJxkaTFW0DCwBLguwBKMjqwndiDANxDnbZ0kvNEecwxkv0Zmgdr96cGtAA=="
|
||||||
|
},
|
||||||
"node_modules/dompurify": {
|
"node_modules/dompurify": {
|
||||||
"version": "2.4.1",
|
"version": "2.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.1.tgz",
|
||||||
@ -937,6 +944,7 @@
|
|||||||
"version": "1.4.1",
|
"version": "1.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
|
||||||
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
|
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
|
||||||
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"css-line-break": "^2.1.0",
|
"css-line-break": "^2.1.0",
|
||||||
"text-segmentation": "^1.0.3"
|
"text-segmentation": "^1.0.3"
|
||||||
@ -2142,6 +2150,7 @@
|
|||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
|
||||||
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
|
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
|
||||||
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"utrie": "^1.0.2"
|
"utrie": "^1.0.2"
|
||||||
}
|
}
|
||||||
@ -2206,6 +2215,7 @@
|
|||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
|
||||||
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
|
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
|
||||||
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"base64-arraybuffer": "^1.0.2"
|
"base64-arraybuffer": "^1.0.2"
|
||||||
}
|
}
|
||||||
@ -2461,7 +2471,8 @@
|
|||||||
"base64-arraybuffer": {
|
"base64-arraybuffer": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
|
||||||
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ=="
|
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
|
||||||
|
"optional": true
|
||||||
},
|
},
|
||||||
"brace-expansion": {
|
"brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
@ -2576,6 +2587,7 @@
|
|||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
|
||||||
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
|
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
|
||||||
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"utrie": "^1.0.2"
|
"utrie": "^1.0.2"
|
||||||
}
|
}
|
||||||
@ -2648,6 +2660,11 @@
|
|||||||
"esutils": "^2.0.2"
|
"esutils": "^2.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"dom-to-image-more": {
|
||||||
|
"version": "3.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/dom-to-image-more/-/dom-to-image-more-3.1.6.tgz",
|
||||||
|
"integrity": "sha512-VMO0jNme32T06mWtkOC9QXfj+1npoJxkaTFW0DCwBLguwBKMjqwndiDANxDnbZ0kvNEecwxkv0Zmgdr96cGtAA=="
|
||||||
|
},
|
||||||
"dompurify": {
|
"dompurify": {
|
||||||
"version": "2.4.1",
|
"version": "2.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.1.tgz",
|
||||||
@ -2966,6 +2983,7 @@
|
|||||||
"version": "1.4.1",
|
"version": "1.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
|
||||||
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
|
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
|
||||||
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"css-line-break": "^2.1.0",
|
"css-line-break": "^2.1.0",
|
||||||
"text-segmentation": "^1.0.3"
|
"text-segmentation": "^1.0.3"
|
||||||
@ -3749,6 +3767,7 @@
|
|||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
|
||||||
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
|
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
|
||||||
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"utrie": "^1.0.2"
|
"utrie": "^1.0.2"
|
||||||
}
|
}
|
||||||
@ -3800,6 +3819,7 @@
|
|||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
|
||||||
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
|
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
|
||||||
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"base64-arraybuffer": "^1.0.2"
|
"base64-arraybuffer": "^1.0.2"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,8 +26,8 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@svgdotjs/svg.js": "^3.0.16",
|
"@svgdotjs/svg.js": "^3.0.16",
|
||||||
"deepmerge": "^1.5.2",
|
"deepmerge": "^1.5.2",
|
||||||
|
"dom-to-image-more": "^3.1.6",
|
||||||
"eventemitter3": "^4.0.7",
|
"eventemitter3": "^4.0.7",
|
||||||
"html2canvas": "^1.4.1",
|
|
||||||
"jspdf": "^2.5.1",
|
"jspdf": "^2.5.1",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
"mdast-util-from-markdown": "^1.3.0",
|
"mdast-util-from-markdown": "^1.3.0",
|
||||||
|
|||||||
@ -126,5 +126,10 @@ export const defaultOpt = {
|
|||||||
// 指定内部一些元素(节点文本编辑元素、节点备注显示元素、关联线文本编辑元素、节点图片调整按钮元素)添加到的位置,默认添加到document.body下
|
// 指定内部一些元素(节点文本编辑元素、节点备注显示元素、关联线文本编辑元素、节点图片调整按钮元素)添加到的位置,默认添加到document.body下
|
||||||
customInnerElsAppendTo: null,
|
customInnerElsAppendTo: null,
|
||||||
// 拖拽元素时,指示元素新位置的块的最大高度
|
// 拖拽元素时,指示元素新位置的块的最大高度
|
||||||
nodeDragPlaceholderMaxSize: 20
|
nodeDragPlaceholderMaxSize: 20,
|
||||||
|
// 是否允许创建一个隐藏的输入框,该输入框会在节点激活时聚焦,用于粘贴数据和自动进入文本编辑状态
|
||||||
|
enableCreateHiddenInput: true,
|
||||||
|
// 是否在存在一个激活节点时,当按下中文、英文、数字按键时自动进入文本编辑模式
|
||||||
|
// 该配置在enableCreateHiddenInput设为true时生效
|
||||||
|
enableAutoEnterTextEditWhenKeydown: true
|
||||||
}
|
}
|
||||||
|
|||||||
@ -108,6 +108,11 @@ export default class KeyCommand {
|
|||||||
return arr
|
return arr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 判断是否按下了组合键
|
||||||
|
hasCombinationKey(e) {
|
||||||
|
return e.ctrlKey || e.metaKey || e.altKey || e.shiftKey
|
||||||
|
}
|
||||||
|
|
||||||
// 获取快捷键对应的键值数组
|
// 获取快捷键对应的键值数组
|
||||||
getKeyCodeArr(key) {
|
getKeyCodeArr(key) {
|
||||||
let keyArr = key.split(/\s*\+\s*/)
|
let keyArr = key.split(/\s*\+\s*/)
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { getStrWithBrFromHtml, checkNodeOuter } from '../../utils'
|
import { getStrWithBrFromHtml, checkNodeOuter, isMobile } from '../../utils'
|
||||||
|
|
||||||
// 节点文字编辑类
|
// 节点文字编辑类
|
||||||
export default class TextEdit {
|
export default class TextEdit {
|
||||||
@ -67,7 +67,9 @@ export default class TextEdit {
|
|||||||
|
|
||||||
// 创建一个隐藏的文本输入框
|
// 创建一个隐藏的文本输入框
|
||||||
createHiddenInput() {
|
createHiddenInput() {
|
||||||
if (this.hiddenInputEl) return
|
const { enableCreateHiddenInput, enableAutoEnterTextEditWhenKeydown } =
|
||||||
|
this.mindMap.opt
|
||||||
|
if (this.hiddenInputEl || isMobile() || !enableCreateHiddenInput) return
|
||||||
this.hiddenInputEl = document.createElement('input')
|
this.hiddenInputEl = document.createElement('input')
|
||||||
this.hiddenInputEl.type = 'text'
|
this.hiddenInputEl.type = 'text'
|
||||||
this.hiddenInputEl.style.cssText = `
|
this.hiddenInputEl.style.cssText = `
|
||||||
@ -75,6 +77,25 @@ export default class TextEdit {
|
|||||||
left: -99999px;
|
left: -99999px;
|
||||||
top: -99999px;
|
top: -99999px;
|
||||||
`
|
`
|
||||||
|
// 监听按键事件
|
||||||
|
if (enableAutoEnterTextEditWhenKeydown) {
|
||||||
|
this.hiddenInputEl.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)
|
||||||
|
) {
|
||||||
|
this.show(node)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
// 监听粘贴事件
|
// 监听粘贴事件
|
||||||
this.hiddenInputEl.addEventListener('paste', async event => {
|
this.hiddenInputEl.addEventListener('paste', async event => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
@ -106,7 +127,7 @@ export default class TextEdit {
|
|||||||
stopFocusOnNodeActive() {
|
stopFocusOnNodeActive() {
|
||||||
this.enableFocus = false
|
this.enableFocus = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 开启默认聚焦
|
// 开启默认聚焦
|
||||||
openFocusOnNodeActive() {
|
openFocusOnNodeActive() {
|
||||||
this.enableFocus = true
|
this.enableFocus = true
|
||||||
@ -148,7 +169,7 @@ export default class TextEdit {
|
|||||||
this.mindMap.richText.showEditText(node, rect, isInserting)
|
this.mindMap.richText.showEditText(node, rect, isInserting)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.showEditTextBox(node, rect)
|
this.showEditTextBox(node, rect, isInserting)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理画布缩放
|
// 处理画布缩放
|
||||||
@ -166,7 +187,7 @@ export default class TextEdit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 显示文本编辑框
|
// 显示文本编辑框
|
||||||
showEditTextBox(node, rect) {
|
showEditTextBox(node, rect, isInserting) {
|
||||||
this.mindMap.emit('before_show_text_edit')
|
this.mindMap.emit('before_show_text_edit')
|
||||||
this.registerTmpShortcut()
|
this.registerTmpShortcut()
|
||||||
if (!this.textEditNode) {
|
if (!this.textEditNode) {
|
||||||
@ -179,10 +200,11 @@ export default class TextEdit {
|
|||||||
this.textEditNode.addEventListener('click', e => {
|
this.textEditNode.addEventListener('click', e => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
})
|
})
|
||||||
this.textEditNode.addEventListener('mousedown', (e) => {
|
this.textEditNode.addEventListener('mousedown', e => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
})
|
})
|
||||||
const targetNode = this.mindMap.opt.customInnerElsAppendTo || document.body
|
const targetNode =
|
||||||
|
this.mindMap.opt.customInnerElsAppendTo || document.body
|
||||||
targetNode.appendChild(this.textEditNode)
|
targetNode.appendChild(this.textEditNode)
|
||||||
}
|
}
|
||||||
let scale = this.mindMap.view.scale
|
let scale = this.mindMap.view.scale
|
||||||
@ -209,12 +231,27 @@ export default class TextEdit {
|
|||||||
}
|
}
|
||||||
this.showTextEdit = true
|
this.showTextEdit = true
|
||||||
// 选中文本
|
// 选中文本
|
||||||
if (!this.cacheEditingText) {
|
// if (!this.cacheEditingText) {
|
||||||
|
// this.selectNodeText()
|
||||||
|
// }
|
||||||
|
if (isInserting) {
|
||||||
this.selectNodeText()
|
this.selectNodeText()
|
||||||
|
} else {
|
||||||
|
this.focus()
|
||||||
}
|
}
|
||||||
this.cacheEditingText = ''
|
this.cacheEditingText = ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 聚焦
|
||||||
|
focus() {
|
||||||
|
let selection = window.getSelection()
|
||||||
|
let range = document.createRange()
|
||||||
|
range.selectNodeContents(this.textEditNode)
|
||||||
|
range.collapse()
|
||||||
|
selection.removeAllRanges()
|
||||||
|
selection.addRange(range)
|
||||||
|
}
|
||||||
|
|
||||||
// 选中文本
|
// 选中文本
|
||||||
selectNodeText() {
|
selectNodeText() {
|
||||||
let selection = window.getSelection()
|
let selection = window.getSelection()
|
||||||
|
|||||||
@ -204,7 +204,7 @@ class Drag extends Base {
|
|||||||
|
|
||||||
// 检测重叠节点
|
// 检测重叠节点
|
||||||
checkOverlapNode() {
|
checkOverlapNode() {
|
||||||
if (!this.drawTransform) {
|
if (!this.drawTransform || !this.placeholder) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const { nodeDragPlaceholderMaxSize } = this.mindMap.opt
|
const { nodeDragPlaceholderMaxSize } = this.mindMap.opt
|
||||||
|
|||||||
@ -1,7 +1,12 @@
|
|||||||
import Quill from 'quill'
|
import Quill from 'quill'
|
||||||
import 'quill/dist/quill.snow.css'
|
import 'quill/dist/quill.snow.css'
|
||||||
import html2canvas from 'html2canvas'
|
import domtoimage from 'dom-to-image-more'
|
||||||
import { walk, getTextFromHtml, isWhite, getVisibleColorFromTheme } from '../utils'
|
import {
|
||||||
|
walk,
|
||||||
|
getTextFromHtml,
|
||||||
|
isWhite,
|
||||||
|
getVisibleColorFromTheme
|
||||||
|
} from '../utils'
|
||||||
import { CONSTANTS } from '../constants/constant'
|
import { CONSTANTS } from '../constants/constant'
|
||||||
|
|
||||||
let extended = false
|
let extended = false
|
||||||
@ -172,10 +177,11 @@ class RichText {
|
|||||||
this.textEditNode.addEventListener('click', e => {
|
this.textEditNode.addEventListener('click', e => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
})
|
})
|
||||||
this.textEditNode.addEventListener('mousedown', (e) => {
|
this.textEditNode.addEventListener('mousedown', e => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
})
|
})
|
||||||
const targetNode = this.mindMap.opt.customInnerElsAppendTo || document.body
|
const targetNode =
|
||||||
|
this.mindMap.opt.customInnerElsAppendTo || document.body
|
||||||
targetNode.appendChild(this.textEditNode)
|
targetNode.appendChild(this.textEditNode)
|
||||||
}
|
}
|
||||||
// 使用节点的填充色,否则如果节点颜色是白色的话编辑时看不见
|
// 使用节点的填充色,否则如果节点颜色是白色的话编辑时看不见
|
||||||
@ -185,7 +191,11 @@ class RichText {
|
|||||||
this.textEditNode.style.marginTop = `-${paddingY * scaleY}px`
|
this.textEditNode.style.marginTop = `-${paddingY * scaleY}px`
|
||||||
this.textEditNode.style.zIndex = this.mindMap.opt.nodeTextEditZIndex
|
this.textEditNode.style.zIndex = this.mindMap.opt.nodeTextEditZIndex
|
||||||
this.textEditNode.style.backgroundColor =
|
this.textEditNode.style.backgroundColor =
|
||||||
bgColor === 'transparent' ? isWhite(color) ? getVisibleColorFromTheme(this.mindMap.themeConfig) : '#fff' : bgColor
|
bgColor === 'transparent'
|
||||||
|
? isWhite(color)
|
||||||
|
? getVisibleColorFromTheme(this.mindMap.themeConfig)
|
||||||
|
: '#fff'
|
||||||
|
: bgColor
|
||||||
this.textEditNode.style.minWidth = originWidth + paddingX * 2 + 'px'
|
this.textEditNode.style.minWidth = originWidth + paddingX * 2 + 'px'
|
||||||
this.textEditNode.style.minHeight = originHeight + 'px'
|
this.textEditNode.style.minHeight = originHeight + 'px'
|
||||||
this.textEditNode.style.left = rect.left + 'px'
|
this.textEditNode.style.left = rect.left + 'px'
|
||||||
@ -507,11 +517,16 @@ class RichText {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
walk(node)
|
walk(node)
|
||||||
let canvas = await html2canvas(el, {
|
|
||||||
backgroundColor: null
|
// 如果使用html2canvas
|
||||||
})
|
// let canvas = await html2canvas(el, {
|
||||||
|
// backgroundColor: null
|
||||||
|
// })
|
||||||
|
// return canvas.toDataURL()
|
||||||
|
|
||||||
|
const res = await domtoimage.toPng(el)
|
||||||
this.mindMap.el.removeChild(el)
|
this.mindMap.el.removeChild(el)
|
||||||
return canvas.toDataURL()
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将所有节点转换成非富文本节点
|
// 将所有节点转换成非富文本节点
|
||||||
|
|||||||
@ -58,7 +58,6 @@ class TouchEvent {
|
|||||||
let { x: touch2ClientX, y: touch2ClientY } = this.mindMap.toPos(touch2.clientX, touch2.clientY)
|
let { x: touch2ClientX, y: touch2ClientY } = this.mindMap.toPos(touch2.clientX, touch2.clientY)
|
||||||
let cx = (touch1ClientX + touch2ClientX) / 2
|
let cx = (touch1ClientX + touch2ClientX) / 2
|
||||||
let cy = (touch1ClientY + touch2ClientY) / 2
|
let cy = (touch1ClientY + touch2ClientY) / 2
|
||||||
|
|
||||||
// 手势缩放,基于最开始的位置进行缩放(基于前一个位置缩放不是线性关系); 缩放同时支持位置拖动
|
// 手势缩放,基于最开始的位置进行缩放(基于前一个位置缩放不是线性关系); 缩放同时支持位置拖动
|
||||||
var view = this.mindMap.view;
|
var view = this.mindMap.view;
|
||||||
if(!this.touchScaleViewBefore){
|
if(!this.touchScaleViewBefore){
|
||||||
|
|||||||
@ -455,25 +455,25 @@ export const loadImage = imgFile => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 移除字符串中的html实体
|
// 移除字符串中的html实体
|
||||||
export const removeHTMLEntities = (str) => {
|
export const removeHTMLEntities = str => {
|
||||||
[[' ', ' ']].forEach((item) => {
|
;[[' ', ' ']].forEach(item => {
|
||||||
str = str.replaceAll(item[0], item[1])
|
str = str.replaceAll(item[0], item[1])
|
||||||
})
|
})
|
||||||
return str
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取一个数据的类型
|
// 获取一个数据的类型
|
||||||
export const getType = (data) => {
|
export const getType = data => {
|
||||||
return Object.prototype.toString.call(data).slice(7, -1)
|
return Object.prototype.toString.call(data).slice(7, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断一个数据是否是null和undefined和空字符串
|
// 判断一个数据是否是null和undefined和空字符串
|
||||||
export const isUndef = (data) => {
|
export const isUndef = data => {
|
||||||
return data === null || data === undefined || data === ''
|
return data === null || data === undefined || data === ''
|
||||||
}
|
}
|
||||||
|
|
||||||
// 移除html字符串中节点的内联样式
|
// 移除html字符串中节点的内联样式
|
||||||
export const removeHtmlStyle = (html) => {
|
export const removeHtmlStyle = html => {
|
||||||
return html.replaceAll(/(<[^\s]+)\s+style=["'][^'"]+["']\s*(>)/g, '$1$2')
|
return html.replaceAll(/(<[^\s]+)\s+style=["'][^'"]+["']\s*(>)/g, '$1$2')
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -485,12 +485,12 @@ export const addHtmlStyle = (html, tag, style) => {
|
|||||||
|
|
||||||
// 检查一个字符串是否是富文本字符
|
// 检查一个字符串是否是富文本字符
|
||||||
let checkIsRichTextEl = null
|
let checkIsRichTextEl = null
|
||||||
export const checkIsRichText = (str) => {
|
export const checkIsRichText = str => {
|
||||||
if (!checkIsRichTextEl) {
|
if (!checkIsRichTextEl) {
|
||||||
checkIsRichTextEl = document.createElement('div')
|
checkIsRichTextEl = document.createElement('div')
|
||||||
}
|
}
|
||||||
checkIsRichTextEl.innerHTML = str
|
checkIsRichTextEl.innerHTML = str
|
||||||
for (let c = checkIsRichTextEl.childNodes, i = c.length; i--;) {
|
for (let c = checkIsRichTextEl.childNodes, i = c.length; i--; ) {
|
||||||
if (c[i].nodeType == 1) return true
|
if (c[i].nodeType == 1) return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@ -503,13 +503,20 @@ export const replaceHtmlText = (html, searchText, replaceText) => {
|
|||||||
replaceHtmlTextEl = document.createElement('div')
|
replaceHtmlTextEl = document.createElement('div')
|
||||||
}
|
}
|
||||||
replaceHtmlTextEl.innerHTML = html
|
replaceHtmlTextEl.innerHTML = html
|
||||||
let walk = (root) => {
|
let walk = root => {
|
||||||
let childNodes = root.childNodes
|
let childNodes = root.childNodes
|
||||||
childNodes.forEach((node) => {
|
childNodes.forEach(node => {
|
||||||
if (node.nodeType === 1) {// 元素节点
|
if (node.nodeType === 1) {
|
||||||
|
// 元素节点
|
||||||
walk(node)
|
walk(node)
|
||||||
} else if (node.nodeType === 3) {// 文本节点
|
} else if (node.nodeType === 3) {
|
||||||
root.replaceChild(document.createTextNode(node.nodeValue.replaceAll(searchText, replaceText)), node)
|
// 文本节点
|
||||||
|
root.replaceChild(
|
||||||
|
document.createTextNode(
|
||||||
|
node.nodeValue.replaceAll(searchText, replaceText)
|
||||||
|
),
|
||||||
|
node
|
||||||
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -518,22 +525,39 @@ export const replaceHtmlText = (html, searchText, replaceText) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 判断一个颜色是否是白色
|
// 判断一个颜色是否是白色
|
||||||
export const isWhite = (color) => {
|
export const isWhite = color => {
|
||||||
color = String(color).replaceAll(/\s+/g, '')
|
color = String(color).replaceAll(/\s+/g, '')
|
||||||
return ['#fff', '#ffffff', '#FFF', '#FFFFFF', 'rgb(255,255,255)'].includes(color) || /rgba\(255,255,255,[^)]+\)/.test(color)
|
return (
|
||||||
|
['#fff', '#ffffff', '#FFF', '#FFFFFF', 'rgb(255,255,255)'].includes(
|
||||||
|
color
|
||||||
|
) || /rgba\(255,255,255,[^)]+\)/.test(color)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断一个颜色是否是透明
|
// 判断一个颜色是否是透明
|
||||||
export const isTransparent = (color) => {
|
export const isTransparent = color => {
|
||||||
color = String(color).replaceAll(/\s+/g, '')
|
color = String(color).replaceAll(/\s+/g, '')
|
||||||
return ['', 'transparent'].includes(color) || /rgba\(\d+,\d+,\d+,0\)/.test(color)
|
return (
|
||||||
|
['', 'transparent'].includes(color) || /rgba\(\d+,\d+,\d+,0\)/.test(color)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从当前主题里获取一个非透明非白色的颜色
|
// 从当前主题里获取一个非透明非白色的颜色
|
||||||
export const getVisibleColorFromTheme = (themeConfig) => {
|
export const getVisibleColorFromTheme = themeConfig => {
|
||||||
let { lineColor, root, second, node } = themeConfig
|
let { lineColor, root, second, node } = themeConfig
|
||||||
let list = [lineColor, root.fillColor, root.color, second.fillColor, second.color, node.fillColor, node.color, root.borderColor, second.borderColor, node.borderColor]
|
let list = [
|
||||||
for(let i = 0; i < list.length; i++) {
|
lineColor,
|
||||||
|
root.fillColor,
|
||||||
|
root.color,
|
||||||
|
second.fillColor,
|
||||||
|
second.color,
|
||||||
|
node.fillColor,
|
||||||
|
node.color,
|
||||||
|
root.borderColor,
|
||||||
|
second.borderColor,
|
||||||
|
node.borderColor
|
||||||
|
]
|
||||||
|
for (let i = 0; i < list.length; i++) {
|
||||||
let color = list[i]
|
let color = list[i]
|
||||||
if (!isTransparent(color) && !isWhite(color)) {
|
if (!isTransparent(color) && !isWhite(color)) {
|
||||||
return color
|
return color
|
||||||
@ -543,22 +567,24 @@ export const getVisibleColorFromTheme = (themeConfig) => {
|
|||||||
|
|
||||||
// 将<p><span></span><p>形式的节点富文本内容转换成\n换行的文本
|
// 将<p><span></span><p>形式的节点富文本内容转换成\n换行的文本
|
||||||
let nodeRichTextToTextWithWrapEl = null
|
let nodeRichTextToTextWithWrapEl = null
|
||||||
export const nodeRichTextToTextWithWrap = (html) => {
|
export const nodeRichTextToTextWithWrap = html => {
|
||||||
if (!nodeRichTextToTextWithWrapEl) {
|
if (!nodeRichTextToTextWithWrapEl) {
|
||||||
nodeRichTextToTextWithWrapEl = document.createElement('div')
|
nodeRichTextToTextWithWrapEl = document.createElement('div')
|
||||||
}
|
}
|
||||||
nodeRichTextToTextWithWrapEl.innerHTML = html
|
nodeRichTextToTextWithWrapEl.innerHTML = html
|
||||||
const childNodes = nodeRichTextToTextWithWrapEl.childNodes
|
const childNodes = nodeRichTextToTextWithWrapEl.childNodes
|
||||||
let res = ''
|
let res = ''
|
||||||
for(let i = 0; i < childNodes.length; i++) {
|
for (let i = 0; i < childNodes.length; i++) {
|
||||||
const node = childNodes[i]
|
const node = childNodes[i]
|
||||||
if (node.nodeType === 1) {// 元素节点
|
if (node.nodeType === 1) {
|
||||||
|
// 元素节点
|
||||||
if (node.tagName.toLowerCase() === 'p') {
|
if (node.tagName.toLowerCase() === 'p') {
|
||||||
res += node.textContent + '\n'
|
res += node.textContent + '\n'
|
||||||
} else {
|
} else {
|
||||||
res += node.textContent
|
res += node.textContent
|
||||||
}
|
}
|
||||||
} else if (node.nodeType === 3) {// 文本节点
|
} else if (node.nodeType === 3) {
|
||||||
|
// 文本节点
|
||||||
res += node.nodeValue
|
res += node.nodeValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -567,7 +593,7 @@ export const nodeRichTextToTextWithWrap = (html) => {
|
|||||||
|
|
||||||
// 将<br>换行的文本转换成<p><span></span><p>形式的节点富文本内容
|
// 将<br>换行的文本转换成<p><span></span><p>形式的节点富文本内容
|
||||||
let textToNodeRichTextWithWrapEl = null
|
let textToNodeRichTextWithWrapEl = null
|
||||||
export const textToNodeRichTextWithWrap = (html) => {
|
export const textToNodeRichTextWithWrap = html => {
|
||||||
if (!textToNodeRichTextWithWrapEl) {
|
if (!textToNodeRichTextWithWrapEl) {
|
||||||
textToNodeRichTextWithWrapEl = document.createElement('div')
|
textToNodeRichTextWithWrapEl = document.createElement('div')
|
||||||
}
|
}
|
||||||
@ -575,23 +601,34 @@ export const textToNodeRichTextWithWrap = (html) => {
|
|||||||
const childNodes = textToNodeRichTextWithWrapEl.childNodes
|
const childNodes = textToNodeRichTextWithWrapEl.childNodes
|
||||||
let list = []
|
let list = []
|
||||||
let str = ''
|
let str = ''
|
||||||
for(let i = 0; i < childNodes.length; i++) {
|
for (let i = 0; i < childNodes.length; i++) {
|
||||||
const node = childNodes[i]
|
const node = childNodes[i]
|
||||||
if (node.nodeType === 1) {// 元素节点
|
if (node.nodeType === 1) {
|
||||||
|
// 元素节点
|
||||||
if (node.tagName.toLowerCase() === 'br') {
|
if (node.tagName.toLowerCase() === 'br') {
|
||||||
list.push(str)
|
list.push(str)
|
||||||
str = ''
|
str = ''
|
||||||
} else {
|
} else {
|
||||||
str += node.textContent
|
str += node.textContent
|
||||||
}
|
}
|
||||||
} else if (node.nodeType === 3) {// 文本节点
|
} else if (node.nodeType === 3) {
|
||||||
|
// 文本节点
|
||||||
str += node.nodeValue
|
str += node.nodeValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (str) {
|
if (str) {
|
||||||
list.push(str)
|
list.push(str)
|
||||||
}
|
}
|
||||||
return list.map((item) => {
|
return list
|
||||||
return `<p><span>${item}</span></p>`
|
.map(item => {
|
||||||
}).join('')
|
return `<p><span>${item}</span></p>`
|
||||||
}
|
})
|
||||||
|
.join('')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否是移动端环境
|
||||||
|
export const isMobile = () => {
|
||||||
|
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
|
||||||
|
navigator.userAgent
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
class="contextmenuContainer listBox"
|
class="contextmenuContainer listBox"
|
||||||
v-if="isShow"
|
v-if="isShow"
|
||||||
:style="{ left: left + 'px', top: top + 'px' }"
|
:style="{ left: left + 'px', top: top + 'px' }"
|
||||||
|
:class="{ isDark: isDark }"
|
||||||
>
|
>
|
||||||
<template v-if="type === 'node'">
|
<template v-if="type === 'node'">
|
||||||
<div
|
<div
|
||||||
@ -13,7 +14,11 @@
|
|||||||
{{ $t('contextmenu.insertSiblingNode') }}
|
{{ $t('contextmenu.insertSiblingNode') }}
|
||||||
<span class="desc">Enter</span>
|
<span class="desc">Enter</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="item" @click="exec('INSERT_CHILD_NODE')" :class="{ disabled: isGeneralization }">
|
<div
|
||||||
|
class="item"
|
||||||
|
@click="exec('INSERT_CHILD_NODE')"
|
||||||
|
:class="{ disabled: isGeneralization }"
|
||||||
|
>
|
||||||
{{ $t('contextmenu.insertChildNode') }}
|
{{ $t('contextmenu.insertChildNode') }}
|
||||||
<span class="desc">Tab</span>
|
<span class="desc">Tab</span>
|
||||||
</div>
|
</div>
|
||||||
@ -45,18 +50,23 @@
|
|||||||
{{ $t('contextmenu.deleteNode') }}
|
{{ $t('contextmenu.deleteNode') }}
|
||||||
<span class="desc">Delete</span>
|
<span class="desc">Delete</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="item" @click="exec('COPY_NODE')" :class="{ disabled: isGeneralization }">
|
<div
|
||||||
|
class="item"
|
||||||
|
@click="exec('COPY_NODE')"
|
||||||
|
:class="{ disabled: isGeneralization }"
|
||||||
|
>
|
||||||
{{ $t('contextmenu.copyNode') }}
|
{{ $t('contextmenu.copyNode') }}
|
||||||
<span class="desc">Ctrl + C</span>
|
<span class="desc">Ctrl + C</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="item" @click="exec('CUT_NODE')" :class="{ disabled: isGeneralization }">
|
<div
|
||||||
|
class="item"
|
||||||
|
@click="exec('CUT_NODE')"
|
||||||
|
:class="{ disabled: isGeneralization }"
|
||||||
|
>
|
||||||
{{ $t('contextmenu.cutNode') }}
|
{{ $t('contextmenu.cutNode') }}
|
||||||
<span class="desc">Ctrl + X</span>
|
<span class="desc">Ctrl + X</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div class="item" @click="exec('PASTE_NODE')">
|
||||||
class="item"
|
|
||||||
@click="exec('PASTE_NODE')"
|
|
||||||
>
|
|
||||||
{{ $t('contextmenu.pasteNode') }}
|
{{ $t('contextmenu.pasteNode') }}
|
||||||
<span class="desc">Ctrl + V</span>
|
<span class="desc">Ctrl + V</span>
|
||||||
</div>
|
</div>
|
||||||
@ -74,7 +84,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="item">
|
<div class="item">
|
||||||
{{ $t('contextmenu.expandTo') }}
|
{{ $t('contextmenu.expandTo') }}
|
||||||
<div class="subItems listBox">
|
<div class="subItems listBox" :class="{ isDark: isDark }">
|
||||||
<div
|
<div
|
||||||
class="item"
|
class="item"
|
||||||
v-for="(item, index) in expandList"
|
v-for="(item, index) in expandList"
|
||||||
@ -130,7 +140,8 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState({
|
...mapState({
|
||||||
isZenMode: state => state.localConfig.isZenMode
|
isZenMode: state => state.localConfig.isZenMode,
|
||||||
|
isDark: state => state.isDark
|
||||||
}),
|
}),
|
||||||
expandList() {
|
expandList() {
|
||||||
return [
|
return [
|
||||||
@ -309,6 +320,10 @@ export default {
|
|||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding-top: 16px;
|
padding-top: 16px;
|
||||||
padding-bottom: 16px;
|
padding-bottom: 16px;
|
||||||
|
|
||||||
|
&.isDark {
|
||||||
|
background: #363b3f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.contextmenuContainer {
|
.contextmenuContainer {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
@ -317,6 +332,16 @@ export default {
|
|||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
color: #1a1a1a;
|
color: #1a1a1a;
|
||||||
|
|
||||||
|
&.isDark {
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
.item {
|
||||||
|
&:hover {
|
||||||
|
background: hsla(0, 0%, 100%, 0.05);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.item {
|
.item {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
|
|||||||
@ -61,7 +61,7 @@ export default {
|
|||||||
},
|
},
|
||||||
currentData: null,
|
currentData: null,
|
||||||
notHandleDataChange: false,
|
notHandleDataChange: false,
|
||||||
handleNodeTreeRenderEnd: false,
|
isHandleNodeTreeRenderEnd: false,
|
||||||
beInsertNodeUid: '',
|
beInsertNodeUid: '',
|
||||||
insertType: '',
|
insertType: '',
|
||||||
isInTreArea: false,
|
isInTreArea: false,
|
||||||
@ -106,8 +106,8 @@ export default {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// 插入了新节点后需要做一些操作
|
// 插入了新节点后需要做一些操作
|
||||||
if (this.handleNodeTreeRenderEnd) {
|
if (this.isHandleNodeTreeRenderEnd) {
|
||||||
this.handleNodeTreeRenderEnd = false
|
this.isHandleNodeTreeRenderEnd = false
|
||||||
this.refresh()
|
this.refresh()
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.afterCreateNewNode()
|
this.afterCreateNewNode()
|
||||||
@ -236,7 +236,7 @@ export default {
|
|||||||
// 插入兄弟节点
|
// 插入兄弟节点
|
||||||
insertNode() {
|
insertNode() {
|
||||||
this.notHandleDataChange = true
|
this.notHandleDataChange = true
|
||||||
this.handleNodeTreeRenderEnd = true
|
this.isHandleNodeTreeRenderEnd = true
|
||||||
this.beInsertNodeUid = createUid()
|
this.beInsertNodeUid = createUid()
|
||||||
this.mindMap.execCommand('INSERT_NODE', false, [], {
|
this.mindMap.execCommand('INSERT_NODE', false, [], {
|
||||||
uid: this.beInsertNodeUid
|
uid: this.beInsertNodeUid
|
||||||
@ -246,7 +246,7 @@ export default {
|
|||||||
// 插入下级节点
|
// 插入下级节点
|
||||||
insertChildNode() {
|
insertChildNode() {
|
||||||
this.notHandleDataChange = true
|
this.notHandleDataChange = true
|
||||||
this.handleNodeTreeRenderEnd = true
|
this.isHandleNodeTreeRenderEnd = true
|
||||||
this.beInsertNodeUid = createUid()
|
this.beInsertNodeUid = createUid()
|
||||||
this.mindMap.execCommand('INSERT_CHILD_NODE', false, [], {
|
this.mindMap.execCommand('INSERT_CHILD_NODE', false, [], {
|
||||||
uid: this.beInsertNodeUid
|
uid: this.beInsertNodeUid
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
class="richTextToolbar"
|
class="richTextToolbar"
|
||||||
ref="richTextToolbar"
|
ref="richTextToolbar"
|
||||||
:style="style"
|
:style="style"
|
||||||
|
:class="{ isDark: isDark }"
|
||||||
@click.stop.passive
|
@click.stop.passive
|
||||||
v-show="showRichTextToolbar"
|
v-show="showRichTextToolbar"
|
||||||
>
|
>
|
||||||
@ -44,7 +45,7 @@
|
|||||||
|
|
||||||
<el-tooltip content="字体" placement="top">
|
<el-tooltip content="字体" placement="top">
|
||||||
<el-popover placement="bottom" trigger="hover">
|
<el-popover placement="bottom" trigger="hover">
|
||||||
<div class="fontOptionsList">
|
<div class="fontOptionsList" :class="{ isDark: isDark }">
|
||||||
<div
|
<div
|
||||||
class="fontOptionItem"
|
class="fontOptionItem"
|
||||||
v-for="item in fontFamilyList"
|
v-for="item in fontFamilyList"
|
||||||
@ -64,7 +65,7 @@
|
|||||||
|
|
||||||
<el-tooltip content="字号" placement="top">
|
<el-tooltip content="字号" placement="top">
|
||||||
<el-popover placement="bottom" trigger="hover">
|
<el-popover placement="bottom" trigger="hover">
|
||||||
<div class="fontOptionsList">
|
<div class="fontOptionsList" :class="{ isDark: isDark }">
|
||||||
<div
|
<div
|
||||||
class="fontOptionItem"
|
class="fontOptionItem"
|
||||||
v-for="item in fontSizeList"
|
v-for="item in fontSizeList"
|
||||||
@ -93,17 +94,18 @@
|
|||||||
|
|
||||||
<el-tooltip content="背景颜色" placement="top">
|
<el-tooltip content="背景颜色" placement="top">
|
||||||
<el-popover placement="bottom" trigger="hover">
|
<el-popover placement="bottom" trigger="hover">
|
||||||
<Color :color="fontBackgroundColor" @change="changeFontBackgroundColor"></Color>
|
<Color
|
||||||
|
:color="fontBackgroundColor"
|
||||||
|
@change="changeFontBackgroundColor"
|
||||||
|
></Color>
|
||||||
<div class="btn" slot="reference">
|
<div class="btn" slot="reference">
|
||||||
<span class="icon iconfont iconbeijingyanse"></span>
|
<span class="icon iconfont iconbeijingyanse"></span>
|
||||||
</div>
|
</div>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
|
|
||||||
<el-tooltip content="清除样式" placement="top">
|
<el-tooltip content="清除样式" placement="top">
|
||||||
<div
|
<div class="btn" @click="removeFormat">
|
||||||
class="btn" @click="removeFormat"
|
|
||||||
>
|
|
||||||
<span class="icon iconfont iconqingchu"></span>
|
<span class="icon iconfont iconqingchu"></span>
|
||||||
</div>
|
</div>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
@ -113,6 +115,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import { fontFamilyList, fontSizeList } from '@/config'
|
import { fontFamilyList, fontSizeList } from '@/config'
|
||||||
import Color from './Color'
|
import Color from './Color'
|
||||||
|
import { mapState } from 'vuex'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'RichTextToolbar',
|
name: 'RichTextToolbar',
|
||||||
@ -138,6 +141,8 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
...mapState(['isDark']),
|
||||||
|
|
||||||
fontFamilyList() {
|
fontFamilyList() {
|
||||||
return fontFamilyList[this.$i18n.locale] || fontFamilyList.zh
|
return fontFamilyList[this.$i18n.locale] || fontFamilyList.zh
|
||||||
}
|
}
|
||||||
@ -211,7 +216,7 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
changeFontBackgroundColor(background) {
|
changeFontBackgroundColor(background) {
|
||||||
this.formatInfo.background = background
|
this.formatInfo.background = background
|
||||||
this.mindMap.richText.formatText({
|
this.mindMap.richText.formatText({
|
||||||
background
|
background
|
||||||
})
|
})
|
||||||
@ -237,6 +242,18 @@ export default {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
|
|
||||||
|
&.isDark {
|
||||||
|
background: #363b3f;
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: hsla(0, 0%, 100%, 0.05);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
width: 55px;
|
width: 55px;
|
||||||
height: 55px;
|
height: 55px;
|
||||||
@ -266,6 +283,16 @@ export default {
|
|||||||
.fontOptionsList {
|
.fontOptionsList {
|
||||||
width: 150px;
|
width: 150px;
|
||||||
|
|
||||||
|
&.isDark {
|
||||||
|
.fontOptionItem {
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: hsla(0, 0%, 100%, 0.05);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.fontOptionItem {
|
.fontOptionItem {
|
||||||
height: 30px;
|
height: 30px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user