Feature:支持导入和导出为markdown格式文件
This commit is contained in:
parent
cabe286ebb
commit
5fa0ff7b5c
@ -5,9 +5,13 @@ import KeyboardNavigation from './src/KeyboardNavigation.js'
|
|||||||
import Export from './src/Export.js'
|
import Export from './src/Export.js'
|
||||||
import Drag from './src/Drag.js'
|
import Drag from './src/Drag.js'
|
||||||
import Select from './src/Select.js'
|
import Select from './src/Select.js'
|
||||||
|
import AssociativeLine from './src/AssociativeLine'
|
||||||
|
import RichText from './src/RichText'
|
||||||
import xmind from './src/parse/xmind.js'
|
import xmind from './src/parse/xmind.js'
|
||||||
|
import markdown from './src/parse/markdown.js'
|
||||||
|
|
||||||
MindMap.xmind = xmind
|
MindMap.xmind = xmind
|
||||||
|
MindMap.markdown = markdown
|
||||||
|
|
||||||
MindMap
|
MindMap
|
||||||
.usePlugin(MiniMap)
|
.usePlugin(MiniMap)
|
||||||
@ -16,5 +20,7 @@ MindMap
|
|||||||
.usePlugin(KeyboardNavigation)
|
.usePlugin(KeyboardNavigation)
|
||||||
.usePlugin(Export)
|
.usePlugin(Export)
|
||||||
.usePlugin(Select)
|
.usePlugin(Select)
|
||||||
|
.usePlugin(AssociativeLine)
|
||||||
|
.usePlugin(RichText)
|
||||||
|
|
||||||
export default MindMap
|
export default MindMap
|
||||||
914
simple-mind-map/package-lock.json
generated
914
simple-mind-map/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -31,6 +31,7 @@
|
|||||||
"html2canvas": "^1.4.1",
|
"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",
|
||||||
"quill": "^1.3.6",
|
"quill": "^1.3.6",
|
||||||
"uuid": "^9.0.0",
|
"uuid": "^9.0.0",
|
||||||
"xml-js": "^1.6.11"
|
"xml-js": "^1.6.11"
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { imgToDataUrl, downloadFile } from './utils'
|
|||||||
import JsPDF from 'jspdf'
|
import JsPDF from 'jspdf'
|
||||||
import { SVG } from '@svgdotjs/svg.js'
|
import { SVG } from '@svgdotjs/svg.js'
|
||||||
import drawBackgroundImageToCanvas from './utils/simulateCSSBackgroundInCanvas'
|
import drawBackgroundImageToCanvas from './utils/simulateCSSBackgroundInCanvas'
|
||||||
|
import { transformToMarkdown } from './parse/toMarkdown'
|
||||||
const URL = window.URL || window.webkitURL || window
|
const URL = window.URL || window.webkitURL || window
|
||||||
|
|
||||||
// 导出类
|
// 导出类
|
||||||
@ -236,6 +237,14 @@ class Export {
|
|||||||
smm(name, withConfig) {
|
smm(name, withConfig) {
|
||||||
return this.json(name, withConfig)
|
return this.json(name, withConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// markdown文件
|
||||||
|
md() {
|
||||||
|
let data = this.mindMap.getData()
|
||||||
|
let content = transformToMarkdown(data)
|
||||||
|
let blob = new Blob([content])
|
||||||
|
return URL.createObjectURL(blob)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Export.instanceName = 'doExport'
|
Export.instanceName = 'doExport'
|
||||||
|
|||||||
7
simple-mind-map/src/parse/markdown.js
Normal file
7
simple-mind-map/src/parse/markdown.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { transformToMarkdown } from './toMarkdown'
|
||||||
|
import { transformMarkdownTo } from './markdownTo'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
transformToMarkdown,
|
||||||
|
transformMarkdownTo
|
||||||
|
}
|
||||||
98
simple-mind-map/src/parse/markdownTo.js
Normal file
98
simple-mind-map/src/parse/markdownTo.js
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import { fromMarkdown } from 'mdast-util-from-markdown'
|
||||||
|
|
||||||
|
// 处理list的情况
|
||||||
|
const handleList = node => {
|
||||||
|
let list = []
|
||||||
|
let walk = (arr, newArr) => {
|
||||||
|
for (let i = 0; i < arr.length; i++) {
|
||||||
|
let cur = arr[i]
|
||||||
|
let node = {}
|
||||||
|
node.data = {
|
||||||
|
// 节点内容
|
||||||
|
text: cur.children[0].children[0].value
|
||||||
|
}
|
||||||
|
node.children = []
|
||||||
|
newArr.push(node)
|
||||||
|
if (cur.children.length > 1) {
|
||||||
|
for (let j = 1; j < cur.children.length; j++) {
|
||||||
|
let cur2 = cur.children[j]
|
||||||
|
if (cur2.type === 'list') {
|
||||||
|
walk(cur2.children, node.children)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
walk(node.children, list)
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将markdown转换成节点树
|
||||||
|
export const transformMarkdownTo = async md => {
|
||||||
|
const tree = fromMarkdown(md)
|
||||||
|
let root = {
|
||||||
|
children: []
|
||||||
|
}
|
||||||
|
let childrenQueue = [root.children]
|
||||||
|
let currentChildren = root.children
|
||||||
|
let depthQueue = [-1]
|
||||||
|
let currentDepth = -1
|
||||||
|
for (let i = 0; i < tree.children.length; i++) {
|
||||||
|
let cur = tree.children[i]
|
||||||
|
if (cur.type === 'heading') {
|
||||||
|
if (!cur.children[0]) continue
|
||||||
|
// 创建新节点
|
||||||
|
let node = {}
|
||||||
|
node.data = {
|
||||||
|
// 节点内容
|
||||||
|
text: cur.children[0].value
|
||||||
|
}
|
||||||
|
node.children = []
|
||||||
|
// 如果当前的层级大于上一个节点的层级,那么是其子节点
|
||||||
|
if (cur.depth > currentDepth) {
|
||||||
|
// 添加到上一个节点的子节点列表里
|
||||||
|
currentChildren.push(node)
|
||||||
|
// 更新当前栈和数据
|
||||||
|
childrenQueue.push(node.children)
|
||||||
|
currentChildren = node.children
|
||||||
|
depthQueue.push(cur.depth)
|
||||||
|
currentDepth = cur.depth
|
||||||
|
} else if (cur.depth === currentDepth) {
|
||||||
|
// 如果当前层级等于上一个节点的层级,说明它们是同级节点
|
||||||
|
// 将上一个节点出栈
|
||||||
|
childrenQueue.pop()
|
||||||
|
currentChildren = childrenQueue[childrenQueue.length - 1]
|
||||||
|
depthQueue.pop()
|
||||||
|
currentDepth = depthQueue[depthQueue.length - 1]
|
||||||
|
// 追加到上上个节点的子节点列表里
|
||||||
|
currentChildren.push(node)
|
||||||
|
// 更新当前栈和数据
|
||||||
|
childrenQueue.push(node.children)
|
||||||
|
currentChildren = node.children
|
||||||
|
depthQueue.push(cur.depth)
|
||||||
|
currentDepth = cur.depth
|
||||||
|
} else {
|
||||||
|
// 如果当前层级小于上一个节点的层级,那么一直出栈,直到遇到比当前层级小的节点
|
||||||
|
while (depthQueue.length) {
|
||||||
|
childrenQueue.pop()
|
||||||
|
currentChildren = childrenQueue[childrenQueue.length - 1]
|
||||||
|
depthQueue.pop()
|
||||||
|
currentDepth = depthQueue[depthQueue.length - 1]
|
||||||
|
if (currentDepth < cur.depth) {
|
||||||
|
// 追加到该节点的子节点列表里
|
||||||
|
currentChildren.push(node)
|
||||||
|
// 更新当前栈和数据
|
||||||
|
childrenQueue.push(node.children)
|
||||||
|
currentChildren = node.children
|
||||||
|
depthQueue.push(cur.depth)
|
||||||
|
currentDepth = cur.depth
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (cur.type === 'list') {
|
||||||
|
currentChildren.push(...handleList(cur))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return root.children[0]
|
||||||
|
}
|
||||||
53
simple-mind-map/src/parse/toMarkdown.js
Normal file
53
simple-mind-map/src/parse/toMarkdown.js
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import { walk } from '../utils'
|
||||||
|
|
||||||
|
let el = null
|
||||||
|
const getText = str => {
|
||||||
|
if (!el) {
|
||||||
|
el = document.createElement('div')
|
||||||
|
}
|
||||||
|
el.innerHTML = str
|
||||||
|
return el.textContent
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTitleMark = level => {
|
||||||
|
return new Array(level).fill('#').join('')
|
||||||
|
}
|
||||||
|
|
||||||
|
const getIndentMark = level => {
|
||||||
|
return new Array(level - 6).fill(' ').join('') + '*'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换成markdown格式
|
||||||
|
export const transformToMarkdown = root => {
|
||||||
|
let content = ''
|
||||||
|
walk(
|
||||||
|
root,
|
||||||
|
null,
|
||||||
|
(node, parent, isRoot, layerIndex) => {
|
||||||
|
let level = layerIndex + 1
|
||||||
|
let text = node.data.richText ? getText(node.data.text) : node.data.text
|
||||||
|
if (level <= 6) {
|
||||||
|
content += getTitleMark(level)
|
||||||
|
} else {
|
||||||
|
content += getIndentMark(level)
|
||||||
|
}
|
||||||
|
content += ' ' + text
|
||||||
|
// 概要
|
||||||
|
let generalization = node.data.generalization
|
||||||
|
if (generalization && generalization.text) {
|
||||||
|
let generalizationText = generalization.richText
|
||||||
|
? getText(generalization.text)
|
||||||
|
: generalization.text
|
||||||
|
content += `[${generalizationText}]`
|
||||||
|
}
|
||||||
|
content += '\n\n'
|
||||||
|
// 备注
|
||||||
|
if (node.data.note) {
|
||||||
|
content += node.data.note + '\n\n'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
() => {},
|
||||||
|
true
|
||||||
|
)
|
||||||
|
return content
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user