diff --git a/packages/editor/README.md b/packages/editor/README.md index 9a81c0ce..2ca790c4 100644 --- a/packages/editor/README.md +++ b/packages/editor/README.md @@ -11,7 +11,6 @@ This is a work in progress and for now mindplot needs to be instantiated using t ReactDOM.render( console.log('action called:', action)} diff --git a/packages/editor/package.json b/packages/editor/package.json index b08accde..7d88d4be 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -8,8 +8,8 @@ "cy:run": "cypress run", "test:integration": "start-server-and-test 'yarn playground' http-get://localhost:8081 'yarn cy:run'", "test": "yarn test:integration", - "extract": "for lang in {'es','en','fr','de'};do formatjs extract 'src/**/*.ts*' --ignore 'src/@types/**/*' --out-file lang/${lang}.json;done", - "compile": "formatjs compile" + "i18n:extract": "formatjs extract 'src/**/*.ts*' --ignore 'src/@types/**/*' --out-file lang/es.json", + "i18n:compile": "for lang in {'es','en','fr','de','zh','ru'};do formatjs compile lang/${lang}.json --ast --out-file src/compiled-lang/${lang}.json;done" }, "repository": "http://www.wisemapping.com", "author": "Paulo Veiga , Ezequiel Bergamaschi ", diff --git a/packages/editor/src/classes/menu/KeyboardShortcutDialog.js b/packages/editor/src/classes/menu/KeyboardShortcutDialog.js index 99e82694..dda05336 100644 --- a/packages/editor/src/classes/menu/KeyboardShortcutDialog.js +++ b/packages/editor/src/classes/menu/KeyboardShortcutDialog.js @@ -128,8 +128,8 @@ class KeyboardShortcutDialog extends BootstrapDialog { ${$msg('TOPIC_NOTE')} - Ctrl + n - ⌘ + n + Ctrl + k + ⌘ + k ${$msg('TOPIC_LINK')} diff --git a/packages/editor/src/classes/menu/Menu.ts b/packages/editor/src/classes/menu/Menu.ts index eb2a4a9b..57b7a035 100644 --- a/packages/editor/src/classes/menu/Menu.ts +++ b/packages/editor/src/classes/menu/Menu.ts @@ -211,7 +211,7 @@ class Menu extends IMenu { if (undoButton) { undoButton.disable(); } - Menu._registerTooltip('undoEdition', $msg('UNDO'), 'meta+Z'); + Menu._registerTooltip('undoEdition', $msg('UNDO')); const redoButton = this._addButton('redoEdition', false, false, () => { designer.redo(); @@ -219,7 +219,7 @@ class Menu extends IMenu { if (redoButton) { redoButton.disable(); } - Menu._registerTooltip('redoEdition', $msg('REDO'), 'meta+shift+Z'); + Menu._registerTooltip('redoEdition', $msg('REDO')); if (redoButton && undoButton) { designer.addEvent('modelUpdate', (event) => { @@ -239,12 +239,12 @@ class Menu extends IMenu { this._addButton('addTopic', true, false, () => { designer.createSiblingForSelectedNode(); }); - Menu._registerTooltip('addTopic', $msg('ADD_TOPIC'), 'Enter'); + Menu._registerTooltip('addTopic', $msg('ADD_TOPIC')); this._addButton('deleteTopic', true, true, () => { designer.deleteSelectedEntities(); }); - Menu._registerTooltip('deleteTopic', $msg('TOPIC_DELETE'), 'Delete'); + Menu._registerTooltip('deleteTopic', $msg('TOPIC_DELETE')); this._addButton('topicLink', true, false, () => { designer.addLink(); @@ -279,7 +279,7 @@ class Menu extends IMenu { () => { this.save(saveElem, designer, true); }); - Menu._registerTooltip('save', $msg('SAVE'), 'meta+S'); + Menu._registerTooltip('save', $msg('SAVE')); // Register unload save ... window.addEventListener('beforeunload', () => { diff --git a/packages/editor/src/global-styled.css b/packages/editor/src/global-styled.css index d978078e..06d15195 100644 --- a/packages/editor/src/global-styled.css +++ b/packages/editor/src/global-styled.css @@ -9,18 +9,6 @@ html { font-size: initial; } -body { - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - overflow: hidden; - margin: 0; - font-family: Arial, Helvetica, sans-serif; -} - div#mindplot { position: relative; top: 50px; diff --git a/packages/mindplot/package.json b/packages/mindplot/package.json index e8833eaf..5ff5fd8c 100644 --- a/packages/mindplot/package.json +++ b/packages/mindplot/package.json @@ -1,6 +1,6 @@ { "name": "@wisemapping/mindplot", - "version": "5.0.8", + "version": "5.0.9", "description": "WiseMapping - Mindplot Canvas Library", "homepage": "http://www.wisemapping.org/", "directories": { @@ -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/DesignerKeyboard.ts b/packages/mindplot/src/components/DesignerKeyboard.ts index 278de869..e7050f0b 100644 --- a/packages/mindplot/src/components/DesignerKeyboard.ts +++ b/packages/mindplot/src/components/DesignerKeyboard.ts @@ -125,7 +125,7 @@ class DesignerKeyboard extends Keyboard { }, ); this.addShortcut( - ['ctrl+n', 'meta+n'], (event: Event) => { + ['ctrl+k', 'meta+k'], (event: Event) => { event.preventDefault(); event.stopPropagation(); designer.addNote(); diff --git a/packages/mindplot/src/components/ImageIcon.js b/packages/mindplot/src/components/ImageIcon.js index d5880742..7a3b1269 100644 --- a/packages/mindplot/src/components/ImageIcon.js +++ b/packages/mindplot/src/components/ImageIcon.js @@ -73,7 +73,7 @@ class ImageIcon extends Icon { static _getNextFamilyIconId(iconId) { const familyIcons = ImageIcon._getFamilyIcons(iconId); - $assert(familyIcons != null, 'Family Icon not found!'); + $assert(familyIcons !== null, `Family Icon not found: ${iconId}`); let result = null; for (let i = 0; i < familyIcons.length && result == null; i++) { diff --git a/packages/mindplot/src/components/RestPersistenceManager.ts b/packages/mindplot/src/components/RestPersistenceManager.ts index bcf0e0e6..514b4e41 100644 --- a/packages/mindplot/src/components/RestPersistenceManager.ts +++ b/packages/mindplot/src/components/RestPersistenceManager.ts @@ -27,27 +27,19 @@ class RESTPersistenceManager extends PersistenceManager { private lockUrl: string; - private timestamp: string; - - private session: string; - private onSave: boolean; private clearTimeout; - constructor(options) { + constructor(options: { documentUrl: string, revertUrl: string, lockUrl: string }) { $assert(options.documentUrl, 'documentUrl can not be null'); $assert(options.revertUrl, 'revertUrl can not be null'); $assert(options.lockUrl, 'lockUrl can not be null'); - $assert(options.session, 'session can not be null'); - $assert(options.timestamp, 'timestamp can not be null'); super(); this.documentUrl = options.documentUrl; this.revertUrl = options.revertUrl; this.lockUrl = options.lockUrl; - this.timestamp = options.timestamp; - this.session = options.session; } saveMapXml(mapId: string, mapXml: Document, pref: string, saveHistory: boolean, events): void { @@ -57,9 +49,7 @@ class RESTPersistenceManager extends PersistenceManager { properties: pref, }; - let query = `minor=${!saveHistory}`; - query = `${query}×tamp=${this.timestamp}`; - query = `${query}&session=${this.session}`; + const query = `minor=${!saveHistory}`; if (!this.onSave) { // Mark save in process and fire a event unlocking the save ... @@ -80,7 +70,6 @@ class RESTPersistenceManager extends PersistenceManager { }, ).then(async (response: Response) => { if (response.ok) { - persistence.timestamp = await response.text(); events.onSuccess(); } else { console.log(`Saving error: ${response.status}`); 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/components/lang/de.js b/packages/mindplot/src/components/lang/de.js index 90308caa..c2cb2111 100644 --- a/packages/mindplot/src/components/lang/de.js +++ b/packages/mindplot/src/components/lang/de.js @@ -79,7 +79,7 @@ const DE = { MULTIPLE_LINES: 'Füge mehrer Textzeilen hinzu', BACK_TO_MAP_LIST: 'Zurück zur Kartenliste', KEYBOARD_SHOTCUTS: 'Tastaturkürzel', - + PASTE_URL_HERE: 'Fügen Sie hier die gewünschte URL-Adresse ein:', }; export default DE; diff --git a/packages/mindplot/src/components/lang/en.js b/packages/mindplot/src/components/lang/en.js index 751055e3..0ebe385f 100644 --- a/packages/mindplot/src/components/lang/en.js +++ b/packages/mindplot/src/components/lang/en.js @@ -79,6 +79,7 @@ const EN = { MULTIPLE_LINES: 'Add multiple text lines', BACK_TO_MAP_LIST: 'Back to Maps List', KEYBOARD_SHOTCUTS: 'Keyboard Shorcuts', + PASTE_URL_HERE: 'Paste your url address here:', }; export default EN; diff --git a/packages/mindplot/src/components/lang/es.js b/packages/mindplot/src/components/lang/es.js index 7e052167..87f65188 100644 --- a/packages/mindplot/src/components/lang/es.js +++ b/packages/mindplot/src/components/lang/es.js @@ -79,6 +79,7 @@ const ES = { MULTIPLE_LINES: 'Ajouter plusieurs lignes de texte', BACK_TO_MAP_LIST: 'Volver a la lista de mapas', KEYBOARD_SHOTCUTS: 'Métodos abreviados de teclado', + PASTE_URL_HERE: 'Copie la URL que desea aca:', }; export default ES; diff --git a/packages/mindplot/src/components/lang/fr.js b/packages/mindplot/src/components/lang/fr.js index 2356e2c3..f8a90848 100644 --- a/packages/mindplot/src/components/lang/fr.js +++ b/packages/mindplot/src/components/lang/fr.js @@ -79,6 +79,7 @@ const FR = { MULTIPLE_LINES: 'Ajouter plusieurs lignes de texte', BACK_TO_MAP_LIST: 'Retour à la liste des cartes', KEYBOARD_SHOTCUTS: 'Raccourcis clavier', + PASTE_URL_HERE: 'Collez l\'adresse URL souhaitée ici :', }; export default FR; diff --git a/packages/mindplot/src/components/lang/ru.js b/packages/mindplot/src/components/lang/ru.js index 751055e3..d962cd26 100644 --- a/packages/mindplot/src/components/lang/ru.js +++ b/packages/mindplot/src/components/lang/ru.js @@ -79,6 +79,7 @@ const EN = { MULTIPLE_LINES: 'Add multiple text lines', BACK_TO_MAP_LIST: 'Back to Maps List', KEYBOARD_SHOTCUTS: 'Keyboard Shorcuts', + PASTE_URL_HERE: 'Вставьте нужный URL-адрес здесь:', }; export default EN; diff --git a/packages/mindplot/src/components/lang/zh.js b/packages/mindplot/src/components/lang/zh.js index b4eb5c96..ef262eef 100644 --- a/packages/mindplot/src/components/lang/zh.js +++ b/packages/mindplot/src/components/lang/zh.js @@ -79,6 +79,8 @@ const ZH = { MULTIPLE_LINES: '添加多行文本', BACK_TO_MAP_LIST: '回到脑图列表', KEYBOARD_SHOTCUTS: '键盘快捷键', + PASTE_URL_HERE: '在此处粘贴所需的 URL 地址:', + }; export default ZH; diff --git a/packages/mindplot/src/components/persistence/XMLSerializerTango.ts b/packages/mindplot/src/components/persistence/XMLSerializerTango.ts index a0a47be0..e8e7b719 100644 --- a/packages/mindplot/src/components/persistence/XMLSerializerTango.ts +++ b/packages/mindplot/src/components/persistence/XMLSerializerTango.ts @@ -445,7 +445,7 @@ class XMLSerializerTango implements XMLMindmapSerializer { return value; } - static _deserializeNodeText(domElem) { + static _deserializeNodeText(domElem: ChildNode) { const children = domElem.childNodes; let value = null; for (let i = 0; i < children.length; i++) { @@ -457,7 +457,7 @@ class XMLSerializerTango implements XMLMindmapSerializer { return value; } - static _deserializeRelationship(domElement, mindmap) { + static _deserializeRelationship(domElement: Element, mindmap: Mindmap): RelationshipModel { const srcId = Number.parseInt(domElement.getAttribute('srcTopicId'), 10); const destId = Number.parseInt(domElement.getAttribute('destTopicId'), 10); const lineType = Number.parseInt(domElement.getAttribute('lineType'), 10); @@ -468,6 +468,7 @@ class XMLSerializerTango implements XMLMindmapSerializer { if (srcId === destId) { throw new Error('Invalid relationship, dest and source are equals'); } + // Is the connections points valid ?. If it's not, do not load the relationship ... if (mindmap.findNodeById(srcId) == null || mindmap.findNodeById(destId) == null) { throw new Error('Transition could not created, missing node for relationship'); @@ -481,8 +482,8 @@ class XMLSerializerTango implements XMLMindmapSerializer { if ($defined(destCtrlPoint) && destCtrlPoint !== '') { model.setDestCtrlPoint(Point.fromString(destCtrlPoint)); } - model.setEndArrow('false'); - model.setStartArrow('true'); + model.setEndArrow(false); + model.setStartArrow(true); return model; } diff --git a/packages/mindplot/src/components/widget/LinkEditor.js b/packages/mindplot/src/components/widget/LinkEditor.js index cc83f2f8..f4dbcabc 100644 --- a/packages/mindplot/src/components/widget/LinkEditor.js +++ b/packages/mindplot/src/components/widget/LinkEditor.js @@ -49,7 +49,7 @@ class LinkEditor extends BootstrapDialog { action: 'none', id: 'linkFormId', }); - const text = $('

').text('Paste your url here:'); + const text = $('

').text($msg('PASTE_URL_HERE')); text.css('margin', '0px 0px 20px'); this.form.append(text); @@ -60,7 +60,7 @@ class LinkEditor extends BootstrapDialog { // Add Input const input = $('').attr({ - placeholder: 'http://www.example.com/', + placeholder: 'https://www.example.com/', required: 'true', autofocus: 'autofocus', class: 'form-control', @@ -92,9 +92,10 @@ class LinkEditor extends BootstrapDialog { const me = this; this.form.unbind('submit').submit((event) => { event.preventDefault(); - if (me.checkURL(input.val())) { + let inputValue = input.val(); + inputValue = this.hasProtocol(inputValue) ? inputValue : `https://${inputValue}`; + if (me.checkURL(inputValue)) { me.cleanError(); - const inputValue = input.val(); if (inputValue != null && $.trim(inputValue) !== '') { model.setValue(inputValue); } @@ -115,7 +116,16 @@ class LinkEditor extends BootstrapDialog { * @return {Boolean} true if the url is valid */ checkURL(url) { - const regex = /^(http|https|ftp):\/\/[a-z0-9]+([-.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/i; + const regex = /^(http|https):\/\/[a-z0-9]+([-.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/i; + return (regex.test(url)); + } + + /** + * checks whether the input is a valid url + * @return {Boolean} true if the url is valid + */ + hasProtocol(url) { + const regex = /^(http|https):\/\//i; return (regex.test(url)); } diff --git a/packages/mindplot/src/components/widget/LinkIconTooltip.js b/packages/mindplot/src/components/widget/LinkIconTooltip.js index 62e28a9c..a40b56fc 100644 --- a/packages/mindplot/src/components/widget/LinkIconTooltip.js +++ b/packages/mindplot/src/components/widget/LinkIconTooltip.js @@ -40,8 +40,8 @@ class LinkIconTooltip extends FloatingTip { static _buildContent(linkIcon) { const url = linkIcon.getModel().getUrl(); - const linkText = `URL: ${url}`; - const linkPreview = `http://free.pagepeeker.com/v2/thumbs.php?size=m&url=${url}`; + const linkText = `${url}`; + const linkPreview = `https://free.pagepeeker.com/v2/thumbs.php?size=m&url=${url}`; const result = $('
').css({ padding: '5px', diff --git a/packages/mindplot/src/components/widget/NoteEditor.js b/packages/mindplot/src/components/widget/NoteEditor.js index 584aa376..3d127996 100644 --- a/packages/mindplot/src/components/widget/NoteEditor.js +++ b/packages/mindplot/src/components/widget/NoteEditor.js @@ -23,7 +23,7 @@ import { $msg } from '../Messages'; class NoteEditor extends BootstrapDialog { constructor(model) { $assert(model, 'model can not be null'); - super($msg('Note'), { + super($msg('NOTE'), { cancelButton: true, closeButton: true, acceptButton: true, 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/src/indexLoader.ts b/packages/mindplot/src/indexLoader.ts index e3fd4c64..7d8bd52a 100644 --- a/packages/mindplot/src/indexLoader.ts +++ b/packages/mindplot/src/indexLoader.ts @@ -22,7 +22,6 @@ import { import { buildDesigner, } from './components/DesignerBuilder'; -import RESTPersistenceManager from './components/RestPersistenceManager'; import PersistenceManager from './components/PersistenceManager'; import LocalStorageManager from './components/LocalStorageManager'; import DesignerOptionsBuilder from './components/DesignerOptionsBuilder'; @@ -34,15 +33,7 @@ require('../../../libraries/bootstrap/js/bootstrap.min'); // Configure designer options ... let persistence: PersistenceManager; -if (!global.memoryPersistence && !global.readOnly) { - persistence = new RESTPersistenceManager({ - documentUrl: '/c/restful/maps/{id}/document', - revertUrl: '/c/restful/maps/{id}/history/latest', - lockUrl: '/c/restful/maps/{id}/lock', - timestamp: global.lockTimestamp, - session: global.lockSession, - }); -} else { +if (global.readOnly) { const historyId = global.historyId ? `${global.historyId}/` : ''; persistence = new LocalStorageManager( `/c/restful/maps/{id}/${historyId}document/xml${!global.isAuth ? '-pub' : ''}`, diff --git a/packages/mindplot/test/unit/export/expected/bug2.md b/packages/mindplot/test/unit/export/expected/bug2.md index 2dd2052f..ea1c7fc8 100644 --- a/packages/mindplot/test/unit/export/expected/bug2.md +++ b/packages/mindplot/test/unit/export/expected/bug2.md @@ -6,14 +6,14 @@ - Naturaleza - Animales, Plantas, Piedras - Arqueología + - Culturas Antiguas + - Egipto, Grecia, China... - Energía + - Paleontología - Astronomía - Arquitectura - Cocina - Poesía - - Culturas Antiguas - - Egipto, Grecia, China... - - Paleontología - Duración limitada: 5-6 semanas - Niños y niñas que quieren saber más - Alternativa a otras actividades de ocio @@ -25,11 +25,11 @@ - Actividades centradas en el contexto cercano - Flexibilidad en el uso de las lenguas de trabajo (inglés, castellano, esukara?) - Complementamos el trabajo de la escuela[^1] + - SaberMás trabaja con, desde y para la motivación + - Trabajamos en equipo en nuestros proyectos - Cada uno va a su ritmo, y cada cual pone sus límites - Aprendemos todos de todos - Valoramos lo que hemos aprendido - - SaberMás trabaja con, desde y para la motivación - - Trabajamos en equipo en nuestros proyectos diff --git a/packages/mindplot/test/unit/export/expected/bug2.mm b/packages/mindplot/test/unit/export/expected/bug2.mm index 3baf15c5..ccd871e5 100644 --- a/packages/mindplot/test/unit/export/expected/bug2.mm +++ b/packages/mindplot/test/unit/export/expected/bug2.mm @@ -7,15 +7,15 @@ + + + + - - - - @@ -41,11 +41,11 @@ + + - - \ No newline at end of file diff --git a/packages/mindplot/test/unit/export/expected/bug2.txt b/packages/mindplot/test/unit/export/expected/bug2.txt index 426423e8..829e3610 100644 --- a/packages/mindplot/test/unit/export/expected/bug2.txt +++ b/packages/mindplot/test/unit/export/expected/bug2.txt @@ -5,14 +5,14 @@ 1.3.1 Naturaleza 1.3.1.1 Animales, Plantas, Piedras 1.3.2 Arqueología - 1.3.3 Energía - 1.3.4 Astronomía - 1.3.5 Arquitectura - 1.3.6 Cocina - 1.3.7 Poesía - 1.3.8 Culturas Antiguas - 1.3.8.1 Egipto, Grecia, China... - 1.3.9 Paleontología + 1.3.3 Culturas Antiguas + 1.3.3.1 Egipto, Grecia, China... + 1.3.4 Energía + 1.3.5 Paleontología + 1.3.6 Astronomía + 1.3.7 Arquitectura + 1.3.8 Cocina + 1.3.9 Poesía 1.4 Duración limitada: 5-6 semanas 1.5 Niños y niñas que quieren saber más 1.6 Alternativa a otras actividades de ocio @@ -30,8 +30,8 @@ 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á.] - 1.14.1 Cada uno va a su ritmo, y cada cual pone sus límites - 1.14.2 Aprendemos todos de todos - 1.14.3 Valoramos lo que hemos aprendido - 1.14.4 SaberMás trabaja con, desde y para la motivación - 1.14.5 Trabajamos en equipo en nuestros proyectos + 1.14.1 SaberMás trabaja con, desde y para la motivación + 1.14.2 Trabajamos en equipo en nuestros proyectos + 1.14.3 Cada uno va a su ritmo, y cada cual pone sus límites + 1.14.4 Aprendemos todos de todos + 1.14.5 Valoramos lo que hemos aprendido diff --git a/packages/mindplot/test/unit/export/expected/bug2.wxml b/packages/mindplot/test/unit/export/expected/bug2.wxml index 227024c2..65ae6963 100644 --- a/packages/mindplot/test/unit/export/expected/bug2.wxml +++ b/packages/mindplot/test/unit/export/expected/bug2.wxml @@ -1,6 +1,6 @@ - \ No newline at end of file + 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/export/expected/bug3.mm b/packages/mindplot/test/unit/export/expected/bug3.mm index ebbb2f0b..4cd9b74b 100644 --- a/packages/mindplot/test/unit/export/expected/bug3.mm +++ b/packages/mindplot/test/unit/export/expected/bug3.mm @@ -332,7 +332,7 @@ - + @@ -944,7 +944,7 @@ - + diff --git a/packages/mindplot/test/unit/export/expected/complex.wxml b/packages/mindplot/test/unit/export/expected/complex.wxml index 91268870..76b3603a 100644 --- a/packages/mindplot/test/unit/export/expected/complex.wxml +++ b/packages/mindplot/test/unit/export/expected/complex.wxml @@ -1,5 +1,5 @@ + @@ -117,7 +118,6 @@ - diff --git a/packages/mindplot/test/unit/export/expected/enc.txt b/packages/mindplot/test/unit/export/expected/enc.txt index 616c6491..ab0dd50b 100644 --- a/packages/mindplot/test/unit/export/expected/enc.txt +++ b/packages/mindplot/test/unit/export/expected/enc.txt @@ -41,7 +41,8 @@ the investment in complete sampling may be worthwhile for at least some traits. [Note: Falar que isso corrobora nossa sugestão de utilizar poucas medidas, mas que elas sejam confiáveis.] 1.2 Chazdon 2010. Biotropica. 42(1): 31–40 - 1.2.1 Here, we develop a new approach that links functional attributes + 1.2.1 Falar no artigo que esse trabalho fala que é inadequada a divisão entre pioneira e não pioneira devido a grande variação que há entre elas. Além de terem descoberto que durante a ontogenia a resposta a luminosidade muda dentro de uma mesma espécie. Porém recomendar que essa classificação continue sendo usada em curto prazo enquanto não há informações confiáveis suficiente para esta simples classificação. Outras classificações como esta do artigo são bem vinda, contanto que tenham dados confiáveis. Porém dados estáticos já são difíceis de se obter, dados temporais, como taxa de crescimento em diâmetro ou altura, são mais difíceis ainda. Falar que vários tipos de classificações podem ser utilizadas e quanto mais detalhe melhor, porém os dados é que são mais limitantes. Se focarmos em dados de germinação e crescimento limitantes, como sugerem sainete e whitmore, da uma idéia maismrápida e a curto prazo da classificação destas espécies. Depois com o tempo conseguiremos construir classificações mais detalhadas e com mais dados confiáveis. + 1.2.2 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 @@ -49,12 +50,11 @@ 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). - 1.2.2 Since we have data on leaf + 1.2.3 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. - 1.2.3 Falar no artigo que esse trabalho fala que é inadequada a divisão entre pioneira e não pioneira devido a grande variação que há entre elas. Além de terem descoberto que durante a ontogenia a resposta a luminosidade muda dentro de uma mesma espécie. Porém recomendar que essa classificação continue sendo usada em curto prazo enquanto não há informações confiáveis suficiente para esta simples classificação. Outras classificações como esta do artigo são bem vinda, contanto que tenham dados confiáveis. Porém dados estáticos já são difíceis de se obter, dados temporais, como taxa de crescimento em diâmetro ou altura, são mais difíceis ainda. Falar que vários tipos de classificações podem ser utilizadas e quanto mais detalhe melhor, porém os dados é que são mais limitantes. Se focarmos em dados de germinação e crescimento limitantes, como sugerem sainete e whitmore, da uma idéia maismrápida e a curto prazo da classificação destas espécies. Depois com o tempo conseguiremos construir classificações mais detalhadas e com mais dados confiáveis. 1.2.4 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 diff --git a/packages/mindplot/test/unit/export/expected/enc.wxml b/packages/mindplot/test/unit/export/expected/enc.wxml index b4136958..8194da80 100644 --- a/packages/mindplot/test/unit/export/expected/enc.wxml +++ b/packages/mindplot/test/unit/export/expected/enc.wxml @@ -28,18 +28,18 @@ 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.]]> - - + + diff --git a/packages/mindplot/test/unit/export/expected/welcome.mm b/packages/mindplot/test/unit/export/expected/welcome.mm index d4497d04..e9c6cde4 100644 --- a/packages/mindplot/test/unit/export/expected/welcome.mm +++ b/packages/mindplot/test/unit/export/expected/welcome.mm @@ -12,7 +12,7 @@ - + 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 64d285a4..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" }, @@ -500,5 +503,14 @@ }, "label.title": { "defaultMessage": "Etikett hinzufügen" + }, + "footer.donations": { + "defaultMessage": "Spenden" + }, + "footer.support": { + "defaultMessage": "Unterstützt" + }, + "footer.team": { + "defaultMessage": "Ausrüstung" } } \ No newline at end of file diff --git a/packages/webapp/lang/en.json b/packages/webapp/lang/en.json index c744821f..52c42809 100644 --- a/packages/webapp/lang/en.json +++ b/packages/webapp/lang/en.json @@ -167,6 +167,15 @@ "footer.others": { "defaultMessage": "Others" }, + "footer.support": { + "defaultMessage": "Support" + }, + "footer.team": { + "defaultMessage": "Our Team" + }, + "footer.donations": { + "defaultMessage": "Donations" + }, "footer.termsandconditions": { "defaultMessage": "Term And Conditions" }, @@ -210,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" }, @@ -258,7 +270,7 @@ "defaultMessage": "Add label" }, "label.add-for": { - "defaultMessage": "Editing labels for maps:" + "defaultMessage": "Editing labels for" }, "label.add-placeholder": { "defaultMessage": "Label title" @@ -275,6 +287,9 @@ "label.description": { "defaultMessage": "Use labels to organize your maps." }, + "label.maps-count": { + "defaultMessage": "{count} maps" + }, "label.title": { "defaultMessage": "Add a label" }, diff --git a/packages/webapp/lang/es.json b/packages/webapp/lang/es.json index a46899fe..0c87194e 100644 --- a/packages/webapp/lang/es.json +++ b/packages/webapp/lang/es.json @@ -141,7 +141,16 @@ "defaultMessage": "El export a formatos de imagen (SVG, PNG, JPEG, PDF) solo está disponible en la barra de herramientas del editor." }, "footer.aboutus": { - "defaultMessage": "Sobre nosotros" + "defaultMessage": "Sobre Nosotros" + }, + "footer.donations": { + "defaultMessage": "Donaciones" + }, + "footer.support": { + "defaultMessage": "Soporte" + }, + "footer.team": { + "defaultMessage": "Equipo" }, "footer.contactus": { "defaultMessage": "Contáctenos" @@ -204,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 95b36f63..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" }, @@ -500,5 +503,14 @@ }, "label.title": { "defaultMessage": "Ajouter une étiquette" + }, + "footer.donations": { + "defaultMessage": "Des dons" + }, + "footer.support": { + "defaultMessage": "Service" + }, + "footer.team": { + "defaultMessage": "Equipe" } } \ No newline at end of file diff --git a/packages/webapp/lang/ru.json b/packages/webapp/lang/ru.json index 1f73adea..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": "Основная информация" }, @@ -473,5 +476,14 @@ }, "editor.try-welcome-description": { "defaultMessage": "Зарегистрируйтесь, чтобы создавать, делиться и публиковать майнд-карты бесплатно и без ограничений!" + }, + "footer.donations": { + "defaultMessage": "Пожертвования" + }, + "footer.support": { + "defaultMessage": "Услуги" + }, + "footer.team": { + "defaultMessage": "команда" } } \ No newline at end of file diff --git a/packages/webapp/lang/zh.json b/packages/webapp/lang/zh.json index 2629fedd..ffaf7528 100644 --- a/packages/webapp/lang/zh.json +++ b/packages/webapp/lang/zh.json @@ -1,5 +1,5 @@ { - "account.delete-warning": { + "account.delete-warning警告": { "defaultMessage": "请记住,您将无法访问您添加的任何思维导图。您的所有信息都将被删除,并且无法恢复。" }, "accountinfo.button": { @@ -135,7 +135,7 @@ "defaultMessage": "文档:将你的思维导图导出到一个独立的文档中来分享" }, "export.image": { - "defaultMessage": "Image: Get a graphic representation of your map including all colors and shapes.图像:以图片形式获取包含所有颜色和形状的脑图" + "defaultMessage": "图像:以图片形式获取包含所有颜色和形状的脑图" }, "export.img-center": { "defaultMessage": "居中并缩放合适大小" @@ -210,11 +210,14 @@ "defaultMessage": "创建" }, "import.description": { - "defaultMessage": "您可以将WiseMapping脑图导入到您的脑图列表中。选择要导入的文件。" + "defaultMessage": "您可以将脑图从 WiseMapping 和 Freemind 导入到您的脑图列表中。选择要导入的文件。" }, "import.title": { "defaultMessage": "导入现有的思维导图" }, + "import.error-file": { + "defaultMessage": "文件扩展名无效" + }, "info.basic-info": { "defaultMessage": "基本信息" }, @@ -249,7 +252,7 @@ "defaultMessage": "分享" }, "info.starred": { - "defaultMessage": "星标" + "defaultMessage": "收藏" }, "info.title": { "defaultMessage": "信息" @@ -364,16 +367,16 @@ "defaultMessage": "所有" }, "maps.nav-onwned": { - "defaultMessage": "拥有" + "defaultMessage": "我的" }, "maps.nav-public": { - "defaultMessage": "公共" + "defaultMessage": "公开" }, "maps.nav-shared": { "defaultMessage": "与我分享" }, "maps.nav-starred": { - "defaultMessage": "星标" + "defaultMessage": "收藏" }, "maps.page-title": { "defaultMessage": "我的脑图|WiseMapping" @@ -388,7 +391,7 @@ "defaultMessage": "打开编辑" }, "maps.tooltip-starred": { - "defaultMessage": "星标" + "defaultMessage": "收藏" }, "maps.view": { "defaultMessage": "查看" @@ -430,7 +433,7 @@ "defaultMessage": "注册成功|WiseMapping" }, "registration.desc": { - "defaultMessage": "Signing up is free and just take a moment注册免费,分分钟就好" + "defaultMessage": "注册免费,分分钟就好" }, "registration.email": { "defaultMessage": "电子邮件" @@ -500,5 +503,14 @@ }, "share.message": { "defaultMessage": "消息" + }, + "footer.support": { + "defaultMessage": "支持" + }, + "footer.team": { + "defaultMessage": "学期" + }, + "footer.donations": { + "defaultMessage": "捐款" } -} +} \ No newline at end of file diff --git a/packages/webapp/package.json b/packages/webapp/package.json index cf5225aa..050678a5 100644 --- a/packages/webapp/package.json +++ b/packages/webapp/package.json @@ -1,6 +1,6 @@ { "name": "@wisemapping/webapp", - "version": "5.0.8", + "version": "5.0.9", "main": "app.jsx", "scripts": { "start": "webpack serve --config webpack.dev.js ", @@ -9,8 +9,8 @@ "lint": "eslint src", "cy:run": "cypress run", "test:integration": "start-server-and-test start http-get://localhost:3000 cy:run", - "extract": "formatjs extract 'src/**/*.ts*' --ignore 'src/@types/**/*' --out-file lang/en.json", - "compile": "formatjs compile", + "i18n:extract": "formatjs extract 'src/**/*.ts*' --ignore 'src/@types/**/*' --out-file lang/en.json", + "i18n:compile": "for lang in {'es','en','fr','de','zh','ru'};do formatjs compile lang/${lang}.json --ast --out-file src/compiled-lang/${lang}.json;done", "test": "yarn test:integration" }, "files": [ diff --git a/packages/webapp/src/@types/index.d.ts b/packages/webapp/src/@types/index.d.ts index 18f29971..daeadc97 100644 --- a/packages/webapp/src/@types/index.d.ts +++ b/packages/webapp/src/@types/index.d.ts @@ -2,8 +2,6 @@ declare module '*.png'; declare module '*.svg'; declare module '*.wxml'; declare global { - const lockTimestamp: string; - const lockSession: string; const isAuth: boolean; const mapId: number; const userOptions: { zoom: string | number } | null; diff --git a/packages/webapp/src/app.tsx b/packages/webapp/src/app.tsx index f5b1ac02..2cc517fc 100644 --- a/packages/webapp/src/app.tsx +++ b/packages/webapp/src/app.tsx @@ -38,7 +38,7 @@ const queryClient = new QueryClient({ }); const App = (): ReactElement => { - const locale = AppI18n.getBrowserLocale(); + const locale = AppI18n.getDefaultLocale(); const EnhacedEditorPage = withSessionExpirationHandling(EditorPage); return locale.message ? ( @@ -81,7 +81,7 @@ const App = (): ReactElement => { component={withSessionExpirationHandling(MapsPage)} /> - + diff --git a/packages/webapp/src/classes/app-i18n/index.ts b/packages/webapp/src/classes/app-i18n/index.ts index e5af79f5..3019ea71 100644 --- a/packages/webapp/src/classes/app-i18n/index.ts +++ b/packages/webapp/src/classes/app-i18n/index.ts @@ -2,7 +2,9 @@ import { fetchAccount } from './../../redux/clientSlice'; import 'dayjs/locale/fr'; import 'dayjs/locale/en'; import 'dayjs/locale/es'; +import 'dayjs/locale/de'; import 'dayjs/locale/ru'; +import 'dayjs/locale/zh'; export class Locale { code: LocaleCode; @@ -17,15 +19,23 @@ export class Locale { } export default abstract class AppI18n { + private static LOCAL_STORAGE_KEY = 'user.locale'; + public static getUserLocale(): Locale { // @Todo Hack: Try page must not account info. Add this to avoid 403 errors. const isTryPage = window.location.href.endsWith('/try'); let result: Locale; if (!isTryPage) { const account = fetchAccount(); - result = account?.locale ? account.locale : this.getBrowserLocale(); + result = account?.locale ? account.locale : this.getDefaultLocale(); + + // If the local storage value is different, update ... + if (account?.locale && result.code !== localStorage.getItem(AppI18n.LOCAL_STORAGE_KEY)) { + localStorage.setItem(AppI18n.LOCAL_STORAGE_KEY, result.code); + } + } else { - result = this.getBrowserLocale(); + result = this.getDefaultLocale(); } return result; } @@ -45,6 +55,21 @@ export default abstract class AppI18n { return result; } + + public static getDefaultLocale(): Locale { + // Fetch local from local storage ... + let result: Locale; + const userLocaleCode: string = localStorage.getItem(AppI18n.LOCAL_STORAGE_KEY); + if (userLocaleCode) { + result = localeFromStr(userLocaleCode); + } + + // Ok, use browser default ... + if (!result) { + result = this.getBrowserLocale(); + } + return result; + } } export type LocaleCode = 'en' | 'es' | 'fr' | 'de' | 'ru' | 'zh'; @@ -55,7 +80,7 @@ export const Locales = { DE: new Locale('fr', 'Français', require('./../../compiled-lang/fr.json')), // eslint-disable-line FR: new Locale('de', 'Deutsch', require('./../../compiled-lang/de.json')), // eslint-disable-line RU: new Locale('ru', 'Pусский', require('./../../compiled-lang/ru.json')), // eslint-disable-line - ZH: new Locale('zh', '中文', require('./../../compiled-lang/zh.json')), // eslint-disable-line + ZH: new Locale('zh', '中文 (简体)', require('./../../compiled-lang/zh.json')), // eslint-disable-line }; diff --git a/packages/webapp/src/classes/client/rest-client/index.ts b/packages/webapp/src/classes/client/rest-client/index.ts index a0ace132..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); } @@ -618,17 +618,10 @@ export default class RestClient implements Client { let persistence: PersistenceManager; if (editorMode === 'edition-owner' || editorMode === 'edition-editor') { - - if (!global.lockSession) { - throw new Error(`Session could not be found: global.lockSession: '${global.lockSession}' - global.lockTimestamp: '${global.lockTimestamp}' - ${global.mindmapLocked} - ${global.mindmapLockedMsg}`) - } - persistence = new RESTPersistenceManager({ documentUrl: '/c/restful/maps/{id}/document', revertUrl: '/c/restful/maps/{id}/history/latest', lockUrl: '/c/restful/maps/{id}/lock', - timestamp: global.lockTimestamp, - session: global.lockSession, }); } else { persistence = new LocalStorageManager( diff --git a/packages/webapp/src/compiled-lang/de.json b/packages/webapp/src/compiled-lang/de.json index 8d7bd3be..61e3d268 100644 --- a/packages/webapp/src/compiled-lang/de.json +++ b/packages/webapp/src/compiled-lang/de.json @@ -311,6 +311,12 @@ "value": "Kontaktiere uns" } ], + "footer.donations": [ + { + "type": 0, + "value": "Spenden" + } + ], "footer.faq": [ { "type": 0, @@ -341,6 +347,18 @@ "value": "Andere" } ], + "footer.support": [ + { + "type": 0, + "value": "Unterstützt" + } + ], + "footer.team": [ + { + "type": 0, + "value": "Ausrüstung" + } + ], "footer.termsandconditions": [ { "type": 0, @@ -428,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 b473d642..9bd7fa1e 100644 --- a/packages/webapp/src/compiled-lang/en.json +++ b/packages/webapp/src/compiled-lang/en.json @@ -275,6 +275,12 @@ "value": "Image: Get a graphic representation of your map including all colors and shapes." } ], + "export.img-center": [ + { + "type": 0, + "value": "Center and zoom to fit" + } + ], "export.title": [ { "type": 0, @@ -299,6 +305,12 @@ "value": "Contact Us" } ], + "footer.donations": [ + { + "type": 0, + "value": "Donations" + } + ], "footer.faq": [ { "type": 0, @@ -329,6 +341,18 @@ "value": "Others" } ], + "footer.support": [ + { + "type": 0, + "value": "Support" + } + ], + "footer.team": [ + { + "type": 0, + "value": "Our Team" + } + ], "footer.termsandconditions": [ { "type": 0, @@ -416,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": [ @@ -512,7 +542,7 @@ "label.add-for": [ { "type": 0, - "value": "Editing labels for maps:" + "value": "Editing labels for" } ], "label.add-placeholder": [ @@ -545,6 +575,16 @@ "value": "Use labels to organize your maps." } ], + "label.maps-count": [ + { + "type": 1, + "value": "count" + }, + { + "type": 0, + "value": " maps" + } + ], "label.title": [ { "type": 0, @@ -887,6 +927,12 @@ "value": "Last Name" } ], + "registration.page-title": [ + { + "type": 0, + "value": "Registration | WiseMapping" + } + ], "registration.password": [ { "type": 0, @@ -914,7 +960,7 @@ "registration.title": [ { "type": 0, - "value": "Registration | WiseMapping" + "value": "Become a member" } ], "rename.description": [ diff --git a/packages/webapp/src/compiled-lang/es.json b/packages/webapp/src/compiled-lang/es.json index 5c33da5f..6db49829 100644 --- a/packages/webapp/src/compiled-lang/es.json +++ b/packages/webapp/src/compiled-lang/es.json @@ -296,7 +296,7 @@ "footer.aboutus": [ { "type": 0, - "value": "Sobre nosotros" + "value": "Sobre Nosotros" } ], "footer.contactus": [ @@ -305,6 +305,12 @@ "value": "Contáctenos" } ], + "footer.donations": [ + { + "type": 0, + "value": "Donaciones" + } + ], "footer.faq": [ { "type": 0, @@ -335,6 +341,18 @@ "value": "Otros" } ], + "footer.support": [ + { + "type": 0, + "value": "Soporte" + } + ], + "footer.team": [ + { + "type": 0, + "value": "Equipo" + } + ], "footer.termsandconditions": [ { "type": 0, @@ -422,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 ca5171f4..0fc32086 100644 --- a/packages/webapp/src/compiled-lang/fr.json +++ b/packages/webapp/src/compiled-lang/fr.json @@ -303,6 +303,12 @@ "value": "Nous contacter" } ], + "footer.donations": [ + { + "type": 0, + "value": "Des dons" + } + ], "footer.faq": [ { "type": 0, @@ -333,6 +339,18 @@ "value": "Autres" } ], + "footer.support": [ + { + "type": 0, + "value": "Service" + } + ], + "footer.team": [ + { + "type": 0, + "value": "Equipe" + } + ], "footer.termsandconditions": [ { "type": 0, @@ -420,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 b34910a2..9ff4ffcc 100644 --- a/packages/webapp/src/compiled-lang/ru.json +++ b/packages/webapp/src/compiled-lang/ru.json @@ -305,6 +305,12 @@ "value": "Контакты" } ], + "footer.donations": [ + { + "type": 0, + "value": "Пожертвования" + } + ], "footer.faq": [ { "type": 0, @@ -335,6 +341,18 @@ "value": "Прочее" } ], + "footer.support": [ + { + "type": 0, + "value": "Услуги" + } + ], + "footer.team": [ + { + "type": 0, + "value": "команда" + } + ], "footer.termsandconditions": [ { "type": 0, @@ -425,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 b249b5b4..74ce6b48 100644 --- a/packages/webapp/src/compiled-lang/zh.json +++ b/packages/webapp/src/compiled-lang/zh.json @@ -1,5 +1,5 @@ { - "account.delete-warning": [ + "account.delete-warning警告": [ { "type": 0, "value": "请记住,您将无法访问您添加的任何思维导图。您的所有信息都将被删除,并且无法恢复。" @@ -272,7 +272,7 @@ "export.image": [ { "type": 0, - "value": "Image: Get a graphic representation of your map including all colors and shapes.图像:以图片形式获取包含所有颜色和形状的脑图" + "value": "图像:以图片形式获取包含所有颜色和形状的脑图" } ], "export.img-center": [ @@ -305,6 +305,12 @@ "value": "联系我们" } ], + "footer.donations": [ + { + "type": 0, + "value": "捐款" + } + ], "footer.faq": [ { "type": 0, @@ -335,6 +341,18 @@ "value": "其它" } ], + "footer.support": [ + { + "type": 0, + "value": "支持" + } + ], + "footer.team": [ + { + "type": 0, + "value": "学期" + } + ], "footer.termsandconditions": [ { "type": 0, @@ -422,7 +440,13 @@ "import.description": [ { "type": 0, - "value": "您可以将WiseMapping脑图导入到您的脑图列表中。选择要导入的文件。" + "value": "您可以将脑图从 WiseMapping 和 Freemind 导入到您的脑图列表中。选择要导入的文件。" + } + ], + "import.error-file": [ + { + "type": 0, + "value": "文件扩展名无效" } ], "import.title": [ @@ -500,7 +524,7 @@ "info.starred": [ { "type": 0, - "value": "星标" + "value": "收藏" } ], "info.title": [ @@ -740,13 +764,13 @@ "maps.nav-onwned": [ { "type": 0, - "value": "拥有" + "value": "我的" } ], "maps.nav-public": [ { "type": 0, - "value": "公共" + "value": "公开" } ], "maps.nav-shared": [ @@ -758,7 +782,7 @@ "maps.nav-starred": [ { "type": 0, - "value": "星标" + "value": "收藏" } ], "maps.page-title": [ @@ -788,7 +812,7 @@ "maps.tooltip-starred": [ { "type": 0, - "value": "星标" + "value": "收藏" } ], "maps.view": [ @@ -872,7 +896,7 @@ "registration.desc": [ { "type": 0, - "value": "Signing up is free and just take a moment注册免费,分分钟就好" + "value": "注册免费,分分钟就好" } ], "registration.email": [ diff --git a/packages/webapp/src/components/editor-page/EditorOptionsBuilder.ts b/packages/webapp/src/components/editor-page/EditorOptionsBuilder.ts index cf6a2ff7..a348692f 100644 --- a/packages/webapp/src/components/editor-page/EditorOptionsBuilder.ts +++ b/packages/webapp/src/components/editor-page/EditorOptionsBuilder.ts @@ -2,7 +2,7 @@ import { EditorOptions } from '@wisemapping/editor'; import { EditorRenderMode } from '@wisemapping/mindplot'; import AppConfig from '../../classes/app-config'; -export default class EditorOptionsBuilder { +class EditorOptionsBuilder { static build(locale: string, mode: EditorRenderMode, hotkeys: boolean): EditorOptions { let options: EditorOptions = { @@ -35,6 +35,11 @@ export default class EditorOptionsBuilder { } static loadMapId(): number { - return !AppConfig.isDevelopEnv() ? global.mapId : 11; + const result = !AppConfig.isDevelopEnv() ? global.mapId : 11; + if (result === undefined) { + throw Error(`Could not resolve mapId. Map Id: global.mapId: ${result} , global.mapTitle: ${global.mapTitle}, global.lockSession: ${global.lockSession}`); + } + return result; } -} \ No newline at end of file +} +export default EditorOptionsBuilder; diff --git a/packages/webapp/src/components/editor-page/index.tsx b/packages/webapp/src/components/editor-page/index.tsx index 2651230f..ff561203 100644 --- a/packages/webapp/src/components/editor-page/index.tsx +++ b/packages/webapp/src/components/editor-page/index.tsx @@ -3,8 +3,8 @@ import ActionDispatcher from '../maps-page/action-dispatcher'; import { ActionType } from '../maps-page/action-chooser'; import Editor from '@wisemapping/editor'; import { EditorRenderMode, PersistenceManager } from '@wisemapping/mindplot'; - -import AppI18n from '../../classes/app-i18n'; +import { IntlProvider } from 'react-intl'; +import AppI18n, { Locales } from '../../classes/app-i18n'; import { useSelector } from 'react-redux'; import { hotkeysEnabled } from '../../redux/editorSlice'; import ReactGA from 'react-ga'; @@ -23,7 +23,6 @@ const EditorPage = ({ isTryMode }: EditorPropsType): React.ReactElement => { const client: Client = useSelector(activeInstance); useEffect(() => { - document.title = `${global.mapTitle ? global.mapTitle : 'unknown'} | WiseMapping `; ReactGA.pageview(window.location.pathname + window.location.search); }, []); @@ -37,9 +36,13 @@ const EditorPage = ({ isTryMode }: EditorPropsType): React.ReactElement => { const fetchResult = fetchMapById(mapId); if (!fetchResult.isLoading) { if (fetchResult.error) { - throw new Error(`Map information could not be loaded: ${JSON.stringify(fetchResult)}`); + throw new Error(`Map info could not be loaded: ${JSON.stringify(fetchResult.error)}`); } - result = `edition-${fetchResult?.map?.role}`; + + if (!fetchResult.map) { + throw new Error(`Map info could not be loaded. Info not present: ${JSON.stringify(fetchResult)}`); + } + result = `edition-${fetchResult.map.role}`; } } return result; @@ -61,7 +64,11 @@ const EditorPage = ({ isTryMode }: EditorPropsType): React.ReactElement => { } return loadCompleted ? ( - <> + } + > { fromEditor /> } - ) : <> + ) : <> } diff --git a/packages/webapp/src/components/layout/footer/index.tsx b/packages/webapp/src/components/layout/footer/index.tsx index 48536609..acdd6e6e 100644 --- a/packages/webapp/src/components/layout/footer/index.tsx +++ b/packages/webapp/src/components/layout/footer/index.tsx @@ -16,6 +16,11 @@ const Footer = (): React.ReactElement => {

+
+ + + +
+ +
+

+ +

+
+ + + +
+
+ + + +
@@ -40,13 +60,11 @@ const Footer = (): React.ReactElement => {
- - - -
-
diff --git a/packages/webapp/src/components/layout/footer/styled.ts b/packages/webapp/src/components/layout/footer/styled.ts index a6abdf7a..dc19e089 100644 --- a/packages/webapp/src/components/layout/footer/styled.ts +++ b/packages/webapp/src/components/layout/footer/styled.ts @@ -4,10 +4,10 @@ import styled from 'styled-components'; export const StyledFooter = styled.footer` height: 250px; margin-top: 80px; - padding: 60px 40px 10px 50px; + padding: 30px 40px 10px 50px; background-color: #f9a826; display: grid; - grid-template-columns: 200px 1fr 1fr 3fr; + grid-template-columns: 200px 1fr 1fr 1fr 3fr; & a { font-size: 14px; @@ -34,9 +34,12 @@ export const StyledFooter = styled.footer` & div:nth-child(3) { grid-column: 3; } - & div:nth-child(4) { grid-column: 4; + } + + & div:nth-child(5) { + grid-column: 5; text-align: right; display: inline-block; visibility: visible; 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 && + + + + } { {Locales.RU.label} + + {Locales.ZH.label} + + { } // Seach for object... map = data?.find((m) => m.id == id); - if (map === null && !errorMsg) { - errorMsg = { msg: `Map with id ${id} could not be found. Please, reflesh the page` } + if (!map && !errorMsg) { + errorMsg = { msg: `Map with id ${id} could not be found. Please, reflesh the page. Map: ${JSON.stringify(data)}` } } } return { isLoading: isLoading, error: errorMsg, map: map };