From 888b8e725ad3a77832bfaf8abfc5d6d1c22bec8e Mon Sep 17 00:00:00 2001 From: Xbs233 <32960078+Xbs233@users.noreply.github.com> Date: Tue, 8 Aug 2023 21:23:12 +0800 Subject: [PATCH 1/9] =?UTF-8?q?fix:=E6=89=8B=E5=8A=BF=E7=BC=A9=E5=B0=8F?= =?UTF-8?q?=E6=97=B6=20=E4=BC=9A=E5=85=88=E6=94=BE=E5=A4=A7=E4=B8=80?= =?UTF-8?q?=E6=AC=A1=20=E5=86=8D=E7=BC=A9=E5=B0=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复初次onTouchmove时 必然是放大的情况 --- simple-mind-map/src/plugins/TouchEvent.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/simple-mind-map/src/plugins/TouchEvent.js b/simple-mind-map/src/plugins/TouchEvent.js index ea8681b4..e8328ae5 100644 --- a/simple-mind-map/src/plugins/TouchEvent.js +++ b/simple-mind-map/src/plugins/TouchEvent.js @@ -57,7 +57,10 @@ class TouchEvent { let { x: touch2ClientX, y: touch2ClientY } = this.mindMap.toPos(touch2.clientX, touch2.clientY) let cx = (touch1ClientX + touch2ClientX) / 2 let cy = (touch1ClientY + touch2ClientY) / 2 - if (distance > this.doubleTouchmoveDistance) { + if (this.doubleTouchmoveDistance === 0) { + this.doubleTouchmoveDistance = distance + return; + } else if (distance > this.doubleTouchmoveDistance) { // 放大 this.mindMap.view.enlarge(cx, cy, true) } else { From 2fef76c55cebb220499fe6a1b7d7db56c5f8760c Mon Sep 17 00:00:00 2001 From: wanglin2 <1013335014@qq.com> Date: Wed, 9 Aug 2023 17:01:35 +0800 Subject: [PATCH 2/9] =?UTF-8?q?Feat=EF=BC=9A=E5=AF=BC=E5=87=BA=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E7=94=B1html2canvas=E5=BA=93=E6=94=B9=E4=B8=BAdom-to-?= =?UTF-8?q?image-more=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/package-lock.json | 28 ++++++++++++++++++--- simple-mind-map/package.json | 2 +- simple-mind-map/src/plugins/RichText.js | 33 ++++++++++++++++++------- 3 files changed, 49 insertions(+), 14 deletions(-) diff --git a/simple-mind-map/package-lock.json b/simple-mind-map/package-lock.json index 160c304d..ee730af9 100644 --- a/simple-mind-map/package-lock.json +++ b/simple-mind-map/package-lock.json @@ -1,17 +1,17 @@ { "name": "simple-mind-map", - "version": "0.6.11-fix.1", + "version": "0.6.12", "lockfileVersion": 2, "requires": true, "packages": { "": { - "version": "0.6.11-fix.1", + "version": "0.6.12", "license": "MIT", "dependencies": { "@svgdotjs/svg.js": "^3.0.16", "deepmerge": "^1.5.2", + "dom-to-image-more": "^3.1.6", "eventemitter3": "^4.0.7", - "html2canvas": "^1.4.1", "jspdf": "^2.5.1", "jszip": "^3.10.1", "mdast-util-from-markdown": "^1.3.0", @@ -255,6 +255,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", + "optional": true, "engines": { "node": ">= 0.6.0" } @@ -411,6 +412,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", + "optional": true, "dependencies": { "utrie": "^1.0.2" } @@ -516,6 +518,11 @@ "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": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.1.tgz", @@ -937,6 +944,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", + "optional": true, "dependencies": { "css-line-break": "^2.1.0", "text-segmentation": "^1.0.3" @@ -2142,6 +2150,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", + "optional": true, "dependencies": { "utrie": "^1.0.2" } @@ -2206,6 +2215,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", + "optional": true, "dependencies": { "base64-arraybuffer": "^1.0.2" } @@ -2461,7 +2471,8 @@ "base64-arraybuffer": { "version": "1.0.2", "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": { "version": "1.1.11", @@ -2576,6 +2587,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", + "optional": true, "requires": { "utrie": "^1.0.2" } @@ -2648,6 +2660,11 @@ "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": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.1.tgz", @@ -2966,6 +2983,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", + "optional": true, "requires": { "css-line-break": "^2.1.0", "text-segmentation": "^1.0.3" @@ -3749,6 +3767,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", + "optional": true, "requires": { "utrie": "^1.0.2" } @@ -3800,6 +3819,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", + "optional": true, "requires": { "base64-arraybuffer": "^1.0.2" } diff --git a/simple-mind-map/package.json b/simple-mind-map/package.json index 8bcf3c53..1e2eea22 100644 --- a/simple-mind-map/package.json +++ b/simple-mind-map/package.json @@ -26,8 +26,8 @@ "dependencies": { "@svgdotjs/svg.js": "^3.0.16", "deepmerge": "^1.5.2", + "dom-to-image-more": "^3.1.6", "eventemitter3": "^4.0.7", - "html2canvas": "^1.4.1", "jspdf": "^2.5.1", "jszip": "^3.10.1", "mdast-util-from-markdown": "^1.3.0", diff --git a/simple-mind-map/src/plugins/RichText.js b/simple-mind-map/src/plugins/RichText.js index 1a640b2e..f55ad867 100644 --- a/simple-mind-map/src/plugins/RichText.js +++ b/simple-mind-map/src/plugins/RichText.js @@ -1,7 +1,12 @@ import Quill from 'quill' import 'quill/dist/quill.snow.css' -import html2canvas from 'html2canvas' -import { walk, getTextFromHtml, isWhite, getVisibleColorFromTheme } from '../utils' +import domtoimage from 'dom-to-image-more' +import { + walk, + getTextFromHtml, + isWhite, + getVisibleColorFromTheme +} from '../utils' import { CONSTANTS } from '../constants/constant' let extended = false @@ -172,10 +177,11 @@ class RichText { this.textEditNode.addEventListener('click', e => { e.stopPropagation() }) - this.textEditNode.addEventListener('mousedown', (e) => { + this.textEditNode.addEventListener('mousedown', e => { e.stopPropagation() }) - const targetNode = this.mindMap.opt.customInnerElsAppendTo || document.body + const targetNode = + this.mindMap.opt.customInnerElsAppendTo || document.body targetNode.appendChild(this.textEditNode) } // 使用节点的填充色,否则如果节点颜色是白色的话编辑时看不见 @@ -185,7 +191,11 @@ class RichText { this.textEditNode.style.marginTop = `-${paddingY * scaleY}px` this.textEditNode.style.zIndex = this.mindMap.opt.nodeTextEditZIndex 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.minHeight = originHeight + 'px' this.textEditNode.style.left = rect.left + 'px' @@ -502,11 +512,16 @@ class RichText { } } 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) - return canvas.toDataURL() + return res } // 将所有节点转换成非富文本节点 From e81e0a551218ea5e0597c3885887b5eb5f58194e Mon Sep 17 00:00:00 2001 From: wanglin2 <1013335014@qq.com> Date: Wed, 9 Aug 2023 17:12:55 +0800 Subject: [PATCH 3/9] =?UTF-8?q?Fix=EF=BC=9A=E4=BF=AE=E5=A4=8D=E5=BF=AB?= =?UTF-8?q?=E9=80=9F=E6=8B=96=E5=8A=A8=E8=8A=82=E7=82=B9=E5=87=A0=E6=AC=A1?= =?UTF-8?q?=E5=90=8E=E4=BC=9A=E6=A6=82=E7=8E=87=E6=80=A7=E6=8A=A5=E9=94=99?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/src/plugins/Drag.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simple-mind-map/src/plugins/Drag.js b/simple-mind-map/src/plugins/Drag.js index 28a8b354..fd99c5bf 100644 --- a/simple-mind-map/src/plugins/Drag.js +++ b/simple-mind-map/src/plugins/Drag.js @@ -204,7 +204,7 @@ class Drag extends Base { // 检测重叠节点 checkOverlapNode() { - if (!this.drawTransform) { + if (!this.drawTransform || !this.placeholder) { return } const { nodeDragPlaceholderMaxSize } = this.mindMap.opt From 5a32c1d99d3d20053895a598514d0f7c83e1650a Mon Sep 17 00:00:00 2001 From: wanglin2 <1013335014@qq.com> Date: Wed, 9 Aug 2023 17:16:31 +0800 Subject: [PATCH 4/9] =?UTF-8?q?Fix=EF=BC=9A=E4=BF=AE=E5=A4=8D=E5=9C=A8?= =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E7=AB=AF=E6=BF=80=E6=B4=BB=E8=8A=82=E7=82=B9?= =?UTF-8?q?=E3=80=81=E5=B1=95=E5=BC=80=E6=94=B6=E8=B5=B7=E6=97=B6=E7=AD=89?= =?UTF-8?q?=E6=93=8D=E4=BD=9C=E6=97=B6=E4=BC=9A=E6=8B=89=E8=B5=B7=E8=BE=93?= =?UTF-8?q?=E5=85=A5=E6=B3=95=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/src/plugins/TouchEvent.js | 1 + 1 file changed, 1 insertion(+) diff --git a/simple-mind-map/src/plugins/TouchEvent.js b/simple-mind-map/src/plugins/TouchEvent.js index ea8681b4..850f6612 100644 --- a/simple-mind-map/src/plugins/TouchEvent.js +++ b/simple-mind-map/src/plugins/TouchEvent.js @@ -7,6 +7,7 @@ class TouchEvent { this.singleTouchstartEvent = null this.clickNum = 0 this.doubleTouchmoveDistance = 0 + this.mindMap.renderer.textEdit.stopFocusOnNodeActive() this.bindEvent() } From 69e192ea9d114bccf203f9deab59e0b8eca66c92 Mon Sep 17 00:00:00 2001 From: wanglin2 <1013335014@qq.com> Date: Wed, 9 Aug 2023 17:22:23 +0800 Subject: [PATCH 5/9] =?UTF-8?q?Fix=EF=BC=9A=E4=BF=AE=E5=A4=8D=E5=9C=A8?= =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E7=AB=AF=E6=BF=80=E6=B4=BB=E8=8A=82=E7=82=B9?= =?UTF-8?q?=E3=80=81=E5=B1=95=E5=BC=80=E6=94=B6=E8=B5=B7=E6=97=B6=E7=AD=89?= =?UTF-8?q?=E6=93=8D=E4=BD=9C=E6=97=B6=E4=BC=9A=E6=8B=89=E8=B5=B7=E8=BE=93?= =?UTF-8?q?=E5=85=A5=E6=B3=95=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/src/core/render/TextEdit.js | 4 +- simple-mind-map/src/plugins/TouchEvent.js | 1 - simple-mind-map/src/utils/index.js | 99 ++++++++++++++------- 3 files changed, 70 insertions(+), 34 deletions(-) diff --git a/simple-mind-map/src/core/render/TextEdit.js b/simple-mind-map/src/core/render/TextEdit.js index 7fbf7698..70abc840 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 } from '../../utils' +import { getStrWithBrFromHtml, checkNodeOuter, isMobile } from '../../utils' // 节点文字编辑类 export default class TextEdit { @@ -67,7 +67,7 @@ export default class TextEdit { // 创建一个隐藏的文本输入框 createHiddenInput() { - if (this.hiddenInputEl) return + if (this.hiddenInputEl || isMobile()) return this.hiddenInputEl = document.createElement('input') this.hiddenInputEl.type = 'text' this.hiddenInputEl.style.cssText = ` diff --git a/simple-mind-map/src/plugins/TouchEvent.js b/simple-mind-map/src/plugins/TouchEvent.js index 850f6612..ea8681b4 100644 --- a/simple-mind-map/src/plugins/TouchEvent.js +++ b/simple-mind-map/src/plugins/TouchEvent.js @@ -7,7 +7,6 @@ class TouchEvent { this.singleTouchstartEvent = null this.clickNum = 0 this.doubleTouchmoveDistance = 0 - this.mindMap.renderer.textEdit.stopFocusOnNodeActive() this.bindEvent() } diff --git a/simple-mind-map/src/utils/index.js b/simple-mind-map/src/utils/index.js index 90236598..c934eca6 100644 --- a/simple-mind-map/src/utils/index.js +++ b/simple-mind-map/src/utils/index.js @@ -455,25 +455,25 @@ export const loadImage = imgFile => { } // 移除字符串中的html实体 -export const removeHTMLEntities = (str) => { - [[' ', ' ']].forEach((item) => { +export const removeHTMLEntities = str => { + ;[[' ', ' ']].forEach(item => { str = str.replaceAll(item[0], item[1]) }) return str } // 获取一个数据的类型 -export const getType = (data) => { +export const getType = data => { return Object.prototype.toString.call(data).slice(7, -1) } // 判断一个数据是否是null和undefined和空字符串 -export const isUndef = (data) => { +export const isUndef = data => { return data === null || data === undefined || data === '' } // 移除html字符串中节点的内联样式 -export const removeHtmlStyle = (html) => { +export const removeHtmlStyle = html => { return html.replaceAll(/(<[^\s]+)\s+style=["'][^'"]+["']\s*(>)/g, '$1$2') } @@ -485,12 +485,12 @@ export const addHtmlStyle = (html, tag, style) => { // 检查一个字符串是否是富文本字符 let checkIsRichTextEl = null -export const checkIsRichText = (str) => { +export const checkIsRichText = str => { if (!checkIsRichTextEl) { checkIsRichTextEl = document.createElement('div') } 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 } return false @@ -503,13 +503,20 @@ export const replaceHtmlText = (html, searchText, replaceText) => { replaceHtmlTextEl = document.createElement('div') } replaceHtmlTextEl.innerHTML = html - let walk = (root) => { + let walk = root => { let childNodes = root.childNodes - childNodes.forEach((node) => { - if (node.nodeType === 1) {// 元素节点 + childNodes.forEach(node => { + if (node.nodeType === 1) { + // 元素节点 walk(node) - } else if (node.nodeType === 3) {// 文本节点 - root.replaceChild(document.createTextNode(node.nodeValue.replaceAll(searchText, replaceText)), node) + } else if (node.nodeType === 3) { + // 文本节点 + 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, '') - 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, '') - 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 list = [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 list = [ + 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] if (!isTransparent(color) && !isWhite(color)) { return color @@ -543,22 +567,24 @@ export const getVisibleColorFromTheme = (themeConfig) => { // 将
形式的节点富文本内容转换成\n换行的文本
let nodeRichTextToTextWithWrapEl = null
-export const nodeRichTextToTextWithWrap = (html) => {
+export const nodeRichTextToTextWithWrap = html => {
if (!nodeRichTextToTextWithWrapEl) {
nodeRichTextToTextWithWrapEl = document.createElement('div')
}
nodeRichTextToTextWithWrapEl.innerHTML = html
const childNodes = nodeRichTextToTextWithWrapEl.childNodes
let res = ''
- for(let i = 0; i < childNodes.length; i++) {
+ for (let i = 0; i < childNodes.length; i++) {
const node = childNodes[i]
- if (node.nodeType === 1) {// 元素节点
+ if (node.nodeType === 1) {
+ // 元素节点
if (node.tagName.toLowerCase() === 'p') {
res += node.textContent + '\n'
} else {
res += node.textContent
}
- } else if (node.nodeType === 3) {// 文本节点
+ } else if (node.nodeType === 3) {
+ // 文本节点
res += node.nodeValue
}
}
@@ -567,7 +593,7 @@ export const nodeRichTextToTextWithWrap = (html) => {
// 将
换行的文本转换成
形式的节点富文本内容 let textToNodeRichTextWithWrapEl = null -export const textToNodeRichTextWithWrap = (html) => { +export const textToNodeRichTextWithWrap = html => { if (!textToNodeRichTextWithWrapEl) { textToNodeRichTextWithWrapEl = document.createElement('div') } @@ -575,23 +601,34 @@ export const textToNodeRichTextWithWrap = (html) => { const childNodes = textToNodeRichTextWithWrapEl.childNodes let list = [] let str = '' - for(let i = 0; i < childNodes.length; i++) { + for (let i = 0; i < childNodes.length; i++) { const node = childNodes[i] - if (node.nodeType === 1) {// 元素节点 + if (node.nodeType === 1) { + // 元素节点 if (node.tagName.toLowerCase() === 'br') { list.push(str) str = '' } else { str += node.textContent } - } else if (node.nodeType === 3) {// 文本节点 + } else if (node.nodeType === 3) { + // 文本节点 str += node.nodeValue } } if (str) { list.push(str) } - return list.map((item) => { - return `
${item}
` - }).join('') -} \ No newline at end of file + return list + .map(item => { + return `${item}
` + }) + .join('') +} + +// 判断是否是移动端环境 +export const isMobile = () => { + return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test( + navigator.userAgent + ) +} From bbf424c6d2b1449d3474d29e8e11be07b29016c9 Mon Sep 17 00:00:00 2001 From: wanglin2 <1013335014@qq.com> Date: Wed, 9 Aug 2023 18:26:50 +0800 Subject: [PATCH 6/9] =?UTF-8?q?Feat:1.=E9=9D=9E=E5=AF=8C=E6=96=87=E6=9C=AC?= =?UTF-8?q?=E8=BE=93=E5=85=A5=E6=A1=86=E8=BF=9B=E5=85=A5=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E6=97=B6=E5=8F=96=E6=B6=88=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E5=85=A8=E9=80=89=EF=BC=9B2.=E5=AD=98=E5=9C=A8=E4=B8=80?= =?UTF-8?q?=E4=B8=AA=E6=BF=80=E6=B4=BB=E8=8A=82=E7=82=B9=E6=97=B6=EF=BC=8C?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=8C=89=E4=B8=8B=E4=B8=AD=E6=96=87=E3=80=81?= =?UTF-8?q?=E6=95=B0=E5=AD=97=E3=80=81=E8=8B=B1=E6=96=87=E6=8C=89=E9=94=AE?= =?UTF-8?q?=E6=97=B6=E8=87=AA=E5=8A=A8=E8=BF=9B=E5=85=A5=E6=96=87=E6=9C=AC?= =?UTF-8?q?=E7=BC=96=E8=BE=91=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/constants/defaultOptions.js | 7 ++- .../src/core/command/KeyCommand.js | 5 ++ simple-mind-map/src/core/render/TextEdit.js | 51 ++++++++++++++++--- 3 files changed, 55 insertions(+), 8 deletions(-) diff --git a/simple-mind-map/src/constants/defaultOptions.js b/simple-mind-map/src/constants/defaultOptions.js index 2c72933e..97560ac6 100644 --- a/simple-mind-map/src/constants/defaultOptions.js +++ b/simple-mind-map/src/constants/defaultOptions.js @@ -126,5 +126,10 @@ export const defaultOpt = { // 指定内部一些元素(节点文本编辑元素、节点备注显示元素、关联线文本编辑元素、节点图片调整按钮元素)添加到的位置,默认添加到document.body下 customInnerElsAppendTo: null, // 拖拽元素时,指示元素新位置的块的最大高度 - nodeDragPlaceholderMaxSize: 20 + nodeDragPlaceholderMaxSize: 20, + // 是否允许创建一个隐藏的输入框,该输入框会在节点激活时聚焦,用于粘贴数据和自动进入文本编辑状态 + enableCreateHiddenInput: true, + // 是否在存在一个激活节点时,当按下中文、英文、数字按键时自动进入文本编辑模式 + // 该配置在enableCreateHiddenInput设为true时生效 + enableAutoEnterTextEditWhenKeydown: true } diff --git a/simple-mind-map/src/core/command/KeyCommand.js b/simple-mind-map/src/core/command/KeyCommand.js index e894516c..4b493fd6 100644 --- a/simple-mind-map/src/core/command/KeyCommand.js +++ b/simple-mind-map/src/core/command/KeyCommand.js @@ -108,6 +108,11 @@ export default class KeyCommand { return arr } + // 判断是否按下了组合键 + hasCombinationKey(e) { + return e.ctrlKey || e.metaKey || e.altKey || e.shiftKey + } + // 获取快捷键对应的键值数组 getKeyCodeArr(key) { let keyArr = key.split(/\s*\+\s*/) diff --git a/simple-mind-map/src/core/render/TextEdit.js b/simple-mind-map/src/core/render/TextEdit.js index 70abc840..92499d98 100644 --- a/simple-mind-map/src/core/render/TextEdit.js +++ b/simple-mind-map/src/core/render/TextEdit.js @@ -67,7 +67,9 @@ export default class TextEdit { // 创建一个隐藏的文本输入框 createHiddenInput() { - if (this.hiddenInputEl || isMobile()) return + 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 = ` @@ -75,6 +77,25 @@ export default class TextEdit { left: -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 => { event.preventDefault() @@ -106,7 +127,7 @@ export default class TextEdit { stopFocusOnNodeActive() { this.enableFocus = false } - + // 开启默认聚焦 openFocusOnNodeActive() { this.enableFocus = true @@ -148,7 +169,7 @@ export default class TextEdit { this.mindMap.richText.showEditText(node, rect, isInserting) 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.registerTmpShortcut() if (!this.textEditNode) { @@ -179,10 +200,11 @@ export default class TextEdit { this.textEditNode.addEventListener('click', e => { e.stopPropagation() }) - this.textEditNode.addEventListener('mousedown', (e) => { + this.textEditNode.addEventListener('mousedown', e => { e.stopPropagation() }) - const targetNode = this.mindMap.opt.customInnerElsAppendTo || document.body + const targetNode = + this.mindMap.opt.customInnerElsAppendTo || document.body targetNode.appendChild(this.textEditNode) } let scale = this.mindMap.view.scale @@ -209,12 +231,27 @@ export default class TextEdit { } this.showTextEdit = true // 选中文本 - if (!this.cacheEditingText) { + // if (!this.cacheEditingText) { + // this.selectNodeText() + // } + if (isInserting) { this.selectNodeText() + } else { + this.focus() } this.cacheEditingText = '' } + // 聚焦 + focus() { + let selection = window.getSelection() + let range = document.createRange() + range.selectNodeContents(this.textEditNode) + range.collapse() + selection.removeAllRanges() + selection.addRange(range) + } + // 选中文本 selectNodeText() { let selection = window.getSelection() From d9a6981df40a128cfc51b524617d3bc5a0febdcf Mon Sep 17 00:00:00 2001 From: wanglin2 <1013335014@qq.com> Date: Wed, 9 Aug 2023 18:43:43 +0800 Subject: [PATCH 7/9] =?UTF-8?q?Fix=EF=BC=9A=E4=BF=AE=E5=A4=8D=E4=B8=BB?= =?UTF-8?q?=E9=A2=98=E9=85=8D=E7=BD=AE=E4=B8=AD=E8=83=8C=E6=99=AF=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E4=B8=BAnone=E6=97=B6=E4=BC=9A=E5=8F=91=E8=B5=B7?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=E5=BC=82=E5=B8=B8=E8=AF=B7=E6=B1=82=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/src/core/render/node/Style.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simple-mind-map/src/core/render/node/Style.js b/simple-mind-map/src/core/render/node/Style.js index 99e7def9..9cd452d2 100644 --- a/simple-mind-map/src/core/render/node/Style.js +++ b/simple-mind-map/src/core/render/node/Style.js @@ -17,7 +17,7 @@ class Style { // 设置新样式 let { backgroundColor, backgroundImage, backgroundRepeat, backgroundPosition, backgroundSize } = themeConfig el.style.backgroundColor = backgroundColor - if (backgroundImage) { + if (backgroundImage && backgroundImage !== 'none') { el.style.backgroundImage = `url(${backgroundImage})` el.style.backgroundRepeat = backgroundRepeat el.style.backgroundPosition = backgroundPosition From 962512969197b98f46c79fe6639ca00386ac3e63 Mon Sep 17 00:00:00 2001 From: wanglin2 <1013335014@qq.com> Date: Thu, 10 Aug 2023 08:47:16 +0800 Subject: [PATCH 8/9] =?UTF-8?q?Demo:=E5=AE=8C=E5=96=84=E5=8F=B3=E9=94=AE?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E5=92=8C=E5=AF=8C=E6=96=87=E6=9C=AC=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E6=9D=A1=E7=9A=84=E6=9A=97=E9=BB=91=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/pages/Edit/components/Contextmenu.vue | 43 +++++++++++++++---- .../pages/Edit/components/RichTextToolbar.vue | 43 +++++++++++++++---- 2 files changed, 69 insertions(+), 17 deletions(-) diff --git a/web/src/pages/Edit/components/Contextmenu.vue b/web/src/pages/Edit/components/Contextmenu.vue index c2d1d829..b3e9d461 100644 --- a/web/src/pages/Edit/components/Contextmenu.vue +++ b/web/src/pages/Edit/components/Contextmenu.vue @@ -3,6 +3,7 @@ class="contextmenuContainer listBox" v-if="isShow" :style="{ left: left + 'px', top: top + 'px' }" + :class="{ isDark: isDark }" >