From 1c84862f80d97a80c6c43804a5b349143996bc62 Mon Sep 17 00:00:00 2001 From: Ezequiel Vega Date: Sun, 27 Mar 2022 00:07:45 +0000 Subject: [PATCH] Add support for Freemind import. --- packages/mindplot/package.json | 2 +- .../src/components/export/freemind/Map.ts | 125 +- .../src/components/export/freemind/Node.ts | 40 + .../export/freemind/importer/VersionNumber.ts | 46 + .../import/FreemindIconConverter.ts | 10 + .../src/components/import/FreemindImporter.ts | 446 +++++++ .../src/components/import/Importer.ts | 3 + .../components/import/TextImporterFactory.ts | 19 + .../components/import/WisemappingImporter.ts | 29 + packages/mindplot/src/index.ts | 4 + packages/mindplot/test/unit/import/Helper.ts | 43 + .../unit/import/TextImporterTestSuite.test.ts | 27 + .../test/unit/import/expected/Cs2.wxml | 86 ++ .../test/unit/import/expected/SQLServer.wxml | 60 + .../expected/anonymity_on_the_edge.wxml | 140 +++ .../test/unit/import/expected/bug2.wxml | 44 + .../test/unit/import/expected/bug3.wxml | 514 ++++++++ .../unit/import/expected/cdata-support.wxml | 3 + .../import/expected/coderToDeveloper.wxml | 87 ++ .../test/unit/import/expected/complex.wxml | 26 + .../test/unit/import/expected/emptyNodes.wxml | 89 ++ .../test/unit/import/expected/enc.wxml | 117 ++ .../import/expected/freeMind_resources.wxml | 123 ++ .../test/unit/import/expected/i18n.wxml | 7 + .../test/unit/import/expected/i18n2.wxml | 11 + .../test/unit/import/expected/issue.wxml | 50 + .../test/unit/import/expected/npe.wxml | 3 + .../test/unit/import/expected/process.wxml | 100 ++ .../test/unit/import/expected/pub_sub.wxml | 415 +++++++ .../test/unit/import/expected/python.wxml | 284 +++++ .../test/unit/import/expected/sample3.wxml | 3 + .../test/unit/import/expected/sample4.wxml | 3 + .../test/unit/import/expected/welcome.wxml | 53 + .../expected/writing_an_essay_with.wxml | 251 ++++ .../mindplot/test/unit/import/input/Cs2.mm | 90 ++ .../test/unit/import/input/SQLServer.mm | 64 + .../import/input/anonymity_on_the_edge.mm | 112 ++ .../mindplot/test/unit/import/input/bug2.mm | 51 + .../mindplot/test/unit/import/input/bug3.mm | 1030 +++++++++++++++++ .../test/unit/import/input/cdata-support.mm | 12 + .../unit/import/input/coderToDeveloper.mm | 106 ++ .../test/unit/import/input/complex.mm | 51 + .../test/unit/import/input/emptyNodes.mm | 116 ++ .../mindplot/test/unit/import/input/enc.mm | 216 ++++ .../unit/import/input/freeMind_resources.mm | 134 +++ .../mindplot/test/unit/import/input/i18n.mm | 7 + .../mindplot/test/unit/import/input/i18n2.mm | 25 + .../mindplot/test/unit/import/input/issue.mm | 187 +++ .../mindplot/test/unit/import/input/npe.mm | 7 + .../test/unit/import/input/process.mm | 100 ++ .../test/unit/import/input/pub_sub.mm | 419 +++++++ .../mindplot/test/unit/import/input/python.mm | 316 +++++ .../test/unit/import/input/sample3.mm | 3 + .../test/unit/import/input/sample4.mm | 3 + .../test/unit/import/input/welcome.mm | 81 ++ .../import/input/writing_an_essay_with.mm | 543 +++++++++ packages/webapp/lang/de.json | 5 +- packages/webapp/lang/en.json | 5 +- packages/webapp/lang/es.json | 5 +- packages/webapp/lang/fr.json | 5 +- packages/webapp/lang/ru.json | 3 + packages/webapp/lang/zh.json | 5 +- .../src/classes/client/rest-client/index.ts | 2 +- packages/webapp/src/compiled-lang/de.json | 8 +- packages/webapp/src/compiled-lang/en.json | 8 +- packages/webapp/src/compiled-lang/es.json | 8 +- packages/webapp/src/compiled-lang/fr.json | 8 +- packages/webapp/src/compiled-lang/ru.json | 6 + packages/webapp/src/compiled-lang/zh.json | 8 +- .../action-dispatcher/import-dialog/index.tsx | 48 +- 70 files changed, 7034 insertions(+), 26 deletions(-) create mode 100644 packages/mindplot/src/components/import/FreemindIconConverter.ts create mode 100644 packages/mindplot/src/components/import/FreemindImporter.ts create mode 100644 packages/mindplot/src/components/import/Importer.ts create mode 100644 packages/mindplot/src/components/import/TextImporterFactory.ts create mode 100644 packages/mindplot/src/components/import/WisemappingImporter.ts create mode 100644 packages/mindplot/test/unit/import/Helper.ts create mode 100644 packages/mindplot/test/unit/import/TextImporterTestSuite.test.ts create mode 100644 packages/mindplot/test/unit/import/expected/Cs2.wxml create mode 100644 packages/mindplot/test/unit/import/expected/SQLServer.wxml create mode 100644 packages/mindplot/test/unit/import/expected/anonymity_on_the_edge.wxml create mode 100644 packages/mindplot/test/unit/import/expected/bug2.wxml create mode 100644 packages/mindplot/test/unit/import/expected/bug3.wxml create mode 100644 packages/mindplot/test/unit/import/expected/cdata-support.wxml create mode 100644 packages/mindplot/test/unit/import/expected/coderToDeveloper.wxml create mode 100644 packages/mindplot/test/unit/import/expected/complex.wxml create mode 100644 packages/mindplot/test/unit/import/expected/emptyNodes.wxml create mode 100644 packages/mindplot/test/unit/import/expected/enc.wxml create mode 100644 packages/mindplot/test/unit/import/expected/freeMind_resources.wxml create mode 100644 packages/mindplot/test/unit/import/expected/i18n.wxml create mode 100644 packages/mindplot/test/unit/import/expected/i18n2.wxml create mode 100644 packages/mindplot/test/unit/import/expected/issue.wxml create mode 100644 packages/mindplot/test/unit/import/expected/npe.wxml create mode 100644 packages/mindplot/test/unit/import/expected/process.wxml create mode 100644 packages/mindplot/test/unit/import/expected/pub_sub.wxml create mode 100644 packages/mindplot/test/unit/import/expected/python.wxml create mode 100644 packages/mindplot/test/unit/import/expected/sample3.wxml create mode 100644 packages/mindplot/test/unit/import/expected/sample4.wxml create mode 100644 packages/mindplot/test/unit/import/expected/welcome.wxml create mode 100644 packages/mindplot/test/unit/import/expected/writing_an_essay_with.wxml create mode 100644 packages/mindplot/test/unit/import/input/Cs2.mm create mode 100644 packages/mindplot/test/unit/import/input/SQLServer.mm create mode 100644 packages/mindplot/test/unit/import/input/anonymity_on_the_edge.mm create mode 100644 packages/mindplot/test/unit/import/input/bug2.mm create mode 100644 packages/mindplot/test/unit/import/input/bug3.mm create mode 100644 packages/mindplot/test/unit/import/input/cdata-support.mm create mode 100644 packages/mindplot/test/unit/import/input/coderToDeveloper.mm create mode 100644 packages/mindplot/test/unit/import/input/complex.mm create mode 100644 packages/mindplot/test/unit/import/input/emptyNodes.mm create mode 100644 packages/mindplot/test/unit/import/input/enc.mm create mode 100644 packages/mindplot/test/unit/import/input/freeMind_resources.mm create mode 100644 packages/mindplot/test/unit/import/input/i18n.mm create mode 100644 packages/mindplot/test/unit/import/input/i18n2.mm create mode 100644 packages/mindplot/test/unit/import/input/issue.mm create mode 100644 packages/mindplot/test/unit/import/input/npe.mm create mode 100644 packages/mindplot/test/unit/import/input/process.mm create mode 100644 packages/mindplot/test/unit/import/input/pub_sub.mm create mode 100644 packages/mindplot/test/unit/import/input/python.mm create mode 100644 packages/mindplot/test/unit/import/input/sample3.mm create mode 100644 packages/mindplot/test/unit/import/input/sample4.mm create mode 100644 packages/mindplot/test/unit/import/input/welcome.mm create mode 100644 packages/mindplot/test/unit/import/input/writing_an_essay_with.mm diff --git a/packages/mindplot/package.json b/packages/mindplot/package.json index 1eeb1747..5ff5fd8c 100644 --- a/packages/mindplot/package.json +++ b/packages/mindplot/package.json @@ -26,7 +26,7 @@ "lint": "eslint src --ext js,ts", "playground": "webpack serve --config webpack.playground.js", "cy:run": "cypress run", - "test:unit": "jest ./test/unit/export/*.ts ./test/unit/layout/*.js", + "test:unit": "jest ./test/unit/export/*.ts ./test/unit/import/*.ts ./test/unit/layout/*.js --verbose --silent --detectOpenHandles", "test:integration": "start-server-and-test playground http-get://localhost:8083 cy:run", "test": "yarn test:unit && yarn test:integration" }, diff --git a/packages/mindplot/src/components/export/freemind/Map.ts b/packages/mindplot/src/components/export/freemind/Map.ts index a12b74bd..f336212f 100644 --- a/packages/mindplot/src/components/export/freemind/Map.ts +++ b/packages/mindplot/src/components/export/freemind/Map.ts @@ -1,4 +1,4 @@ -import { createDocument } from '@wisemapping/core-js'; +import { createDocument, $assert } from '@wisemapping/core-js'; import Arrowlink from './Arrowlink'; import Cloud from './Cloud'; import Edge from './Edge'; @@ -7,7 +7,7 @@ import Icon from './Icon'; import Node, { Choise } from './Node'; import Richcontent from './Richcontent'; -export default class Map { +export default class Freemap { protected node: Node; protected version: string; @@ -52,6 +52,127 @@ export default class Map { return document; } + loadFromDom(dom: Document): Freemap { + $assert(dom, 'dom can not be null'); + + const rootElem = dom.documentElement; + + // Is a freemap? + $assert( + rootElem.tagName === 'map', + `This seem not to be a map document. Found tag: ${rootElem.tagName}`, + ); + + // Start the loading process... + const version = rootElem.getAttribute('version') || '1.0.1'; + const freemap: Freemap = new Freemap(); + freemap.setVesion(version); + + const mainTopicElement = rootElem.firstElementChild; + const mainTopic: Node = new Node().loadFromElement(mainTopicElement); + freemap.setNode(mainTopic); + + const childNodes = Array.from(mainTopicElement.childNodes); + const childsNodes = childNodes + .filter( + (child: ChildNode) => child.nodeType === 1 && (child as Element).tagName === 'node', + ) + .map((c) => c as Element); + + childsNodes.forEach((child: Element) => { + const node = this.domToNode(child); + mainTopic.setArrowlinkOrCloudOrEdge(node); + }); + + return freemap; + } + + private filterNodes(child: ChildNode): Element { + let element: Element; + if (child.nodeType === 1) { + if ( + (child as Element).tagName === 'node' + || (child as Element).tagName === 'richcontent' + || (child as Element).tagName === 'font' + || (child as Element).tagName === 'edge' + || (child as Element).tagName === 'arrowlink' + || (child as Element).tagName === 'clud' + || (child as Element).tagName === 'icon' + ) element = child as Element; + } + + return element; + } + + private domToNode(nodeElem: Element): Choise { + let node: Choise; + + if (nodeElem.tagName === 'node') { + node = new Node().loadFromElement(nodeElem); + + if (nodeElem.childNodes.length > 0) { + const childNodes = Array.from(nodeElem.childNodes); + const childsNodes = childNodes + .filter((child: ChildNode) => this.filterNodes(child)) + .map((c) => c as Element); + + childsNodes.forEach((child) => { + const childNode = this.domToNode(child); + if (node instanceof Node) node.setArrowlinkOrCloudOrEdge(childNode); + }); + } + } + + if (nodeElem.tagName === 'font') { + node = new Font(); + if (nodeElem.getAttribute('NAME')) node.setName(nodeElem.getAttribute('NAME')); + if (nodeElem.getAttribute('BOLD')) node.setBold(nodeElem.getAttribute('BOLD')); + if (nodeElem.getAttribute('ITALIC')) node.setItalic(nodeElem.getAttribute('ITALIC')); + if (nodeElem.getAttribute('SIZE')) node.setSize(nodeElem.getAttribute('SIZE')); + } + + if (nodeElem.tagName === 'edge') { + node = new Edge(); + if (nodeElem.getAttribute('COLOR')) node.setColor(nodeElem.getAttribute('COLOR')); + if (nodeElem.getAttribute('STYLE')) node.setStyle(nodeElem.getAttribute('STYLE')); + if (nodeElem.getAttribute('WIDTH')) node.setWidth(nodeElem.getAttribute('WIDTH')); + } + + if (nodeElem.tagName === 'arrowlink') { + node = new Arrowlink(); + if (nodeElem.getAttribute('COLOR')) node.setColor(nodeElem.getAttribute('COLOR')); + if (nodeElem.getAttribute('DESTINATION')) node.setDestination(nodeElem.getAttribute('DESTINATION')); + if (nodeElem.getAttribute('ENDARROW')) node.setEndarrow(nodeElem.getAttribute('ENDARROW')); + if (nodeElem.getAttribute('ENDINCLINATION')) node.setEndinclination(nodeElem.getAttribute('ENDINCLINATION')); + if (nodeElem.getAttribute('ID')) node.setId(nodeElem.getAttribute('ID')); + if (nodeElem.getAttribute('STARTARROW')) node.setStartarrow(nodeElem.getAttribute('STARTARROW')); + if (nodeElem.getAttribute('STARTINCLINATION')) node.setStartinclination(nodeElem.getAttribute('STARTINCLINATION')); + } + + if (nodeElem.tagName === 'cloud') { + node = new Cloud(); + if (nodeElem.getAttribute('COLOR')) node.setColor(nodeElem.getAttribute('COLOR')); + } + + if (nodeElem.tagName === 'icon') { + node = new Icon(); + if (nodeElem.getAttribute('BUILTIN')) node.setBuiltin(nodeElem.getAttribute('BUILTIN')); + } + + if (nodeElem.tagName === 'richcontent') { + node = new Richcontent(); + + if (nodeElem.getAttribute('TYPE')) node.setType(nodeElem.getAttribute('TYPE')); + if (nodeElem.firstChild && nodeElem.getElementsByTagName('html')) { + const content = nodeElem.getElementsByTagName('html'); + const html = content[0] ? content[0].outerHTML : ''; + node.setHtml(html); + } + } + + return node; + } + private nodeToXml(childNode: Choise, parentNode: HTMLElement, document: Document): HTMLElement { if (childNode instanceof Node) { childNode.setCentralTopic(false); diff --git a/packages/mindplot/src/components/export/freemind/Node.ts b/packages/mindplot/src/components/export/freemind/Node.ts index 3402e431..68e7e295 100644 --- a/packages/mindplot/src/components/export/freemind/Node.ts +++ b/packages/mindplot/src/components/export/freemind/Node.ts @@ -226,6 +226,46 @@ class Node { return nodeElem; } + + loadFromElement(element: Element): Node { + const node = new Node(); + + const nodeId = element.getAttribute('ID'); + const nodePosition = element.getAttribute('POSITION'); + const nodeStyle = element.getAttribute('STYLE'); + const nodeBGColor = element.getAttribute('BACKGROUND_COLOR'); + const nodeColor = element.getAttribute('COLOR'); + const nodeText = element.getAttribute('TEXT'); + const nodeLink = element.getAttribute('LINK'); + const nodeFolded = element.getAttribute('FOLDED'); + const nodeCreated = element.getAttribute('CREATED'); + const nodeModified = element.getAttribute('MODIFIED'); + const nodeHgap = element.getAttribute('HGAP'); + const nodeVgap = element.getAttribute('VGAP'); + const nodeWcoords = element.getAttribute('WCOORDS'); + const nodeWorder = element.getAttribute('WORDER'); + const nodeVshift = element.getAttribute('VSHIFT'); + const nodeEncryptedContent = element.getAttribute('ENCRYPTED_CONTENT'); + + if (nodeId) node.setId(nodeId); + if (nodePosition) node.setPosition(nodePosition); + if (nodeStyle) node.setStyle(nodeStyle); + if (nodeBGColor) node.setBackgorundColor(nodeBGColor); + if (nodeColor) node.setColor(nodeColor); + if (nodeText) node.setText(nodeText); + if (nodeLink) node.setLink(nodeLink); + if (nodeFolded) node.setFolded(nodeFolded); + if (nodeCreated) node.setCreated(nodeCreated); + if (nodeModified) node.setModified(nodeModified); + if (nodeHgap) node.setHgap(nodeHgap); + if (nodeVgap) node.setVgap(nodeVgap); + if (nodeWcoords) node.setWcoords(nodeWcoords); + if (nodeWorder) node.setWorder(nodeWorder); + if (nodeVshift) node.setVshift(nodeVshift); + if (nodeEncryptedContent) node.setEncryptedContent(nodeEncryptedContent); + + return node; + } } export type Choise = Arrowlink | Cloud | Edge | Font | Hook | Icon | Richcontent | Node diff --git a/packages/mindplot/src/components/export/freemind/importer/VersionNumber.ts b/packages/mindplot/src/components/export/freemind/importer/VersionNumber.ts index 0761213a..5f78c362 100644 --- a/packages/mindplot/src/components/export/freemind/importer/VersionNumber.ts +++ b/packages/mindplot/src/components/export/freemind/importer/VersionNumber.ts @@ -8,4 +8,50 @@ export default class VersionNumber { public getVersion(): string { return this.version; } + + public isGreaterThan(versionNumber: VersionNumber): boolean { + return this.compareTo(versionNumber) < 0; + } + + public compareTo(otherObject: VersionNumber): number { + if (this.equals(otherObject)) { + return 0; + } + + const ownTokinizer = this.getTokinizer(); + const otherTokinizer = otherObject.getTokinizer(); + + for (let i = 0; i < ownTokinizer.length; i++) { + let ownNumber: number; + let ohterNumber: number; + + try { + ownNumber = parseInt(ownTokinizer[i], 10); + ohterNumber = parseInt(otherTokinizer[i], 10); + } catch (e) { + return 1; + } + + if (ownNumber > ohterNumber) { + return 1; + } + if (ownNumber < ohterNumber) { + return -1; + } + } + + return -1; + } + + public equals(o: T): boolean { + if (!(o instanceof VersionNumber)) { + return false; + } + const versionNumber: VersionNumber = o as VersionNumber; + return this.version === versionNumber.version; + } + + private getTokinizer(): Array { + return this.getVersion().split('.'); + } } diff --git a/packages/mindplot/src/components/import/FreemindIconConverter.ts b/packages/mindplot/src/components/import/FreemindIconConverter.ts new file mode 100644 index 00000000..4ffc154c --- /dev/null +++ b/packages/mindplot/src/components/import/FreemindIconConverter.ts @@ -0,0 +1,10 @@ +import IconModel from '../model/IconModel'; + +export default class FreemindIconConverter { + private static freeIdToIcon: Map = new Map(); + + public static toWiseId(iconId: string): number | null { + const result: IconModel = this.freeIdToIcon.get(iconId); + return result ? result.getId() : null; + } +} diff --git a/packages/mindplot/src/components/import/FreemindImporter.ts b/packages/mindplot/src/components/import/FreemindImporter.ts new file mode 100644 index 00000000..64cbf660 --- /dev/null +++ b/packages/mindplot/src/components/import/FreemindImporter.ts @@ -0,0 +1,446 @@ +import xmlFormatter from 'xml-formatter'; +import Importer from './Importer'; +import Mindmap from '../model/Mindmap'; +import RelationshipModel from '../model/RelationshipModel'; +import NodeModel from '../model/NodeModel'; +import { TopicShape } from '../model/INodeModel'; +import FreemindConstant from '../export/freemind/FreemindConstant'; +import FreemindMap from '../export/freemind/Map'; +import FreemindNode, { Choise } from '../export/freemind/Node'; +import FreemindFont from '../export/freemind/Font'; +import FreemindEdge from '../export/freemind/Edge'; +import FreemindIcon from '../export/freemind/Icon'; +import FreemindHook from '../export/freemind/Hook'; +import FreemindRichcontent from '../export/freemind/Richcontent'; +import FreemindArrowLink from '../export/freemind/Arrowlink'; +import VersionNumber from '../export/freemind/importer/VersionNumber'; +import FreemindIconConverter from './FreemindIconConverter'; +import NoteModel from '../model/NoteModel'; +import FeatureModelFactory from '../model/FeatureModelFactory'; +import FeatureModel from '../model/FeatureModel'; +import XMLSerializerFactory from '../persistence/XMLSerializerFactory'; + +export default class FreemindImporter extends Importer { + private mindmap: Mindmap; + + private freemindInput: string; + + private freemindMap: FreemindMap; + + private nodesmap: Map; + + private relationship: Array; + + private idDefault = 0; + + constructor(map: string) { + super(); + this.freemindInput = map; + } + + import(nameMap: string, description: string): Promise { + this.mindmap = new Mindmap(nameMap); + this.nodesmap = new Map(); + this.relationship = new Array(); + + const parser = new DOMParser(); + const freemindDoc = parser.parseFromString(this.freemindInput, 'application/xml'); + this.freemindMap = new FreemindMap().loadFromDom(freemindDoc); + + const version: string = this.freemindMap.getVersion(); + + if (!version || version.startsWith('freeplane')) { + throw new Error('You seems to be be trying to import a Freeplane map. FreePlane is not supported format.'); + } else { + const mapVersion: VersionNumber = new VersionNumber(version); + if (mapVersion.isGreaterThan(FreemindConstant.SUPPORTED_FREEMIND_VERSION)) { + throw new Error(`FreeMind version ${mapVersion.getVersion()} is not supported.`); + } + } + + const freeNode: FreemindNode = this.freemindMap.getNode(); + this.mindmap.setVersion(FreemindConstant.CODE_VERSION); + + const wiseTopicId = this.getIdNode(this.freemindMap.getNode()); + const wiseTopic = this.mindmap.createNode('CentralTopic'); + wiseTopic.setPosition(0, 0); + wiseTopic.setId(wiseTopicId); + + this.convertNodeProperties(freeNode, wiseTopic, true); + + this.nodesmap.set(freeNode.getId(), wiseTopic); + + this.convertChildNodes(freeNode, wiseTopic, this.mindmap, 1); + this.addRelationship(this.mindmap); + + this.mindmap.setDescription(description); + this.mindmap.addBranch(wiseTopic); + + const serialize = XMLSerializerFactory.createInstanceFromMindmap(this.mindmap); + const domMindmap = serialize.toXML(this.mindmap); + const xmlToString = new XMLSerializer().serializeToString(domMindmap); + const formatXml = xmlFormatter(xmlToString, { + indentation: ' ', + collapseContent: true, + lineSeparator: '\n', + }); + + return Promise.resolve(formatXml); + } + + private addRelationship(mindmap: Mindmap): void { + const mapRelaitonship: Array = mindmap.getRelationships(); + + mapRelaitonship.forEach((relationship: RelationshipModel) => { + this.fixRelationshipControlPoints(relationship); + + // Fix dest ID + const destId: string = relationship.getDestCtrlPoint(); + const destTopic: NodeModel = this.nodesmap.get(destId); + relationship.setDestCtrlPoint(destTopic.getId()); + + // Fix src ID + const srcId: string = relationship.getSrcCtrlPoint(); + const srcTopic: NodeModel = this.nodesmap.get(srcId); + relationship.setSrcCtrlPoint(srcTopic.getId()); + + mapRelaitonship.push(relationship); + }); + } + + private fixRelationshipControlPoints(relationship: RelationshipModel): void { + const srcTopic: NodeModel = this.nodesmap.get(relationship.getToNode().toString()); + const destNode: NodeModel = this.nodesmap.get(relationship.getFromNode().toString()); + + // Fix x coord + const srcCtrlPoint: string = relationship.getSrcCtrlPoint(); + if (srcCtrlPoint) { + const coords = srcTopic.getPosition(); + if (coords.x < 0) { + const x = coords.x * -1; + relationship.setSrcCtrlPoint(`${x},${coords.y}`); + + // Fix coord + if (srcTopic.getOrder() && srcTopic.getOrder() % 2 !== 0) { + const y = coords.y * -1; + relationship.setSrcCtrlPoint(`${coords.x},${y}`); + } + } + } + + const destCtrlPoint: string = relationship.getDestCtrlPoint(); + if (destCtrlPoint) { + const coords = destNode.getPosition(); + + if (coords.x < 0) { + const x = coords.x * -1; + relationship.setDestCtrlPoint(`${x},${coords.y}`); + } + + if (destNode.getOrder() && destNode.getOrder() % 2 !== 0) { + const y = coords.y * -1; + relationship.setDestCtrlPoint(`${coords.x},${y}`); + } + } + } + + private convertNodeProperties(freeNode: FreemindNode, wiseTopic: NodeModel, centralTopic: boolean): void { + const text: string = freeNode.getText(); + if (text) wiseTopic.setText(text); + + const bgColor: string = freeNode.getBackgorundColor(); + if (bgColor) wiseTopic.setBackgroundColor(bgColor); + + if (centralTopic === false) { + const shape = this.getShapeFromFreeNode(freeNode); + if (shape && shape !== 'fork') wiseTopic.setShapeType(shape); + } + + // Check for style... + const fontStyle = this.generateFontStyle(freeNode, null); + if (fontStyle && fontStyle !== ';;;;') wiseTopic.setFontStyle(fontStyle); + + // Is there any link... + const url: string = freeNode.getLink(); + if (url) { + const link: FeatureModel = FeatureModelFactory.createModel('link', { url }); + wiseTopic.addFeature(link); + } + + const folded = Boolean(freeNode.getFolded()); + if (folded) wiseTopic.setChildrenShrunken(folded); + } + + private convertChildNodes(freeParent: FreemindNode, wiseParent: NodeModel, mindmap: Mindmap, depth: number): void { + const freeChilden = freeParent.getArrowlinkOrCloudOrEdge(); + let currentWiseTopic: NodeModel = wiseParent; + let order = 0; + let firstLevelRightOrder = 0; + let firstLevelLeftOrder = 1; + + freeChilden.forEach((child) => { + if (child instanceof FreemindNode) { + const wiseId = this.getIdNode(child); + const wiseChild = mindmap.createNode('MainTopic', wiseId); + + this.nodesmap.set(child.getId(), wiseChild); + + let norder: number; + if (depth !== 1) { + norder = order++; + } else if (child.getPosition() && child.getPosition() === FreemindConstant.POSITION_LEFT) { + norder = firstLevelLeftOrder; + firstLevelLeftOrder += 2; + } else { + norder = firstLevelRightOrder; + firstLevelRightOrder += 2; + } + + wiseChild.setOrder(norder); + + // Convert node position... + const childrenCountSameSide = this.getChildrenCountSameSide(freeChilden, child); + const position: {x: number, y: number} = this.convertPosition(wiseParent, child, depth, norder, childrenCountSameSide); + wiseChild.setPosition(position.x, position.y); + + // Convert the rest of the node properties... + this.convertNodeProperties(child, wiseChild, false); + + this.convertChildNodes(child, wiseChild, mindmap, depth++); + + if (wiseChild !== wiseParent) { + wiseParent.append(wiseChild); + } + + currentWiseTopic = wiseChild; + } + + if (child instanceof FreemindFont) { + const font: FreemindFont = child as FreemindFont; + const fontStyle: string = this.generateFontStyle(freeParent, font); + if (fontStyle) { + currentWiseTopic.setFontStyle(fontStyle); + } + } + + if (child instanceof FreemindEdge) { + const edge: FreemindEdge = child as FreemindEdge; + currentWiseTopic.setBackgroundColor(edge.getColor()); + } + + if (child instanceof FreemindIcon) { + const freeIcon: FreemindIcon = child as FreemindIcon; + const iconId: string = freeIcon.getBuiltin(); + const wiseIconId = FreemindIconConverter.toWiseId(iconId); + if (wiseIconId) { + const mindmapIcon: FeatureModel = FeatureModelFactory.createModel('icon', { id: wiseIconId }); + currentWiseTopic.addFeature(mindmapIcon); + } + } + + if (child instanceof FreemindHook) { + const hook: FreemindHook = child as FreemindHook; + const mindmapNote: NoteModel = new NoteModel({ text: '' }); + + let textNote: string = hook.getText(); + if (!textNote) { + textNote = FreemindConstant.EMPTY_NOTE; + mindmapNote.setText(textNote); + currentWiseTopic.addFeature(mindmapNote); + } + } + + if (child instanceof FreemindRichcontent) { + const type = child.getType(); + const html = child.getHtml(); + const text = this.html2Text(html); + + switch (type) { + case 'NOTE': { + const noteModel: FeatureModel = FeatureModelFactory.createModel('note', { text: text || FreemindConstant.EMPTY_NOTE }); + currentWiseTopic.addFeature(noteModel); + break; + } + + case 'NODE': { + currentWiseTopic.setText(text); + break; + } + + default: { + const noteModel: FeatureModel = FeatureModelFactory.createModel('note', { text: text || FreemindConstant.EMPTY_NOTE }); + currentWiseTopic.addFeature(noteModel); + } + } + } + + if (child instanceof FreemindArrowLink) { + const arrow: FreemindArrowLink = child as FreemindArrowLink; + const relationship: RelationshipModel = new RelationshipModel(0, 0); + const destId: string = arrow.getDestination(); + + relationship.setSrcCtrlPoint(destId); + relationship.setDestCtrlPoint(freeParent.getId()); + const endinclination: string = arrow.getEndInclination(); + if (endinclination) { + const inclination: Array = endinclination.split(';'); + relationship.setDestCtrlPoint(`${inclination[0]},${inclination[1]}`); + } + + const startinclination: string = arrow.getStartinclination(); + if (startinclination) { + const inclination: Array = startinclination.split(';'); + relationship.setSrcCtrlPoint(`${inclination[0]},${inclination[1]}`); + } + + const endarrow: string = arrow.getEndarrow(); + if (endarrow) { + relationship.setEndArrow(endarrow.toLowerCase() !== 'none'); + } + + const startarrow: string = arrow.getStartarrow(); + if (startarrow) { + relationship.setStartArrow(startarrow.toLowerCase() !== 'none'); + } + + relationship.setLineType(3); + this.relationship.push(relationship); + } + }); + } + + private getIdNode(node: FreemindNode): number { + const id = node.getId(); + let idFreeToIdWise: number; + + if (id) { + if (id === '_') { + this.idDefault++; + idFreeToIdWise = this.idDefault; + } else { + idFreeToIdWise = parseInt(id.split('_').pop(), 10); + } + } else { + this.idDefault++; + idFreeToIdWise = this.idDefault; + } + + return idFreeToIdWise; + } + + private getChildrenCountSameSide(freeChilden: Array, freeChild: FreemindNode): number { + let result = 0; + let childSide: string = freeChild.getPosition(); + + if (!childSide) { + childSide = FreemindConstant.POSITION_RIGHT; + } + + freeChilden.forEach((child) => { + if (child instanceof FreemindNode) { + let side = child.getPosition(); + if (!side) { + side = FreemindConstant.POSITION_RIGHT; + } + if (childSide === side) { + result++; + } + } + }); + + return result; + } + + private getShapeFromFreeNode(node: FreemindNode): string { + let result: string = node.getStyle(); + + if (result === 'bubble') { + result = TopicShape.ROUNDED_RECT; + } else if (node.getBackgorundColor()) { + result = TopicShape.RECTANGLE; + } else { + result = TopicShape.LINE; + } + return result; + } + + private generateFontStyle(node: FreemindNode, font: FreemindFont | undefined): string { + const fontStyle: Array = []; + + // Font family + if (font) { + fontStyle.push(font.getName()); + } + fontStyle.push(';'); + + // Font Size + if (font) { + const fontSize: number = ((!font.getSize() || parseInt(font.getSize(), 10) < 8) ? FreemindConstant.FONT_SIZE_NORMAL : parseInt(font.getSize(), 10)); + let wiseFontSize: number = FreemindConstant.FONT_SIZE_SMALL; + if (fontSize >= 24) { + wiseFontSize = FreemindConstant.FONT_SIZE_HUGE; + } + if (fontSize >= 16) { + wiseFontSize = FreemindConstant.FONT_SIZE_LARGE; + } + if (fontSize >= 8) { + wiseFontSize = FreemindConstant.FONT_SIZE_NORMAL; + } + fontStyle.push(wiseFontSize.toString()); + } + fontStyle.push(';'); + + // Font Color + const color: string = node.getColor(); + if (color && color !== '') { + fontStyle.push(color); + } + fontStyle.push(';'); + + // Font Italic + if (font) { + const hasItalic = Boolean(font.getItalic()); + fontStyle.push(hasItalic ? FreemindConstant.ITALIC : ''); + } + fontStyle.push(';'); + + const result: string = fontStyle.join(''); + return result; + } + + private convertPosition(wiseParent: NodeModel, freeChild: FreemindNode, depth: number, order: number, childrenCount: number): {x: number, y: number} { + let x: number = FreemindConstant.CENTRAL_TO_TOPIC_DISTANCE + ((depth - 1) * FreemindConstant.TOPIC_TO_TOPIC_DISTANCE); + if (depth === 1) { + const side: string = freeChild.getPosition(); + x *= (side && FreemindConstant.POSITION_LEFT === side ? -1 : 1); + } else { + const position = wiseParent.getPosition(); + x *= position.x < 0 ? 1 : -1; + } + + let y: number; + if (depth === 1) { + if (order % 2 === 0) { + const multiplier = ((order + 1) - childrenCount) * 2; + y = multiplier * FreemindConstant.ROOT_LEVEL_TOPIC_HEIGHT; + } else { + const multiplier = (order - childrenCount) * 2; + y = multiplier * FreemindConstant.ROOT_LEVEL_TOPIC_HEIGHT; + } + } else { + const position = wiseParent.getPosition(); + y = Math.round(position.y - ((childrenCount / 2) * FreemindConstant.SECOND_LEVEL_TOPIC_HEIGHT - (order * FreemindConstant.SECOND_LEVEL_TOPIC_HEIGHT))); + } + + return { + x, + y, + }; + } + + private html2Text(content: string): string { + const temporalDivElement = document.createElement('div'); + temporalDivElement.innerHTML = content; + return temporalDivElement.textContent.trim() || temporalDivElement.innerText.trim() || ''; + } +} diff --git a/packages/mindplot/src/components/import/Importer.ts b/packages/mindplot/src/components/import/Importer.ts new file mode 100644 index 00000000..249a0a7a --- /dev/null +++ b/packages/mindplot/src/components/import/Importer.ts @@ -0,0 +1,3 @@ +export default abstract class Importer { + abstract import(nameMap: string, description: string): Promise; +} diff --git a/packages/mindplot/src/components/import/TextImporterFactory.ts b/packages/mindplot/src/components/import/TextImporterFactory.ts new file mode 100644 index 00000000..9797dd67 --- /dev/null +++ b/packages/mindplot/src/components/import/TextImporterFactory.ts @@ -0,0 +1,19 @@ +import WisemappingImporter from './WisemappingImporter'; +import FreemindImporter from './FreemindImporter'; +import Importer from './Importer'; + +export default class TextImporterFactory { + static create(type: string, map: string): Importer { + let result: Importer; + switch (type) { + case 'wxml': + result = new WisemappingImporter(map); + return result; + case 'mm': + result = new FreemindImporter(map); + return result; + default: + throw new Error(`Unsupported type ${type}`); + } + } +} diff --git a/packages/mindplot/src/components/import/WisemappingImporter.ts b/packages/mindplot/src/components/import/WisemappingImporter.ts new file mode 100644 index 00000000..31a58a37 --- /dev/null +++ b/packages/mindplot/src/components/import/WisemappingImporter.ts @@ -0,0 +1,29 @@ +import Mindmap from '../model/Mindmap'; +import XMLSerializerFactory from '../persistence/XMLSerializerFactory'; +import Importer from './Importer'; + +export default class WisemappingImporter extends Importer { + private wisemappingInput: string; + + private mindmap: Mindmap; + + constructor(map: string) { + super(); + this.wisemappingInput = map; + } + + import(nameMap: string, description: string): Promise { + const parser = new DOMParser(); + const wiseDoc = parser.parseFromString(this.wisemappingInput, 'application/xml'); + + const serialize = XMLSerializerFactory.createInstanceFromDocument(wiseDoc); + this.mindmap = serialize.loadFromDom(wiseDoc, nameMap); + + this.mindmap.setDescription(description); + + const mindmapToXml = serialize.toXML(this.mindmap); + + const xmlStr = new XMLSerializer().serializeToString(mindmapToXml); + return Promise.resolve(xmlStr); + } +} diff --git a/packages/mindplot/src/index.ts b/packages/mindplot/src/index.ts index 82cb67b0..8cd70ae2 100644 --- a/packages/mindplot/src/index.ts +++ b/packages/mindplot/src/index.ts @@ -26,7 +26,9 @@ import MockPersistenceManager from './components/MockPersistenceManager'; import DesignerOptionsBuilder from './components/DesignerOptionsBuilder'; import ImageExporterFactory from './components/export/ImageExporterFactory'; import TextExporterFactory from './components/export/TextExporterFactory'; +import TextImporterFactory from './components/import/TextImporterFactory'; import Exporter from './components/export/Exporter'; +import Importer from './components/import/Importer'; import DesignerKeyboard from './components/DesignerKeyboard'; import EditorRenderMode from './components/EditorRenderMode'; import ImageIcon from './components/ImageIcon'; @@ -61,7 +63,9 @@ export { EditorRenderMode, TextExporterFactory, ImageExporterFactory, + TextImporterFactory, Exporter, + Importer, ImageIcon, $notify, $msg, diff --git a/packages/mindplot/test/unit/import/Helper.ts b/packages/mindplot/test/unit/import/Helper.ts new file mode 100644 index 00000000..60366a5a --- /dev/null +++ b/packages/mindplot/test/unit/import/Helper.ts @@ -0,0 +1,43 @@ +/* eslint-disable import/no-extraneous-dependencies */ +/* eslint-disable import/prefer-default-export */ +import fs from 'fs'; +import path from 'path'; +import { expect } from '@jest/globals'; +import { diff } from 'jest-diff'; +import Importer from '../../../src/components/import/Importer'; + +const saveOutputRecord = false; + +export const parseXMLString = (xmlStr: string, mimeType: DOMParserSupportedType) => { + const parser = new DOMParser(); + const xmlDoc = parser.parseFromString(xmlStr, mimeType); + + return xmlDoc; +}; + +export const parseXMLFile = (filePath: fs.PathOrFileDescriptor, mimeType: DOMParserSupportedType) => { + const stream = fs.readFileSync(filePath, { encoding: 'utf-8' }); + + const content = stream.toString(); + + return parseXMLString(content, mimeType); +}; + +export const exporterAssert = async (testName: string, importer: Importer) => { + const actualMindmap = await importer.import(testName, ''); + + // Load mindmap file.. + const mindmapPath = path.resolve(__dirname, `./expected/${testName}.wxml`); + if (saveOutputRecord) { + fs.writeFileSync(mindmapPath, actualMindmap); + } + + const mindmapExpect = fs.readFileSync(mindmapPath).toString(); + + // Compare with expected... + if (actualMindmap !== mindmapExpect) { + const diffResult = diff(actualMindmap, mindmapExpect); + console.log(diffResult); + expect(actualMindmap).toEqual(mindmapExpect); + } +}; diff --git a/packages/mindplot/test/unit/import/TextImporterTestSuite.test.ts b/packages/mindplot/test/unit/import/TextImporterTestSuite.test.ts new file mode 100644 index 00000000..12446a6f --- /dev/null +++ b/packages/mindplot/test/unit/import/TextImporterTestSuite.test.ts @@ -0,0 +1,27 @@ +/* eslint-disable import/no-extraneous-dependencies */ +import path from 'path'; +import fs from 'fs'; +import { test } from '@jest/globals'; +import { exporterAssert, parseXMLFile } from './Helper'; +import FreemindMap from '../../../src/components/export/freemind/Map'; +import TextImporterFactory from '../../../src/components/import/TextImporterFactory'; + +const testNames = fs + .readdirSync(path.resolve(__dirname, './input/')) + .map((filename: string) => filename.split('.')[0]); + +describe('MM import test execution', () => { + test.each(testNames)('Importing %p suite', async (testName: string) => { + // load freemap... + const freemapPath = path.resolve(__dirname, `./input/${testName}.mm`); + const mapDocument = parseXMLFile(freemapPath, 'text/xml'); + + const freemap: FreemindMap = new FreemindMap().loadFromDom(mapDocument); + const freemapXml = freemap.toXml(); + const freemapStr = new XMLSerializer().serializeToString(freemapXml); + + const importer = TextImporterFactory.create('mm', freemapStr); + + await exporterAssert(testName, importer); + }); +}); diff --git a/packages/mindplot/test/unit/import/expected/Cs2.wxml b/packages/mindplot/test/unit/import/expected/Cs2.wxml new file mode 100644 index 00000000..dfecc973 --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/Cs2.wxml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/SQLServer.wxml b/packages/mindplot/test/unit/import/expected/SQLServer.wxml new file mode 100644 index 00000000..d5411c31 --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/SQLServer.wxml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/anonymity_on_the_edge.wxml b/packages/mindplot/test/unit/import/expected/anonymity_on_the_edge.wxml new file mode 100644 index 00000000..6bbb9f41 --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/anonymity_on_the_edge.wxml @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/bug2.wxml b/packages/mindplot/test/unit/import/expected/bug2.wxml new file mode 100644 index 00000000..9e9dc0eb --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/bug2.wxml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/bug3.wxml b/packages/mindplot/test/unit/import/expected/bug3.wxml new file mode 100644 index 00000000..032d6b12 --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/bug3.wxml @@ -0,0 +1,514 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/cdata-support.wxml b/packages/mindplot/test/unit/import/expected/cdata-support.wxml new file mode 100644 index 00000000..a0b3d4c2 --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/cdata-support.wxml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/coderToDeveloper.wxml b/packages/mindplot/test/unit/import/expected/coderToDeveloper.wxml new file mode 100644 index 00000000..df0cd6a6 --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/coderToDeveloper.wxml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/complex.wxml b/packages/mindplot/test/unit/import/expected/complex.wxml new file mode 100644 index 00000000..5254b667 --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/complex.wxml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/emptyNodes.wxml b/packages/mindplot/test/unit/import/expected/emptyNodes.wxml new file mode 100644 index 00000000..50803a15 --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/emptyNodes.wxml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/enc.wxml b/packages/mindplot/test/unit/import/expected/enc.wxml new file mode 100644 index 00000000..d819fefd --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/enc.wxml @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/freeMind_resources.wxml b/packages/mindplot/test/unit/import/expected/freeMind_resources.wxml new file mode 100644 index 00000000..0242d1ac --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/freeMind_resources.wxml @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/i18n.wxml b/packages/mindplot/test/unit/import/expected/i18n.wxml new file mode 100644 index 00000000..91ed0e2b --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/i18n.wxml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/i18n2.wxml b/packages/mindplot/test/unit/import/expected/i18n2.wxml new file mode 100644 index 00000000..34523624 --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/i18n2.wxml @@ -0,0 +1,11 @@ + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/issue.wxml b/packages/mindplot/test/unit/import/expected/issue.wxml new file mode 100644 index 00000000..b7fe5309 --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/issue.wxml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/npe.wxml b/packages/mindplot/test/unit/import/expected/npe.wxml new file mode 100644 index 00000000..086c7442 --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/npe.wxml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/process.wxml b/packages/mindplot/test/unit/import/expected/process.wxml new file mode 100644 index 00000000..21972ee1 --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/process.wxml @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/pub_sub.wxml b/packages/mindplot/test/unit/import/expected/pub_sub.wxml new file mode 100644 index 00000000..a8c567d7 --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/pub_sub.wxml @@ -0,0 +1,415 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/python.wxml b/packages/mindplot/test/unit/import/expected/python.wxml new file mode 100644 index 00000000..51fc0e1b --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/python.wxml @@ -0,0 +1,284 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/sample3.wxml b/packages/mindplot/test/unit/import/expected/sample3.wxml new file mode 100644 index 00000000..e94e61f5 --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/sample3.wxml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/sample4.wxml b/packages/mindplot/test/unit/import/expected/sample4.wxml new file mode 100644 index 00000000..f5c6506f --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/sample4.wxml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/welcome.wxml b/packages/mindplot/test/unit/import/expected/welcome.wxml new file mode 100644 index 00000000..e7df51bb --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/welcome.wxml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/writing_an_essay_with.wxml b/packages/mindplot/test/unit/import/expected/writing_an_essay_with.wxml new file mode 100644 index 00000000..1e638af5 --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/writing_an_essay_with.wxml @@ -0,0 +1,251 @@ + + + + + + + + + + + + + + When you're working on your essay, you'll find it helpful to switch between this map, and the one you're creating. To switch between maps, go to the Maps menu, and select the name of the map you want. + + + (When you're a bit more familiar with FreeMind, you'll find it quicker to use the Shortcut Keys -- you can also use Alt + Shift + Left, or Alt + Shift + Right to move between maps.)]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/input/Cs2.mm b/packages/mindplot/test/unit/import/input/Cs2.mm new file mode 100644 index 00000000..8b1ca7fa --- /dev/null +++ b/packages/mindplot/test/unit/import/input/Cs2.mm @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/mindplot/test/unit/import/input/SQLServer.mm b/packages/mindplot/test/unit/import/input/SQLServer.mm new file mode 100644 index 00000000..da93e708 --- /dev/null +++ b/packages/mindplot/test/unit/import/input/SQLServer.mm @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/mindplot/test/unit/import/input/anonymity_on_the_edge.mm b/packages/mindplot/test/unit/import/input/anonymity_on_the_edge.mm new file mode 100644 index 00000000..0462ba93 --- /dev/null +++ b/packages/mindplot/test/unit/import/input/anonymity_on_the_edge.mm @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/mindplot/test/unit/import/input/bug2.mm b/packages/mindplot/test/unit/import/input/bug2.mm new file mode 100644 index 00000000..3baf15c5 --- /dev/null +++ b/packages/mindplot/test/unit/import/input/bug2.mm @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Todos los contenidos de los talleres están relacionados con el currículo de la enseñanza básica.

+

A diferencia de la práctica tradicional, pretendemos ahondar en el conocimiento partiendo de lo que realmente interesa al niño o niña,

+

ayudándole a que encuentre respuesta a las preguntas que él o ella se plantea.

+

+

Por ese motivo, SaberMás proyecta estar al lado de los niños que necesitan una motivación extra para entender la escuela y fluir en ella,

+

y también al lado de aquellos a quienes la curiosidad y las ganas de saber les lleva más allá.

+ + +
+ + + + + + + +
\ No newline at end of file diff --git a/packages/mindplot/test/unit/import/input/bug3.mm b/packages/mindplot/test/unit/import/input/bug3.mm new file mode 100644 index 00000000..0a19d68b --- /dev/null +++ b/packages/mindplot/test/unit/import/input/bug3.mm @@ -0,0 +1,1030 @@ + + + + + + + + +

Identifying new measures or investments that should be implemented.

+ + +
+ + + + + + + +

Number of different innovations policy instruments existing in the region as a share of a total number representing a full typology of instruments

+ + +
+
+ + + + + + + + + + + + + +

Understanding how to design the details of a particular measure and how to implement them.

+ + +
+ + + + + + + + + + +

Firms turnover from (new to firm)

+

product innovation (as a pecentage of total turnover)

+ + +
+ +
+ + + + + +

Increase in the probability to innovate linked to ICT use

+

(in product innovation, process innovation, organisational innovaton, marketing innovation)

+ + +
+
+ + + + + +

Scientific articles by type of collaboration (per capita)

+

(international co-authoriship, domestic co-authoriship, single author)

+ + +
+ +
+ + + + + +

Increase in a share of expenditures on technological

+

innovations in the total amount of regional firms’ expenditures, %

+ + +
+ +
+ + + + + + + + + + + +

Increase in th number of firms with

+

international/national collaboration on innovation

+ + +
+ +
+ + + + + +

Highly cited scientific articles (as a percentage of

+

highly cited scientific article in the whole Federation)

+ + +
+ +
+ + + + + +

Patents filed by public research organisations

+

(as a percentafe of patent application filed under PCT)

+ + +
+ +
+ + + + + + + + + + + + + + +
+
+ + + + + +

Understanding the level of effort the region needs to take to compete on innovation and where to put this effort

+ + +
+ + + + + + +

This is what policy makers care about in the end

+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

WB

+ + +
+ + + +
+ + + + + +

GCR

+ + +
+
+ + + + + + +

GCR

+ + +
+ + + +
+ + + + + + +

per 100 population aged 25-64

+ + +
+ +
+ + + + + + + + +

Amount of university and colleague

+

students per 10 thousands population

+ + +
+
+ + + + + +

Share of employees with higher education in

+

the total amount of population at the working age

+ + +
+
+ + + + + + + + + + + + + + +

GCR

+ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

GCR

+ + +
+
+ + + + + + + + + + + + + + + + +

: the percentage of the workforce employed by foreign companies [%].

+ + +
+
+ + + + + + + + + + +

: exports as a share of total output in manufacturing and services [%].

+ + +
+ +
+ + + + + +

Share of high-technology export in the total volume

+

of production of goods, works and services

+ + +
+ +
+ + + + + +

Share of innovation production/serivces that goes for export,

+

by zones (EU, US, CIS, other countries

+ + +
+ +
+
+ + + + + + + + +

GEM

+ + +
+
+ + + + + +

GEM

+ + +
+
+ + + + + +

GEM

+ + +
+
+
+ + + + + + + +

UNESCO

+ + +
+
+ + + + + +

CIS

+ + +
+
+ + + + + +

Share of Innovative companies collaborating

+

with research institutions on innovation

+ + +
+
+ + + + + +

Number of joint projects conducted by the local comapnies

+

and local consulting/intermediary agencies

+ + +
+
+ + + + + + + + +

GCR

+ + +
+
+ + + + + +

Share of expenditures on technological innovations

+

in the amount of sales

+ + +
+
+ + + + + + + + +

Investments in ICT by asset (IT equipment,

+

communication equipment, software)

+ + +
+
+ + + + + + + +

Level of energy efficiency of the regional economy

+

(can be measured by sectors and for the whole region)

+ + +
+ +
+ + + +
+ + + + + + + + +

CIS, BEEPS

+ + +
+
+ + + + + + + + + + + + + + + + + + + + +

Number of new organizations per thousand working age population (WBI)

+ + +
+
+ + + + + +

(as a percentage of all registered corporations)

+ + +
+
+ + + + + + + + + +

Amount of domestically protected intellectual

+

property per 1 mln. population

+ + +
+
+ + + + + + + +

Number of intellectual property exploited by regional

+

enterprises per 1 mln. population

+ + +
+ +
+ + + + + + + + + + + + + +

Number of advanced ICT introduced in the budgetary organizations

+

(regional power, municipal bodies, social and educational organizations)

+ + +
+
+ + + + + + +

Number of management innovations introduced in the budgetary organizations

+

(regional power, municipal bodies, social and educational organizations)

+ + +
+
+
+
+ + + + + + + + +

Number of interactions between universities

+

and large companies by university size

+ + +
+ +
+
+ + + + + + + + + + + + + + +

Publications: Academic articles in international peer-reviewed

+

journals per 1,000 researchers [articles/1,000 researchers].

+ + +
+
+
+ + + + + + + + +

Number of measures offered by the unversity within a preset range (NCET2 survey)

+ + +
+
+
+ + + + + + + +

Academic licenses: Number of licenses

+

per 1,000 researchers.[licenses/researcher]

+ + +
+
+
+ + + + 1:146: unclosed tag: p + + + + + + + + + + +

Foreign contracts: Number of contracts with foreign industria

+

l companies at scientific and educational organizations

+

per 1,000 researchers [contracts/researchers]

+ + +
+
+ + + + 1:142: unclosed tag: p + + + + + +
+ + + + + + +

(design firms, IP consultants, etc.)

+ + +
+
+ + + + + +

(e.g. accelerators, incubators)

+ + +
+
+ + + + + + + + + + + + + + + + + + + + + +

Understanding which measures should be strengthened, dropped or improved, and how.

+ + +
+ + + + + + + + + + +

WIPO SURVEY OF INTELLECTUAL PROPERTY SERVICES OF

+

EUROPEAN TECHNOLOGY INCUBATORS

+ + +
+
+ + + + + + +

Gazelle tenant: Share of tenants with

+

annual revenue growth of more than 20%

+

for each of the past four years or since formation [%]

+ + +
+
+ + + + + +

Globalization of tenants: Median share of tenant

+

revenues obtained from exports [%]

+ + +
+
+
+ + + + + + + + + + + + + +

Perception (opinion poll) of business managers

+

regarding public support programmes

+ + +
+
+
+ + + + + + +

Perception of business managers in terms

+

of level of transparency of support measures in the region

+ + +
+ +
+
+ + + + + +

Description by regional business managers of the way the

+

select and apply for regional and federal support schemes

+ + +
+ +
+
+ + + + + + + + + + + + + +

JL: not sure how this would be measured

+ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Average leverage of 1rub (there would be

+

several programs with different leverage)

+ + +
+ +
+ + + + + +

Volume of attracted money per one ruble

+

of regional budget expenditures on innovation projects

+ + +
+ +
+
+ +
+ + + + + +

Understanding what investments should be made in innovative projects.

+ + +
+ + + + + + + + + + + + + + + +

Growth of the volume of production in the cluster companies

+

to the volume of state support for the cluster

+ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

FASIE projects: Number of projects supported

+

by the FASIE per 1,000 workers [awards/worker]

+ + +
+
+
+
+
+ + + + + + + + + + + + + +
\ No newline at end of file diff --git a/packages/mindplot/test/unit/import/input/cdata-support.mm b/packages/mindplot/test/unit/import/input/cdata-support.mm new file mode 100644 index 00000000..99cdd7d4 --- /dev/null +++ b/packages/mindplot/test/unit/import/input/cdata-support.mm @@ -0,0 +1,12 @@ + + + + + + +

Always ask

+ + +
+
+
\ No newline at end of file diff --git a/packages/mindplot/test/unit/import/input/coderToDeveloper.mm b/packages/mindplot/test/unit/import/input/coderToDeveloper.mm new file mode 100644 index 00000000..61cd1f31 --- /dev/null +++ b/packages/mindplot/test/unit/import/input/coderToDeveloper.mm @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/mindplot/test/unit/import/input/complex.mm b/packages/mindplot/test/unit/import/input/complex.mm new file mode 100644 index 00000000..952ac68b --- /dev/null +++ b/packages/mindplot/test/unit/import/input/complex.mm @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

HR Vision: Freeform Solutions is successful at its mission, sustainable as an organization AND is a great place to work.

+

HR Mission: To provide a positive HR service experience for applicants and employees, and collaborate with departments to recruit, develop, support, and retain diverse and talented employees who are the key to Freeform’s reputation and success.

+ + +
+ +
+ + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/packages/mindplot/test/unit/import/input/emptyNodes.mm b/packages/mindplot/test/unit/import/input/emptyNodes.mm new file mode 100644 index 00000000..0a685dc2 --- /dev/null +++ b/packages/mindplot/test/unit/import/input/emptyNodes.mm @@ -0,0 +1,116 @@ + + + + + + +

+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/packages/mindplot/test/unit/import/input/enc.mm b/packages/mindplot/test/unit/import/input/enc.mm new file mode 100644 index 00000000..48f63d6a --- /dev/null +++ b/packages/mindplot/test/unit/import/input/enc.mm @@ -0,0 +1,216 @@ + + + + + + + 1:590: disallowed character in entity name. + + + + + + + +

However, the fast pace of

+

development of plant trait meta-analyses also suggests that

+

trait acquisition in the field is a factor limiting the growth of

+

plant trait data bases.

+ + +
+
+ + + + + +

We measured

+

traits for every individual tree in nine 1-ha plots in tropical

+

lowland rainforest (N = 4709). Each plant was sampled for

+

10 functional traits related to wood and leaf morphology and

+

ecophysiology. Here, we contrast the trait means and variances

+

obtained with a full sampling strategy with those of

+

other sampling designs used in the recent literature, which we

+

obtain by simulation. We assess the differences in community-

+

level estimates of functional trait means and variances

+

among design types and sampling intensities. We then contrast

+

the relative costs of these designs and discuss the appropriateness

+

of different sampling designs and intensities for

+

different questions and systems.

+ + +
+
+ + + + + + + + +

With regard to estimating mean trait values, strategies

+

alternative to BRIDGE were consistently cost-effective. On

+

the other hand, strategies alternative to BRIDGE clearly

+

failed to accurately estimate the variance of trait values. This

+

indicates that in situations where accurate estimation of plotlevel

+

variance is desired, complete censuses are essential.

+ + +
+ + 1:134: unclosed tag: p + +
+ + + + + +

We suggest that, in these studies,

+

the investment in complete sampling may be worthwhile

+

for at least some traits.

+ + +
+ + + + +

Falar que isso corrobora nossa sugestão de utilizar poucas medidas, mas que elas sejam confiáveis.

+ + +
+
+
+ + + + + + + +

Here, we develop a new approach that links functional attributes

+

of tree species with studies of forest recovery and regional

+

land-use transitions (Chazdon et al. 2007). Grouping species according

+

to their functional attributes or demographic rates provides

+

insight into both applied and theoretical questions, such as selecting

+

species for reforestation programs, assessing ecosystem services, and

+

understanding community assembly processes in tropical forests

+

(Diaz et al. 2007, Kraft et al. 2008).

+ + +
+
+ + + + + +

Since we have data on leaf

+

and wood functional traits for only a subset of the species in our

+

study sites, we based our functional type classification on information

+

for a large number of tree species obtained through vegetation

+

monitoring studies.

+ + +
+
+ + + + + + +

Our approach avoided preconceived notions of successional

+

behavior or shade tolerance of tree species by developing an objective

+

and independent classification of functional types based on vegetation

+

monitoring data from permanent sample plots in mature and

+

secondary forests of northeastern Costa Rica (Finegan et al. 1999,

+

Chazdon et al. 2007).We apply an independent, prior classification

+

of 293 tree species from our study region into five functional types, based on two species attributes: canopy strata and diameter growth

+

rates for individuals Z10 cm dbh (Finegan et al. 1999, Salgado-

+

Negret 2007).

+ + +
+
+ + + + + +

Our results demonstrate strong linkages between functional

+

types defined by adult height and growth rates of large trees and

+

colonization groups based on the timing of seedling, sapling, and

+

tree recruitment in secondary forests.

+ + +
+
+ + + 1:325: unclosed tag: p + + + + + 1:691: unclosed tag: p + + + + + 1:1875: unclosed tag: p + + + + + + + +

Classifying functional types

+

based on functional traits with low plasticity, such as wood density

+

and seed size, could potentially serve as robust proxies for demographic

+

variables (Poorter et al. 2008, Zhang et al. 2008).

+ + +
+
+ + + + + +

CONDIT, R., S. P. HUBBELL, AND R. B. FOSTER. 1996. Assessing the response of

+

plant functional types in tropical forests to climatic change. J. Veg. Sci.

+

7: 405–416.

+

DALLING, J. S., AND S. P. HUBBELL. 2002. Seed size, growth rate and gap microsite

+

conditions as determinants of recruitment success for pioneer species.

+

J. Ecol. 90: 557–568.

+

FINEGAN, B. 1996. Pattern and process in neotropical secondary forests: The first

+

100 years of succession. Trends Ecol. Evol. 11: 119–124.

+

POORTER, L., S. J. WRIGHT, H. PAZ, D. D. ACKERLY, R. CONDIT, G.

+

IBARRA-MANRI´QUEZ, K. E. HARMS, J. C. LICONA, M.MARTI´NEZ-RAMOS,

+

S. J. MAZER, H. C. MULLER-LANDAU, M. PEN˜ A-CLAROS, C. O. WEBB,

+

AND I. J. WRIGHT. 2008. Are functional traits good predictors of demographic

+

rates? Evidence from five Neotropical forests. Ecology 89:

+

1908–1920.

+

ZHANG, Z. D., R. G. ZANG, AND Y. D. QI. 2008. Spatiotemporal patterns and

+

dynamics of species richness and abundance of woody plant functional

+

groups in a tropical forest landscape of Hainan Island, South China.

+

J. Integr. Plant Biol. 50: 547–558.

+

+ + +
+
+
+ + + + + + + +
\ No newline at end of file diff --git a/packages/mindplot/test/unit/import/input/freeMind_resources.mm b/packages/mindplot/test/unit/import/input/freeMind_resources.mm new file mode 100644 index 00000000..5bc019af --- /dev/null +++ b/packages/mindplot/test/unit/import/input/freeMind_resources.mm @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Here we collect a list of asked questions and answers
related to free mind mapping software FreeMind. Help
if you can (see To edit this FAQ). If you're searching for
an answer to your question, why don't you just press
Ctrl + F in your browser?

+
+ + +

notes for ehqoei hoi poi joij  joi oi o oipc coimcojoij0dijo;i jd  di doi oid podidpoi podij aoi jpoij poij aoij oij oij oij oij doid jfoij oifj ofij fojf oifj oifjdofi f jfoidf jothe rain in spanin stays mainly

+
+
+
+
+ + + + + + + + + + + + + + + + + + + +

Early example of Map (from SF Site)

+
+ +

Multi level Mindmap set of personal reading material covering a variety of topics (useful in itself).

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Good example for "What is it?"
and "How to do?" structure.

+
+
+ + + + + + + + + + + + +
diff --git a/packages/mindplot/test/unit/import/input/i18n.mm b/packages/mindplot/test/unit/import/input/i18n.mm new file mode 100644 index 00000000..29b35329 --- /dev/null +++ b/packages/mindplot/test/unit/import/input/i18n.mm @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/input/i18n2.mm b/packages/mindplot/test/unit/import/input/i18n2.mm new file mode 100644 index 00000000..40e022e5 --- /dev/null +++ b/packages/mindplot/test/unit/import/input/i18n2.mm @@ -0,0 +1,25 @@ + + + + + + + +

This is a not in languange أَبْجَدِيَّة عَرَبِ

+ + +
+
+ + + + + +

Long text node:

+

أَبْجَدِيَّة عَرَب

+ + +
+
+
+
\ No newline at end of file diff --git a/packages/mindplot/test/unit/import/input/issue.mm b/packages/mindplot/test/unit/import/input/issue.mm new file mode 100644 index 00000000..1586b623 --- /dev/null +++ b/packages/mindplot/test/unit/import/input/issue.mm @@ -0,0 +1,187 @@ + + + + + + + + + +

Hardware

+

(componentes físicos)

+ + +
+ + + + + + + +

Entrada de datos

+

+ + +
+ + + + + + + +

Ratón, Teclado, Joystick,

+

Cámara digital, Micrófono, Escáner.

+ + +
+ + +
+
+ + + + + + + + +

Monitor, Impresora, Bocinas, Plóter.

+

+ + +
+ + +
+
+ + + + + + + + +

Disquete, Disco compacto, DVD,

+

BD, Disco duro, Memoria flash.

+ + +
+ + +
+
+
+ + + + + +

Software

+

(Programas y datos con los que funciona la computadora)

+

+ + +
+ + + + + + + +

Software de Sistema:Permite el entendimiento

+

entre el usuario y la maquina.

+ + +
+ + + + + + + + + + + + + + +
+ + + + + +

Software de Aplicación: Permite hacer hojas de

+

calculo navegar en internet, base de datos, etc.

+ + +
+ + + + + + + + + + + + + + + + + + +
+ + + + + +

Software de Desarrollo

+

+ + +
+ + +
+
+ + + + + + + + + + +

PDA

+

+ + +
+ +
+ + + + + + + + + +
+
+
\ No newline at end of file diff --git a/packages/mindplot/test/unit/import/input/npe.mm b/packages/mindplot/test/unit/import/input/npe.mm new file mode 100644 index 00000000..1bc47622 --- /dev/null +++ b/packages/mindplot/test/unit/import/input/npe.mm @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/input/process.mm b/packages/mindplot/test/unit/import/input/process.mm new file mode 100644 index 00000000..376f942a --- /dev/null +++ b/packages/mindplot/test/unit/import/input/process.mm @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/input/pub_sub.mm b/packages/mindplot/test/unit/import/input/pub_sub.mm new file mode 100644 index 00000000..463bb4dc --- /dev/null +++ b/packages/mindplot/test/unit/import/input/pub_sub.mm @@ -0,0 +1,419 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/mindplot/test/unit/import/input/python.mm b/packages/mindplot/test/unit/import/input/python.mm new file mode 100644 index 00000000..d0058d56 --- /dev/null +++ b/packages/mindplot/test/unit/import/input/python.mm @@ -0,0 +1,316 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/mindplot/test/unit/import/input/sample3.mm b/packages/mindplot/test/unit/import/input/sample3.mm new file mode 100644 index 00000000..a91075fc --- /dev/null +++ b/packages/mindplot/test/unit/import/input/sample3.mm @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/input/sample4.mm b/packages/mindplot/test/unit/import/input/sample4.mm new file mode 100644 index 00000000..a91075fc --- /dev/null +++ b/packages/mindplot/test/unit/import/input/sample4.mm @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/input/welcome.mm b/packages/mindplot/test/unit/import/input/welcome.mm new file mode 100644 index 00000000..d4497d04 --- /dev/null +++ b/packages/mindplot/test/unit/import/input/welcome.mm @@ -0,0 +1,81 @@ + + + + + + + + +

5 min tutorial video ?

+

Follow the link !

+ + +
+ + +
+ + + + + + + + + +

Press "enter" to add a

+

Sibling

+ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/packages/mindplot/test/unit/import/input/writing_an_essay_with.mm b/packages/mindplot/test/unit/import/input/writing_an_essay_with.mm new file mode 100644 index 00000000..834a27ee --- /dev/null +++ b/packages/mindplot/test/unit/import/input/writing_an_essay_with.mm @@ -0,0 +1,543 @@ + + + + + + + + + + + + + + + + + + + + + + + +

+ When you're working on your essay, you'll find it helpful to switch between this map, and the one you're creating. To switch between maps, go to the Maps menu, and select the name of the map you want. +

+

+ (When you're a bit more familiar with FreeMind, you'll find it quicker to use the Shortcut Keys -- you can also use Alt + Shift + Left, or Alt + Shift + Right to move between maps.) +

+ +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ You should also make sure that the main point you're making in the essay provides a full answer to the question you have been asked, or you will probably be marked down for irrelevance. +

+ +
+ +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ I usually keep a separate mind map for this. It's psychologically easier to put your discarded ideas somewhere else, rather than to delete them entirely. And if you've saved them elsewhere, you can easily reincorporate them if you decide that they were relevant after all. +

+ +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ Another way of asking this question is can you sum up in a sentence what the main point is that your essay is making?) If you don't have a main claim (or don't know what your main claim is!), then your essay will not get a good mark. You are assessed on the quality of the argument you put forward for your main claim, and in order to be able to do this we (and you) need to know what your main claim is. +

+ +
+ + +
+ + + + + + +

+ You must be honest with yourself at this point: if you suspect that you haven't fully answered the question, then you must either (a) revise your answer so that you do have a full answer to the question, or (b) provide an argument for why it is that the angle you want to bring to the question is legitimate (for example, explain why it is legitimate to focus on just one aspect of the question). +

+ +
+ + +
+ + + + + + +

+ You should state what your main claim is in at least two places, first in the introduction, and second in the conclusion. (The bits in between should be devoted to arguing for your main claim). +

+ +
+ + +
+ + + + + + +

+ What reasons have you put forward as to why a reasonable (but sceptical) person should accept that your main claim is true? If you don't have any reasons (but merely a gut intuition) then you need to go back and revise, and find some arguments. +

+ +
+ + +
+ + + + + + +

+ Does your main claim follow logically from the supporting reasons you put forward? And are those supporting reasons themselves true (or at least plausibly true)? +

+ +
+ + +
+ + + + + + +

+ It is not enough e.g. to say that “I will be looking at arguments on both sides of this issue and coming to a conclusion”. You should tell us which arguments you will be looking at, whatyour evaluation of each of these arguments will be, and howthis analysis justifies the overall main claim you will be making. There are two reasons to give an overview of the structure of your argument: (a) it makes it much easier for the reader to grasp what you are saying, and why; (b) writing a summary of the structure of your argument is a good way of testing that you do in fact have a coherent argument. +

+ +
+ + +
+ + + + + + +

+ Remember that in any academic debate, anything worth saying will be disputed. If you can't think of any reasons why someone might doubt your main claim, it's likely that you are in the grip of a dogmatic certainty that you are right. This is not good: your essay will come across as a rant, which is the last thing you want. +

+ +
+ + +
+ + + + + + +

+ To be convincing, you might show that the doubts, while reasonable, are not well founded; or you could make your main claim more specific or nuanced in deference to them. +

+ +
+ + +
+ + + + + + +

+ If there is, then either delete this material, or explain why this material is after all relevant. +

+ +
+ + +
+ + + + + + +

+ If not then you are guilty of plagiarism. This is a serious offence, and you are likely to fail your course.. +

+ +
+ + +
+
+
+ + + + + + + + + + + + + + + + + +

+ This map is intended to help someone who has to write an argumentative essay in a subject such as history or philosophy to write better essays with the help of FreeMind. Copyright for this map resides with the author. Released under the Creative Commons Attribution-ShareAlike licence v.2.00. http://creativecommons.org/licenses/by-sa/2.0/uk/ +

+

+ You are free: +

+

+ * to copy, distribute, display, and perform the work +

+

+ * to make derivative works +

+

+ Under the following conditions: +

+

+ * Attribution. You must give the original author credit. +

+

+ * Share Alike. If you alter, transform, or build upon this work, you may distribute the resulting work only under a licence identical to this one. +

+

+ +

+

+ For any reuse or distribution, you must make clear to others the licence terms of this work. +

+

+ Any of these conditions can be waived if you get permission from the copyright holder. +

+

+ Nothing in this license impairs or restricts the author's moral rights. +

+ +
+ + +
+
+
+
diff --git a/packages/webapp/lang/de.json b/packages/webapp/lang/de.json index 65cd0caa..bf8bae01 100644 --- a/packages/webapp/lang/de.json +++ b/packages/webapp/lang/de.json @@ -204,11 +204,14 @@ "defaultMessage": "Erstellen" }, "import.description": { - "defaultMessage": "Sie können WiseMapping-Karten in Ihre Kartenliste importieren. Wählen Sie die Datei aus, die Sie importieren möchten." + "defaultMessage": "Sie können Karten von WiseMapping oder Freemind in Ihre Kartenliste importieren. Wählen Sie die Datei aus, die Sie importieren möchten." }, "import.title": { "defaultMessage": "Importieren Sie vorhandene Mindmaps" }, + "import.error-file": { + "defaultMessage": "Die Dateierweiterung ist ungültig" + }, "info.basic-info": { "defaultMessage": "Basisinformation" }, diff --git a/packages/webapp/lang/en.json b/packages/webapp/lang/en.json index 4f5c3321..52c42809 100644 --- a/packages/webapp/lang/en.json +++ b/packages/webapp/lang/en.json @@ -219,11 +219,14 @@ "defaultMessage": "Create" }, "import.description": { - "defaultMessage": "You can import WiseMapping maps to your list of maps. Select the file you want to import." + "defaultMessage": "You can import WiseMapping and Freemind maps to your list of maps. Select the file you want to import." }, "import.title": { "defaultMessage": "Import existing mindmap" }, + "import.error-file": { + "defaultMessage": "The file extension is invalid" + }, "info.basic-info": { "defaultMessage": "Basic Info" }, diff --git a/packages/webapp/lang/es.json b/packages/webapp/lang/es.json index 6e17c441..0c87194e 100644 --- a/packages/webapp/lang/es.json +++ b/packages/webapp/lang/es.json @@ -213,11 +213,14 @@ "defaultMessage": "Crear" }, "import.description": { - "defaultMessage": "Puede importar mapas de WiseMapping a su lista de mapas. Seleccione el archivo que desea importar." + "defaultMessage": "Puede importar mapas de WiseMapping y Freemind a su lista de mapas. Seleccione el archivo que desea importar." }, "import.title": { "defaultMessage": "Importar mapa mental existente" }, + "import.error-file": { + "defaultMessage": "La extension del archivo es invalida" + }, "info.basic-info": { "defaultMessage": "Información básica" }, diff --git a/packages/webapp/lang/fr.json b/packages/webapp/lang/fr.json index a6017fba..59108651 100644 --- a/packages/webapp/lang/fr.json +++ b/packages/webapp/lang/fr.json @@ -204,11 +204,14 @@ "defaultMessage": "Créer" }, "import.description": { - "defaultMessage": "Vous pouvez importer des cartes WiseMapping dans votre liste de cartes. Sélectionnez le fichier que vous souhaitez importer." + "defaultMessage": "Sie können WiseMapping- oder Freemind-Karten in Ihre Kartenliste importieren. Selectionnez le fichier que vous souhaitez Importeur." }, "import.title": { "defaultMessage": "Importer une carte mentale existante" }, + "import.error-file": { + "defaultMessage": "L'extension de fichier n'est pas valide" + }, "info.basic-info": { "defaultMessage": "Informations de base" }, diff --git a/packages/webapp/lang/ru.json b/packages/webapp/lang/ru.json index d4eaf445..3fac91a7 100644 --- a/packages/webapp/lang/ru.json +++ b/packages/webapp/lang/ru.json @@ -209,6 +209,9 @@ "import.title": { "defaultMessage": "Загрузить майнд-карту с компьютера" }, + "import.error-file": { + "defaultMessage": "Недопустимое расширение файла" + }, "info.basic-info": { "defaultMessage": "Основная информация" }, diff --git a/packages/webapp/lang/zh.json b/packages/webapp/lang/zh.json index d62ad359..ffaf7528 100644 --- a/packages/webapp/lang/zh.json +++ b/packages/webapp/lang/zh.json @@ -210,11 +210,14 @@ "defaultMessage": "创建" }, "import.description": { - "defaultMessage": "您可以将WiseMapping脑图导入到您的脑图列表中。选择要导入的文件。" + "defaultMessage": "您可以将脑图从 WiseMapping 和 Freemind 导入到您的脑图列表中。选择要导入的文件。" }, "import.title": { "defaultMessage": "导入现有的思维导图" }, + "import.error-file": { + "defaultMessage": "文件扩展名无效" + }, "info.basic-info": { "defaultMessage": "基本信息" }, diff --git a/packages/webapp/src/classes/client/rest-client/index.ts b/packages/webapp/src/classes/client/rest-client/index.ts index 5aaeec0f..7eee8810 100644 --- a/packages/webapp/src/classes/client/rest-client/index.ts +++ b/packages/webapp/src/classes/client/rest-client/index.ts @@ -226,7 +226,7 @@ export default class RestClient implements Client { const errorInfo = this.parseResponseOnError(error.response); reject(errorInfo); }); - }; + }; return new Promise(handler); } diff --git a/packages/webapp/src/compiled-lang/de.json b/packages/webapp/src/compiled-lang/de.json index 2c1995c7..61e3d268 100644 --- a/packages/webapp/src/compiled-lang/de.json +++ b/packages/webapp/src/compiled-lang/de.json @@ -446,7 +446,13 @@ "import.description": [ { "type": 0, - "value": "Sie können WiseMapping-Karten in Ihre Kartenliste importieren. Wählen Sie die Datei aus, die Sie importieren möchten." + "value": "Sie können Karten von WiseMapping oder Freemind in Ihre Kartenliste importieren. Wählen Sie die Datei aus, die Sie importieren möchten." + } + ], + "import.error-file": [ + { + "type": 0, + "value": "Die Dateierweiterung ist ungültig" } ], "import.title": [ diff --git a/packages/webapp/src/compiled-lang/en.json b/packages/webapp/src/compiled-lang/en.json index 71d5c6d6..9bd7fa1e 100644 --- a/packages/webapp/src/compiled-lang/en.json +++ b/packages/webapp/src/compiled-lang/en.json @@ -440,7 +440,13 @@ "import.description": [ { "type": 0, - "value": "You can import WiseMapping maps to your list of maps. Select the file you want to import." + "value": "You can import WiseMapping and Freemind maps to your list of maps. Select the file you want to import." + } + ], + "import.error-file": [ + { + "type": 0, + "value": "The file extension is invalid" } ], "import.title": [ diff --git a/packages/webapp/src/compiled-lang/es.json b/packages/webapp/src/compiled-lang/es.json index 17fbe91a..6db49829 100644 --- a/packages/webapp/src/compiled-lang/es.json +++ b/packages/webapp/src/compiled-lang/es.json @@ -440,7 +440,13 @@ "import.description": [ { "type": 0, - "value": "Puede importar mapas de WiseMapping a su lista de mapas. Seleccione el archivo que desea importar." + "value": "Puede importar mapas de WiseMapping y Freemind a su lista de mapas. Seleccione el archivo que desea importar." + } + ], + "import.error-file": [ + { + "type": 0, + "value": "La extension del archivo es invalida" } ], "import.title": [ diff --git a/packages/webapp/src/compiled-lang/fr.json b/packages/webapp/src/compiled-lang/fr.json index 261da559..0fc32086 100644 --- a/packages/webapp/src/compiled-lang/fr.json +++ b/packages/webapp/src/compiled-lang/fr.json @@ -438,7 +438,13 @@ "import.description": [ { "type": 0, - "value": "Vous pouvez importer des cartes WiseMapping dans votre liste de cartes. Sélectionnez le fichier que vous souhaitez importer." + "value": "Sie können WiseMapping- oder Freemind-Karten in Ihre Kartenliste importieren. Selectionnez le fichier que vous souhaitez Importeur." + } + ], + "import.error-file": [ + { + "type": 0, + "value": "L'extension de fichier n'est pas valide" } ], "import.title": [ diff --git a/packages/webapp/src/compiled-lang/ru.json b/packages/webapp/src/compiled-lang/ru.json index d382a1bc..9ff4ffcc 100644 --- a/packages/webapp/src/compiled-lang/ru.json +++ b/packages/webapp/src/compiled-lang/ru.json @@ -443,6 +443,12 @@ "value": "Можно импортировать FreeMind 1.0.1 и WiseMapping файлы. Выберите файл, который хотите импортировать." } ], + "import.error-file": [ + { + "type": 0, + "value": "Недопустимое расширение файла" + } + ], "import.title": [ { "type": 0, diff --git a/packages/webapp/src/compiled-lang/zh.json b/packages/webapp/src/compiled-lang/zh.json index 209598e4..74ce6b48 100644 --- a/packages/webapp/src/compiled-lang/zh.json +++ b/packages/webapp/src/compiled-lang/zh.json @@ -440,7 +440,13 @@ "import.description": [ { "type": 0, - "value": "您可以将WiseMapping脑图导入到您的脑图列表中。选择要导入的文件。" + "value": "您可以将脑图从 WiseMapping 和 Freemind 导入到您的脑图列表中。选择要导入的文件。" + } + ], + "import.error-file": [ + { + "type": 0, + "value": "文件扩展名无效" } ], "import.title": [ diff --git a/packages/webapp/src/components/maps-page/action-dispatcher/import-dialog/index.tsx b/packages/webapp/src/components/maps-page/action-dispatcher/import-dialog/index.tsx index 61fd9948..04fa8092 100644 --- a/packages/webapp/src/components/maps-page/action-dispatcher/import-dialog/index.tsx +++ b/packages/webapp/src/components/maps-page/action-dispatcher/import-dialog/index.tsx @@ -1,5 +1,7 @@ +import { Alert } from '@mui/material'; import Button from '@mui/material/Button'; import FormControl from '@mui/material/FormControl'; +import { Importer, TextImporterFactory } from '@wisemapping/mindplot'; import React from 'react'; import { FormattedMessage, useIntl } from 'react-intl'; @@ -14,7 +16,7 @@ export type ImportModel = { title: string; description?: string; contentType?: string; - content?: ArrayBuffer | null | string; + content?: null | string; }; export type CreateProps = { @@ -26,10 +28,11 @@ const ImportDialog = ({ onClose }: CreateProps): React.ReactElement => { const client: Client = useSelector(activeInstance); const [model, setModel] = React.useState(defaultModel); const [error, setError] = React.useState(); + const [errorFile, setErrorFile] = React.useState(false); const intl = useIntl(); const mutation = useMutation( - (model: ImportModel) => { + (model: ImportModel) => { return client.importMap(model); }, { @@ -69,9 +72,6 @@ const ImportDialog = ({ onClose }: CreateProps): React.ReactElement => { const file = files[0]; // Closure to capture the file information. reader.onload = (event) => { - const fileContent = event?.target?.result; - model.content = fileContent; - // Suggest file name ... const fileName = file.name; if (fileName) { @@ -80,13 +80,29 @@ const ImportDialog = ({ onClose }: CreateProps): React.ReactElement => { model.title = title; } } - model.contentType = - file.name.lastIndexOf('.wxml') != -1 - ? 'application/xml' - : 'application/freemind'; - setModel({ ...model }); - }; + const extensionFile = file.name.split('.').pop(); + const extensionAccept = ['wxml', 'mm']; + + if (!extensionAccept.includes(extensionFile)) { + setErrorFile(true); + } + + model.contentType = 'application/xml' + + const fileContent = event?.target?.result; + const mapConent: string = typeof fileContent === 'string' ? fileContent : fileContent.toString(); + + const importer: Importer = TextImporterFactory.create(extensionFile, mapConent) + + importer.import(model.title, model.description) + .then(res => { + model.content = res; + setModel({ ...model }); + }) + .catch(e => console.log(e)); + }; + // Read in the image file as a data URL. reader.readAsText(file); } @@ -105,10 +121,18 @@ const ImportDialog = ({ onClose }: CreateProps): React.ReactElement => { description={intl.formatMessage({ id: 'import.description', defaultMessage: - 'You can import WiseMapping maps to your list of maps. Select the file you want to import.', + 'You can import WiseMapping and Freemind maps to your list of maps. Select the file you want to import.', })} submitButton={intl.formatMessage({ id: 'import.button', defaultMessage: 'Create' })} > + {errorFile && + + + + }