From 7e207a52854614fc340bf57f6db0427d907baa89 Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Sun, 13 Mar 2022 23:55:10 -0300 Subject: [PATCH 01/26] Remove shortcuts display from menu --- packages/editor/src/classes/menu/Menu.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/editor/src/classes/menu/Menu.ts b/packages/editor/src/classes/menu/Menu.ts index eb2a4a9b..816c02f2 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', () => { From ce5ec6d6719485520edbf76b81e842fea5cfb759 Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Sun, 13 Mar 2022 23:58:57 -0300 Subject: [PATCH 02/26] Add Chinese to lang toolbar --- .../webapp/src/components/maps-page/language-menu/index.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/webapp/src/components/maps-page/language-menu/index.tsx b/packages/webapp/src/components/maps-page/language-menu/index.tsx index befefe3d..02aa8957 100644 --- a/packages/webapp/src/components/maps-page/language-menu/index.tsx +++ b/packages/webapp/src/components/maps-page/language-menu/index.tsx @@ -106,6 +106,10 @@ const LanguageMenu = (): React.ReactElement => { {Locales.RU.label} + + {Locales.ZH.label} + + Date: Mon, 14 Mar 2022 00:02:15 -0300 Subject: [PATCH 03/26] Fix compilation --- packages/editor/src/classes/menu/Menu.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor/src/classes/menu/Menu.ts b/packages/editor/src/classes/menu/Menu.ts index 816c02f2..57b7a035 100644 --- a/packages/editor/src/classes/menu/Menu.ts +++ b/packages/editor/src/classes/menu/Menu.ts @@ -239,7 +239,7 @@ class Menu extends IMenu { this._addButton('addTopic', true, false, () => { designer.createSiblingForSelectedNode(); }); - Menu._registerTooltip('addTopic', $msg('ADD_TOPIC'); + Menu._registerTooltip('addTopic', $msg('ADD_TOPIC')); this._addButton('deleteTopic', true, true, () => { designer.deleteSelectedEntities(); From f2a98129f7f827a541eb7d872adb1a6f2fd43417 Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Mon, 14 Mar 2022 00:05:09 -0300 Subject: [PATCH 04/26] v5.0.9 --- packages/webapp/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webapp/package.json b/packages/webapp/package.json index cf5225aa..ef72bd5b 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 ", From 08242dcbadf7fd37507cbcc2c6898406424b6c7a Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Mon, 14 Mar 2022 00:17:41 -0300 Subject: [PATCH 05/26] Fix time display on de and zh --- packages/mindplot/package.json | 2 +- packages/webapp/src/classes/app-i18n/index.ts | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/mindplot/package.json b/packages/mindplot/package.json index e8833eaf..1eeb1747 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": { diff --git a/packages/webapp/src/classes/app-i18n/index.ts b/packages/webapp/src/classes/app-i18n/index.ts index e5af79f5..48cfa9a2 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; From 8e263e4047c041c84cf29e5f0e38a5e4311d18dd Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Mon, 14 Mar 2022 00:27:04 -0300 Subject: [PATCH 06/26] Change add note shorcut to avoid collision with chrome shortcuts --- packages/editor/src/classes/menu/KeyboardShortcutDialog.js | 4 ++-- packages/mindplot/src/components/DesignerKeyboard.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) 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/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(); From 7701d00159a71f23eaf3afb2be375b0020c8f779 Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Mon, 14 Mar 2022 00:37:42 -0300 Subject: [PATCH 07/26] Add type infomation to deserializer --- .../src/components/persistence/XMLSerializerTango.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/mindplot/src/components/persistence/XMLSerializerTango.ts b/packages/mindplot/src/components/persistence/XMLSerializerTango.ts index a0a47be0..cf074747 100644 --- a/packages/mindplot/src/components/persistence/XMLSerializerTango.ts +++ b/packages/mindplot/src/components/persistence/XMLSerializerTango.ts @@ -25,6 +25,7 @@ import NodeModel from '../model/NodeModel'; import RelationshipModel from '../model/RelationshipModel'; import XMLMindmapSerializer from './XMLMindmapSerializer'; import FeatureType from '../model/FeatureType'; +import Relationship from '../Relationship'; class XMLSerializerTango implements XMLMindmapSerializer { private static MAP_ROOT_NODE = 'map'; @@ -457,7 +458,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 +469,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 +483,9 @@ 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; } From fdfb67a5fefeaf56c0d30b48644ee26c2632d151 Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Mon, 14 Mar 2022 00:52:19 -0300 Subject: [PATCH 08/26] Update automation tests --- .../persistence/XMLSerializerTango.ts | 4 +-- .../test/unit/export/expected/bug2.md | 10 +++---- .../test/unit/export/expected/bug2.mm | 12 ++++----- .../test/unit/export/expected/bug2.txt | 26 +++++++++---------- .../test/unit/export/expected/bug2.wxml | 4 +-- .../test/unit/export/expected/bug3.mm | 4 +-- .../test/unit/export/expected/complex.wxml | 4 +-- .../mindplot/test/unit/export/expected/enc.md | 2 +- .../mindplot/test/unit/export/expected/enc.mm | 2 +- .../test/unit/export/expected/enc.txt | 6 ++--- .../test/unit/export/expected/enc.wxml | 6 ++--- .../test/unit/export/expected/process.mm | 4 +-- .../test/unit/export/expected/welcome.mm | 2 +- 13 files changed, 42 insertions(+), 44 deletions(-) diff --git a/packages/mindplot/src/components/persistence/XMLSerializerTango.ts b/packages/mindplot/src/components/persistence/XMLSerializerTango.ts index cf074747..e8e7b719 100644 --- a/packages/mindplot/src/components/persistence/XMLSerializerTango.ts +++ b/packages/mindplot/src/components/persistence/XMLSerializerTango.ts @@ -25,7 +25,6 @@ import NodeModel from '../model/NodeModel'; import RelationshipModel from '../model/RelationshipModel'; import XMLMindmapSerializer from './XMLMindmapSerializer'; import FeatureType from '../model/FeatureType'; -import Relationship from '../Relationship'; class XMLSerializerTango implements XMLMindmapSerializer { private static MAP_ROOT_NODE = 'map'; @@ -446,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++) { @@ -483,7 +482,6 @@ class XMLSerializerTango implements XMLMindmapSerializer { if ($defined(destCtrlPoint) && destCtrlPoint !== '') { model.setDestCtrlPoint(Point.fromString(destCtrlPoint)); } - model.setEndArrow(false); model.setStartArrow(true); return model; 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 @@ - + From fdbad76428bf5e8b7accb19fae03df2f9046e5bf Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Mon, 14 Mar 2022 14:37:45 -0300 Subject: [PATCH 09/26] Fix location resources. --- packages/editor/package.json | 4 +-- packages/webapp/lang/en.json | 5 +++- packages/webapp/lang/zh.json | 12 ++++----- packages/webapp/package.json | 4 +-- packages/webapp/src/classes/app-i18n/index.ts | 2 +- packages/webapp/src/compiled-lang/en.json | 26 +++++++++++++++++-- packages/webapp/src/compiled-lang/zh.json | 12 ++++----- 7 files changed, 45 insertions(+), 20 deletions(-) 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/webapp/lang/en.json b/packages/webapp/lang/en.json index c744821f..b6dc8426 100644 --- a/packages/webapp/lang/en.json +++ b/packages/webapp/lang/en.json @@ -258,7 +258,7 @@ "defaultMessage": "Add label" }, "label.add-for": { - "defaultMessage": "Editing labels for maps:" + "defaultMessage": "Editing labels for" }, "label.add-placeholder": { "defaultMessage": "Label title" @@ -275,6 +275,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/zh.json b/packages/webapp/lang/zh.json index 2629fedd..8fbeab6a 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": { @@ -249,7 +249,7 @@ "defaultMessage": "分享" }, "info.starred": { - "defaultMessage": "星标" + "defaultMessage": "收藏" }, "info.title": { "defaultMessage": "信息" @@ -364,16 +364,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 +388,7 @@ "defaultMessage": "打开编辑" }, "maps.tooltip-starred": { - "defaultMessage": "星标" + "defaultMessage": "收藏" }, "maps.view": { "defaultMessage": "查看" diff --git a/packages/webapp/package.json b/packages/webapp/package.json index ef72bd5b..050678a5 100644 --- a/packages/webapp/package.json +++ b/packages/webapp/package.json @@ -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/classes/app-i18n/index.ts b/packages/webapp/src/classes/app-i18n/index.ts index 48cfa9a2..9dbb79dc 100644 --- a/packages/webapp/src/classes/app-i18n/index.ts +++ b/packages/webapp/src/classes/app-i18n/index.ts @@ -57,7 +57,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/compiled-lang/en.json b/packages/webapp/src/compiled-lang/en.json index b473d642..048200d6 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, @@ -512,7 +518,7 @@ "label.add-for": [ { "type": 0, - "value": "Editing labels for maps:" + "value": "Editing labels for" } ], "label.add-placeholder": [ @@ -545,6 +551,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 +903,12 @@ "value": "Last Name" } ], + "registration.page-title": [ + { + "type": 0, + "value": "Registration | WiseMapping" + } + ], "registration.password": [ { "type": 0, @@ -914,7 +936,7 @@ "registration.title": [ { "type": 0, - "value": "Registration | WiseMapping" + "value": "Become a member" } ], "rename.description": [ diff --git a/packages/webapp/src/compiled-lang/zh.json b/packages/webapp/src/compiled-lang/zh.json index b249b5b4..6a386e91 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": "请记住,您将无法访问您添加的任何思维导图。您的所有信息都将被删除,并且无法恢复。" @@ -500,7 +500,7 @@ "info.starred": [ { "type": 0, - "value": "星标" + "value": "收藏" } ], "info.title": [ @@ -740,13 +740,13 @@ "maps.nav-onwned": [ { "type": 0, - "value": "拥有" + "value": "我的" } ], "maps.nav-public": [ { "type": 0, - "value": "公共" + "value": "公开" } ], "maps.nav-shared": [ @@ -758,7 +758,7 @@ "maps.nav-starred": [ { "type": 0, - "value": "星标" + "value": "收藏" } ], "maps.page-title": [ @@ -788,7 +788,7 @@ "maps.tooltip-starred": [ { "type": 0, - "value": "星标" + "value": "收藏" } ], "maps.view": [ From ce284a12024343d05aacb2024bef87b2b1c0b36b Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Mon, 14 Mar 2022 14:47:42 -0300 Subject: [PATCH 10/26] Fix i18n issue on editor dialog --- .../src/components/editor-page/index.tsx | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/packages/webapp/src/components/editor-page/index.tsx b/packages/webapp/src/components/editor-page/index.tsx index 2651230f..53f72be4 100644 --- a/packages/webapp/src/components/editor-page/index.tsx +++ b/packages/webapp/src/components/editor-page/index.tsx @@ -3,14 +3,15 @@ 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'; import Client from '../../classes/client'; import { activeInstance, fetchAccount, fetchMapById } from '../../redux/clientSlice'; -import EditorOptionsBuilder from './EditorOptionsBuilder'; +import EditorOptionsBulder from './EditorOptionsBuider'; + export type EditorPropsType = { isTryMode: boolean; @@ -23,7 +24,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,16 +37,16 @@ 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(`User coild not be loaded: ${JSON.stringify(fetchResult.error)}`); } - result = `edition-${fetchResult?.map?.role}`; + result = fetchResult.map.role === 'owner' ? 'edition-owner' : 'edition-editor'; } } return result; } // What is the role ? - const mapId = EditorOptionsBuilder.loadMapId(); + const mapId = EditorOptionsBulder.loadMapId(); const mode = findEditorMode(isTryMode, mapId); // Account settings can be null and editor cannot be initilized multiple times. This creates problems @@ -56,12 +56,16 @@ const EditorPage = ({ isTryMode }: EditorPropsType): React.ReactElement => { let options, persistence: PersistenceManager; if (loadCompleted) { - options = EditorOptionsBuilder.build(userLocale.code, mode, hotkey); + options = EditorOptionsBulder.build(userLocale.code, mode, hotkey); persistence = client.buildPersistenceManager(mode); } return loadCompleted ? ( - <> + } + > { fromEditor /> } - ) : <> + ) : <> } From 034d514cb58713669068df4e96170ba48eb71284 Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Mon, 14 Mar 2022 14:57:07 -0300 Subject: [PATCH 11/26] Fix compilation --- .../src/components/editor-page/EditorOptionsBuilder.ts | 5 +++-- packages/webapp/src/components/editor-page/index.tsx | 7 +++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/webapp/src/components/editor-page/EditorOptionsBuilder.ts b/packages/webapp/src/components/editor-page/EditorOptionsBuilder.ts index cf6a2ff7..2a00ab1e 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 = { @@ -37,4 +37,5 @@ export default class EditorOptionsBuilder { static loadMapId(): number { return !AppConfig.isDevelopEnv() ? global.mapId : 11; } -} \ 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 53f72be4..bef42b0b 100644 --- a/packages/webapp/src/components/editor-page/index.tsx +++ b/packages/webapp/src/components/editor-page/index.tsx @@ -10,8 +10,7 @@ import { hotkeysEnabled } from '../../redux/editorSlice'; import ReactGA from 'react-ga'; import Client from '../../classes/client'; import { activeInstance, fetchAccount, fetchMapById } from '../../redux/clientSlice'; -import EditorOptionsBulder from './EditorOptionsBuider'; - +import EditorOptionsBuilder from './EditorOptionsBuilder'; export type EditorPropsType = { isTryMode: boolean; @@ -46,7 +45,7 @@ const EditorPage = ({ isTryMode }: EditorPropsType): React.ReactElement => { } // What is the role ? - const mapId = EditorOptionsBulder.loadMapId(); + const mapId = EditorOptionsBuilder.loadMapId(); const mode = findEditorMode(isTryMode, mapId); // Account settings can be null and editor cannot be initilized multiple times. This creates problems @@ -56,7 +55,7 @@ const EditorPage = ({ isTryMode }: EditorPropsType): React.ReactElement => { let options, persistence: PersistenceManager; if (loadCompleted) { - options = EditorOptionsBulder.build(userLocale.code, mode, hotkey); + options = EditorOptionsBuilder.build(userLocale.code, mode, hotkey); persistence = client.buildPersistenceManager(mode); } From b84d7f333834d490e8d79a17f4100b5a35dc340e Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Mon, 14 Mar 2022 15:18:31 -0300 Subject: [PATCH 12/26] Fix hardcoded resources --- packages/mindplot/src/components/lang/de.js | 2 +- packages/mindplot/src/components/lang/en.js | 1 + packages/mindplot/src/components/lang/es.js | 1 + packages/mindplot/src/components/lang/fr.js | 1 + packages/mindplot/src/components/lang/ru.js | 1 + packages/mindplot/src/components/lang/zh.js | 2 ++ packages/mindplot/src/components/widget/LinkEditor.js | 2 +- packages/mindplot/src/components/widget/NoteEditor.js | 2 +- 8 files changed, 9 insertions(+), 3 deletions(-) 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/widget/LinkEditor.js b/packages/mindplot/src/components/widget/LinkEditor.js index cc83f2f8..681429c1 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); 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, From ee3b5e6ea4bfda6b580335ed9a3fbc53ab75f49c Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Mon, 14 Mar 2022 22:59:25 -0300 Subject: [PATCH 13/26] Fix resource in Chinese --- packages/webapp/lang/zh.json | 4 ++-- packages/webapp/src/compiled-lang/zh.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/webapp/lang/zh.json b/packages/webapp/lang/zh.json index 8fbeab6a..ab4be629 100644 --- a/packages/webapp/lang/zh.json +++ b/packages/webapp/lang/zh.json @@ -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": "居中并缩放合适大小" @@ -430,7 +430,7 @@ "defaultMessage": "注册成功|WiseMapping" }, "registration.desc": { - "defaultMessage": "Signing up is free and just take a moment注册免费,分分钟就好" + "defaultMessage": "注册免费,分分钟就好" }, "registration.email": { "defaultMessage": "电子邮件" diff --git a/packages/webapp/src/compiled-lang/zh.json b/packages/webapp/src/compiled-lang/zh.json index 6a386e91..f2bdbe7f 100644 --- a/packages/webapp/src/compiled-lang/zh.json +++ b/packages/webapp/src/compiled-lang/zh.json @@ -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": [ @@ -872,7 +872,7 @@ "registration.desc": [ { "type": 0, - "value": "Signing up is free and just take a moment注册免费,分分钟就好" + "value": "注册免费,分分钟就好" } ], "registration.email": [ From 75274e5cc84f0eda9d446a180754efb5568ba966 Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Mon, 14 Mar 2022 23:17:28 -0300 Subject: [PATCH 14/26] Add local storage of user settings locale. --- packages/webapp/src/classes/app-i18n/index.ts | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/packages/webapp/src/classes/app-i18n/index.ts b/packages/webapp/src/classes/app-i18n/index.ts index 9dbb79dc..e3354608 100644 --- a/packages/webapp/src/classes/app-i18n/index.ts +++ b/packages/webapp/src/classes/app-i18n/index.ts @@ -19,13 +19,21 @@ 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(); } @@ -47,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'; From 0f8d3a3c89dc51df85cca2f5b45890f70214bdcd Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Mon, 14 Mar 2022 23:19:03 -0300 Subject: [PATCH 15/26] Minor change. --- packages/webapp/src/app.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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)} /> - + From 152d7d9fad9ff8ac7803f2c915ed945362464ccc Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Mon, 14 Mar 2022 23:20:58 -0300 Subject: [PATCH 16/26] Change locale resolution --- packages/webapp/src/classes/app-i18n/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webapp/src/classes/app-i18n/index.ts b/packages/webapp/src/classes/app-i18n/index.ts index e3354608..3019ea71 100644 --- a/packages/webapp/src/classes/app-i18n/index.ts +++ b/packages/webapp/src/classes/app-i18n/index.ts @@ -35,7 +35,7 @@ export default abstract class AppI18n { } } else { - result = this.getBrowserLocale(); + result = this.getDefaultLocale(); } return result; } From 758b156db2bed3a2cece3879cfd8639437ea5551 Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Tue, 15 Mar 2022 16:23:41 -0300 Subject: [PATCH 17/26] Add debug info for map role loading --- packages/webapp/src/components/editor-page/index.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/webapp/src/components/editor-page/index.tsx b/packages/webapp/src/components/editor-page/index.tsx index bef42b0b..3ff8da81 100644 --- a/packages/webapp/src/components/editor-page/index.tsx +++ b/packages/webapp/src/components/editor-page/index.tsx @@ -36,7 +36,11 @@ const EditorPage = ({ isTryMode }: EditorPropsType): React.ReactElement => { const fetchResult = fetchMapById(mapId); if (!fetchResult.isLoading) { if (fetchResult.error) { - throw new Error(`User coild not be loaded: ${JSON.stringify(fetchResult.error)}`); + throw new Error(`Map info could not be loaded: ${JSON.stringify(fetchResult.error)}`); + } + + if (!fetchResult.map) { + throw new Error(`Map info could not be loaded. Info not present: ${JSON.stringify(fetchResult)}`); } result = fetchResult.map.role === 'owner' ? 'edition-owner' : 'edition-editor'; } From b3843e7f8834c4afe308112acfff0c03ad6b13c9 Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Tue, 15 Mar 2022 23:39:37 -0300 Subject: [PATCH 18/26] Add donations button --- packages/webapp/lang/de.json | 9 +++++ packages/webapp/lang/en.json | 9 +++++ packages/webapp/lang/es.json | 11 +++++- packages/webapp/lang/fr.json | 9 +++++ packages/webapp/lang/ru.json | 9 +++++ packages/webapp/lang/zh.json | 11 +++++- packages/webapp/src/compiled-lang/de.json | 18 ++++++++++ packages/webapp/src/compiled-lang/en.json | 18 ++++++++++ packages/webapp/src/compiled-lang/es.json | 20 ++++++++++- packages/webapp/src/compiled-lang/fr.json | 18 ++++++++++ packages/webapp/src/compiled-lang/ru.json | 18 ++++++++++ packages/webapp/src/compiled-lang/zh.json | 18 ++++++++++ .../src/components/layout/footer/index.tsx | 34 ++++++++++++++----- .../src/components/layout/footer/styled.ts | 9 +++-- 14 files changed, 197 insertions(+), 14 deletions(-) diff --git a/packages/webapp/lang/de.json b/packages/webapp/lang/de.json index 64d285a4..65cd0caa 100644 --- a/packages/webapp/lang/de.json +++ b/packages/webapp/lang/de.json @@ -500,5 +500,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 b6dc8426..4f5c3321 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" }, diff --git a/packages/webapp/lang/es.json b/packages/webapp/lang/es.json index a46899fe..6e17c441 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" diff --git a/packages/webapp/lang/fr.json b/packages/webapp/lang/fr.json index 95b36f63..a6017fba 100644 --- a/packages/webapp/lang/fr.json +++ b/packages/webapp/lang/fr.json @@ -500,5 +500,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..d4eaf445 100644 --- a/packages/webapp/lang/ru.json +++ b/packages/webapp/lang/ru.json @@ -473,5 +473,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 ab4be629..d62ad359 100644 --- a/packages/webapp/lang/zh.json +++ b/packages/webapp/lang/zh.json @@ -500,5 +500,14 @@ }, "share.message": { "defaultMessage": "消息" + }, + "footer.support": { + "defaultMessage": "支持" + }, + "footer.team": { + "defaultMessage": "学期" + }, + "footer.donations": { + "defaultMessage": "捐款" } -} +} \ No newline at end of file diff --git a/packages/webapp/src/compiled-lang/de.json b/packages/webapp/src/compiled-lang/de.json index 8d7bd3be..2c1995c7 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, diff --git a/packages/webapp/src/compiled-lang/en.json b/packages/webapp/src/compiled-lang/en.json index 048200d6..71d5c6d6 100644 --- a/packages/webapp/src/compiled-lang/en.json +++ b/packages/webapp/src/compiled-lang/en.json @@ -305,6 +305,12 @@ "value": "Contact Us" } ], + "footer.donations": [ + { + "type": 0, + "value": "Donations" + } + ], "footer.faq": [ { "type": 0, @@ -335,6 +341,18 @@ "value": "Others" } ], + "footer.support": [ + { + "type": 0, + "value": "Support" + } + ], + "footer.team": [ + { + "type": 0, + "value": "Our Team" + } + ], "footer.termsandconditions": [ { "type": 0, diff --git a/packages/webapp/src/compiled-lang/es.json b/packages/webapp/src/compiled-lang/es.json index 5c33da5f..17fbe91a 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, diff --git a/packages/webapp/src/compiled-lang/fr.json b/packages/webapp/src/compiled-lang/fr.json index ca5171f4..261da559 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, diff --git a/packages/webapp/src/compiled-lang/ru.json b/packages/webapp/src/compiled-lang/ru.json index b34910a2..d382a1bc 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, diff --git a/packages/webapp/src/compiled-lang/zh.json b/packages/webapp/src/compiled-lang/zh.json index f2bdbe7f..209598e4 100644 --- a/packages/webapp/src/compiled-lang/zh.json +++ b/packages/webapp/src/compiled-lang/zh.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, 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; From f5600cbe6e366fd48a1d4088b8c1591802423a1a Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Wed, 16 Mar 2022 22:01:37 -0300 Subject: [PATCH 19/26] Fix bug on errror resolution. --- packages/webapp/src/redux/clientSlice.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/webapp/src/redux/clientSlice.ts b/packages/webapp/src/redux/clientSlice.ts index b15a765b..0ea10a33 100644 --- a/packages/webapp/src/redux/clientSlice.ts +++ b/packages/webapp/src/redux/clientSlice.ts @@ -57,8 +57,8 @@ export const fetchMapById = (id: number): MapLoadResult => { } // 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 }; From 8907452bc50e9ca9a850dfcfc604ac378d23c939 Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Thu, 17 Mar 2022 15:41:32 -0300 Subject: [PATCH 20/26] Fix role resolution issue. --- packages/webapp/src/components/editor-page/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webapp/src/components/editor-page/index.tsx b/packages/webapp/src/components/editor-page/index.tsx index 3ff8da81..ff561203 100644 --- a/packages/webapp/src/components/editor-page/index.tsx +++ b/packages/webapp/src/components/editor-page/index.tsx @@ -42,7 +42,7 @@ const EditorPage = ({ isTryMode }: EditorPropsType): React.ReactElement => { if (!fetchResult.map) { throw new Error(`Map info could not be loaded. Info not present: ${JSON.stringify(fetchResult)}`); } - result = fetchResult.map.role === 'owner' ? 'edition-owner' : 'edition-editor'; + result = `edition-${fetchResult.map.role}`; } } return result; From de78c882ccfbe7675eee5eb8d778fc367c82b96c Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Tue, 22 Mar 2022 00:15:27 -0300 Subject: [PATCH 21/26] Add additional debug info. --- .../src/components/editor-page/EditorOptionsBuilder.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/webapp/src/components/editor-page/EditorOptionsBuilder.ts b/packages/webapp/src/components/editor-page/EditorOptionsBuilder.ts index 2a00ab1e..a348692f 100644 --- a/packages/webapp/src/components/editor-page/EditorOptionsBuilder.ts +++ b/packages/webapp/src/components/editor-page/EditorOptionsBuilder.ts @@ -35,7 +35,11 @@ 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; } } export default EditorOptionsBuilder; From 954b0cdbe21869e65c158cd3eae48ba768022f4e Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Tue, 22 Mar 2022 08:50:16 -0300 Subject: [PATCH 22/26] Remove overflow style --- packages/editor/src/global-styled.css | 12 ------------ 1 file changed, 12 deletions(-) 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; From 56906fd2fdabf4b8325c68d10ee610a995fdffd5 Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Tue, 22 Mar 2022 09:01:41 -0300 Subject: [PATCH 23/26] Improve log message. --- packages/mindplot/src/components/ImageIcon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mindplot/src/components/ImageIcon.js b/packages/mindplot/src/components/ImageIcon.js index d5880742..6f704c7d 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++) { From 602e58f58e432b462b5d1bae6cac5afe4aa3c909 Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Wed, 23 Mar 2022 23:33:44 -0300 Subject: [PATCH 24/26] Simplify map lock support. --- packages/editor/README.md | 1 - packages/mindplot/src/components/ImageIcon.js | 2 +- .../src/components/RestPersistenceManager.ts | 15 ++------------- packages/mindplot/src/indexLoader.ts | 11 +---------- packages/webapp/src/@types/index.d.ts | 2 -- .../src/classes/client/rest-client/index.ts | 7 ------- 6 files changed, 4 insertions(+), 34 deletions(-) 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/mindplot/src/components/ImageIcon.js b/packages/mindplot/src/components/ImageIcon.js index 6f704c7d..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: ${iconId}`); + $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/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/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/classes/client/rest-client/index.ts b/packages/webapp/src/classes/client/rest-client/index.ts index a0ace132..5aaeec0f 100644 --- a/packages/webapp/src/classes/client/rest-client/index.ts +++ b/packages/webapp/src/classes/client/rest-client/index.ts @@ -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( From ed8fe3a455d8a3a0919592de763473f3e568a4d2 Mon Sep 17 00:00:00 2001 From: Paulo Gustavo Veiga Date: Fri, 25 Mar 2022 16:50:25 -0300 Subject: [PATCH 25/26] Improve link url dialog --- .../src/components/widget/LinkEditor.js | 18 ++++++++++++++---- .../src/components/widget/LinkIconTooltip.js | 4 ++-- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/packages/mindplot/src/components/widget/LinkEditor.js b/packages/mindplot/src/components/widget/LinkEditor.js index 681429c1..f4dbcabc 100644 --- a/packages/mindplot/src/components/widget/LinkEditor.js +++ b/packages/mindplot/src/components/widget/LinkEditor.js @@ -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', From 1c84862f80d97a80c6c43804a5b349143996bc62 Mon Sep 17 00:00:00 2001 From: Ezequiel Vega Date: Sun, 27 Mar 2022 00:07:45 +0000 Subject: [PATCH 26/26] Add support for Freemind import. --- packages/mindplot/package.json | 2 +- .../src/components/export/freemind/Map.ts | 125 +- .../src/components/export/freemind/Node.ts | 40 + .../export/freemind/importer/VersionNumber.ts | 46 + .../import/FreemindIconConverter.ts | 10 + .../src/components/import/FreemindImporter.ts | 446 +++++++ .../src/components/import/Importer.ts | 3 + .../components/import/TextImporterFactory.ts | 19 + .../components/import/WisemappingImporter.ts | 29 + packages/mindplot/src/index.ts | 4 + packages/mindplot/test/unit/import/Helper.ts | 43 + .../unit/import/TextImporterTestSuite.test.ts | 27 + .../test/unit/import/expected/Cs2.wxml | 86 ++ .../test/unit/import/expected/SQLServer.wxml | 60 + .../expected/anonymity_on_the_edge.wxml | 140 +++ .../test/unit/import/expected/bug2.wxml | 44 + .../test/unit/import/expected/bug3.wxml | 514 ++++++++ .../unit/import/expected/cdata-support.wxml | 3 + .../import/expected/coderToDeveloper.wxml | 87 ++ .../test/unit/import/expected/complex.wxml | 26 + .../test/unit/import/expected/emptyNodes.wxml | 89 ++ .../test/unit/import/expected/enc.wxml | 117 ++ .../import/expected/freeMind_resources.wxml | 123 ++ .../test/unit/import/expected/i18n.wxml | 7 + .../test/unit/import/expected/i18n2.wxml | 11 + .../test/unit/import/expected/issue.wxml | 50 + .../test/unit/import/expected/npe.wxml | 3 + .../test/unit/import/expected/process.wxml | 100 ++ .../test/unit/import/expected/pub_sub.wxml | 415 +++++++ .../test/unit/import/expected/python.wxml | 284 +++++ .../test/unit/import/expected/sample3.wxml | 3 + .../test/unit/import/expected/sample4.wxml | 3 + .../test/unit/import/expected/welcome.wxml | 53 + .../expected/writing_an_essay_with.wxml | 251 ++++ .../mindplot/test/unit/import/input/Cs2.mm | 90 ++ .../test/unit/import/input/SQLServer.mm | 64 + .../import/input/anonymity_on_the_edge.mm | 112 ++ .../mindplot/test/unit/import/input/bug2.mm | 51 + .../mindplot/test/unit/import/input/bug3.mm | 1030 +++++++++++++++++ .../test/unit/import/input/cdata-support.mm | 12 + .../unit/import/input/coderToDeveloper.mm | 106 ++ .../test/unit/import/input/complex.mm | 51 + .../test/unit/import/input/emptyNodes.mm | 116 ++ .../mindplot/test/unit/import/input/enc.mm | 216 ++++ .../unit/import/input/freeMind_resources.mm | 134 +++ .../mindplot/test/unit/import/input/i18n.mm | 7 + .../mindplot/test/unit/import/input/i18n2.mm | 25 + .../mindplot/test/unit/import/input/issue.mm | 187 +++ .../mindplot/test/unit/import/input/npe.mm | 7 + .../test/unit/import/input/process.mm | 100 ++ .../test/unit/import/input/pub_sub.mm | 419 +++++++ .../mindplot/test/unit/import/input/python.mm | 316 +++++ .../test/unit/import/input/sample3.mm | 3 + .../test/unit/import/input/sample4.mm | 3 + .../test/unit/import/input/welcome.mm | 81 ++ .../import/input/writing_an_essay_with.mm | 543 +++++++++ packages/webapp/lang/de.json | 5 +- packages/webapp/lang/en.json | 5 +- packages/webapp/lang/es.json | 5 +- packages/webapp/lang/fr.json | 5 +- packages/webapp/lang/ru.json | 3 + packages/webapp/lang/zh.json | 5 +- .../src/classes/client/rest-client/index.ts | 2 +- packages/webapp/src/compiled-lang/de.json | 8 +- packages/webapp/src/compiled-lang/en.json | 8 +- packages/webapp/src/compiled-lang/es.json | 8 +- packages/webapp/src/compiled-lang/fr.json | 8 +- packages/webapp/src/compiled-lang/ru.json | 6 + packages/webapp/src/compiled-lang/zh.json | 8 +- .../action-dispatcher/import-dialog/index.tsx | 48 +- 70 files changed, 7034 insertions(+), 26 deletions(-) create mode 100644 packages/mindplot/src/components/import/FreemindIconConverter.ts create mode 100644 packages/mindplot/src/components/import/FreemindImporter.ts create mode 100644 packages/mindplot/src/components/import/Importer.ts create mode 100644 packages/mindplot/src/components/import/TextImporterFactory.ts create mode 100644 packages/mindplot/src/components/import/WisemappingImporter.ts create mode 100644 packages/mindplot/test/unit/import/Helper.ts create mode 100644 packages/mindplot/test/unit/import/TextImporterTestSuite.test.ts create mode 100644 packages/mindplot/test/unit/import/expected/Cs2.wxml create mode 100644 packages/mindplot/test/unit/import/expected/SQLServer.wxml create mode 100644 packages/mindplot/test/unit/import/expected/anonymity_on_the_edge.wxml create mode 100644 packages/mindplot/test/unit/import/expected/bug2.wxml create mode 100644 packages/mindplot/test/unit/import/expected/bug3.wxml create mode 100644 packages/mindplot/test/unit/import/expected/cdata-support.wxml create mode 100644 packages/mindplot/test/unit/import/expected/coderToDeveloper.wxml create mode 100644 packages/mindplot/test/unit/import/expected/complex.wxml create mode 100644 packages/mindplot/test/unit/import/expected/emptyNodes.wxml create mode 100644 packages/mindplot/test/unit/import/expected/enc.wxml create mode 100644 packages/mindplot/test/unit/import/expected/freeMind_resources.wxml create mode 100644 packages/mindplot/test/unit/import/expected/i18n.wxml create mode 100644 packages/mindplot/test/unit/import/expected/i18n2.wxml create mode 100644 packages/mindplot/test/unit/import/expected/issue.wxml create mode 100644 packages/mindplot/test/unit/import/expected/npe.wxml create mode 100644 packages/mindplot/test/unit/import/expected/process.wxml create mode 100644 packages/mindplot/test/unit/import/expected/pub_sub.wxml create mode 100644 packages/mindplot/test/unit/import/expected/python.wxml create mode 100644 packages/mindplot/test/unit/import/expected/sample3.wxml create mode 100644 packages/mindplot/test/unit/import/expected/sample4.wxml create mode 100644 packages/mindplot/test/unit/import/expected/welcome.wxml create mode 100644 packages/mindplot/test/unit/import/expected/writing_an_essay_with.wxml create mode 100644 packages/mindplot/test/unit/import/input/Cs2.mm create mode 100644 packages/mindplot/test/unit/import/input/SQLServer.mm create mode 100644 packages/mindplot/test/unit/import/input/anonymity_on_the_edge.mm create mode 100644 packages/mindplot/test/unit/import/input/bug2.mm create mode 100644 packages/mindplot/test/unit/import/input/bug3.mm create mode 100644 packages/mindplot/test/unit/import/input/cdata-support.mm create mode 100644 packages/mindplot/test/unit/import/input/coderToDeveloper.mm create mode 100644 packages/mindplot/test/unit/import/input/complex.mm create mode 100644 packages/mindplot/test/unit/import/input/emptyNodes.mm create mode 100644 packages/mindplot/test/unit/import/input/enc.mm create mode 100644 packages/mindplot/test/unit/import/input/freeMind_resources.mm create mode 100644 packages/mindplot/test/unit/import/input/i18n.mm create mode 100644 packages/mindplot/test/unit/import/input/i18n2.mm create mode 100644 packages/mindplot/test/unit/import/input/issue.mm create mode 100644 packages/mindplot/test/unit/import/input/npe.mm create mode 100644 packages/mindplot/test/unit/import/input/process.mm create mode 100644 packages/mindplot/test/unit/import/input/pub_sub.mm create mode 100644 packages/mindplot/test/unit/import/input/python.mm create mode 100644 packages/mindplot/test/unit/import/input/sample3.mm create mode 100644 packages/mindplot/test/unit/import/input/sample4.mm create mode 100644 packages/mindplot/test/unit/import/input/welcome.mm create mode 100644 packages/mindplot/test/unit/import/input/writing_an_essay_with.mm diff --git a/packages/mindplot/package.json b/packages/mindplot/package.json index 1eeb1747..5ff5fd8c 100644 --- a/packages/mindplot/package.json +++ b/packages/mindplot/package.json @@ -26,7 +26,7 @@ "lint": "eslint src --ext js,ts", "playground": "webpack serve --config webpack.playground.js", "cy:run": "cypress run", - "test:unit": "jest ./test/unit/export/*.ts ./test/unit/layout/*.js", + "test:unit": "jest ./test/unit/export/*.ts ./test/unit/import/*.ts ./test/unit/layout/*.js --verbose --silent --detectOpenHandles", "test:integration": "start-server-and-test playground http-get://localhost:8083 cy:run", "test": "yarn test:unit && yarn test:integration" }, diff --git a/packages/mindplot/src/components/export/freemind/Map.ts b/packages/mindplot/src/components/export/freemind/Map.ts index a12b74bd..f336212f 100644 --- a/packages/mindplot/src/components/export/freemind/Map.ts +++ b/packages/mindplot/src/components/export/freemind/Map.ts @@ -1,4 +1,4 @@ -import { createDocument } from '@wisemapping/core-js'; +import { createDocument, $assert } from '@wisemapping/core-js'; import Arrowlink from './Arrowlink'; import Cloud from './Cloud'; import Edge from './Edge'; @@ -7,7 +7,7 @@ import Icon from './Icon'; import Node, { Choise } from './Node'; import Richcontent from './Richcontent'; -export default class Map { +export default class Freemap { protected node: Node; protected version: string; @@ -52,6 +52,127 @@ export default class Map { return document; } + loadFromDom(dom: Document): Freemap { + $assert(dom, 'dom can not be null'); + + const rootElem = dom.documentElement; + + // Is a freemap? + $assert( + rootElem.tagName === 'map', + `This seem not to be a map document. Found tag: ${rootElem.tagName}`, + ); + + // Start the loading process... + const version = rootElem.getAttribute('version') || '1.0.1'; + const freemap: Freemap = new Freemap(); + freemap.setVesion(version); + + const mainTopicElement = rootElem.firstElementChild; + const mainTopic: Node = new Node().loadFromElement(mainTopicElement); + freemap.setNode(mainTopic); + + const childNodes = Array.from(mainTopicElement.childNodes); + const childsNodes = childNodes + .filter( + (child: ChildNode) => child.nodeType === 1 && (child as Element).tagName === 'node', + ) + .map((c) => c as Element); + + childsNodes.forEach((child: Element) => { + const node = this.domToNode(child); + mainTopic.setArrowlinkOrCloudOrEdge(node); + }); + + return freemap; + } + + private filterNodes(child: ChildNode): Element { + let element: Element; + if (child.nodeType === 1) { + if ( + (child as Element).tagName === 'node' + || (child as Element).tagName === 'richcontent' + || (child as Element).tagName === 'font' + || (child as Element).tagName === 'edge' + || (child as Element).tagName === 'arrowlink' + || (child as Element).tagName === 'clud' + || (child as Element).tagName === 'icon' + ) element = child as Element; + } + + return element; + } + + private domToNode(nodeElem: Element): Choise { + let node: Choise; + + if (nodeElem.tagName === 'node') { + node = new Node().loadFromElement(nodeElem); + + if (nodeElem.childNodes.length > 0) { + const childNodes = Array.from(nodeElem.childNodes); + const childsNodes = childNodes + .filter((child: ChildNode) => this.filterNodes(child)) + .map((c) => c as Element); + + childsNodes.forEach((child) => { + const childNode = this.domToNode(child); + if (node instanceof Node) node.setArrowlinkOrCloudOrEdge(childNode); + }); + } + } + + if (nodeElem.tagName === 'font') { + node = new Font(); + if (nodeElem.getAttribute('NAME')) node.setName(nodeElem.getAttribute('NAME')); + if (nodeElem.getAttribute('BOLD')) node.setBold(nodeElem.getAttribute('BOLD')); + if (nodeElem.getAttribute('ITALIC')) node.setItalic(nodeElem.getAttribute('ITALIC')); + if (nodeElem.getAttribute('SIZE')) node.setSize(nodeElem.getAttribute('SIZE')); + } + + if (nodeElem.tagName === 'edge') { + node = new Edge(); + if (nodeElem.getAttribute('COLOR')) node.setColor(nodeElem.getAttribute('COLOR')); + if (nodeElem.getAttribute('STYLE')) node.setStyle(nodeElem.getAttribute('STYLE')); + if (nodeElem.getAttribute('WIDTH')) node.setWidth(nodeElem.getAttribute('WIDTH')); + } + + if (nodeElem.tagName === 'arrowlink') { + node = new Arrowlink(); + if (nodeElem.getAttribute('COLOR')) node.setColor(nodeElem.getAttribute('COLOR')); + if (nodeElem.getAttribute('DESTINATION')) node.setDestination(nodeElem.getAttribute('DESTINATION')); + if (nodeElem.getAttribute('ENDARROW')) node.setEndarrow(nodeElem.getAttribute('ENDARROW')); + if (nodeElem.getAttribute('ENDINCLINATION')) node.setEndinclination(nodeElem.getAttribute('ENDINCLINATION')); + if (nodeElem.getAttribute('ID')) node.setId(nodeElem.getAttribute('ID')); + if (nodeElem.getAttribute('STARTARROW')) node.setStartarrow(nodeElem.getAttribute('STARTARROW')); + if (nodeElem.getAttribute('STARTINCLINATION')) node.setStartinclination(nodeElem.getAttribute('STARTINCLINATION')); + } + + if (nodeElem.tagName === 'cloud') { + node = new Cloud(); + if (nodeElem.getAttribute('COLOR')) node.setColor(nodeElem.getAttribute('COLOR')); + } + + if (nodeElem.tagName === 'icon') { + node = new Icon(); + if (nodeElem.getAttribute('BUILTIN')) node.setBuiltin(nodeElem.getAttribute('BUILTIN')); + } + + if (nodeElem.tagName === 'richcontent') { + node = new Richcontent(); + + if (nodeElem.getAttribute('TYPE')) node.setType(nodeElem.getAttribute('TYPE')); + if (nodeElem.firstChild && nodeElem.getElementsByTagName('html')) { + const content = nodeElem.getElementsByTagName('html'); + const html = content[0] ? content[0].outerHTML : ''; + node.setHtml(html); + } + } + + return node; + } + private nodeToXml(childNode: Choise, parentNode: HTMLElement, document: Document): HTMLElement { if (childNode instanceof Node) { childNode.setCentralTopic(false); diff --git a/packages/mindplot/src/components/export/freemind/Node.ts b/packages/mindplot/src/components/export/freemind/Node.ts index 3402e431..68e7e295 100644 --- a/packages/mindplot/src/components/export/freemind/Node.ts +++ b/packages/mindplot/src/components/export/freemind/Node.ts @@ -226,6 +226,46 @@ class Node { return nodeElem; } + + loadFromElement(element: Element): Node { + const node = new Node(); + + const nodeId = element.getAttribute('ID'); + const nodePosition = element.getAttribute('POSITION'); + const nodeStyle = element.getAttribute('STYLE'); + const nodeBGColor = element.getAttribute('BACKGROUND_COLOR'); + const nodeColor = element.getAttribute('COLOR'); + const nodeText = element.getAttribute('TEXT'); + const nodeLink = element.getAttribute('LINK'); + const nodeFolded = element.getAttribute('FOLDED'); + const nodeCreated = element.getAttribute('CREATED'); + const nodeModified = element.getAttribute('MODIFIED'); + const nodeHgap = element.getAttribute('HGAP'); + const nodeVgap = element.getAttribute('VGAP'); + const nodeWcoords = element.getAttribute('WCOORDS'); + const nodeWorder = element.getAttribute('WORDER'); + const nodeVshift = element.getAttribute('VSHIFT'); + const nodeEncryptedContent = element.getAttribute('ENCRYPTED_CONTENT'); + + if (nodeId) node.setId(nodeId); + if (nodePosition) node.setPosition(nodePosition); + if (nodeStyle) node.setStyle(nodeStyle); + if (nodeBGColor) node.setBackgorundColor(nodeBGColor); + if (nodeColor) node.setColor(nodeColor); + if (nodeText) node.setText(nodeText); + if (nodeLink) node.setLink(nodeLink); + if (nodeFolded) node.setFolded(nodeFolded); + if (nodeCreated) node.setCreated(nodeCreated); + if (nodeModified) node.setModified(nodeModified); + if (nodeHgap) node.setHgap(nodeHgap); + if (nodeVgap) node.setVgap(nodeVgap); + if (nodeWcoords) node.setWcoords(nodeWcoords); + if (nodeWorder) node.setWorder(nodeWorder); + if (nodeVshift) node.setVshift(nodeVshift); + if (nodeEncryptedContent) node.setEncryptedContent(nodeEncryptedContent); + + return node; + } } export type Choise = Arrowlink | Cloud | Edge | Font | Hook | Icon | Richcontent | Node diff --git a/packages/mindplot/src/components/export/freemind/importer/VersionNumber.ts b/packages/mindplot/src/components/export/freemind/importer/VersionNumber.ts index 0761213a..5f78c362 100644 --- a/packages/mindplot/src/components/export/freemind/importer/VersionNumber.ts +++ b/packages/mindplot/src/components/export/freemind/importer/VersionNumber.ts @@ -8,4 +8,50 @@ export default class VersionNumber { public getVersion(): string { return this.version; } + + public isGreaterThan(versionNumber: VersionNumber): boolean { + return this.compareTo(versionNumber) < 0; + } + + public compareTo(otherObject: VersionNumber): number { + if (this.equals(otherObject)) { + return 0; + } + + const ownTokinizer = this.getTokinizer(); + const otherTokinizer = otherObject.getTokinizer(); + + for (let i = 0; i < ownTokinizer.length; i++) { + let ownNumber: number; + let ohterNumber: number; + + try { + ownNumber = parseInt(ownTokinizer[i], 10); + ohterNumber = parseInt(otherTokinizer[i], 10); + } catch (e) { + return 1; + } + + if (ownNumber > ohterNumber) { + return 1; + } + if (ownNumber < ohterNumber) { + return -1; + } + } + + return -1; + } + + public equals(o: T): boolean { + if (!(o instanceof VersionNumber)) { + return false; + } + const versionNumber: VersionNumber = o as VersionNumber; + return this.version === versionNumber.version; + } + + private getTokinizer(): Array { + return this.getVersion().split('.'); + } } diff --git a/packages/mindplot/src/components/import/FreemindIconConverter.ts b/packages/mindplot/src/components/import/FreemindIconConverter.ts new file mode 100644 index 00000000..4ffc154c --- /dev/null +++ b/packages/mindplot/src/components/import/FreemindIconConverter.ts @@ -0,0 +1,10 @@ +import IconModel from '../model/IconModel'; + +export default class FreemindIconConverter { + private static freeIdToIcon: Map = new Map(); + + public static toWiseId(iconId: string): number | null { + const result: IconModel = this.freeIdToIcon.get(iconId); + return result ? result.getId() : null; + } +} diff --git a/packages/mindplot/src/components/import/FreemindImporter.ts b/packages/mindplot/src/components/import/FreemindImporter.ts new file mode 100644 index 00000000..64cbf660 --- /dev/null +++ b/packages/mindplot/src/components/import/FreemindImporter.ts @@ -0,0 +1,446 @@ +import xmlFormatter from 'xml-formatter'; +import Importer from './Importer'; +import Mindmap from '../model/Mindmap'; +import RelationshipModel from '../model/RelationshipModel'; +import NodeModel from '../model/NodeModel'; +import { TopicShape } from '../model/INodeModel'; +import FreemindConstant from '../export/freemind/FreemindConstant'; +import FreemindMap from '../export/freemind/Map'; +import FreemindNode, { Choise } from '../export/freemind/Node'; +import FreemindFont from '../export/freemind/Font'; +import FreemindEdge from '../export/freemind/Edge'; +import FreemindIcon from '../export/freemind/Icon'; +import FreemindHook from '../export/freemind/Hook'; +import FreemindRichcontent from '../export/freemind/Richcontent'; +import FreemindArrowLink from '../export/freemind/Arrowlink'; +import VersionNumber from '../export/freemind/importer/VersionNumber'; +import FreemindIconConverter from './FreemindIconConverter'; +import NoteModel from '../model/NoteModel'; +import FeatureModelFactory from '../model/FeatureModelFactory'; +import FeatureModel from '../model/FeatureModel'; +import XMLSerializerFactory from '../persistence/XMLSerializerFactory'; + +export default class FreemindImporter extends Importer { + private mindmap: Mindmap; + + private freemindInput: string; + + private freemindMap: FreemindMap; + + private nodesmap: Map; + + private relationship: Array; + + private idDefault = 0; + + constructor(map: string) { + super(); + this.freemindInput = map; + } + + import(nameMap: string, description: string): Promise { + this.mindmap = new Mindmap(nameMap); + this.nodesmap = new Map(); + this.relationship = new Array(); + + const parser = new DOMParser(); + const freemindDoc = parser.parseFromString(this.freemindInput, 'application/xml'); + this.freemindMap = new FreemindMap().loadFromDom(freemindDoc); + + const version: string = this.freemindMap.getVersion(); + + if (!version || version.startsWith('freeplane')) { + throw new Error('You seems to be be trying to import a Freeplane map. FreePlane is not supported format.'); + } else { + const mapVersion: VersionNumber = new VersionNumber(version); + if (mapVersion.isGreaterThan(FreemindConstant.SUPPORTED_FREEMIND_VERSION)) { + throw new Error(`FreeMind version ${mapVersion.getVersion()} is not supported.`); + } + } + + const freeNode: FreemindNode = this.freemindMap.getNode(); + this.mindmap.setVersion(FreemindConstant.CODE_VERSION); + + const wiseTopicId = this.getIdNode(this.freemindMap.getNode()); + const wiseTopic = this.mindmap.createNode('CentralTopic'); + wiseTopic.setPosition(0, 0); + wiseTopic.setId(wiseTopicId); + + this.convertNodeProperties(freeNode, wiseTopic, true); + + this.nodesmap.set(freeNode.getId(), wiseTopic); + + this.convertChildNodes(freeNode, wiseTopic, this.mindmap, 1); + this.addRelationship(this.mindmap); + + this.mindmap.setDescription(description); + this.mindmap.addBranch(wiseTopic); + + const serialize = XMLSerializerFactory.createInstanceFromMindmap(this.mindmap); + const domMindmap = serialize.toXML(this.mindmap); + const xmlToString = new XMLSerializer().serializeToString(domMindmap); + const formatXml = xmlFormatter(xmlToString, { + indentation: ' ', + collapseContent: true, + lineSeparator: '\n', + }); + + return Promise.resolve(formatXml); + } + + private addRelationship(mindmap: Mindmap): void { + const mapRelaitonship: Array = mindmap.getRelationships(); + + mapRelaitonship.forEach((relationship: RelationshipModel) => { + this.fixRelationshipControlPoints(relationship); + + // Fix dest ID + const destId: string = relationship.getDestCtrlPoint(); + const destTopic: NodeModel = this.nodesmap.get(destId); + relationship.setDestCtrlPoint(destTopic.getId()); + + // Fix src ID + const srcId: string = relationship.getSrcCtrlPoint(); + const srcTopic: NodeModel = this.nodesmap.get(srcId); + relationship.setSrcCtrlPoint(srcTopic.getId()); + + mapRelaitonship.push(relationship); + }); + } + + private fixRelationshipControlPoints(relationship: RelationshipModel): void { + const srcTopic: NodeModel = this.nodesmap.get(relationship.getToNode().toString()); + const destNode: NodeModel = this.nodesmap.get(relationship.getFromNode().toString()); + + // Fix x coord + const srcCtrlPoint: string = relationship.getSrcCtrlPoint(); + if (srcCtrlPoint) { + const coords = srcTopic.getPosition(); + if (coords.x < 0) { + const x = coords.x * -1; + relationship.setSrcCtrlPoint(`${x},${coords.y}`); + + // Fix coord + if (srcTopic.getOrder() && srcTopic.getOrder() % 2 !== 0) { + const y = coords.y * -1; + relationship.setSrcCtrlPoint(`${coords.x},${y}`); + } + } + } + + const destCtrlPoint: string = relationship.getDestCtrlPoint(); + if (destCtrlPoint) { + const coords = destNode.getPosition(); + + if (coords.x < 0) { + const x = coords.x * -1; + relationship.setDestCtrlPoint(`${x},${coords.y}`); + } + + if (destNode.getOrder() && destNode.getOrder() % 2 !== 0) { + const y = coords.y * -1; + relationship.setDestCtrlPoint(`${coords.x},${y}`); + } + } + } + + private convertNodeProperties(freeNode: FreemindNode, wiseTopic: NodeModel, centralTopic: boolean): void { + const text: string = freeNode.getText(); + if (text) wiseTopic.setText(text); + + const bgColor: string = freeNode.getBackgorundColor(); + if (bgColor) wiseTopic.setBackgroundColor(bgColor); + + if (centralTopic === false) { + const shape = this.getShapeFromFreeNode(freeNode); + if (shape && shape !== 'fork') wiseTopic.setShapeType(shape); + } + + // Check for style... + const fontStyle = this.generateFontStyle(freeNode, null); + if (fontStyle && fontStyle !== ';;;;') wiseTopic.setFontStyle(fontStyle); + + // Is there any link... + const url: string = freeNode.getLink(); + if (url) { + const link: FeatureModel = FeatureModelFactory.createModel('link', { url }); + wiseTopic.addFeature(link); + } + + const folded = Boolean(freeNode.getFolded()); + if (folded) wiseTopic.setChildrenShrunken(folded); + } + + private convertChildNodes(freeParent: FreemindNode, wiseParent: NodeModel, mindmap: Mindmap, depth: number): void { + const freeChilden = freeParent.getArrowlinkOrCloudOrEdge(); + let currentWiseTopic: NodeModel = wiseParent; + let order = 0; + let firstLevelRightOrder = 0; + let firstLevelLeftOrder = 1; + + freeChilden.forEach((child) => { + if (child instanceof FreemindNode) { + const wiseId = this.getIdNode(child); + const wiseChild = mindmap.createNode('MainTopic', wiseId); + + this.nodesmap.set(child.getId(), wiseChild); + + let norder: number; + if (depth !== 1) { + norder = order++; + } else if (child.getPosition() && child.getPosition() === FreemindConstant.POSITION_LEFT) { + norder = firstLevelLeftOrder; + firstLevelLeftOrder += 2; + } else { + norder = firstLevelRightOrder; + firstLevelRightOrder += 2; + } + + wiseChild.setOrder(norder); + + // Convert node position... + const childrenCountSameSide = this.getChildrenCountSameSide(freeChilden, child); + const position: {x: number, y: number} = this.convertPosition(wiseParent, child, depth, norder, childrenCountSameSide); + wiseChild.setPosition(position.x, position.y); + + // Convert the rest of the node properties... + this.convertNodeProperties(child, wiseChild, false); + + this.convertChildNodes(child, wiseChild, mindmap, depth++); + + if (wiseChild !== wiseParent) { + wiseParent.append(wiseChild); + } + + currentWiseTopic = wiseChild; + } + + if (child instanceof FreemindFont) { + const font: FreemindFont = child as FreemindFont; + const fontStyle: string = this.generateFontStyle(freeParent, font); + if (fontStyle) { + currentWiseTopic.setFontStyle(fontStyle); + } + } + + if (child instanceof FreemindEdge) { + const edge: FreemindEdge = child as FreemindEdge; + currentWiseTopic.setBackgroundColor(edge.getColor()); + } + + if (child instanceof FreemindIcon) { + const freeIcon: FreemindIcon = child as FreemindIcon; + const iconId: string = freeIcon.getBuiltin(); + const wiseIconId = FreemindIconConverter.toWiseId(iconId); + if (wiseIconId) { + const mindmapIcon: FeatureModel = FeatureModelFactory.createModel('icon', { id: wiseIconId }); + currentWiseTopic.addFeature(mindmapIcon); + } + } + + if (child instanceof FreemindHook) { + const hook: FreemindHook = child as FreemindHook; + const mindmapNote: NoteModel = new NoteModel({ text: '' }); + + let textNote: string = hook.getText(); + if (!textNote) { + textNote = FreemindConstant.EMPTY_NOTE; + mindmapNote.setText(textNote); + currentWiseTopic.addFeature(mindmapNote); + } + } + + if (child instanceof FreemindRichcontent) { + const type = child.getType(); + const html = child.getHtml(); + const text = this.html2Text(html); + + switch (type) { + case 'NOTE': { + const noteModel: FeatureModel = FeatureModelFactory.createModel('note', { text: text || FreemindConstant.EMPTY_NOTE }); + currentWiseTopic.addFeature(noteModel); + break; + } + + case 'NODE': { + currentWiseTopic.setText(text); + break; + } + + default: { + const noteModel: FeatureModel = FeatureModelFactory.createModel('note', { text: text || FreemindConstant.EMPTY_NOTE }); + currentWiseTopic.addFeature(noteModel); + } + } + } + + if (child instanceof FreemindArrowLink) { + const arrow: FreemindArrowLink = child as FreemindArrowLink; + const relationship: RelationshipModel = new RelationshipModel(0, 0); + const destId: string = arrow.getDestination(); + + relationship.setSrcCtrlPoint(destId); + relationship.setDestCtrlPoint(freeParent.getId()); + const endinclination: string = arrow.getEndInclination(); + if (endinclination) { + const inclination: Array = endinclination.split(';'); + relationship.setDestCtrlPoint(`${inclination[0]},${inclination[1]}`); + } + + const startinclination: string = arrow.getStartinclination(); + if (startinclination) { + const inclination: Array = startinclination.split(';'); + relationship.setSrcCtrlPoint(`${inclination[0]},${inclination[1]}`); + } + + const endarrow: string = arrow.getEndarrow(); + if (endarrow) { + relationship.setEndArrow(endarrow.toLowerCase() !== 'none'); + } + + const startarrow: string = arrow.getStartarrow(); + if (startarrow) { + relationship.setStartArrow(startarrow.toLowerCase() !== 'none'); + } + + relationship.setLineType(3); + this.relationship.push(relationship); + } + }); + } + + private getIdNode(node: FreemindNode): number { + const id = node.getId(); + let idFreeToIdWise: number; + + if (id) { + if (id === '_') { + this.idDefault++; + idFreeToIdWise = this.idDefault; + } else { + idFreeToIdWise = parseInt(id.split('_').pop(), 10); + } + } else { + this.idDefault++; + idFreeToIdWise = this.idDefault; + } + + return idFreeToIdWise; + } + + private getChildrenCountSameSide(freeChilden: Array, freeChild: FreemindNode): number { + let result = 0; + let childSide: string = freeChild.getPosition(); + + if (!childSide) { + childSide = FreemindConstant.POSITION_RIGHT; + } + + freeChilden.forEach((child) => { + if (child instanceof FreemindNode) { + let side = child.getPosition(); + if (!side) { + side = FreemindConstant.POSITION_RIGHT; + } + if (childSide === side) { + result++; + } + } + }); + + return result; + } + + private getShapeFromFreeNode(node: FreemindNode): string { + let result: string = node.getStyle(); + + if (result === 'bubble') { + result = TopicShape.ROUNDED_RECT; + } else if (node.getBackgorundColor()) { + result = TopicShape.RECTANGLE; + } else { + result = TopicShape.LINE; + } + return result; + } + + private generateFontStyle(node: FreemindNode, font: FreemindFont | undefined): string { + const fontStyle: Array = []; + + // Font family + if (font) { + fontStyle.push(font.getName()); + } + fontStyle.push(';'); + + // Font Size + if (font) { + const fontSize: number = ((!font.getSize() || parseInt(font.getSize(), 10) < 8) ? FreemindConstant.FONT_SIZE_NORMAL : parseInt(font.getSize(), 10)); + let wiseFontSize: number = FreemindConstant.FONT_SIZE_SMALL; + if (fontSize >= 24) { + wiseFontSize = FreemindConstant.FONT_SIZE_HUGE; + } + if (fontSize >= 16) { + wiseFontSize = FreemindConstant.FONT_SIZE_LARGE; + } + if (fontSize >= 8) { + wiseFontSize = FreemindConstant.FONT_SIZE_NORMAL; + } + fontStyle.push(wiseFontSize.toString()); + } + fontStyle.push(';'); + + // Font Color + const color: string = node.getColor(); + if (color && color !== '') { + fontStyle.push(color); + } + fontStyle.push(';'); + + // Font Italic + if (font) { + const hasItalic = Boolean(font.getItalic()); + fontStyle.push(hasItalic ? FreemindConstant.ITALIC : ''); + } + fontStyle.push(';'); + + const result: string = fontStyle.join(''); + return result; + } + + private convertPosition(wiseParent: NodeModel, freeChild: FreemindNode, depth: number, order: number, childrenCount: number): {x: number, y: number} { + let x: number = FreemindConstant.CENTRAL_TO_TOPIC_DISTANCE + ((depth - 1) * FreemindConstant.TOPIC_TO_TOPIC_DISTANCE); + if (depth === 1) { + const side: string = freeChild.getPosition(); + x *= (side && FreemindConstant.POSITION_LEFT === side ? -1 : 1); + } else { + const position = wiseParent.getPosition(); + x *= position.x < 0 ? 1 : -1; + } + + let y: number; + if (depth === 1) { + if (order % 2 === 0) { + const multiplier = ((order + 1) - childrenCount) * 2; + y = multiplier * FreemindConstant.ROOT_LEVEL_TOPIC_HEIGHT; + } else { + const multiplier = (order - childrenCount) * 2; + y = multiplier * FreemindConstant.ROOT_LEVEL_TOPIC_HEIGHT; + } + } else { + const position = wiseParent.getPosition(); + y = Math.round(position.y - ((childrenCount / 2) * FreemindConstant.SECOND_LEVEL_TOPIC_HEIGHT - (order * FreemindConstant.SECOND_LEVEL_TOPIC_HEIGHT))); + } + + return { + x, + y, + }; + } + + private html2Text(content: string): string { + const temporalDivElement = document.createElement('div'); + temporalDivElement.innerHTML = content; + return temporalDivElement.textContent.trim() || temporalDivElement.innerText.trim() || ''; + } +} diff --git a/packages/mindplot/src/components/import/Importer.ts b/packages/mindplot/src/components/import/Importer.ts new file mode 100644 index 00000000..249a0a7a --- /dev/null +++ b/packages/mindplot/src/components/import/Importer.ts @@ -0,0 +1,3 @@ +export default abstract class Importer { + abstract import(nameMap: string, description: string): Promise; +} diff --git a/packages/mindplot/src/components/import/TextImporterFactory.ts b/packages/mindplot/src/components/import/TextImporterFactory.ts new file mode 100644 index 00000000..9797dd67 --- /dev/null +++ b/packages/mindplot/src/components/import/TextImporterFactory.ts @@ -0,0 +1,19 @@ +import WisemappingImporter from './WisemappingImporter'; +import FreemindImporter from './FreemindImporter'; +import Importer from './Importer'; + +export default class TextImporterFactory { + static create(type: string, map: string): Importer { + let result: Importer; + switch (type) { + case 'wxml': + result = new WisemappingImporter(map); + return result; + case 'mm': + result = new FreemindImporter(map); + return result; + default: + throw new Error(`Unsupported type ${type}`); + } + } +} diff --git a/packages/mindplot/src/components/import/WisemappingImporter.ts b/packages/mindplot/src/components/import/WisemappingImporter.ts new file mode 100644 index 00000000..31a58a37 --- /dev/null +++ b/packages/mindplot/src/components/import/WisemappingImporter.ts @@ -0,0 +1,29 @@ +import Mindmap from '../model/Mindmap'; +import XMLSerializerFactory from '../persistence/XMLSerializerFactory'; +import Importer from './Importer'; + +export default class WisemappingImporter extends Importer { + private wisemappingInput: string; + + private mindmap: Mindmap; + + constructor(map: string) { + super(); + this.wisemappingInput = map; + } + + import(nameMap: string, description: string): Promise { + const parser = new DOMParser(); + const wiseDoc = parser.parseFromString(this.wisemappingInput, 'application/xml'); + + const serialize = XMLSerializerFactory.createInstanceFromDocument(wiseDoc); + this.mindmap = serialize.loadFromDom(wiseDoc, nameMap); + + this.mindmap.setDescription(description); + + const mindmapToXml = serialize.toXML(this.mindmap); + + const xmlStr = new XMLSerializer().serializeToString(mindmapToXml); + return Promise.resolve(xmlStr); + } +} diff --git a/packages/mindplot/src/index.ts b/packages/mindplot/src/index.ts index 82cb67b0..8cd70ae2 100644 --- a/packages/mindplot/src/index.ts +++ b/packages/mindplot/src/index.ts @@ -26,7 +26,9 @@ import MockPersistenceManager from './components/MockPersistenceManager'; import DesignerOptionsBuilder from './components/DesignerOptionsBuilder'; import ImageExporterFactory from './components/export/ImageExporterFactory'; import TextExporterFactory from './components/export/TextExporterFactory'; +import TextImporterFactory from './components/import/TextImporterFactory'; import Exporter from './components/export/Exporter'; +import Importer from './components/import/Importer'; import DesignerKeyboard from './components/DesignerKeyboard'; import EditorRenderMode from './components/EditorRenderMode'; import ImageIcon from './components/ImageIcon'; @@ -61,7 +63,9 @@ export { EditorRenderMode, TextExporterFactory, ImageExporterFactory, + TextImporterFactory, Exporter, + Importer, ImageIcon, $notify, $msg, diff --git a/packages/mindplot/test/unit/import/Helper.ts b/packages/mindplot/test/unit/import/Helper.ts new file mode 100644 index 00000000..60366a5a --- /dev/null +++ b/packages/mindplot/test/unit/import/Helper.ts @@ -0,0 +1,43 @@ +/* eslint-disable import/no-extraneous-dependencies */ +/* eslint-disable import/prefer-default-export */ +import fs from 'fs'; +import path from 'path'; +import { expect } from '@jest/globals'; +import { diff } from 'jest-diff'; +import Importer from '../../../src/components/import/Importer'; + +const saveOutputRecord = false; + +export const parseXMLString = (xmlStr: string, mimeType: DOMParserSupportedType) => { + const parser = new DOMParser(); + const xmlDoc = parser.parseFromString(xmlStr, mimeType); + + return xmlDoc; +}; + +export const parseXMLFile = (filePath: fs.PathOrFileDescriptor, mimeType: DOMParserSupportedType) => { + const stream = fs.readFileSync(filePath, { encoding: 'utf-8' }); + + const content = stream.toString(); + + return parseXMLString(content, mimeType); +}; + +export const exporterAssert = async (testName: string, importer: Importer) => { + const actualMindmap = await importer.import(testName, ''); + + // Load mindmap file.. + const mindmapPath = path.resolve(__dirname, `./expected/${testName}.wxml`); + if (saveOutputRecord) { + fs.writeFileSync(mindmapPath, actualMindmap); + } + + const mindmapExpect = fs.readFileSync(mindmapPath).toString(); + + // Compare with expected... + if (actualMindmap !== mindmapExpect) { + const diffResult = diff(actualMindmap, mindmapExpect); + console.log(diffResult); + expect(actualMindmap).toEqual(mindmapExpect); + } +}; diff --git a/packages/mindplot/test/unit/import/TextImporterTestSuite.test.ts b/packages/mindplot/test/unit/import/TextImporterTestSuite.test.ts new file mode 100644 index 00000000..12446a6f --- /dev/null +++ b/packages/mindplot/test/unit/import/TextImporterTestSuite.test.ts @@ -0,0 +1,27 @@ +/* eslint-disable import/no-extraneous-dependencies */ +import path from 'path'; +import fs from 'fs'; +import { test } from '@jest/globals'; +import { exporterAssert, parseXMLFile } from './Helper'; +import FreemindMap from '../../../src/components/export/freemind/Map'; +import TextImporterFactory from '../../../src/components/import/TextImporterFactory'; + +const testNames = fs + .readdirSync(path.resolve(__dirname, './input/')) + .map((filename: string) => filename.split('.')[0]); + +describe('MM import test execution', () => { + test.each(testNames)('Importing %p suite', async (testName: string) => { + // load freemap... + const freemapPath = path.resolve(__dirname, `./input/${testName}.mm`); + const mapDocument = parseXMLFile(freemapPath, 'text/xml'); + + const freemap: FreemindMap = new FreemindMap().loadFromDom(mapDocument); + const freemapXml = freemap.toXml(); + const freemapStr = new XMLSerializer().serializeToString(freemapXml); + + const importer = TextImporterFactory.create('mm', freemapStr); + + await exporterAssert(testName, importer); + }); +}); diff --git a/packages/mindplot/test/unit/import/expected/Cs2.wxml b/packages/mindplot/test/unit/import/expected/Cs2.wxml new file mode 100644 index 00000000..dfecc973 --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/Cs2.wxml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/SQLServer.wxml b/packages/mindplot/test/unit/import/expected/SQLServer.wxml new file mode 100644 index 00000000..d5411c31 --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/SQLServer.wxml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/anonymity_on_the_edge.wxml b/packages/mindplot/test/unit/import/expected/anonymity_on_the_edge.wxml new file mode 100644 index 00000000..6bbb9f41 --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/anonymity_on_the_edge.wxml @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/bug2.wxml b/packages/mindplot/test/unit/import/expected/bug2.wxml new file mode 100644 index 00000000..9e9dc0eb --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/bug2.wxml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/bug3.wxml b/packages/mindplot/test/unit/import/expected/bug3.wxml new file mode 100644 index 00000000..032d6b12 --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/bug3.wxml @@ -0,0 +1,514 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/cdata-support.wxml b/packages/mindplot/test/unit/import/expected/cdata-support.wxml new file mode 100644 index 00000000..a0b3d4c2 --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/cdata-support.wxml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/coderToDeveloper.wxml b/packages/mindplot/test/unit/import/expected/coderToDeveloper.wxml new file mode 100644 index 00000000..df0cd6a6 --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/coderToDeveloper.wxml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/complex.wxml b/packages/mindplot/test/unit/import/expected/complex.wxml new file mode 100644 index 00000000..5254b667 --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/complex.wxml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/emptyNodes.wxml b/packages/mindplot/test/unit/import/expected/emptyNodes.wxml new file mode 100644 index 00000000..50803a15 --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/emptyNodes.wxml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/enc.wxml b/packages/mindplot/test/unit/import/expected/enc.wxml new file mode 100644 index 00000000..d819fefd --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/enc.wxml @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/freeMind_resources.wxml b/packages/mindplot/test/unit/import/expected/freeMind_resources.wxml new file mode 100644 index 00000000..0242d1ac --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/freeMind_resources.wxml @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/i18n.wxml b/packages/mindplot/test/unit/import/expected/i18n.wxml new file mode 100644 index 00000000..91ed0e2b --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/i18n.wxml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/i18n2.wxml b/packages/mindplot/test/unit/import/expected/i18n2.wxml new file mode 100644 index 00000000..34523624 --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/i18n2.wxml @@ -0,0 +1,11 @@ + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/issue.wxml b/packages/mindplot/test/unit/import/expected/issue.wxml new file mode 100644 index 00000000..b7fe5309 --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/issue.wxml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/npe.wxml b/packages/mindplot/test/unit/import/expected/npe.wxml new file mode 100644 index 00000000..086c7442 --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/npe.wxml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/process.wxml b/packages/mindplot/test/unit/import/expected/process.wxml new file mode 100644 index 00000000..21972ee1 --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/process.wxml @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/pub_sub.wxml b/packages/mindplot/test/unit/import/expected/pub_sub.wxml new file mode 100644 index 00000000..a8c567d7 --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/pub_sub.wxml @@ -0,0 +1,415 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/python.wxml b/packages/mindplot/test/unit/import/expected/python.wxml new file mode 100644 index 00000000..51fc0e1b --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/python.wxml @@ -0,0 +1,284 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/sample3.wxml b/packages/mindplot/test/unit/import/expected/sample3.wxml new file mode 100644 index 00000000..e94e61f5 --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/sample3.wxml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/sample4.wxml b/packages/mindplot/test/unit/import/expected/sample4.wxml new file mode 100644 index 00000000..f5c6506f --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/sample4.wxml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/welcome.wxml b/packages/mindplot/test/unit/import/expected/welcome.wxml new file mode 100644 index 00000000..e7df51bb --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/welcome.wxml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/expected/writing_an_essay_with.wxml b/packages/mindplot/test/unit/import/expected/writing_an_essay_with.wxml new file mode 100644 index 00000000..1e638af5 --- /dev/null +++ b/packages/mindplot/test/unit/import/expected/writing_an_essay_with.wxml @@ -0,0 +1,251 @@ + + + + + + + + + + + + + + When you're working on your essay, you'll find it helpful to switch between this map, and the one you're creating. To switch between maps, go to the Maps menu, and select the name of the map you want. + + + (When you're a bit more familiar with FreeMind, you'll find it quicker to use the Shortcut Keys -- you can also use Alt + Shift + Left, or Alt + Shift + Right to move between maps.)]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/mindplot/test/unit/import/input/Cs2.mm b/packages/mindplot/test/unit/import/input/Cs2.mm new file mode 100644 index 00000000..8b1ca7fa --- /dev/null +++ b/packages/mindplot/test/unit/import/input/Cs2.mm @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/mindplot/test/unit/import/input/SQLServer.mm b/packages/mindplot/test/unit/import/input/SQLServer.mm new file mode 100644 index 00000000..da93e708 --- /dev/null +++ b/packages/mindplot/test/unit/import/input/SQLServer.mm @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/mindplot/test/unit/import/input/anonymity_on_the_edge.mm b/packages/mindplot/test/unit/import/input/anonymity_on_the_edge.mm new file mode 100644 index 00000000..0462ba93 --- /dev/null +++ b/packages/mindplot/test/unit/import/input/anonymity_on_the_edge.mm @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/mindplot/test/unit/import/input/bug2.mm b/packages/mindplot/test/unit/import/input/bug2.mm new file mode 100644 index 00000000..3baf15c5 --- /dev/null +++ b/packages/mindplot/test/unit/import/input/bug2.mm @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

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

+

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

+

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

+

+

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

+

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

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

Identifying new measures or investments that should be implemented.

+ + +
+ + + + + + + +

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

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

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

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

Firms turnover from (new to firm)

+

product innovation (as a pecentage of total turnover)

+ + +
+ +
+ + + + + +

Increase in the probability to innovate linked to ICT use

+

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

+ + +
+
+ + + + + +

Scientific articles by type of collaboration (per capita)

+

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

+ + +
+ +
+ + + + + +

Increase in a share of expenditures on technological

+

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

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

Increase in th number of firms with

+

international/national collaboration on innovation

+ + +
+ +
+ + + + + +

Highly cited scientific articles (as a percentage of

+

highly cited scientific article in the whole Federation)

+ + +
+ +
+ + + + + +

Patents filed by public research organisations

+

(as a percentafe of patent application filed under PCT)

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

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

+ + +
+ + + + + + +

This is what policy makers care about in the end

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

WB

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

GCR

+ + +
+
+ + + + + + +

GCR

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

per 100 population aged 25-64

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

Amount of university and colleague

+

students per 10 thousands population

+ + +
+
+ + + + + +

Share of employees with higher education in

+

the total amount of population at the working age

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

GCR

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

GCR

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

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

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

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

+ + +
+ +
+ + + + + +

Share of high-technology export in the total volume

+

of production of goods, works and services

+ + +
+ +
+ + + + + +

Share of innovation production/serivces that goes for export,

+

by zones (EU, US, CIS, other countries

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

GEM

+ + +
+
+ + + + + +

GEM

+ + +
+
+ + + + + +

GEM

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

UNESCO

+ + +
+
+ + + + + +

CIS

+ + +
+
+ + + + + +

Share of Innovative companies collaborating

+

with research institutions on innovation

+ + +
+
+ + + + + +

Number of joint projects conducted by the local comapnies

+

and local consulting/intermediary agencies

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

GCR

+ + +
+
+ + + + + +

Share of expenditures on technological innovations

+

in the amount of sales

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

Investments in ICT by asset (IT equipment,

+

communication equipment, software)

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

Level of energy efficiency of the regional economy

+

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

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

CIS, BEEPS

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

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

+ + +
+
+ + + + + +

(as a percentage of all registered corporations)

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

Amount of domestically protected intellectual

+

property per 1 mln. population

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

Number of intellectual property exploited by regional

+

enterprises per 1 mln. population

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

Number of advanced ICT introduced in the budgetary organizations

+

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

+ + +
+
+ + + + + + +

Number of management innovations introduced in the budgetary organizations

+

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

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

Number of interactions between universities

+

and large companies by university size

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

Publications: Academic articles in international peer-reviewed

+

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

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

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

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

Academic licenses: Number of licenses

+

per 1,000 researchers.[licenses/researcher]

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

Foreign contracts: Number of contracts with foreign industria

+

l companies at scientific and educational organizations

+

per 1,000 researchers [contracts/researchers]

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

(design firms, IP consultants, etc.)

+ + +
+
+ + + + + +

(e.g. accelerators, incubators)

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

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

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

WIPO SURVEY OF INTELLECTUAL PROPERTY SERVICES OF

+

EUROPEAN TECHNOLOGY INCUBATORS

+ + +
+
+ + + + + + +

Gazelle tenant: Share of tenants with

+

annual revenue growth of more than 20%

+

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

+ + +
+
+ + + + + +

Globalization of tenants: Median share of tenant

+

revenues obtained from exports [%]

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

Perception (opinion poll) of business managers

+

regarding public support programmes

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

Perception of business managers in terms

+

of level of transparency of support measures in the region

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

Description by regional business managers of the way the

+

select and apply for regional and federal support schemes

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

JL: not sure how this would be measured

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

Average leverage of 1rub (there would be

+

several programs with different leverage)

+ + +
+ +
+ + + + + +

Volume of attracted money per one ruble

+

of regional budget expenditures on innovation projects

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

Understanding what investments should be made in innovative projects.

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

Growth of the volume of production in the cluster companies

+

to the volume of state support for the cluster

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

FASIE projects: Number of projects supported

+

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

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

Always ask

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

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

+

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

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

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

However, the fast pace of

+

development of plant trait meta-analyses also suggests that

+

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

+

plant trait data bases.

+ + +
+
+ + + + + +

We measured

+

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

+

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

+

10 functional traits related to wood and leaf morphology and

+

ecophysiology. Here, we contrast the trait means and variances

+

obtained with a full sampling strategy with those of

+

other sampling designs used in the recent literature, which we

+

obtain by simulation. We assess the differences in community-

+

level estimates of functional trait means and variances

+

among design types and sampling intensities. We then contrast

+

the relative costs of these designs and discuss the appropriateness

+

of different sampling designs and intensities for

+

different questions and systems.

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

With regard to estimating mean trait values, strategies

+

alternative to BRIDGE were consistently cost-effective. On

+

the other hand, strategies alternative to BRIDGE clearly

+

failed to accurately estimate the variance of trait values. This

+

indicates that in situations where accurate estimation of plotlevel

+

variance is desired, complete censuses are essential.

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

We suggest that, in these studies,

+

the investment in complete sampling may be worthwhile

+

for at least some traits.

+ + +
+ + + + +

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

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

Here, we develop a new approach that links functional attributes

+

of tree species with studies of forest recovery and regional

+

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

+

to their functional attributes or demographic rates provides

+

insight into both applied and theoretical questions, such as selecting

+

species for reforestation programs, assessing ecosystem services, and

+

understanding community assembly processes in tropical forests

+

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

+ + +
+
+ + + + + +

Since we have data on leaf

+

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

+

study sites, we based our functional type classification on information

+

for a large number of tree species obtained through vegetation

+

monitoring studies.

+ + +
+
+ + + + + + +

Our approach avoided preconceived notions of successional

+

behavior or shade tolerance of tree species by developing an objective

+

and independent classification of functional types based on vegetation

+

monitoring data from permanent sample plots in mature and

+

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

+

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

+

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

+

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

+

Negret 2007).

+ + +
+
+ + + + + +

Our results demonstrate strong linkages between functional

+

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

+

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

+

tree recruitment in secondary forests.

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

Classifying functional types

+

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

+

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

+

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

+ + +
+
+ + + + + +

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

+

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

+

7: 405–416.

+

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

+

conditions as determinants of recruitment success for pioneer species.

+

J. Ecol. 90: 557–568.

+

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

+

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

+

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

+

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

+

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

+

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

+

rates? Evidence from five Neotropical forests. Ecology 89:

+

1908–1920.

+

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

+

dynamics of species richness and abundance of woody plant functional

+

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

+

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

+

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

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

+
+ + +

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

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

Early example of Map (from SF Site)

+
+ +

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

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

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

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

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

+ + +
+
+ + + + + +

Long text node:

+

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

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

Hardware

+

(componentes físicos)

+ + +
+ + + + + + + +

Entrada de datos

+

+ + +
+ + + + + + + +

Ratón, Teclado, Joystick,

+

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

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

Monitor, Impresora, Bocinas, Plóter.

+

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

Disquete, Disco compacto, DVD,

+

BD, Disco duro, Memoria flash.

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

Software

+

(Programas y datos con los que funciona la computadora)

+

+ + +
+ + + + + + + +

Software de Sistema:Permite el entendimiento

+

entre el usuario y la maquina.

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

Software de Aplicación: Permite hacer hojas de

+

calculo navegar en internet, base de datos, etc.

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

Software de Desarrollo

+

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

PDA

+

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

5 min tutorial video ?

+

Follow the link !

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

Press "enter" to add a

+

Sibling

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

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

+

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

+

+ You are free: +

+

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

+

+ * to make derivative works +

+

+ Under the following conditions: +

+

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

+

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

+

+ +

+

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

+

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

+

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

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