From 6e476489f52d1b2adf3bb34add6a5296ed26812e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E7=89=9B=E4=BB=94?= <635750556@qq.com> Date: Fri, 17 Nov 2023 13:47:04 +0800 Subject: [PATCH 1/4] =?UTF-8?q?feat:Xmind=E5=AF=BC=E5=85=A5=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E6=A6=82=E8=A6=81=EF=BC=8C=E5=AF=BC=E5=85=A5=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E6=A6=82=E8=A6=81=E5=B9=B6=E4=B8=94=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E4=B8=BA=E6=9C=80=E6=96=B0=E7=89=88=E6=9C=AC=E7=9A=84xmind?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/src/parse/xmind.js | 285 +++++++++++++++++++++++++++-- 1 file changed, 269 insertions(+), 16 deletions(-) diff --git a/simple-mind-map/src/parse/xmind.js b/simple-mind-map/src/parse/xmind.js index 07cfd7c1..2615fd85 100644 --- a/simple-mind-map/src/parse/xmind.js +++ b/simple-mind-map/src/parse/xmind.js @@ -65,6 +65,15 @@ const transformXmind = async (content, files) => { if (node.labels && node.labels.length > 0) { newNode.data.tag = node.labels } + // 概要 + if (node.currentSummary) { + newNode.data.generalization = { + text: node.currentSummary.title, + expand: true, + isActive: false, + } + } + // 图片 if (node.image && /\.(jpg|jpeg|png|gif|webp)$/.test(node.image.src)) { // 处理异步逻辑 @@ -108,9 +117,42 @@ const transformXmind = async (content, files) => { node.children.attached && node.children.attached.length > 0 ) { - node.children.attached.forEach(item => { + // 分析概要位置 + // xmind 支持合并概要,现在的组件不支持合并概要,分别拆分开来 + let summariesPosition = {} + if (node.summaries && node.summaries.length > 0) { + node.summaries.forEach(item => { + // 使用正则表达式提取第二个数字,例如 (2,3) + const match = item.range.match(/\((\d+),(\d+)\)/) + const firstNumber = match ? parseInt(match[1], 10) : null + const secondNumber = match ? parseInt(match[2], 10) : null + summariesPosition[item.topicId] = [] + for (let i = firstNumber; i <= secondNumber; i++) { + summariesPosition[item.topicId].push(i) + } + }) + } + + let summariesPositionData = {} + if (node.children.summary && node.children.summary.length > 0) { + node.children.summary.forEach(summary => { + if (Object.prototype.hasOwnProperty.call(summariesPosition, summary.id)) { + summariesPosition[summary.id].forEach (index => { + summariesPositionData[index] = summary + }) + } + }) + } + + node.children.attached.forEach((item, index) => { + let currentSummary = null + if (Object.prototype.hasOwnProperty.call(summariesPositionData, index)) { + currentSummary = summariesPositionData[index] + } + let newChild = {} newNode.children.push(newChild) + item.currentSummary = currentSummary walk(item, newChild) }) } @@ -209,21 +251,195 @@ const transformOldXmind = content => { } // 数据转换为xmind文件 +// 直接转换为最新版本的xmind文件 2023.09.11172 const transformToXmind = async (data, name) => { const id = 'simpleMindMap_' + Date.now() const imageList = [] // 转换核心数据 - let newTree = {} + let newTree = { + legend: {}, + topicPositioning: "fixed", + theme: { + "boundary": { + "styleId": "94a6c549-690c-4f1e-b18f-457f114abcb0", + "type": "boundary", + "properties": { + "fo:font-style": "normal", + "svg:fill": "#D5E9FC", + "fo:font-family": "NeverMind", + "shape-class": "org.xmind.boundaryShape.roundedRect", + "fo:font-size": "13pt", + "fo:color": "#FFFFFF", + "fo:font-weight": "500", + "line-pattern": "dash", + "line-color": "#0288D1" + } + }, + "subTopic": { + "styleId": "ddd92ae3-f2b4-48ee-9e47-2dacee6acac4", + "type": "topic", + "properties": { + "fo:text-align": "left", + "fo:font-style": "normal", + "svg:fill": "none", + "fo:font-family": "NeverMind", + "fo:font-size": "13pt", + "shape-class": "org.xmind.topicShape.underline", + "fo:color": "#333333", + "fo:font-weight": "500", + "line-class": "org.xmind.branchConnection.roundedElbow" + } + }, + "summary": { + "styleId": "8aa88864-8667-4627-a763-a84973e0109b", + "type": "summary", + "properties": { + "line-width": "2", + "shape-class": "org.xmind.summaryShape.round", + "line-color": "#0288D1" + } + }, + "calloutTopic": { + "styleId": "9bffcc6a-0526-4db5-b304-ea3830a42846", + "type": "topic", + "properties": { + "fo:font-style": "normal", + "fo:font-family": "NeverMind", + "fo:font-size": "13pt", + "fo:color": "#FFFFFF", + "fo:font-weight": "600", + "callout-shape-class": "org.xmind.calloutTopicShape.balloon.roundedRect" + } + }, + "summaryTopic": { + "styleId": "a82dc72d-29bc-4d81-bd44-3f1bee0ed35c", + "type": "topic", + "properties": { + "fo:font-style": "normal", + "line-width": "1", + "svg:fill": "#333333", + "fo:font-family": "NeverMind", + "fo:font-size": "13pt", + "shape-class": "org.xmind.topicShape.roundedRect", + "border-line-width": "1", + "fo:font-weight": "600", + "line-class": "org.xmind.branchConnection.roundedElbow", + "border-line-color": "none", + "line-color": "#333333" + } + }, + "floatingTopic": { + "styleId": "8286b472-0630-4970-8bf1-510a831dc2b9", + "type": "topic", + "properties": { + "fo:font-style": "normal", + "line-width": "1", + "svg:fill": "#333333", + "fo:font-family": "NeverMind", + "fo:font-size": "13pt", + "shape-class": "org.xmind.topicShape.roundedRect", + "border-line-width": "0", + "fo:color": "#FFFFFF", + "fo:font-weight": "600", + "line-class": "org.xmind.branchConnection.roundedElbow", + "border-line-color": "none", + "line-color": "#333333" + } + }, + "importantTopic": { + "type": "topic", + "properties": { + "svg:fill": "#FFFF00", + "fo:color": "#333333", + "fo:font-weight": "bold" + } + }, + "expiredTopic": { + "type": "topic", + "properties": { + "fo:font-style": "italic", + "fo:text-decoration": " line-through" + } + }, + "centralTopic": { + "styleId": "9a94e1a0-7e67-48df-a231-7fa0c60b7b97", + "type": "topic", + "properties": { + "fo:font-style": "normal", + "line-width": "2", + "svg:fill": "#0288D1", + "fo:font-family": "NeverMind", + "fo:font-size": "28pt", + "shape-class": "org.xmind.topicShape.roundedRect", + "border-line-width": "0", + "fo:font-weight": "600", + "line-class": "org.xmind.branchConnection.curve", + "line-color": "#333333" + } + }, + "mainTopic": { + "styleId": "7565fe37-2200-4483-b343-91bdf53e563e", + "type": "topic", + "properties": { + "fo:font-style": "normal", + "fo:text-align": "left", + "line-width": "1", + "fo:font-family": "NeverMind", + "fo:font-size": "20pt", + "border-line-width": "2", + "fo:font-weight": "600", + "line-class": "org.xmind.branchConnection.roundedElbow", + "line-color": "#333333", + "border-line-color": "#333333" + } + }, + "id": "6518e97a4149b5f96691ab3b5d", + "relationship": { + "styleId": "1611e291-8cc1-4500-93a5-69281d5bedf0", + "type": "relationship", + "properties": { + "line-width": "2", + "fo:font-family": "NeverMind", + "shape-class": "org.xmind.relationshipShape.curved", + "fo:font-size": "13pt", + "fo:color": "#333333", + "fo:font-weight": "normal", + "line-color": "#0288D1" + } + }, + "minorTopic": { + "type": "topic", + "properties": { + "svg:fill": "#FFCB88", + "fo:color": "#333333", + "fo:font-weight": "bold" + } + }, + "map": { + "styleId": "7e90467a-d643-4fa9-84f2-f8f0166e5afb", + "type": "map", + "properties": {} + } + }, + id, + } + let waitLoadImageList = [] + let walk = async (node, newNode, isRoot) => { let newData = { id: node.data.uid, - structureClass: 'org.xmind.ui.logic.right', - title: getTextFromHtml(node.data.text), // 节点文本 + title: getTextFromHtml(node.data.text), + extensions: [], + markers: [], + labels: [], + notes: {}, + comments: [], children: { - attached: [] - } + attached: [], + }, } + // 备注 if (node.data.note !== undefined) { newData.notes = { @@ -243,6 +459,7 @@ const transformToXmind = async (data, name) => { if (node.data.tag !== undefined) { newData.labels = node.data.tag || [] } + // 图片 if (node.data.image) { // 处理异步逻辑 @@ -276,17 +493,12 @@ const transformToXmind = async (data, name) => { resolve() } } + // 样式 // 暂时不考虑样式 if (isRoot) { - newData.class = 'topic' - newNode.id = id - newNode.class = 'sheet' newNode.title = name - newNode.extensions = [] - newNode.topicPositioning = 'fixed' - newNode.topicOverlapping = 'overlap' - newNode.coreVersion = '2.100.0' + newNode.structureClass = "org.xmind.ui.map.unbalanced" newNode.rootTopic = newData } else { Object.keys(newData).forEach(key => { @@ -294,25 +506,66 @@ const transformToXmind = async (data, name) => { }) } if (node.children && node.children.length > 0) { - node.children.forEach(child => { + let summary = [] + let summaries = [] + node.children.forEach((child,index) => { + if (child.data.generalization) { + let summaryTopicId = node.data.uid+'_topic_id_' + index + let summaryTitle = getTextFromHtml(child.data.generalization.text) + summary.push({ + id: summaryTopicId, + title: summaryTitle, + attributedTitle: [ + { + text: summaryTitle + } + ] + }) + + summaries.push({ + id: node.data.uid+'_range_id_' + index, + range: "("+index+","+index+")", + topicId: summaryTopicId + }) + } let newChild = {} walk(child, newChild) newData.children.attached.push(newChild) }) + + if (isRoot) { + if (summaries.length > 0) { + newNode.rootTopic.children.summary = summary + newNode.rootTopic.summaries = summaries + } + } else { + if (summaries.length > 0) { + newNode.children.summary = summary + newNode.summaries = summaries + } + } } } walk(data, newTree, true) + await Promise.all(waitLoadImageList) + const contentData = [newTree] + // 创建压缩包 const zip = new JSZip() zip.file('content.json', JSON.stringify(contentData)) zip.file( 'metadata.json', - `{"modifier":"","dataStructureVersion":"1","layoutEngineVersion":"2","activeSheetId":"${id}"}` + `{"dataStructureVersion":"2","creator":{"name":"mind-map"},"layoutEngineVersion":"3"}` ) + zip.file( + 'content.xml', + ` Warning 警告 Attention Warnung 경고 This file can not be opened normally, please do not modify and save, otherwise the contents will be permanently lost! You can try using XMind 8 Update 3 or later version to open 该文件无法正常打开,请勿修改并保存,否则文件内容将会永久性丢失! 你可以尝试使用 XMind 8 Update 3 或更新版本打开 該文件無法正常打開,請勿修改並保存,否則文件內容將會永久性丟失! 你可以嘗試使用 XMind 8 Update 3 或更新版本打開 この文書は正常に開かないので、修正して保存しないようにしてください。そうでないと、書類の内容が永久に失われます。! XMind 8 Update 3 や更新版を使って開くこともできます Datei kann nicht richtig geöffnet werden. Bitte ändern Sie diese Datei nicht und speichern Sie sie, sonst wird die Datei endgültig gelöscht werden. Bitte versuchen Sie, diese Datei mit XMind 8 Update 3 oder später zu öffnen. Ce fichier ne peut pas ouvert normalement, veuillez le rédiger et sauvegarder, sinon le fichier sera perdu en permanence. Vous pouvez essayer d'ouvrir avec XMind 8 Update 3 ou avec une version plus récente. 파일을 정상적으로 열 수 없으며, 수정 및 저장하지 마십시오. 그렇지 않으면 파일의 내용이 영구적으로 손실됩니다! XMind 8 Update 3 또는 이후 버전을 사용하여 -1 Sheet 1 ` + ) + const manifestData = { - 'file-entries': { 'content.json': {}, 'metadata.json': {} } + 'file-entries': { 'content.json': {}, 'metadata.json': {}, 'Thumbnails/thumbnail.png':{} } } // 图片 if (imageList.length > 0) { From 13dc61a5857391c19946204af77cc59955fb25b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E7=89=9B=E4=BB=94?= <635750556@qq.com> Date: Fri, 17 Nov 2023 16:20:02 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E6=97=A7=E7=89=88=E6=9C=ACxmind8=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E5=AF=BC=E5=85=A5=E6=A6=82=E8=A6=81=EF=BC=8C=E8=80=81?= =?UTF-8?q?=E7=9A=84=E6=B3=A8=E8=A7=A3=E8=A2=AB=E6=90=9E=E6=88=90=E4=BA=86?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=E4=B8=BB=E9=A2=98=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/src/parse/xmind.js | 79 +++++++++++++++++++++++++++--- 1 file changed, 73 insertions(+), 6 deletions(-) diff --git a/simple-mind-map/src/parse/xmind.js b/simple-mind-map/src/parse/xmind.js index 2615fd85..ec630657 100644 --- a/simple-mind-map/src/parse/xmind.js +++ b/simple-mind-map/src/parse/xmind.js @@ -122,7 +122,7 @@ const transformXmind = async (content, files) => { let summariesPosition = {} if (node.summaries && node.summaries.length > 0) { node.summaries.forEach(item => { - // 使用正则表达式提取第二个数字,例如 (2,3) + // 使用正则表达式提取位置数字,例如 (2,3) const match = item.range.match(/\((\d+),(\d+)\)/) const firstNumber = match ? parseInt(match[1], 10) : null const secondNumber = match ? parseInt(match[2], 10) : null @@ -227,20 +227,87 @@ const transformOldXmind = content => { } catch (error) { console.log(error) } + + // 概要 + if (node.currentSummary) { + let summaryText = '' + if (node.currentSummary + && node.currentSummary.elements + && node.currentSummary.elements[0] + && node.currentSummary.elements[0].elements + && node.currentSummary.elements[0].elements[0]) { + summaryText = node.currentSummary.elements[0].elements[0].text + } + newNode.data.generalization = { + text: summaryText, + expand: true, + isActive: false, + } + } + // 子节点 newNode.children = [] + let _children = getItemByName(nodeElements, 'children') if (_children && _children.elements && _children.elements.length > 0) { + let summaryNode = null + let summariesNode = getItemByName(nodeElements, 'summaries') _children.elements.forEach(item => { + if (item.name === 'topics' && item.attributes.type === 'summary') { + summaryNode = item + return + } + }) + + // 分析概要位置 + // xmind 支持合并概要,现在的组件不支持合并概要,分别拆分开来 + let summariesPosition = {} + if (summariesNode !== null && summariesNode.elements && summariesNode.elements.length > 0) { + summariesNode.elements.forEach(item => { + // 使用正则表达式提取位置数字,例如 (2,3) + const match = item.attributes.range.match(/\((\d+),(\d+)\)/) + const firstNumber = match ? parseInt(match[1], 10) : null + const secondNumber = match ? parseInt(match[2], 10) : null + summariesPosition[item.attributes['topic-id']] = [] + for (let i = firstNumber; i <= secondNumber; i++) { + summariesPosition[item.attributes['topic-id']].push(i) + } + }) + } + + let summariesPositionData = {} + if (summaryNode !== null && summaryNode.elements && summaryNode.elements.length > 0) { + summaryNode.elements.forEach(summary => { + if (Object.prototype.hasOwnProperty.call(summariesPosition, summary.attributes.id)) { + summariesPosition[summary.attributes.id].forEach (index => { + summariesPositionData[index] = summary + }) + } + }) + } + + _children.elements.forEach((item, index) => { if (item.name === 'topics') { - ;(item.elements || []).forEach(item2 => { - let newChild = {} - newNode.children.push(newChild) - walk(item2, newChild) - }) + if (item.attributes.type !== 'summary') { + (item.elements || []).forEach((item2, index2) => { + let newChild = {} + let currentSummary = null + if (Object.prototype.hasOwnProperty.call(summariesPositionData, index2)) { + currentSummary = summariesPositionData[index2] + } + newNode.children.push(newChild) + item2.currentSummary = currentSummary + walk(item2, newChild) + }) + } } else { let newChild = {} + let currentSummary = null + if (Object.prototype.hasOwnProperty.call(summariesPositionData, index)) { + currentSummary = summariesPositionData[index] + } newNode.children.push(newChild) + item.currentSummary = currentSummary walk(item, newChild) } }) From 48b5ff5f1c9859882df66261959b9a6c0b0e22aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E7=89=9B=E4=BB=94?= <635750556@qq.com> Date: Fri, 17 Nov 2023 16:56:15 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/src/parse/xmind.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simple-mind-map/src/parse/xmind.js b/simple-mind-map/src/parse/xmind.js index ec630657..430b286d 100644 --- a/simple-mind-map/src/parse/xmind.js +++ b/simple-mind-map/src/parse/xmind.js @@ -262,7 +262,7 @@ const transformOldXmind = content => { // 分析概要位置 // xmind 支持合并概要,现在的组件不支持合并概要,分别拆分开来 let summariesPosition = {} - if (summariesNode !== null && summariesNode.elements && summariesNode.elements.length > 0) { + if (typeof summariesNode == 'undefined' && summariesNode.elements && summariesNode.elements.length > 0) { summariesNode.elements.forEach(item => { // 使用正则表达式提取位置数字,例如 (2,3) const match = item.attributes.range.match(/\((\d+),(\d+)\)/) From a1bbe543ba5e6a5a4f9bf2ea54f59d06f43be9d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E7=89=9B=E4=BB=94?= <635750556@qq.com> Date: Fri, 17 Nov 2023 17:03:35 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/src/parse/xmind.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simple-mind-map/src/parse/xmind.js b/simple-mind-map/src/parse/xmind.js index 430b286d..378b6ede 100644 --- a/simple-mind-map/src/parse/xmind.js +++ b/simple-mind-map/src/parse/xmind.js @@ -262,7 +262,7 @@ const transformOldXmind = content => { // 分析概要位置 // xmind 支持合并概要,现在的组件不支持合并概要,分别拆分开来 let summariesPosition = {} - if (typeof summariesNode == 'undefined' && summariesNode.elements && summariesNode.elements.length > 0) { + if (typeof summariesNode != 'undefined' && summariesNode.elements && summariesNode.elements.length > 0) { summariesNode.elements.forEach(item => { // 使用正则表达式提取位置数字,例如 (2,3) const match = item.attributes.range.match(/\((\d+),(\d+)\)/)