Format all files with prettier

This commit is contained in:
Gustavo Fuhr 2022-07-13 01:45:36 +00:00 committed by Paulo Veiga
parent ae02780a1a
commit cf29f4f953
104 changed files with 2949 additions and 2723 deletions

View File

@ -1,4 +1,4 @@
declare module "*.svg" { declare module '*.svg' {
const content: any; const content: any;
export default content; export default content;
} }

View File

@ -5,26 +5,25 @@ import DE from './../../compiled-lang/de.json';
import RU from './../../compiled-lang/ru.json'; import RU from './../../compiled-lang/ru.json';
import ZH from './../../compiled-lang/zh.json'; import ZH from './../../compiled-lang/zh.json';
class I18nMsg { class I18nMsg {
static loadLocaleData(locale: string) { static loadLocaleData(locale: string) {
switch (locale) { switch (locale) {
case 'fr': case 'fr':
return FR; return FR;
case 'en': case 'en':
return EN; return EN;
case 'es': case 'es':
return ES; return ES;
case 'de': case 'de':
return DE; return DE;
case 'ru': case 'ru':
return RU; return RU;
case 'zh': case 'zh':
return ZH; return ZH;
default: default:
return EN; return EN;
}
} }
}
} }
export default I18nMsg; export default I18nMsg;

View File

@ -48,9 +48,9 @@ class Events {
if (!events) return this; if (!events) return this;
const args = Array.isArray(eventArgs) ? eventArgs : [eventArgs]; const args = Array.isArray(eventArgs) ? eventArgs : [eventArgs];
events.forEach(((fn) => { events.forEach((fn) => {
fn.apply(this, args); fn.apply(this, args);
})); });
return this; return this;
} }

View File

@ -1,25 +1,27 @@
import styled from 'styled-components'; import styled from 'styled-components';
const ActionButton = styled.div` const ActionButton = styled.div`
cursor: pointer; cursor: pointer;
margin: 0px 10px; margin: 0px 10px;
font-family: Arial, Helvetica, sans-serif; font-family: Arial, Helvetica, sans-serif;
user-select: none; user-select: none;
vertical-align: middle; vertical-align: middle;
justify-content: center; justify-content: center;
padding: 10px 25px; padding: 10px 25px;
font-size: 15px; font-size: 15px;
min-width: 64px; min-width: 64px;
box-sizing: border-box; box-sizing: border-box;
font-weight: 600; font-weight: 600;
border-radius: 9px; border-radius: 9px;
color: white; color: white;
background-color: #ffa800; background-color: #ffa800;
display: inline-block; display: inline-block;
&:hover { &:hover {
transition: background-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,box-shadow 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,border 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: background-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,
} box-shadow 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,
border 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
}
`; `;
export default ActionButton; export default ActionButton;

View File

@ -3,29 +3,29 @@ import { times } from '../../size';
import LogoTextBlackSvg from '../../../images/logo-text-black.svg'; import LogoTextBlackSvg from '../../../images/logo-text-black.svg';
export const StyledFooter = styled.div` export const StyledFooter = styled.div`
height: ${times(10)}; height: ${times(10)};
width: 100%; width: 100%;
border: 1px solid black; border: 1px solid black;
`; `;
export const StyledLogo = styled.div` export const StyledLogo = styled.div`
position: fixed; position: fixed;
left: 20px; left: 20px;
bottom: 10px; bottom: 10px;
background: url(${LogoTextBlackSvg}) no-repeat; background: url(${LogoTextBlackSvg}) no-repeat;
width: 90px; width: 90px;
height: 40px; height: 40px;
`; `;
export const Notifier = styled.div` export const Notifier = styled.div`
border: 1px solid rgb(241, 163, 39); border: 1px solid rgb(241, 163, 39);
background-color: rgb(252, 235, 192); background-color: rgb(252, 235, 192);
border-radius: 3px; border-radius: 3px;
position: fixed; position: fixed;
padding: 5px 9px; padding: 5px 9px;
color: back; color: back;
white-space: nowrap; white-space: nowrap;
margin-top: 5px; margin-top: 5px;
display: none; display: none;
bottom: 10px; bottom: 10px;
`; `;

View File

@ -1,50 +1,50 @@
import styled from 'styled-components'; import styled from 'styled-components';
export const HeaderContainer = styled.div` export const HeaderContainer = styled.div`
width: 100%; width: 100%;
height: 0px; height: 0px;
background: #202020; background: #202020;
z-index: 1000; z-index: 1000;
position: absolute; position: absolute;
top: 0; top: 0;
display: flex; display: flex;
`; `;
export const ToolbarContainer = styled.div` export const ToolbarContainer = styled.div`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex: 1; flex: 1;
`; `;
export const ToolbarButton = styled.div` export const ToolbarButton = styled.div`
width: 28px; width: 28px;
height: 28px; height: 28px;
text-align: center; text-align: center;
z-index: 4; z-index: 4;
margin-top: 3px; margin-top: 3px;
padding-top: 2px; padding-top: 2px;
padding-left: 2px; padding-left: 2px;
margin-left: 3px; margin-left: 3px;
display: inline-block; display: inline-block;
`; `;
export const ToolbarButtonExt = styled(ToolbarButton)` export const ToolbarButtonExt = styled(ToolbarButton)`
width: 40px; width: 40px;
text-align: left; text-align: left;
padding-left: 5px; padding-left: 5px;
`; `;
export const AccountButton = styled.div` export const AccountButton = styled.div`
display: inline-block; display: inline-block;
margin-top: 3px; margin-top: 3px;
`; `;
export const ToolbarRightContainer = styled.div` export const ToolbarRightContainer = styled.div`
flex-shrink: 1; flex-shrink: 1;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
justify-content: flex-end; justify-content: flex-end;
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
`; `;

View File

@ -33,10 +33,12 @@
"?": "ignore", "?": "ignore",
">": "ignore", ">": "ignore",
"||": "ignore", "||": "ignore",
"&&": "ignore" "&&": "ignore",
"(": "ignore"
} }
} }
], ],
"object-curly-newline": "off",
"no-underscore-dangle": "off", "no-underscore-dangle": "off",
"no-plusplus": "off", "no-plusplus": "off",
"no-param-reassign": "off", "no-param-reassign": "off",

View File

@ -1,20 +1,20 @@
/* /*
* Copyright [2021] [wisemapping] * Copyright [2021] [wisemapping]
* *
* Licensed under WiseMapping Public License, Version 1.0 (the "License"). * Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the * It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page; * "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the license at * You may obtain a copy of the license at
* *
* http://www.wisemapping.org/license * http://www.wisemapping.org/license
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { $defined } from '@wisemapping/core-js'; import { $defined } from '@wisemapping/core-js';
import CommandContext from './CommandContext'; import CommandContext from './CommandContext';

View File

@ -47,9 +47,9 @@ class CommandContext {
if (result.length !== topicsIds.length) { if (result.length !== topicsIds.length) {
const ids = designerTopics.map((topic) => topic.getId()); const ids = designerTopics.map((topic) => topic.getId());
throw new Error(`Could not find topic. Result:${result throw new Error(
} Filter Criteria:${topicsIds `Could not find topic. Result:${result} Filter Criteria:${topicsIds} Current Topics: [${ids}])`,
} Current Topics: [${ids}])`); );
} }
return result; return result;
} }

View File

@ -17,9 +17,7 @@
*/ */
import { $assert, $defined } from '@wisemapping/core-js'; import { $assert, $defined } from '@wisemapping/core-js';
import { import { Point, CurvedLine, PolyLine, Line } from '@wisemapping/web2d';
Point, CurvedLine, PolyLine, Line,
} from '@wisemapping/web2d';
import { TopicShape } from './model/INodeModel'; import { TopicShape } from './model/INodeModel';
import RelationshipModel from './model/RelationshipModel'; import RelationshipModel from './model/RelationshipModel';
import Topic from './Topic'; import Topic from './Topic';

View File

@ -33,7 +33,22 @@ class DesignerKeyboard extends Keyboard {
private static _disabled: boolean; private static _disabled: boolean;
private static excludeFromEditor = ['Enter', 'CapsLock', 'Escape', 'F1', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9', 'F10', 'F11', 'F12']; private static excludeFromEditor = [
'Enter',
'CapsLock',
'Escape',
'F1',
'F3',
'F4',
'F5',
'F6',
'F7',
'F8',
'F9',
'F10',
'F11',
'F12',
];
constructor(designer: Designer) { constructor(designer: Designer) {
super(); super();
@ -53,9 +68,13 @@ class DesignerKeyboard extends Keyboard {
private _registerEvents(designer: Designer) { private _registerEvents(designer: Designer) {
// Try with the keyboard .. // Try with the keyboard ..
const model = designer.getModel(); const model = designer.getModel();
this.addShortcut(['backspace', 'del'], () => { designer.deleteSelectedEntities(); }); this.addShortcut(['backspace', 'del'], () => {
designer.deleteSelectedEntities();
});
this.addShortcut('space', () => { designer.shrinkSelectedBranch(); }); this.addShortcut('space', () => {
designer.shrinkSelectedBranch();
});
this.addShortcut('f2', () => { this.addShortcut('f2', () => {
const node = model.selectedTopic(); const node = model.selectedTopic();
@ -64,103 +83,128 @@ class DesignerKeyboard extends Keyboard {
} }
}); });
this.addShortcut(['insert', 'tab', 'meta+enter'], () => { designer.createChildForSelectedNode(); }); this.addShortcut(['insert', 'tab', 'meta+enter'], () => {
designer.createChildForSelectedNode();
});
this.addShortcut('enter', () => { designer.createSiblingForSelectedNode(); }); this.addShortcut('enter', () => {
designer.createSiblingForSelectedNode();
});
this.addShortcut(['ctrl+z', 'meta+z'], () => { designer.undo(); }); this.addShortcut(['ctrl+z', 'meta+z'], () => {
designer.undo();
});
this.addShortcut(['ctrl+shift+z', 'meta+shift+z'], () => { designer.redo(); }); this.addShortcut(['ctrl+shift+z', 'meta+shift+z'], () => {
designer.redo();
});
this.addShortcut(['ctrl+c', 'meta+c'], () => { designer.copyToClipboard(); }); this.addShortcut(['ctrl+c', 'meta+c'], () => {
designer.copyToClipboard();
});
this.addShortcut(['ctrl+l', 'meta+l'], () => { designer.addLink(); }); this.addShortcut(['ctrl+l', 'meta+l'], () => {
designer.addLink();
});
this.addShortcut(['ctrl+k', 'meta+k'], () => { designer.addNote(); }); this.addShortcut(['ctrl+k', 'meta+k'], () => {
designer.addNote();
});
this.addShortcut(['ctrl+v', 'meta+v'], () => { designer.pasteClipboard(); }); this.addShortcut(['ctrl+v', 'meta+v'], () => {
designer.pasteClipboard();
});
this.addShortcut(['ctrl+a', 'meta+a'], () => { designer.selectAll(); }); this.addShortcut(['ctrl+a', 'meta+a'], () => {
designer.selectAll();
});
this.addShortcut(['ctrl+b', 'meta+b'], () => { designer.changeFontWeight(); }); this.addShortcut(['ctrl+b', 'meta+b'], () => {
designer.changeFontWeight();
});
this.addShortcut(['ctrl+s', 'meta+s'], () => { $(document).find('#save').trigger('click'); }); this.addShortcut(['ctrl+s', 'meta+s'], () => {
$(document).find('#save').trigger('click');
});
this.addShortcut(['ctrl+i', 'meta+i'], () => { designer.changeFontStyle(); }); this.addShortcut(['ctrl+i', 'meta+i'], () => {
designer.changeFontStyle();
});
this.addShortcut(['ctrl+shift+a', 'meta+shift+a'], () => { designer.deselectAll(); }); this.addShortcut(['ctrl+shift+a', 'meta+shift+a'], () => {
designer.deselectAll();
});
this.addShortcut(['meta+=', 'ctrl+='], () => { designer.zoomIn(); }); this.addShortcut(['meta+=', 'ctrl+='], () => {
designer.zoomIn();
});
this.addShortcut(['meta+-', 'ctrl+-'], () => { designer.zoomOut(); }); this.addShortcut(['meta+-', 'ctrl+-'], () => {
designer.zoomOut();
});
const me = this; const me = this;
this.addShortcut( this.addShortcut('right', () => {
'right', () => { const node = model.selectedTopic();
const node = model.selectedTopic(); if (node) {
if (node) { if (node.isCentralTopic()) {
if (node.isCentralTopic()) { me._goToSideChild(designer, node, 'RIGHT');
me._goToSideChild(designer, node, 'RIGHT'); } else if (node.getPosition().x < 0) {
} else if (node.getPosition().x < 0) { me._goToParent(designer, node);
me._goToParent(designer, node); } else if (!node.areChildrenShrunken()) {
} else if (!node.areChildrenShrunken()) { me._goToChild(designer, node);
me._goToChild(designer, node);
}
} else {
const centralTopic = model.getCentralTopic();
me._goToNode(designer, centralTopic);
} }
}, } else {
); const centralTopic = model.getCentralTopic();
me._goToNode(designer, centralTopic);
}
});
this.addShortcut( this.addShortcut('left', () => {
'left', () => { const node = model.selectedTopic();
const node = model.selectedTopic(); if (node) {
if (node) { if (node.isCentralTopic()) {
if (node.isCentralTopic()) { me._goToSideChild(designer, node, 'LEFT');
me._goToSideChild(designer, node, 'LEFT'); } else if (node.getPosition().x > 0) {
} else if (node.getPosition().x > 0) { me._goToParent(designer, node);
me._goToParent(designer, node); } else if (!node.areChildrenShrunken()) {
} else if (!node.areChildrenShrunken()) { me._goToChild(designer, node);
me._goToChild(designer, node);
}
} else {
const centralTopic = model.getCentralTopic();
me._goToNode(designer, centralTopic);
} }
}, } else {
); const centralTopic = model.getCentralTopic();
me._goToNode(designer, centralTopic);
}
});
this.addShortcut( this.addShortcut('up', () => {
'up', () => { const node = model.selectedTopic();
const node = model.selectedTopic(); if (node) {
if (node) { if (!node.isCentralTopic()) {
if (!node.isCentralTopic()) { me._goToBrother(designer, node, 'UP');
me._goToBrother(designer, node, 'UP');
}
} else {
const centralTopic = model.getCentralTopic();
me._goToNode(designer, centralTopic);
} }
}, } else {
); const centralTopic = model.getCentralTopic();
this.addShortcut( me._goToNode(designer, centralTopic);
'down', () => { }
const node = model.selectedTopic(); });
if (node) { this.addShortcut('down', () => {
if (!node.isCentralTopic()) { const node = model.selectedTopic();
me._goToBrother(designer, node, 'DOWN'); if (node) {
} if (!node.isCentralTopic()) {
} else { me._goToBrother(designer, node, 'DOWN');
const centralTopic = model.getCentralTopic();
me._goToNode(designer, centralTopic);
} }
}, } else {
); const centralTopic = model.getCentralTopic();
me._goToNode(designer, centralTopic);
}
});
$(document).on('keypress', (event) => { $(document).on('keypress', (event) => {
// Needs to be ignored ? // Needs to be ignored ?
if (DesignerKeyboard.isDisabled() || DesignerKeyboard.excludeFromEditor.includes(event.code)) { if (
DesignerKeyboard.isDisabled() ||
DesignerKeyboard.excludeFromEditor.includes(event.code)
) {
return; return;
} }
@ -189,14 +233,14 @@ class DesignerKeyboard extends Keyboard {
const { x } = node.getPosition(); const { x } = node.getPosition();
let dist = null; let dist = null;
for (let i = 0; i < brothers.length; i++) { for (let i = 0; i < brothers.length; i++) {
const sameSide = (x * brothers[i].getPosition().x) >= 0; const sameSide = x * brothers[i].getPosition().x >= 0;
if (brothers[i] !== node && sameSide) { if (brothers[i] !== node && sameSide) {
const brother = brothers[i]; const brother = brothers[i];
const brotherY = brother.getPosition().y; const brotherY = brother.getPosition().y;
if (direction === 'DOWN' && brotherY > y) { if (direction === 'DOWN' && brotherY > y) {
let distancia = y - brotherY; let distancia = y - brotherY;
if (distancia < 0) { if (distancia < 0) {
distancia *= (-1); distancia *= -1;
} }
if (dist == null || dist > distancia) { if (dist == null || dist > distancia) {
dist = distancia; dist = distancia;
@ -205,7 +249,7 @@ class DesignerKeyboard extends Keyboard {
} else if (direction === 'UP' && brotherY < y) { } else if (direction === 'UP' && brotherY < y) {
let distance = y - brotherY; let distance = y - brotherY;
if (distance < 0) { if (distance < 0) {
distance *= (-1); distance *= -1;
} }
if (dist == null || dist > distance) { if (dist == null || dist > distance) {
dist = distance; dist = distance;

View File

@ -117,7 +117,7 @@ class DesignerModel extends Events {
selectedTopic(): Topic | undefined { selectedTopic(): Topic | undefined {
const topics = this.filterSelectedTopics(); const topics = this.filterSelectedTopics();
return (topics.length > 0) ? topics[0] : undefined; return topics.length > 0 ? topics[0] : undefined;
} }
findTopicById(id: number): Topic | undefined { findTopicById(id: number): Topic | undefined {

View File

@ -85,7 +85,7 @@ class DesignerUndoManager {
result = false; result = false;
} else if (undoLength > 0) { } else if (undoLength > 0) {
const command = this._undoQueue[undoLength - 1]; const command = this._undoQueue[undoLength - 1];
result = (this._baseId !== command.getId()); result = this._baseId !== command.getId();
} }
return result; return result;
} }

View File

@ -83,7 +83,7 @@ class DragConnector {
// That's why i need to divide it by two... // That's why i need to divide it by two...
const txborder = tpos.x + (topic.getSize().width / 2) * Math.sign(sPos.x); const txborder = tpos.x + (topic.getSize().width / 2) * Math.sign(sPos.x);
const distance = (sPos.x - txborder) * Math.sign(sPos.x); const distance = (sPos.x - txborder) * Math.sign(sPos.x);
return distance > 0 && (distance < DragConnector.MAX_VERTICAL_CONNECTION_TOLERANCE); return distance > 0 && distance < DragConnector.MAX_VERTICAL_CONNECTION_TOLERANCE;
}); });
// Assign a priority based on the distance: // Assign a priority based on the distance:
@ -99,19 +99,34 @@ class DragConnector {
const av = me._isVerticallyAligned(a.getSize(), aPos, sPos); const av = me._isVerticallyAligned(a.getSize(), aPos, sPos);
const bv = me._isVerticallyAligned(b.getSize(), bPos, sPos); const bv = me._isVerticallyAligned(b.getSize(), bPos, sPos);
return me._proximityWeight(av, a, sPos, currentConnection) return (
- me._proximityWeight(bv, b, sPos, currentConnection); me._proximityWeight(av, a, sPos, currentConnection) -
me._proximityWeight(bv, b, sPos, currentConnection)
);
}); });
return topics; return topics;
} }
private _proximityWeight(isAligned: boolean, target: Topic, sPos: Point, currentConnection: Topic): number { private _proximityWeight(
isAligned: boolean,
target: Topic,
sPos: Point,
currentConnection: Topic,
): number {
const tPos = target.getPosition(); const tPos = target.getPosition();
return (isAligned ? 0 : 200) + Math.abs(tPos.x - sPos.x) return (
+ Math.abs(tPos.y - sPos.y) + (currentConnection === target ? 0 : 100); (isAligned ? 0 : 200) +
Math.abs(tPos.x - sPos.x) +
Math.abs(tPos.y - sPos.y) +
(currentConnection === target ? 0 : 100)
);
} }
private _isVerticallyAligned(targetSize: SizeType, targetPosition: Point, sourcePosition: Point): boolean { private _isVerticallyAligned(
targetSize: SizeType,
targetPosition: Point,
sourcePosition: Point,
): boolean {
return Math.abs(sourcePosition.y - targetPosition.y) < targetSize.height / 2; return Math.abs(sourcePosition.y - targetPosition.y) < targetSize.height / 2;
} }

View File

@ -59,14 +59,14 @@ class DragManager {
// Register mouse move listener ... // Register mouse move listener ...
const mouseMoveListener = dragManager._buildMouseMoveListener( const mouseMoveListener = dragManager._buildMouseMoveListener(
workspace, dragNode, dragManager, workspace,
dragNode,
dragManager,
); );
screen.addEvent('mousemove', mouseMoveListener); screen.addEvent('mousemove', mouseMoveListener);
// Register mouse up listeners ... // Register mouse up listeners ...
const mouseUpListener = dragManager._buildMouseUpListener( const mouseUpListener = dragManager._buildMouseUpListener(workspace, dragNode, dragManager);
workspace, dragNode, dragManager,
);
screen.addEvent('mouseup', mouseUpListener); screen.addEvent('mouseup', mouseUpListener);
// Change cursor. // Change cursor.

View File

@ -1,2 +1,7 @@
type EditorRenderMode = 'viewonly' | 'edition-owner' | 'edition-editor' | 'edition-viewer' | 'showcase'; type EditorRenderMode =
| 'viewonly'
| 'edition-owner'
| 'edition-editor'
| 'edition-viewer'
| 'showcase';
export default EditorRenderMode; export default EditorRenderMode;

View File

@ -48,9 +48,9 @@ class Events {
if (!events) return this; if (!events) return this;
const args = Array.isArray(eventArgs) ? eventArgs : [eventArgs]; const args = Array.isArray(eventArgs) ? eventArgs : [eventArgs];
events.forEach(((fn) => { events.forEach((fn) => {
fn.apply(this, args); fn.apply(this, args);
})); });
return this; return this;
} }

View File

@ -25,12 +25,11 @@ class Keyboard {
addShortcut(shortcuts: string[] | string, callback: () => void) { addShortcut(shortcuts: string[] | string, callback: () => void) {
const shortcutsArray = Array.isArray(shortcuts) ? shortcuts : [shortcuts]; const shortcutsArray = Array.isArray(shortcuts) ? shortcuts : [shortcuts];
shortcutsArray.forEach((shortcut) => { shortcutsArray.forEach((shortcut) => {
$(document).bind('keydown', shortcut, $(document).bind('keydown', shortcut, (e) => {
(e) => { e.stopPropagation();
e.stopPropagation(); e.preventDefault();
e.preventDefault(); callback();
callback(); });
});
}); });
} }
} }

View File

@ -55,7 +55,11 @@ class LocalStorageManager extends PersistenceManager {
if (xml == null || this.forceLoad) { if (xml == null || this.forceLoad) {
$.ajax({ $.ajax({
url: this.documentUrl.replace('{id}', mapId), url: this.documentUrl.replace('{id}', mapId),
headers: { 'Content-Type': 'text/plain', Accept: 'application/xml', 'X-CSRF-Token': this.getCSRFToken() }, headers: {
'Content-Type': 'text/plain',
Accept: 'application/xml',
'X-CSRF-Token': this.getCSRFToken(),
},
type: 'get', type: 'get',
dataType: 'text', dataType: 'text',
async: false, async: false,

View File

@ -26,7 +26,7 @@ import Workspace from './Workspace';
import SizeType from './SizeType'; import SizeType from './SizeType';
class MainTopic extends Topic { class MainTopic extends Topic {
private INNER_RECT_ATTRIBUTES: { stroke: string; }; private INNER_RECT_ATTRIBUTES: { stroke: string };
constructor(model: NodeModel, options) { constructor(model: NodeModel, options) {
super(model, options); super(model, options);

View File

@ -33,23 +33,20 @@ class MultilineTextEditor extends Events {
} }
private static _buildEditor() { private static _buildEditor() {
const result = $('<div></div>') const result = $('<div></div>').attr('id', 'textContainer').css({
.attr('id', 'textContainer') display: 'none',
.css({ zIndex: '8',
display: 'none', border: '0 none',
zIndex: '8', });
border: '0 none',
});
const textareaElem = $('<textarea tabindex="-1" value="" wrap="off" ></textarea>') const textareaElem = $('<textarea tabindex="-1" value="" wrap="off" ></textarea>').css({
.css({ border: '1px gray dashed',
border: '1px gray dashed', background: 'rgba(98, 135, 167, .4)',
background: 'rgba(98, 135, 167, .4)', outline: '0 none',
outline: '0 none', resize: 'none',
resize: 'none', overflow: 'hidden',
overflow: 'hidden', padding: '2px 0px 2px 4px',
padding: '2px 0px 2px 4px', });
});
result.append(textareaElem); result.append(textareaElem);
return result; return result;

View File

@ -77,11 +77,10 @@ class NoteIcon extends Icon {
} }
const result = $('<div id="textPopoverNote"></div>').css({ padding: '5px' }); const result = $('<div id="textPopoverNote"></div>').css({ padding: '5px' });
const text = $('<div></div>').text(this._linksModel.getText()) const text = $('<div></div>').text(this._linksModel.getText()).css({
.css({ 'white-space': 'pre-wrap',
'white-space': 'pre-wrap', 'word-wrap': 'break-word',
'word-wrap': 'break-word', });
});
result.append(text); result.append(text);
return result; return result;
} }

View File

@ -15,6 +15,6 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
type PositionType = { x: number, y: number }; type PositionType = { x: number; y: number };
export default PositionType; export default PositionType;

View File

@ -118,10 +118,7 @@ class Relationship extends ConnectionLine {
this._line2d.setStroke(2); this._line2d.setStroke(2);
const ctrlPoints = this._line2d.getControlPoints(); const ctrlPoints = this._line2d.getControlPoints();
if (!this._line2d.isDestControlPointCustom() && !this._line2d.isSrcControlPointCustom()) { if (!this._line2d.isDestControlPointCustom() && !this._line2d.isSrcControlPointCustom()) {
const defaultPoints = Shape.calculateDefaultControlPoints( const defaultPoints = Shape.calculateDefaultControlPoints(sourcePosition, targetPosition);
sourcePosition,
targetPosition,
);
ctrlPoints[0].x = defaultPoints[0].x; ctrlPoints[0].x = defaultPoints[0].x;
ctrlPoints[0].y = defaultPoints[0].y; ctrlPoints[0].y = defaultPoints[0].y;

View File

@ -31,7 +31,7 @@ class RESTPersistenceManager extends PersistenceManager {
private clearTimeout; private clearTimeout;
constructor(options: { documentUrl: string, revertUrl: string, lockUrl: string }) { constructor(options: { documentUrl: string; revertUrl: string; lockUrl: string }) {
$assert(options.documentUrl, 'documentUrl can not be null'); $assert(options.documentUrl, 'documentUrl can not be null');
$assert(options.revertUrl, 'revertUrl can not be null'); $assert(options.revertUrl, 'revertUrl can not be null');
$assert(options.lockUrl, 'lockUrl can not be null'); $assert(options.lockUrl, 'lockUrl can not be null');
@ -60,78 +60,87 @@ class RESTPersistenceManager extends PersistenceManager {
}, 10000); }, 10000);
const persistence = this; const persistence = this;
fetch( fetch(`${this.documentUrl.replace('{id}', mapId)}?${query}`, {
`${this.documentUrl.replace('{id}', mapId)}?${query}`, method: 'PUT',
{ // Blob helps to resuce the memory on large payload.
method: 'PUT', body: new Blob([JSON.stringify(data)], { type: 'text/plain' }),
// Blob helps to resuce the memory on large payload. headers: {
body: new Blob([JSON.stringify(data)], { type: 'text/plain' }), 'Content-Type': 'application/json; charset=utf-8',
headers: { 'Content-Type': 'application/json; charset=utf-8', Accept: 'application/json', 'X-CSRF-Token': this.getCSRFToken() }, Accept: 'application/json',
'X-CSRF-Token': this.getCSRFToken(),
}, },
).then(async (response: Response) => { })
if (response.ok) { .then(async (response: Response) => {
events.onSuccess(); if (response.ok) {
} else { events.onSuccess();
console.log(`Saving error: ${response.status}`);
let userMsg;
if (response.status === 405) {
userMsg = { severity: 'SEVERE', message: $msg('SESSION_EXPIRED'), errorType: 'session-expired' };
} else { } else {
const responseText = await response.text(); console.log(`Saving error: ${response.status}`);
const contentType = response.headers['Content-Type']; let userMsg;
if (contentType != null && contentType.indexOf('application/json') !== -1) { if (response.status === 405) {
let serverMsg = null; userMsg = {
try { severity: 'SEVERE',
serverMsg = JSON.parse(responseText); message: $msg('SESSION_EXPIRED'),
serverMsg = serverMsg.globalSeverity ? serverMsg : null; errorType: 'session-expired',
} catch (e) { };
// Message could not be decoded ... } else {
const responseText = await response.text();
const contentType = response.headers['Content-Type'];
if (contentType != null && contentType.indexOf('application/json') !== -1) {
let serverMsg = null;
try {
serverMsg = JSON.parse(responseText);
serverMsg = serverMsg.globalSeverity ? serverMsg : null;
} catch (e) {
// Message could not be decoded ...
}
userMsg = persistence._buildError(serverMsg);
} }
userMsg = persistence._buildError(serverMsg);
} }
this.triggerError(userMsg);
events.onError(userMsg);
} }
// Clear event timeout ...
if (persistence.clearTimeout) {
clearTimeout(persistence.clearTimeout);
}
persistence.onSave = false;
})
.catch(() => {
const userMsg: PersistenceError = {
severity: 'SEVERE',
message: $msg('SAVE_COULD_NOT_BE_COMPLETED'),
errorType: 'generic',
};
this.triggerError(userMsg); this.triggerError(userMsg);
events.onError(userMsg); events.onError(userMsg);
}
// Clear event timeout ... // Clear event timeout ...
if (persistence.clearTimeout) { if (persistence.clearTimeout) {
clearTimeout(persistence.clearTimeout); clearTimeout(persistence.clearTimeout);
} }
persistence.onSave = false; persistence.onSave = false;
}).catch(() => { });
const userMsg: PersistenceError = {
severity: 'SEVERE', message: $msg('SAVE_COULD_NOT_BE_COMPLETED'), errorType: 'generic',
};
this.triggerError(userMsg);
events.onError(userMsg);
// Clear event timeout ...
if (persistence.clearTimeout) {
clearTimeout(persistence.clearTimeout);
}
persistence.onSave = false;
});
} }
} }
discardChanges(mapId: string) { discardChanges(mapId: string) {
fetch(this.revertUrl.replace('{id}', mapId), fetch(this.revertUrl.replace('{id}', mapId), {
{ method: 'POST',
method: 'POST', headers: {
headers: { 'Content-Type': 'application/json; charset=utf-8', Accept: 'application/json', 'X-CSRF-Token': this.getCSRFToken() }, 'Content-Type': 'application/json; charset=utf-8',
}); Accept: 'application/json',
'X-CSRF-Token': this.getCSRFToken(),
},
});
} }
unlockMap(mapId: string): void { unlockMap(mapId: string): void {
fetch( fetch(this.lockUrl.replace('{id}', mapId), {
this.lockUrl.replace('{id}', mapId), method: 'PUT',
{ headers: { 'Content-Type': 'text/plain', 'X-CSRF-Token': this.getCSRFToken() },
method: 'PUT', body: 'false',
headers: { 'Content-Type': 'text/plain', 'X-CSRF-Token': this.getCSRFToken() }, });
body: 'false',
},
);
} }
private _buildError(jsonSeverResponse) { private _buildError(jsonSeverResponse) {
@ -154,7 +163,11 @@ class RESTPersistenceManager extends PersistenceManager {
url: `${this.documentUrl.replace('{id}', mapId)}/xml`, url: `${this.documentUrl.replace('{id}', mapId)}/xml`,
method: 'get', method: 'get',
async: false, async: false,
headers: { 'Content-Type': 'text/plain', Accept: 'application/xml', 'X-CSRF-Token': this.getCSRFToken() }, headers: {
'Content-Type': 'text/plain',
Accept: 'application/xml',
'X-CSRF-Token': this.getCSRFToken(),
},
success(responseText) { success(responseText) {
xml = responseText; xml = responseText;
}, },

View File

@ -18,9 +18,7 @@
import $ from 'jquery'; import $ from 'jquery';
import { $assert, $defined } from '@wisemapping/core-js'; import { $assert, $defined } from '@wisemapping/core-js';
import { import { Rect, Image, Line, Text, Group, ElementClass, Point } from '@wisemapping/web2d';
Rect, Image, Line, Text, Group, ElementClass, Point,
} from '@wisemapping/web2d';
import NodeGraph from './NodeGraph'; import NodeGraph from './NodeGraph';
import TopicConfig from './TopicConfig'; import TopicConfig from './TopicConfig';
@ -177,10 +175,7 @@ abstract class Topic extends NodeGraph {
getInnerShape(): ElementClass { getInnerShape(): ElementClass {
if (!$defined(this._innerShape)) { if (!$defined(this._innerShape)) {
// Create inner box. // Create inner box.
this._innerShape = this._buildShape( this._innerShape = this._buildShape(TopicConfig.INNER_RECT_ATTRIBUTES, this.getShapeType());
TopicConfig.INNER_RECT_ATTRIBUTES,
this.getShapeType(),
);
// Update bgcolor ... // Update bgcolor ...
const bgColor = this.getBackgroundColor(); const bgColor = this.getBackgroundColor();
@ -246,7 +241,9 @@ abstract class Topic extends NodeGraph {
result.setStroke(1, 'solid', stokeColor); result.setStroke(1, 'solid', stokeColor);
}; };
result.getSize = function getSize() { return this.size; }; result.getSize = function getSize() {
return this.size;
};
result.setPosition = () => { result.setPosition = () => {
// Overwrite behaviour ... // Overwrite behaviour ...
@ -279,10 +276,7 @@ abstract class Topic extends NodeGraph {
getOuterShape(): ElementClass { getOuterShape(): ElementClass {
if (!$defined(this._outerShape)) { if (!$defined(this._outerShape)) {
const rect = this._buildShape( const rect = this._buildShape(TopicConfig.OUTER_SHAPE_ATTRIBUTES, TopicShape.ROUNDED_RECT);
TopicConfig.OUTER_SHAPE_ATTRIBUTES,
TopicShape.ROUNDED_RECT,
);
rect.setPosition(-2, -3); rect.setPosition(-2, -3);
rect.setOpacity(0); rect.setOpacity(0);
this._outerShape = rect; this._outerShape = rect;
@ -822,8 +816,8 @@ abstract class Topic extends NodeGraph {
} }
/** /**
* Point: references the center of the rect shape.!!! * Point: references the center of the rect shape.!!!
*/ */
setPosition(point: Point) { setPosition(point: Point) {
$assert(point, 'position can not be null'); $assert(point, 'position can not be null');
// allowed param reassign to avoid risks of existing code relying in this side-effect // allowed param reassign to avoid risks of existing code relying in this side-effect
@ -953,9 +947,9 @@ abstract class Topic extends NodeGraph {
const targetParent = targetTopic.getModel().getParent(); const targetParent = targetTopic.getModel().getParent();
const sourceParent = sourceTopic.getModel().getParent(); const sourceParent = sourceTopic.getModel().getParent();
relationship.setVisibility( relationship.setVisibility(
value value &&
&& (targetParent == null || !targetParent.areChildrenShrunken()) (targetParent == null || !targetParent.areChildrenShrunken()) &&
&& (sourceParent == null || !sourceParent.areChildrenShrunken()), (sourceParent == null || !sourceParent.areChildrenShrunken()),
fade, fade,
); );
}); });
@ -1027,7 +1021,8 @@ abstract class Topic extends NodeGraph {
}; };
const oldSize = this.getSize(); const oldSize = this.getSize();
const hasSizeChanged = oldSize.width !== roundedSize.width || oldSize.height !== roundedSize.height; const hasSizeChanged =
oldSize.width !== roundedSize.width || oldSize.height !== roundedSize.height;
if (hasSizeChanged || force) { if (hasSizeChanged || force) {
NodeGraph.prototype.setSize.call(this, roundedSize); NodeGraph.prototype.setSize.call(this, roundedSize);
@ -1259,10 +1254,13 @@ abstract class Topic extends NodeGraph {
const iconGroupWith = iconGroup.getSize().width; const iconGroupWith = iconGroup.getSize().width;
const topicWith = iconGroupWith + 2 * textIconSpacing + textWidth + padding * 2; const topicWith = iconGroupWith + 2 * textIconSpacing + textWidth + padding * 2;
this.setSize({ this.setSize(
width: topicWith, {
height: topicHeight, width: topicWith,
}, false); height: topicHeight,
},
false,
);
// Adjust all topic elements positions ... // Adjust all topic elements positions ...
const yPosition = Math.round((topicHeight - textHeight) / 2); const yPosition = Math.round((topicHeight - textHeight) / 2);

View File

@ -65,9 +65,9 @@ class TopicEventDispatcher extends Events {
// Open the new editor ... // Open the new editor ...
const model = topic.getModel(); const model = topic.getModel();
if ( if (
model.getShapeType() !== TopicShape.IMAGE model.getShapeType() !== TopicShape.IMAGE &&
&& !this._readOnly !this._readOnly &&
&& eventType === TopicEvent.EDIT eventType === TopicEvent.EDIT
) { ) {
this._multilineEditor.show(topic, options ? options.text : null); this._multilineEditor.show(topic, options ? options.text : null);
this._activeEditor = this._multilineEditor; this._activeEditor = this._multilineEditor;

View File

@ -31,15 +31,15 @@ class AddFeatureToTopicCommand extends Command {
private _featureModel: FeatureModel; private _featureModel: FeatureModel;
/* /*
* @classdesc This command class handles do/undo of adding features to topics, e.g. an * @classdesc This command class handles do/undo of adding features to topics, e.g. an
* icon or a note. For a reference of existing features, refer to {@link mindplot.TopicFeature} * icon or a note. For a reference of existing features, refer to {@link mindplot.TopicFeature}
* @constructs * @constructs
* @param {String} topicId the id of the topic * @param {String} topicId the id of the topic
* @param {String} featureType the id of the feature type to add, e.g. "icon" * @param {String} featureType the id of the feature type to add, e.g. "icon"
* @param {Object} attributes the attribute(s) of the respective feature model * @param {Object} attributes the attribute(s) of the respective feature model
* @extends mindplot.Command * @extends mindplot.Command
* @see mindplot.model.FeatureModel and subclasses * @see mindplot.model.FeatureModel and subclasses
*/ */
constructor(topicId: number, featureType: FeatureType, attributes: object) { constructor(topicId: number, featureType: FeatureType, attributes: object) {
$assert($defined(topicId), 'topicId can not be null'); $assert($defined(topicId), 'topicId can not be null');
$assert(featureType, 'featureType can not be null'); $assert(featureType, 'featureType can not be null');

View File

@ -24,8 +24,8 @@ class AddRelationshipCommand extends Command {
private _model: RelationshipModel; private _model: RelationshipModel;
/** /**
* @classdesc This command class handles do/undo of adding a relationship to a topic. * @classdesc This command class handles do/undo of adding a relationship to a topic.
*/ */
constructor(model: RelationshipModel) { constructor(model: RelationshipModel) {
$assert(model, 'Relationship model can not be null'); $assert(model, 'Relationship model can not be null');

View File

@ -31,7 +31,10 @@ class AddTopicCommand extends Command {
*/ */
constructor(models: NodeModel[], parentTopicsId: number[]) { constructor(models: NodeModel[], parentTopicsId: number[]) {
$assert(models, 'models can not be null'); $assert(models, 'models can not be null');
$assert(parentTopicsId == null || parentTopicsId.length === models.length, 'parents and models must have the same size'); $assert(
parentTopicsId == null || parentTopicsId.length === models.length,
'parents and models must have the same size',
);
super(); super();
this._models = models; this._models = models;

View File

@ -46,14 +46,14 @@ class DeleteCommand extends Command {
} }
/** /**
* Overrides abstract parent method * Overrides abstract parent method
*/ */
execute(commandContext: CommandContext) { execute(commandContext: CommandContext) {
// If a parent has been selected for deletion, the children must be excluded from the delete ... // If a parent has been selected for deletion, the children must be excluded from the delete ...
const topics = this._filterChildren(this._topicIds, commandContext); const topics = this._filterChildren(this._topicIds, commandContext);
if (topics.length > 0) { if (topics.length > 0) {
topics.forEach(((topic) => { topics.forEach((topic) => {
// In case that it's editing text node, force close without update ... // In case that it's editing text node, force close without update ...
topic.closeEditors(); topic.closeEditors();
@ -81,22 +81,22 @@ class DeleteCommand extends Command {
// Finally, delete the topic from the workspace... // Finally, delete the topic from the workspace...
commandContext.deleteTopic(topic); commandContext.deleteTopic(topic);
})); });
} }
const rels = commandContext.findRelationships(this._relIds); const rels = commandContext.findRelationships(this._relIds);
if (rels.length > 0) { if (rels.length > 0) {
rels.forEach(((rel) => { rels.forEach((rel) => {
this._deletedRelModel.push(rel.getModel().clone()); this._deletedRelModel.push(rel.getModel().clone());
commandContext.deleteRelationship(rel); commandContext.deleteRelationship(rel);
})); });
} }
} }
/** /**
* Overrides abstract parent method * Overrides abstract parent method
* @see {@link mindplot.Command.undoExecute} * @see {@link mindplot.Command.undoExecute}
*/ */
undoExecute(commandContext: CommandContext) { undoExecute(commandContext: CommandContext) {
// Add all the topics ... // Add all the topics ...
this._deletedTopicModels.forEach((model) => { this._deletedTopicModels.forEach((model) => {
@ -104,7 +104,7 @@ class DeleteCommand extends Command {
}); });
// Do they need to be connected ? // Do they need to be connected ?
this._deletedTopicModels.forEach(((topicModel, index) => { this._deletedTopicModels.forEach((topicModel, index) => {
const topics = commandContext.findTopics([topicModel.getId()]); const topics = commandContext.findTopics([topicModel.getId()]);
const parentId = this._parentTopicIds[index]; const parentId = this._parentTopicIds[index];
@ -112,7 +112,7 @@ class DeleteCommand extends Command {
const parentTopics = commandContext.findTopics([parentId]); const parentTopics = commandContext.findTopics([parentId]);
commandContext.connect(topics[0], parentTopics[0]); commandContext.connect(topics[0], parentTopics[0]);
} }
})); });
// Add rebuild relationships ... // Add rebuild relationships ...
this._deletedRelModel.forEach((model) => { this._deletedRelModel.forEach((model) => {
@ -165,11 +165,10 @@ class DeleteCommand extends Command {
result = result.concat(topic.getRelationships()); result = result.concat(topic.getRelationships());
const children = topic.getChildren(); const children = topic.getChildren();
const rels: (Relationship[])[] = children const rels: Relationship[][] = children.map((t: Topic) => this._collectInDepthRelationships(t));
.map(((t: Topic) => this._collectInDepthRelationships(t)));
// flatten and concact // flatten and concact
result = result.concat(([].concat(...rels))); result = result.concat([].concat(...rels));
if (result.length > 0) { if (result.length > 0) {
// Filter for unique ... // Filter for unique ...

View File

@ -31,9 +31,9 @@ class DragTopicCommand extends Command {
private _order: number; private _order: number;
/** /**
* @classdesc This command class handles do/undo of dragging a topic to a new position. * @classdesc This command class handles do/undo of dragging a topic to a new position.
* @constructs * @constructs
*/ */
constructor(topicId: number, position: Point, order: number, parentTopic: Topic) { constructor(topicId: number, position: Point, order: number, parentTopic: Topic) {
$assert(topicId, 'topicId must be defined'); $assert(topicId, 'topicId must be defined');
super(); super();

View File

@ -29,11 +29,15 @@ class GenericFunctionCommand extends Command {
private _commandFunc: (topic: Topic, value: CommandTypes) => CommandTypes; private _commandFunc: (topic: Topic, value: CommandTypes) => CommandTypes;
private _oldValues: (CommandTypes)[]; private _oldValues: CommandTypes[];
private _applied: boolean; private _applied: boolean;
constructor(commandFunc: (topic: Topic, value: CommandTypes) => CommandTypes, topicsIds: number[], value: CommandTypes = undefined) { constructor(
commandFunc: (topic: Topic, value: CommandTypes) => CommandTypes,
topicsIds: number[],
value: CommandTypes = undefined,
) {
$assert(commandFunc, 'commandFunc must be defined'); $assert(commandFunc, 'commandFunc must be defined');
$assert($defined(topicsIds), 'topicsIds must be defined'); $assert($defined(topicsIds), 'topicsIds must be defined');
@ -45,8 +49,8 @@ class GenericFunctionCommand extends Command {
} }
/** /**
* Overrides abstract parent method * Overrides abstract parent method
*/ */
execute(commandContext: CommandContext) { execute(commandContext: CommandContext) {
if (!this._applied) { if (!this._applied) {
const topics = commandContext.findTopics(this._topicsIds); const topics = commandContext.findTopics(this._topicsIds);
@ -68,9 +72,9 @@ class GenericFunctionCommand extends Command {
if (this._applied) { if (this._applied) {
const topics = commandContext.findTopics(this._topicsIds); const topics = commandContext.findTopics(this._topicsIds);
topics.forEach(((topic: Topic, index: number) => { topics.forEach((topic: Topic, index: number) => {
this._commandFunc(topic, this._oldValues[index]); this._commandFunc(topic, this._oldValues[index]);
})); });
this._applied = false; this._applied = false;
this._oldValues = []; this._oldValues = [];

View File

@ -28,9 +28,9 @@ class RemoveFeatureFromTopicCommand extends Command {
private _oldFeature: FeatureModel; private _oldFeature: FeatureModel;
/** /**
* @classdesc This command handles do/undo of removing a feature from a topic, e.g. an icon or * @classdesc This command handles do/undo of removing a feature from a topic, e.g. an icon or
* a note. For a reference of existing features, refer to {@link mindplot.TopicFeature}. * a note. For a reference of existing features, refer to {@link mindplot.TopicFeature}.
*/ */
constructor(topicId: number, featureId: number) { constructor(topicId: number, featureId: number) {
$assert($defined(topicId), 'topicId can not be null'); $assert($defined(topicId), 'topicId can not be null');
$assert(featureId, 'iconModel can not be null'); $assert(featureId, 'iconModel can not be null');
@ -42,8 +42,8 @@ class RemoveFeatureFromTopicCommand extends Command {
} }
/** /**
* Overrides abstract parent method * Overrides abstract parent method
*/ */
execute(commandContext: CommandContext): void { execute(commandContext: CommandContext): void {
const topic = commandContext.findTopics([this._topicId])[0]; const topic = commandContext.findTopics([this._topicId])[0];
const feature = topic.findFeatureById(this._featureId); const feature = topic.findFeatureById(this._featureId);
@ -52,9 +52,9 @@ class RemoveFeatureFromTopicCommand extends Command {
} }
/** /**
* Overrides abstract parent method * Overrides abstract parent method
* @see {@link mindplot.Command.undoExecute} * @see {@link mindplot.Command.undoExecute}
*/ */
undoExecute(commandContext: CommandContext) { undoExecute(commandContext: CommandContext) {
const topic = commandContext.findTopics([this._topicId])[0]; const topic = commandContext.findTopics([this._topicId])[0];
topic.addFeature(this._oldFeature); topic.addFeature(this._oldFeature);

View File

@ -29,7 +29,13 @@ class BinaryImageExporter extends Exporter {
private adjustToFit: boolean; private adjustToFit: boolean;
constructor(svgElement: Element, width: number, height: number, imgFormat: 'image/png' | 'image/jpeg', adjustToFit = true) { constructor(
svgElement: Element,
width: number,
height: number,
imgFormat: 'image/png' | 'image/jpeg',
adjustToFit = true,
) {
super(imgFormat.split('/')[0], imgFormat); super(imgFormat.split('/')[0], imgFormat);
this.svgElement = svgElement; this.svgElement = svgElement;
this.adjustToFit = adjustToFit; this.adjustToFit = adjustToFit;
@ -55,12 +61,12 @@ class BinaryImageExporter extends Exporter {
if (this.adjustToFit) { if (this.adjustToFit) {
// Size must match with SVG image size ... // Size must match with SVG image size ...
const size = svgExporter.getImgSize(); const size = svgExporter.getImgSize();
width = (size.width * dpr); width = size.width * dpr;
height = (size.height * dpr); height = size.height * dpr;
} else { } else {
// Use screensize as size .. // Use screensize as size ..
width = (this.width * dpr); width = this.width * dpr;
height = (this.height * dpr); height = this.height * dpr;
} }
console.log(`Export size: ${width}:${height}`); console.log(`Export size: ${width}:${height}`);

View File

@ -77,7 +77,11 @@ class FreemindExporter extends Exporter {
if (centralTopic) { if (centralTopic) {
this.nodeMap.set(centralTopic.getId(), main); this.nodeMap.set(centralTopic.getId(), main);
this.setTopicPropertiesToNode({ freemindNode: main, mindmapTopic: centralTopic, isRoot: true }); this.setTopicPropertiesToNode({
freemindNode: main,
mindmapTopic: centralTopic,
isRoot: true,
});
this.addNodeFromTopic(centralTopic, main); this.addNodeFromTopic(centralTopic, main);
} }
@ -91,9 +95,13 @@ class FreemindExporter extends Exporter {
arrowlink.setDestination(destNode.getId()); arrowlink.setDestination(destNode.getId());
if (relationship.getEndArrow() && relationship.getEndArrow()) arrowlink.setEndarrow('Default'); if (relationship.getEndArrow() && relationship.getEndArrow()) {
arrowlink.setEndarrow('Default');
}
if (relationship.getStartArrow() && relationship.getStartArrow()) arrowlink.setStartarrow('Default'); if (relationship.getStartArrow() && relationship.getStartArrow()) {
arrowlink.setStartarrow('Default');
}
srcNode.setArrowlinkOrCloudOrEdge(arrowlink); srcNode.setArrowlinkOrCloudOrEdge(arrowlink);
} }
@ -110,7 +118,15 @@ class FreemindExporter extends Exporter {
return Promise.resolve(formatXml); return Promise.resolve(formatXml);
} }
private setTopicPropertiesToNode({ freemindNode, mindmapTopic, isRoot }: { freemindNode: FreeminNode; mindmapTopic: INodeModel; isRoot: boolean; }): void { private setTopicPropertiesToNode({
freemindNode,
mindmapTopic,
isRoot,
}: {
freemindNode: FreeminNode;
mindmapTopic: INodeModel;
isRoot: boolean;
}): void {
freemindNode.setId(`ID_${mindmapTopic.getId()}`); freemindNode.setId(`ID_${mindmapTopic.getId()}`);
const text = mindmapTopic.getText(); const text = mindmapTopic.getText();
@ -154,7 +170,11 @@ class FreemindExporter extends Exporter {
const newNode: FreeminNode = this.objectFactory.createNode(); const newNode: FreeminNode = this.objectFactory.createNode();
this.nodeMap.set(currentTopic.getId(), newNode); this.nodeMap.set(currentTopic.getId(), newNode);
this.setTopicPropertiesToNode({ freemindNode: newNode, mindmapTopic: currentTopic, isRoot: false }); this.setTopicPropertiesToNode({
freemindNode: newNode,
mindmapTopic: currentTopic,
isRoot: false,
});
destNode.setArrowlinkOrCloudOrEdge(newNode); destNode.setArrowlinkOrCloudOrEdge(newNode);
@ -163,7 +183,7 @@ class FreemindExporter extends Exporter {
const position: PositionNodeType = currentTopic.getPosition(); const position: PositionNodeType = currentTopic.getPosition();
if (position) { if (position) {
const xPos: number = position.x; const xPos: number = position.x;
newNode.setPosition((xPos < 0 ? 'left' : 'right')); newNode.setPosition(xPos < 0 ? 'left' : 'right');
} else newNode.setPosition('left'); } else newNode.setPosition('left');
}); });
} }
@ -193,28 +213,27 @@ class FreemindExporter extends Exporter {
private addFeautreNode(freemindNode: FreeminNode, mindmapTopic: INodeModel): void { private addFeautreNode(freemindNode: FreeminNode, mindmapTopic: INodeModel): void {
const branches: Array<FeatureModel> = mindmapTopic.getFeatures(); const branches: Array<FeatureModel> = mindmapTopic.getFeatures();
branches branches.forEach((feature: FeatureModel) => {
.forEach((feature: FeatureModel) => { const type = feature.getType();
const type = feature.getType();
if (type === 'link') { if (type === 'link') {
const link = feature as LinkModel; const link = feature as LinkModel;
freemindNode.setLink(link.getUrl()); freemindNode.setLink(link.getUrl());
} }
if (type === 'note') { if (type === 'note') {
const note = feature as NoteModel; const note = feature as NoteModel;
const richcontent: Richcontent = this.buildRichcontent(note.getText(), 'NOTE'); const richcontent: Richcontent = this.buildRichcontent(note.getText(), 'NOTE');
freemindNode.setArrowlinkOrCloudOrEdge(richcontent); freemindNode.setArrowlinkOrCloudOrEdge(richcontent);
} }
if (type === 'icon') { if (type === 'icon') {
const icon = feature as IconModel; const icon = feature as IconModel;
const freemindIcon: Icon = new Icon(); const freemindIcon: Icon = new Icon();
freemindIcon.setBuiltin(icon.getIconType()); freemindIcon.setBuiltin(icon.getIconType());
freemindNode.setArrowlinkOrCloudOrEdge(freemindIcon); freemindNode.setArrowlinkOrCloudOrEdge(freemindIcon);
} }
}); });
} }
private addEdgeNode(freemainMap: FreeminNode, mindmapTopic: INodeModel): void { private addEdgeNode(freemainMap: FreeminNode, mindmapTopic: INodeModel): void {
@ -286,7 +305,9 @@ class FreemindExporter extends Exporter {
const g: string = rgb[1].trim(); const g: string = rgb[1].trim();
const b: string = rgb[2].trim(); const b: string = rgb[2].trim();
result = `#${r.length === 1 ? `0${r}` : r}${g.length === 1 ? `0${g}` : g}${b.length === 1 ? `0${b}` : b}`; result = `#${r.length === 1 ? `0${r}` : r}${g.length === 1 ? `0${g}` : g}${
b.length === 1 ? `0${b}` : b
}`;
} }
} }
return result; return result;

View File

@ -21,7 +21,13 @@ import SVGExporter from './SVGExporter';
type imageType = 'svg' | 'png' | 'jpg'; type imageType = 'svg' | 'png' | 'jpg';
class ImageExpoterFactory { class ImageExpoterFactory {
static create(type: imageType, svgElement: Element, width: number, height: number, adjustToFit = true): Exporter { static create(
type: imageType,
svgElement: Element,
width: number,
height: number,
adjustToFit = true,
): Exporter {
let result: Exporter; let result: Exporter;
switch (type) { switch (type) {
case 'svg': { case 'svg': {

View File

@ -39,8 +39,7 @@ class SVGExporter extends Exporter {
export(): Promise<string> { export(): Promise<string> {
// Replace all images for in-line images ... // Replace all images for in-line images ...
let svgTxt: string = new XMLSerializer() let svgTxt: string = new XMLSerializer().serializeToString(this.svgElement);
.serializeToString(this.svgElement);
svgTxt = SVGExporter.prolog + svgTxt; svgTxt = SVGExporter.prolog + svgTxt;
// Are namespace declared ?. Otherwise, force the declaration ... // Are namespace declared ?. Otherwise, force the declaration ...
@ -59,39 +58,37 @@ class SVGExporter extends Exporter {
svgDoc = this._normalizeToFit(svgDoc); svgDoc = this._normalizeToFit(svgDoc);
} }
const result = new XMLSerializer() const result = new XMLSerializer().serializeToString(svgDoc);
.serializeToString(svgDoc);
return Promise.resolve(result); return Promise.resolve(result);
} }
private _calcualteDimensions(): { minX: number, maxX: number, minY: number, maxY: number } { private _calcualteDimensions(): { minX: number; maxX: number; minY: number; maxY: number } {
// Collect all group elements ... // Collect all group elements ...
const rectElems = Array.from(document.querySelectorAll('g>rect')); const rectElems = Array.from(document.querySelectorAll('g>rect'));
const translates: SizeType[] = rectElems const translates: SizeType[] = rectElems.map((rect: Element) => {
.map((rect: Element) => { const g = rect.parentElement;
const g = rect.parentElement; const transformStr = g.getAttribute('transform');
const transformStr = g.getAttribute('transform');
// Looking to parse translate(220.00000,279.00000) scale(1.00000,1.00000) // Looking to parse translate(220.00000,279.00000) scale(1.00000,1.00000)
const match = transformStr.match(SVGExporter.regexpTranslate); const match = transformStr.match(SVGExporter.regexpTranslate);
let result: SizeType = { width: 0, height: 0 }; let result: SizeType = { width: 0, height: 0 };
if (match !== null) { if (match !== null) {
result = { width: Number.parseFloat(match[1]), height: Number.parseFloat(match[2]) }; result = { width: Number.parseFloat(match[1]), height: Number.parseFloat(match[2]) };
// Add rect size ... // Add rect size ...
if (result.width > 0) { if (result.width > 0) {
const rectWidth = Number.parseFloat(rect.getAttribute('width')); const rectWidth = Number.parseFloat(rect.getAttribute('width'));
result.width += rectWidth; result.width += rectWidth;
}
if (result.height > 0) {
const rectHeight = Number.parseFloat(rect.getAttribute('height'));
result.height += rectHeight;
}
} }
return result;
}); if (result.height > 0) {
const rectHeight = Number.parseFloat(rect.getAttribute('height'));
result.height += rectHeight;
}
}
return result;
});
// Find max and mins ... // Find max and mins ...
const widths = translates.map((t) => t.width).sort((a, b) => a - b); const widths = translates.map((t) => t.width).sort((a, b) => a - b);
@ -104,14 +101,15 @@ class SVGExporter extends Exporter {
const maxY = heights[heights.length - 1] + SVGExporter.padding; const maxY = heights[heights.length - 1] + SVGExporter.padding;
return { return {
minX, maxX, minY, maxY, minX,
maxX,
minY,
maxY,
}; };
} }
getImgSize(): SizeType { getImgSize(): SizeType {
const { const { minX, maxX, minY, maxY } = this._calcualteDimensions();
minX, maxX, minY, maxY,
} = this._calcualteDimensions();
let width: number = maxX + Math.abs(minX); let width: number = maxX + Math.abs(minX);
let height: number = maxY + Math.abs(minY); let height: number = maxY + Math.abs(minY);
@ -127,9 +125,7 @@ class SVGExporter extends Exporter {
} }
private _normalizeToFit(document: Document): Document { private _normalizeToFit(document: Document): Document {
const { const { minX, maxX, minY, maxY } = this._calcualteDimensions();
minX, maxX, minY, maxY,
} = this._calcualteDimensions();
const svgElem = document.firstChild as Element; const svgElem = document.firstChild as Element;
const width = maxX + Math.abs(minX); const width = maxX + Math.abs(minX);

View File

@ -39,22 +39,23 @@ class TxtExporter extends Exporter {
private traverseBranch(indent: string, prefix: string, branches: INodeModel[]) { private traverseBranch(indent: string, prefix: string, branches: INodeModel[]) {
let result = ''; let result = '';
branches branches.forEach((node, index) => {
.forEach((node, index) => { result = `${result}${indent}${prefix}${index + 1} ${
result = `${result}${indent}${prefix}${index + 1} ${node.getText() !== undefined ? node.getText() : ''}`; node.getText() !== undefined ? node.getText() : ''
node.getFeatures().forEach((f) => { }`;
const type = f.getType(); node.getFeatures().forEach((f) => {
if (type === 'link') { const type = f.getType();
result = `${result}\n ${indent} [Link: ${(f as LinkModel).getUrl()}]`; if (type === 'link') {
} result = `${result}\n ${indent} [Link: ${(f as LinkModel).getUrl()}]`;
if (type === 'note') { }
result = `${result}\n${indent} [Note: ${(f as NoteModel).getText()}]`; if (type === 'note') {
} result = `${result}\n${indent} [Note: ${(f as NoteModel).getText()}]`;
}); }
result = `${result}\n`;
result += this.traverseBranch(`\t${indent}`, `${prefix}${index + 1}.`, node.getChildren());
}); });
result = `${result}\n`;
result += this.traverseBranch(`\t${indent}`, `${prefix}${index + 1}.`, node.getChildren());
});
return result; return result;
} }
} }

View File

@ -29,12 +29,10 @@ class WiseXMLExporter extends Exporter {
export(): Promise<string> { export(): Promise<string> {
const { mindmap } = this; const { mindmap } = this;
const serializer = XMLSerializerFactory const serializer = XMLSerializerFactory.createInstanceFromMindmap(mindmap);
.createInstanceFromMindmap(mindmap);
const document: Document = serializer.toXML(mindmap); const document: Document = serializer.toXML(mindmap);
const xmlStr: string = new XMLSerializer() const xmlStr: string = new XMLSerializer().serializeToString(document);
.serializeToString(document);
return Promise.resolve(xmlStr); return Promise.resolve(xmlStr);
} }
} }

View File

@ -75,11 +75,21 @@ export default class Arrowlink {
arrowlinkElem.setAttribute('DESTINATION', this.DESTINATION); arrowlinkElem.setAttribute('DESTINATION', this.DESTINATION);
arrowlinkElem.setAttribute('STARTARROW', this.STARTARROW); arrowlinkElem.setAttribute('STARTARROW', this.STARTARROW);
if (this.COLOR) arrowlinkElem.setAttribute('COLOR', this.COLOR); if (this.COLOR) {
if (this.ENDINCLINATION) arrowlinkElem.setAttribute('ENDINCLINATION', this.ENDINCLINATION); arrowlinkElem.setAttribute('COLOR', this.COLOR);
if (this.ENDARROW) arrowlinkElem.setAttribute('ENDARROW', this.ENDARROW); }
if (this.ID) arrowlinkElem.setAttribute('ID', this.ID); if (this.ENDINCLINATION) {
if (this.STARTINCLINATION) arrowlinkElem.setAttribute('STARTINCLINATION', this.STARTINCLINATION); arrowlinkElem.setAttribute('ENDINCLINATION', this.ENDINCLINATION);
}
if (this.ENDARROW) {
arrowlinkElem.setAttribute('ENDARROW', this.ENDARROW);
}
if (this.ID) {
arrowlinkElem.setAttribute('ID', this.ID);
}
if (this.STARTINCLINATION) {
arrowlinkElem.setAttribute('STARTINCLINATION', this.STARTINCLINATION);
}
return arrowlinkElem; return arrowlinkElem;
} }

View File

@ -65,10 +65,7 @@ export default class Freemap {
// Verify that the version attribute exists // Verify that the version attribute exists
console.log(rootElem.getAttribute('version')); console.log(rootElem.getAttribute('version'));
$assert( $assert(rootElem.getAttribute('version') !== null, 'Freemind version not found');
rootElem.getAttribute('version') !== null,
'Freemind version not found',
);
// Start the loading process... // Start the loading process...
const version = rootElem.getAttribute('version') || '1.0.1'; const version = rootElem.getAttribute('version') || '1.0.1';
@ -81,9 +78,7 @@ export default class Freemap {
const childNodes = Array.from(mainTopicElement.childNodes); const childNodes = Array.from(mainTopicElement.childNodes);
const childsNodes = childNodes const childsNodes = childNodes
.filter( .filter((child: ChildNode) => child.nodeType === 1 && (child as Element).tagName === 'node')
(child: ChildNode) => child.nodeType === 1 && (child as Element).tagName === 'node',
)
.map((c) => c as Element); .map((c) => c as Element);
childsNodes.forEach((child: Element) => { childsNodes.forEach((child: Element) => {
@ -98,14 +93,16 @@ export default class Freemap {
let element: Element; let element: Element;
if (child.nodeType === 1) { if (child.nodeType === 1) {
if ( if (
(child as Element).tagName === 'node' (child as Element).tagName === 'node' ||
|| (child as Element).tagName === 'richcontent' (child as Element).tagName === 'richcontent' ||
|| (child as Element).tagName === 'font' (child as Element).tagName === 'font' ||
|| (child as Element).tagName === 'edge' (child as Element).tagName === 'edge' ||
|| (child as Element).tagName === 'arrowlink' (child as Element).tagName === 'arrowlink' ||
|| (child as Element).tagName === 'clud' (child as Element).tagName === 'clud' ||
|| (child as Element).tagName === 'icon' (child as Element).tagName === 'icon'
) element = child as Element; ) {
element = child as Element;
}
} }
return element; return element;
@ -132,44 +129,78 @@ export default class Freemap {
if (nodeElem.tagName === 'font') { if (nodeElem.tagName === 'font') {
node = new Font(); node = new Font();
if (nodeElem.getAttribute('NAME')) node.setName(nodeElem.getAttribute('NAME')); if (nodeElem.getAttribute('NAME')) {
if (nodeElem.getAttribute('BOLD')) node.setBold(nodeElem.getAttribute('BOLD')); node.setName(nodeElem.getAttribute('NAME'));
if (nodeElem.getAttribute('ITALIC')) node.setItalic(nodeElem.getAttribute('ITALIC')); }
if (nodeElem.getAttribute('SIZE')) node.setSize(nodeElem.getAttribute('SIZE')); 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') { if (nodeElem.tagName === 'edge') {
node = new Edge(); node = new Edge();
if (nodeElem.getAttribute('COLOR')) node.setColor(nodeElem.getAttribute('COLOR')); if (nodeElem.getAttribute('COLOR')) {
if (nodeElem.getAttribute('STYLE')) node.setStyle(nodeElem.getAttribute('STYLE')); node.setColor(nodeElem.getAttribute('COLOR'));
if (nodeElem.getAttribute('WIDTH')) node.setWidth(nodeElem.getAttribute('WIDTH')); }
if (nodeElem.getAttribute('STYLE')) {
node.setStyle(nodeElem.getAttribute('STYLE'));
}
if (nodeElem.getAttribute('WIDTH')) {
node.setWidth(nodeElem.getAttribute('WIDTH'));
}
} }
if (nodeElem.tagName === 'arrowlink') { if (nodeElem.tagName === 'arrowlink') {
node = new Arrowlink(); node = new Arrowlink();
if (nodeElem.getAttribute('COLOR')) node.setColor(nodeElem.getAttribute('COLOR')); if (nodeElem.getAttribute('COLOR')) {
if (nodeElem.getAttribute('DESTINATION')) node.setDestination(nodeElem.getAttribute('DESTINATION')); node.setColor(nodeElem.getAttribute('COLOR'));
if (nodeElem.getAttribute('ENDARROW')) node.setEndarrow(nodeElem.getAttribute('ENDARROW')); }
if (nodeElem.getAttribute('ENDINCLINATION')) node.setEndinclination(nodeElem.getAttribute('ENDINCLINATION')); if (nodeElem.getAttribute('DESTINATION')) {
if (nodeElem.getAttribute('ID')) node.setId(nodeElem.getAttribute('ID')); node.setDestination(nodeElem.getAttribute('DESTINATION'));
if (nodeElem.getAttribute('STARTARROW')) node.setStartarrow(nodeElem.getAttribute('STARTARROW')); }
if (nodeElem.getAttribute('STARTINCLINATION')) node.setStartinclination(nodeElem.getAttribute('STARTINCLINATION')); 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') { if (nodeElem.tagName === 'cloud') {
node = new Cloud(); node = new Cloud();
if (nodeElem.getAttribute('COLOR')) node.setColor(nodeElem.getAttribute('COLOR')); if (nodeElem.getAttribute('COLOR')) {
node.setColor(nodeElem.getAttribute('COLOR'));
}
} }
if (nodeElem.tagName === 'icon') { if (nodeElem.tagName === 'icon') {
node = new Icon(); node = new Icon();
if (nodeElem.getAttribute('BUILTIN')) node.setBuiltin(nodeElem.getAttribute('BUILTIN')); if (nodeElem.getAttribute('BUILTIN')) {
node.setBuiltin(nodeElem.getAttribute('BUILTIN'));
}
} }
if (nodeElem.tagName === 'richcontent') { if (nodeElem.tagName === 'richcontent') {
node = new Richcontent(); node = new Richcontent();
if (nodeElem.getAttribute('TYPE')) node.setType(nodeElem.getAttribute('TYPE')); if (nodeElem.getAttribute('TYPE')) {
node.setType(nodeElem.getAttribute('TYPE'));
}
if (nodeElem.firstChild && nodeElem.getElementsByTagName('html')) { if (nodeElem.firstChild && nodeElem.getElementsByTagName('html')) {
const content = nodeElem.getElementsByTagName('html'); const content = nodeElem.getElementsByTagName('html');
const html = content[0] ? content[0].outerHTML : ''; const html = content[0] ? content[0].outerHTML : '';

View File

@ -7,7 +7,9 @@ import Icon from './Icon';
import Richcontent from './Richcontent'; import Richcontent from './Richcontent';
class Node { class Node {
protected arrowlinkOrCloudOrEdge: Array<Arrowlink | Cloud | Edge | Font | Hook | Icon | Richcontent | this>; protected arrowlinkOrCloudOrEdge: Array<
Arrowlink | Cloud | Edge | Font | Hook | Icon | Richcontent | this
>;
protected BACKGROUND_COLOR: string; protected BACKGROUND_COLOR: string;
@ -43,9 +45,14 @@ class Node {
private centralTopic: boolean; private centralTopic: boolean;
getArrowlinkOrCloudOrEdge(): Array<Arrowlink | Cloud | Edge | Font | Hook | Icon | Richcontent | Node> { getArrowlinkOrCloudOrEdge(): Array<
/* eslint-disable */
Arrowlink | Cloud | Edge | Font | Hook | Icon | Richcontent | Node
> {
if (!this.arrowlinkOrCloudOrEdge) { if (!this.arrowlinkOrCloudOrEdge) {
this.arrowlinkOrCloudOrEdge = new Array<Arrowlink | Cloud | Edge | Font | Hook | Icon | Richcontent | this>(); this.arrowlinkOrCloudOrEdge = new Array<
Arrowlink | Cloud | Edge | Font | Hook | Icon | Richcontent | this
>();
} }
return this.arrowlinkOrCloudOrEdge; return this.arrowlinkOrCloudOrEdge;
} }
@ -118,7 +125,9 @@ class Node {
return this.centralTopic; return this.centralTopic;
} }
setArrowlinkOrCloudOrEdge(value: Arrowlink | Cloud | Edge | Font | Hook | Icon | Richcontent | this): void { setArrowlinkOrCloudOrEdge(
value: Arrowlink | Cloud | Edge | Font | Hook | Icon | Richcontent | this,
): void {
this.getArrowlinkOrCloudOrEdge().push(value); this.getArrowlinkOrCloudOrEdge().push(value);
} }
@ -268,6 +277,6 @@ class Node {
} }
} }
export type Choise = Arrowlink | Cloud | Edge | Font | Hook | Icon | Richcontent | Node export type Choise = Arrowlink | Cloud | Edge | Font | Hook | Icon | Richcontent | Node;
export default Node; export default Node;

View File

@ -26,7 +26,9 @@ export default class Richcontent {
richcontentElem.setAttribute('TYPE', this.type); richcontentElem.setAttribute('TYPE', this.type);
if (this.html) { if (this.html) {
const htmlElement: DocumentFragment = document.createRange().createContextualFragment(this.html); const htmlElement: DocumentFragment = document
.createRange()
.createContextualFragment(this.html);
richcontentElem.appendChild(htmlElement); richcontentElem.appendChild(htmlElement);
} }

View File

@ -50,7 +50,9 @@ export default class FreemindImporter extends Importer {
const version: string = this.freemindMap.getVersion(); const version: string = this.freemindMap.getVersion();
if (!version || version.startsWith('freeplane')) { if (!version || version.startsWith('freeplane')) {
throw new Error('You seems to be be trying to import a Freeplane map. FreePlane is not supported format.'); throw new Error(
'You seems to be be trying to import a Freeplane map. FreePlane is not supported format.',
);
} else { } else {
const mapVersion: VersionNumber = new VersionNumber(version); const mapVersion: VersionNumber = new VersionNumber(version);
if (mapVersion.isGreaterThan(FreemindConstant.SUPPORTED_FREEMIND_VERSION)) { if (mapVersion.isGreaterThan(FreemindConstant.SUPPORTED_FREEMIND_VERSION)) {
@ -144,7 +146,11 @@ export default class FreemindImporter extends Importer {
} }
} }
private convertNodeProperties(freeNode: FreemindNode, wiseTopic: NodeModel, centralTopic: boolean): void { private convertNodeProperties(
freeNode: FreemindNode,
wiseTopic: NodeModel,
centralTopic: boolean,
): void {
const text: string = freeNode.getText(); const text: string = freeNode.getText();
if (text) { if (text) {
if (!centralTopic && text.length > 100) { if (!centralTopic && text.length > 100) {
@ -177,7 +183,12 @@ export default class FreemindImporter extends Importer {
if (folded) wiseTopic.setChildrenShrunken(folded); if (folded) wiseTopic.setChildrenShrunken(folded);
} }
private convertChildNodes(freeParent: FreemindNode, wiseParent: NodeModel, mindmap: Mindmap, depth: number): void { private convertChildNodes(
freeParent: FreemindNode,
wiseParent: NodeModel,
mindmap: Mindmap,
depth: number,
): void {
const freeChilden = freeParent.getArrowlinkOrCloudOrEdge(); const freeChilden = freeParent.getArrowlinkOrCloudOrEdge();
let currentWiseTopic: NodeModel = wiseParent; let currentWiseTopic: NodeModel = wiseParent;
let order = 0; let order = 0;
@ -206,7 +217,13 @@ export default class FreemindImporter extends Importer {
// Convert node position... // Convert node position...
const childrenCountSameSide = this.getChildrenCountSameSide(freeChilden, child); const childrenCountSameSide = this.getChildrenCountSameSide(freeChilden, child);
const position: {x: number, y: number} = this.convertPosition(wiseParent, child, depth, norder, childrenCountSameSide); const position: { x: number; y: number } = this.convertPosition(
wiseParent,
child,
depth,
norder,
childrenCountSameSide,
);
wiseChild.setPosition(position.x, position.y); wiseChild.setPosition(position.x, position.y);
// Convert the rest of the node properties... // Convert the rest of the node properties...
@ -239,7 +256,9 @@ export default class FreemindImporter extends Importer {
const iconId: string = freeIcon.getBuiltin(); const iconId: string = freeIcon.getBuiltin();
const wiseIconId = FreemindIconConverter.toWiseId(iconId); const wiseIconId = FreemindIconConverter.toWiseId(iconId);
if (wiseIconId) { if (wiseIconId) {
const mindmapIcon: FeatureModel = FeatureModelFactory.createModel('icon', { id: wiseIconId }); const mindmapIcon: FeatureModel = FeatureModelFactory.createModel('icon', {
id: wiseIconId,
});
currentWiseTopic.addFeature(mindmapIcon); currentWiseTopic.addFeature(mindmapIcon);
} }
} }
@ -263,7 +282,9 @@ export default class FreemindImporter extends Importer {
switch (type) { switch (type) {
case 'NOTE': { case 'NOTE': {
const noteModel: FeatureModel = FeatureModelFactory.createModel('note', { text: text || FreemindConstant.EMPTY_NOTE }); const noteModel: FeatureModel = FeatureModelFactory.createModel('note', {
text: text || FreemindConstant.EMPTY_NOTE,
});
currentWiseTopic.addFeature(noteModel); currentWiseTopic.addFeature(noteModel);
break; break;
} }
@ -274,7 +295,9 @@ export default class FreemindImporter extends Importer {
} }
default: { default: {
const noteModel: FeatureModel = FeatureModelFactory.createModel('note', { text: text || FreemindConstant.EMPTY_NOTE }); const noteModel: FeatureModel = FeatureModelFactory.createModel('note', {
text: text || FreemindConstant.EMPTY_NOTE,
});
currentWiseTopic.addFeature(noteModel); currentWiseTopic.addFeature(noteModel);
} }
} }
@ -381,7 +404,10 @@ export default class FreemindImporter extends Importer {
// Font Size // Font Size
if (font) { if (font) {
const fontSize: number = ((!font.getSize() || parseInt(font.getSize(), 10) < 8) ? FreemindConstant.FONT_SIZE_NORMAL : parseInt(font.getSize(), 10)); 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; let wiseFontSize: number = FreemindConstant.FONT_SIZE_SMALL;
if (fontSize >= 24) { if (fontSize >= 24) {
wiseFontSize = FreemindConstant.FONT_SIZE_HUGE; wiseFontSize = FreemindConstant.FONT_SIZE_HUGE;
@ -414,11 +440,19 @@ export default class FreemindImporter extends Importer {
return result; return result;
} }
private convertPosition(wiseParent: NodeModel, freeChild: FreemindNode, depth: number, order: number, childrenCount: number): {x: number, y: number} { private convertPosition(
let x: number = FreemindConstant.CENTRAL_TO_TOPIC_DISTANCE + ((depth - 1) * FreemindConstant.TOPIC_TO_TOPIC_DISTANCE); 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) { if (depth === 1) {
const side: string = freeChild.getPosition(); const side: string = freeChild.getPosition();
x *= (side && FreemindConstant.POSITION_LEFT === side ? -1 : 1); x *= side && FreemindConstant.POSITION_LEFT === side ? -1 : 1;
} else { } else {
const position = wiseParent.getPosition(); const position = wiseParent.getPosition();
x *= position.x < 0 ? 1 : -1; x *= position.x < 0 ? 1 : -1;
@ -427,7 +461,7 @@ export default class FreemindImporter extends Importer {
let y: number; let y: number;
if (depth === 1) { if (depth === 1) {
if (order % 2 === 0) { if (order % 2 === 0) {
const multiplier = ((order + 1) - childrenCount) * 2; const multiplier = (order + 1 - childrenCount) * 2;
y = multiplier * FreemindConstant.ROOT_LEVEL_TOPIC_HEIGHT; y = multiplier * FreemindConstant.ROOT_LEVEL_TOPIC_HEIGHT;
} else { } else {
const multiplier = (order - childrenCount) * 2; const multiplier = (order - childrenCount) * 2;
@ -435,7 +469,11 @@ export default class FreemindImporter extends Importer {
} }
} else { } else {
const position = wiseParent.getPosition(); const position = wiseParent.getPosition();
y = Math.round(position.y - ((childrenCount / 2) * FreemindConstant.SECOND_LEVEL_TOPIC_HEIGHT - (order * FreemindConstant.SECOND_LEVEL_TOPIC_HEIGHT))); y = Math.round(
position.y -
((childrenCount / 2) * FreemindConstant.SECOND_LEVEL_TOPIC_HEIGHT -
order * FreemindConstant.SECOND_LEVEL_TOPIC_HEIGHT),
);
} }
return { return {

View File

@ -1,3 +1,3 @@
export default abstract class Importer { export default abstract class Importer {
abstract import(nameMap: string, description: string): Promise<string>; abstract import(nameMap: string, description: string): Promise<string>;
} }

View File

@ -17,7 +17,15 @@
*/ */
import Events from '../Events'; import Events from '../Events';
export type EventType = 'topicResize' | 'topicMoved' | 'childShrinked' | 'topicConnected' | 'topicAdded' | 'topicRemoved' | 'forceLayout' | 'topicDisconect'; export type EventType =
| 'topicResize'
| 'topicMoved'
| 'childShrinked'
| 'topicConnected'
| 'topicAdded'
| 'topicRemoved'
| 'forceLayout'
| 'topicDisconect';
class EventBus extends Events { class EventBus extends Events {
// eslint-disable-next-line no-use-before-define // eslint-disable-next-line no-use-before-define
static _instance: EventBus = new EventBus(); static _instance: EventBus = new EventBus();

View File

@ -43,11 +43,11 @@ class EventBusDispatcher {
EventBus.instance.addEvent('forceLayout', this._forceLayout.bind(this)); EventBus.instance.addEvent('forceLayout', this._forceLayout.bind(this));
} }
private _topicResizeEvent(args: { node: Topic, size: SizeType }) { private _topicResizeEvent(args: { node: Topic; size: SizeType }) {
this._layoutManager.updateNodeSize(args.node.getId(), args.size); this._layoutManager.updateNodeSize(args.node.getId(), args.size);
} }
private _topicMoved(args: { node: Topic, position: PositionType }) { private _topicMoved(args: { node: Topic; position: PositionType }) {
this._layoutManager.moveNode(args.node.getId(), args.position); this._layoutManager.moveNode(args.node.getId(), args.position);
} }
@ -55,9 +55,11 @@ class EventBusDispatcher {
this._layoutManager.disconnectNode(node.getId()); this._layoutManager.disconnectNode(node.getId());
} }
private _topicConnected(args: { parentNode: Topic, childNode: Topic }) { private _topicConnected(args: { parentNode: Topic; childNode: Topic }) {
this._layoutManager.connectNode( this._layoutManager.connectNode(
args.parentNode.getId(), args.childNode.getId(), args.childNode.getOrder(), args.parentNode.getId(),
args.childNode.getId(),
args.childNode.getOrder(),
); );
} }

View File

@ -64,13 +64,13 @@ class LayoutManager extends Events {
} }
/** /**
* @param id * @param id
* @param position * @param position
* @throws will throw an error if id is null or undefined * @throws will throw an error if id is null or undefined
* @throws will throw an error if position is null or undefined * @throws will throw an error if position is null or undefined
* @throws will throw an error if the position's x property is null or undefined * @throws will throw an error if the position's x property is null or undefined
* @throws will throw an error if the position's y property is null or undefined * @throws will throw an error if the position's y property is null or undefined
*/ */
moveNode(id: number, position: PositionType) { moveNode(id: number, position: PositionType) {
$assert($defined(id), 'id cannot be null'); $assert($defined(id), 'id cannot be null');
$assert($defined(position), 'position cannot be null'); $assert($defined(position), 'position cannot be null');
@ -97,12 +97,12 @@ class LayoutManager extends Events {
} }
/** /**
* @param id * @param id
* @param size * @param size
* @param position * @param position
* @throws will throw an error if id is null or undefined * @throws will throw an error if id is null or undefined
* @return this * @return this
*/ */
addNode(id: number, size: SizeType, position: PositionType) { addNode(id: number, size: SizeType, position: PositionType) {
$assert($defined(id), 'id can not be null'); $assert($defined(id), 'id can not be null');
const result = this._layout.createNode(id, size, position, 'topic'); const result = this._layout.createNode(id, size, position, 'topic');
@ -126,7 +126,11 @@ class LayoutManager extends Events {
return this; return this;
} }
predict(parentId: number, nodeId: number, position: PositionType): { order: number, position: PositionType } { predict(
parentId: number,
nodeId: number,
position: PositionType,
): { order: number; position: PositionType } {
$assert($defined(parentId), 'parentId can not be null'); $assert($defined(parentId), 'parentId can not be null');
const parent = this._treeSet.find(parentId); const parent = this._treeSet.find(parentId);
@ -179,14 +183,14 @@ class LayoutManager extends Events {
} }
private _flushEvents() { private _flushEvents() {
this._events.forEach(((event) => { this._events.forEach((event) => {
this.fireEvent('change', event); this.fireEvent('change', event);
})); });
this._events = []; this._events = [];
} }
private _collectChanges(nodes: Node[]) { private _collectChanges(nodes: Node[]) {
nodes.forEach(((node) => { nodes.forEach((node) => {
if (node.hasOrderChanged() || node.hasPositionChanged()) { if (node.hasOrderChanged() || node.hasPositionChanged()) {
// Find or create a event ... // Find or create a event ...
const id = node.getId(); const id = node.getId();
@ -205,7 +209,7 @@ class LayoutManager extends Events {
this._events.push(event); this._events.push(event);
} }
this._collectChanges(this._treeSet.getChildren(node)); this._collectChanges(this._treeSet.getChildren(node));
})); });
} }
} }

View File

@ -186,10 +186,12 @@ class Node {
// This is a performance improvement to avoid movements that really could be avoided. // This is a performance improvement to avoid movements that really could be avoided.
const currentPos = this.getPosition(); const currentPos = this.getPosition();
if ( if (
currentPos == null currentPos == null ||
|| Math.abs(currentPos.x - position.x) > 2 Math.abs(currentPos.x - position.x) > 2 ||
|| Math.abs(currentPos.y - position.y) > 2 Math.abs(currentPos.y - position.y) > 2
) this._setProperty('position', position); ) {
this._setProperty('position', position);
}
} }
_setProperty(key: string, value) { _setProperty(key: string, value) {
@ -228,16 +230,11 @@ class Node {
/** @return {String} returns id, order, position, size and shrink information */ /** @return {String} returns id, order, position, size and shrink information */
toString() { toString() {
return ( return `[id:${this.getId()}, order:${this.getOrder()}, position: {${this.getPosition().x},${
`[id:${this.getId() this.getPosition().y
}, order:${this.getOrder() }}, size: {${this.getSize().width},${
}, position: {${this.getPosition().x this.getSize().height
},${this.getPosition().y }}, shrink:${this.areChildrenShrunken()}]`;
}}, size: {${this.getSize().width
},${this.getSize().height
}}, shrink:${this.areChildrenShrunken()
}]`
);
} }
} }

View File

@ -62,12 +62,12 @@ class RootedTreeSet {
} }
/** /**
* @param parentId * @param parentId
* @param childId * @param childId
* @throws will throw an error if parentId is null or undefined * @throws will throw an error if parentId is null or undefined
* @throws will throw an error if childId is null or undefined * @throws will throw an error if childId is null or undefined
* @throws will throw an error if node with id childId is already a child of parent * @throws will throw an error if node with id childId is already a child of parent
*/ */
connect(parentId: number, childId: number) { connect(parentId: number, childId: number) {
$assert($defined(parentId), 'parent can not be null'); $assert($defined(parentId), 'parent can not be null');
$assert($defined(childId), 'child can not be null'); $assert($defined(childId), 'child can not be null');
@ -85,10 +85,10 @@ class RootedTreeSet {
} }
/** /**
* @param nodeId * @param nodeId
* @throws will throw an error if nodeId is null or undefined * @throws will throw an error if nodeId is null or undefined
* @throws will throw an error if node is not connected * @throws will throw an error if node is not connected
*/ */
disconnect(nodeId: number) { disconnect(nodeId: number) {
$assert($defined(nodeId), 'nodeId can not be null'); $assert($defined(nodeId), 'nodeId can not be null');
const node = this.find(nodeId); const node = this.find(nodeId);
@ -100,12 +100,12 @@ class RootedTreeSet {
} }
/** /**
* @param id * @param id
* @param validate * @param validate
* @throws will throw an error if id is null or undefined * @throws will throw an error if id is null or undefined
* @throws will throw an error if node cannot be found * @throws will throw an error if node cannot be found
* @return node * @return node
*/ */
find(id: number, validate = true): Node { find(id: number, validate = true): Node {
$assert($defined(id), 'id can not be null'); $assert($defined(id), 'id can not be null');
@ -143,20 +143,20 @@ class RootedTreeSet {
} }
/** /**
* @param node * @param node
* @throws will throw an error if nodeId is null or undefined * @throws will throw an error if nodeId is null or undefined
* @return children * @return children
*/ */
getChildren(node: Node): Node[] { getChildren(node: Node): Node[] {
$assert(node, 'node cannot be null'); $assert(node, 'node cannot be null');
return node._children; return node._children;
} }
/** /**
* @param node * @param node
* @throws will throw an error if node is null or undefined * @throws will throw an error if node is null or undefined
* @return root node or the provided node, if it has no parent * @return root node or the provided node, if it has no parent
*/ */
getRootNode(node: Node) { getRootNode(node: Node) {
$assert(node, 'node cannot be null'); $assert(node, 'node cannot be null');
const parent = this.getParent(node); const parent = this.getParent(node);
@ -168,9 +168,9 @@ class RootedTreeSet {
} }
/** /**
* @param node * @param node
* @throws will throw an error if node is null or undefined * @throws will throw an error if node is null or undefined
* @return {Array} ancestors */ * @return {Array} ancestors */
getAncestors(node: Node): Node[] { getAncestors(node: Node): Node[] {
$assert(node, 'node cannot be null'); $assert(node, 'node cannot be null');
return this._getAncestors(this.getParent(node), []); return this._getAncestors(this.getParent(node), []);
@ -186,10 +186,10 @@ class RootedTreeSet {
} }
/** /**
* @param node * @param node
* @throws will throw an error if node is null or undefined * @throws will throw an error if node is null or undefined
* @return {Array} siblings * @return {Array} siblings
*/ */
getSiblings(node: Node): Node[] { getSiblings(node: Node): Node[] {
$assert(node, 'node cannot be null'); $assert(node, 'node cannot be null');
if (!$defined(node._parent)) { if (!$defined(node._parent)) {
@ -200,10 +200,10 @@ class RootedTreeSet {
} }
/** /**
* @param node * @param node
* @throws will throw an error if node is null or undefined * @throws will throw an error if node is null or undefined
* @return {Boolean} whether the node has a single path to a single leaf (no branching) * @return {Boolean} whether the node has a single path to a single leaf (no branching)
*/ */
hasSinglePathToSingleLeaf(node: Node): boolean { hasSinglePathToSingleLeaf(node: Node): boolean {
$assert(node, 'node cannot be null'); $assert(node, 'node cannot be null');
return this._hasSinglePathToSingleLeaf(node); return this._hasSinglePathToSingleLeaf(node);
@ -220,27 +220,27 @@ class RootedTreeSet {
} }
/** /**
* @param node * @param node
* @return {Boolean} whether the node is the start of a subbranch */ * @return {Boolean} whether the node is the start of a subbranch */
isStartOfSubBranch(node: Node): boolean { isStartOfSubBranch(node: Node): boolean {
return this.getSiblings(node).length > 0 && this.getChildren(node).length === 1; return this.getSiblings(node).length > 0 && this.getChildren(node).length === 1;
} }
/** /**
* @param node * @param node
* @throws will throw an error if node is null or undefined * @throws will throw an error if node is null or undefined
* @return {Boolean} whether the node is a leaf * @return {Boolean} whether the node is a leaf
*/ */
isLeaf(node: Node): boolean { isLeaf(node: Node): boolean {
$assert(node, 'node cannot be null'); $assert(node, 'node cannot be null');
return this.getChildren(node).length === 0; return this.getChildren(node).length === 0;
} }
/** /**
* @param node * @param node
* @throws will throw an error if node is null or undefined * @throws will throw an error if node is null or undefined
* @return parent * @return parent
*/ */
getParent(node: Node): Node { getParent(node: Node): Node {
$assert(node, 'node cannot be null'); $assert(node, 'node cannot be null');
return node._parent; return node._parent;
@ -271,8 +271,8 @@ class RootedTreeSet {
} }
/** /**
* @param canvas * @param canvas
*/ */
plot(canvas) { plot(canvas) {
const branches = this._rootNodes; const branches = this._rootNodes;
for (let i = 0; i < branches.length; i++) { for (let i = 0; i < branches.length; i++) {
@ -297,9 +297,7 @@ class RootedTreeSet {
if (this._rootNodes.includes(node)) { if (this._rootNodes.includes(node)) {
fillColor = '#000'; fillColor = '#000';
} else { } else {
fillColor = node.isFree() fillColor = node.isFree() ? '#abc' : '#c00';
? '#abc'
: '#c00';
} }
rect.attr('fill', fillColor); rect.attr('fill', fillColor);
@ -310,28 +308,20 @@ class RootedTreeSet {
const rectSize = { width: rect.attr('width'), height: rect.attr('height') }; const rectSize = { width: rect.attr('width'), height: rect.attr('height') };
rect.click(() => { rect.click(() => {
console.log( console.log(
`[id:${node.getId() `[id:${node.getId()}, order:${node.getOrder()}, position:(${rectPosition.x}, ${
}, order:${node.getOrder() rectPosition.y
}, position:(${rectPosition.x }), size:${rectSize.width},${rectSize.height}, freeDisplacement:(${
}, ${rectPosition.y node.getFreeDisplacement().x
}), size:${rectSize.width },${node.getFreeDisplacement().y})]`,
},${rectSize.height
}, freeDisplacement:(${node.getFreeDisplacement().x
},${node.getFreeDisplacement().y
})]`,
); );
}); });
text.click(() => { text.click(() => {
console.log( console.log(
`[id:${node.getId() `[id:${node.getId()}, order:${node.getOrder()}, position:(${rectPosition.x},${
}, order:${node.getOrder() rectPosition.y
}, position:(${rectPosition.x }), size:${rectSize.width}x${rectSize.height}, freeDisplacement:(${
},${rectPosition.y node.getFreeDisplacement().x
}), size:${rectSize.width },${node.getFreeDisplacement().y})]`,
}x${rectSize.height
}, freeDisplacement:(${node.getFreeDisplacement().x
},${node.getFreeDisplacement().y
})]`,
); );
}); });
@ -342,9 +332,9 @@ class RootedTreeSet {
} }
/** /**
* @param node * @param node
* @param position * @param position
*/ */
updateBranchPosition(node: Node, position: PositionType): void { updateBranchPosition(node: Node, position: PositionType): void {
const oldPos = node.getPosition(); const oldPos = node.getPosition();
node.setPosition(position); node.setPosition(position);
@ -360,10 +350,10 @@ class RootedTreeSet {
} }
/** /**
* @param node * @param node
* @param xOffset * @param xOffset
* @param yOffset * @param yOffset
*/ */
shiftBranchPosition(node: Node, xOffset: number, yOffset: number): void { shiftBranchPosition(node: Node, xOffset: number, yOffset: number): void {
const position = node.getPosition(); const position = node.getPosition();
node.setPosition({ x: position.x + xOffset, y: position.y + yOffset }); node.setPosition({ x: position.x + xOffset, y: position.y + yOffset });
@ -376,21 +366,21 @@ class RootedTreeSet {
} }
/** /**
* @param node * @param node
* @param yOffset * @param yOffset
* @return siblings in the offset (vertical) direction, i.e. with lower or higher order * @return siblings in the offset (vertical) direction, i.e. with lower or higher order
*/ */
getSiblingsInVerticalDirection(node: Node, yOffset: number): Node[] { getSiblingsInVerticalDirection(node: Node, yOffset: number): Node[] {
// siblings with lower or higher order // siblings with lower or higher order
// (depending on the direction of the offset and on the same side as their parent) // (depending on the direction of the offset and on the same side as their parent)
const parent = this.getParent(node); const parent = this.getParent(node);
const siblings = this.getSiblings(node).filter((sibling) => { const siblings = this.getSiblings(node).filter((sibling) => {
const sameSide = node.getPosition().x > parent.getPosition().x const sameSide =
? sibling.getPosition().x > parent.getPosition().x node.getPosition().x > parent.getPosition().x
: sibling.getPosition().x < parent.getPosition().x; ? sibling.getPosition().x > parent.getPosition().x
const orderOK = yOffset < 0 : sibling.getPosition().x < parent.getPosition().x;
? sibling.getOrder() < node.getOrder() const orderOK =
: sibling.getOrder() > node.getOrder(); yOffset < 0 ? sibling.getOrder() < node.getOrder() : sibling.getOrder() > node.getOrder();
return orderOK && sameSide; return orderOK && sameSide;
}); });
@ -402,26 +392,27 @@ class RootedTreeSet {
} }
/** /**
* @param node * @param node
* @param yOffset * @param yOffset
* @return branches of the root node on the same side as the given node's, in the given * @return branches of the root node on the same side as the given node's, in the given
* vertical direction * vertical direction
*/ */
getBranchesInVerticalDirection(node: Node, yOffset: number): Node[] { getBranchesInVerticalDirection(node: Node, yOffset: number): Node[] {
// direct descendants of the root that do not contain the node and are on the same side // direct descendants of the root that do not contain the node and are on the same side
// and on the direction of the offset // and on the direction of the offset
const rootNode = this.getRootNode(node); const rootNode = this.getRootNode(node);
const branches = this.getChildren(rootNode) const branches = this.getChildren(rootNode).filter((child) => this._find(node.getId(), child));
.filter(((child) => this._find(node.getId(), child)));
const branch = branches[0]; const branch = branches[0];
const result = this.getSiblings(branch).filter((sibling) => { const result = this.getSiblings(branch).filter((sibling) => {
const sameSide = node.getPosition().x > rootNode.getPosition().x const sameSide =
? sibling.getPosition().x > rootNode.getPosition().x node.getPosition().x > rootNode.getPosition().x
: sibling.getPosition().x < rootNode.getPosition().x; ? sibling.getPosition().x > rootNode.getPosition().x
const sameDirection = yOffset < 0 : sibling.getPosition().x < rootNode.getPosition().x;
? sibling.getOrder() < branch.getOrder() const sameDirection =
: sibling.getOrder() > branch.getOrder(); yOffset < 0
? sibling.getOrder() < branch.getOrder()
: sibling.getOrder() > branch.getOrder();
return sameSide && sameDirection; return sameSide && sameDirection;
}, this); }, this);

View File

@ -28,11 +28,11 @@ class FeatureModel {
private _attributes; private _attributes;
/** /**
* @constructs * @constructs
* @param type * @param type
* @throws will throw an exception if type is null or undefined * @throws will throw an exception if type is null or undefined
* assigns a unique id and the given type to the new model * assigns a unique id and the given type to the new model
*/ */
constructor(type: FeatureType) { constructor(type: FeatureType) {
$assert(type, 'type can not be null'); $assert(type, 'type can not be null');
this._id = FeatureModel._nextUUID(); this._id = FeatureModel._nextUUID();

View File

@ -6,35 +6,38 @@ import FeatureModel from './FeatureModel';
import FeatureType from './FeatureType'; import FeatureType from './FeatureType';
interface NodeById { interface NodeById {
id: FeatureType, id: FeatureType;
model: typeof FeatureModel; model: typeof FeatureModel;
} }
class FeatureModelFactory { class FeatureModelFactory {
static modelById: Array<NodeById> = [{ static modelById: Array<NodeById> = [
id: 'icon', {
model: IconModel, id: 'icon',
}, { model: IconModel,
id: 'link', },
model: LinkModel, {
}, { id: 'link',
id: 'note', model: LinkModel,
model: NoteModel, },
}]; {
id: 'note',
model: NoteModel,
},
];
static createModel(type: FeatureType, attributes): FeatureModel { static createModel(type: FeatureType, attributes): FeatureModel {
$assert(type, 'type can not be null'); $assert(type, 'type can not be null');
$assert(attributes, 'attributes can not be null'); $assert(attributes, 'attributes can not be null');
const { model: Model } = FeatureModelFactory.modelById const { model: Model } = FeatureModelFactory.modelById.filter((elem) => elem.id === type)[0];
.filter((elem) => elem.id === type)[0];
return new Model(attributes); return new Model(attributes);
} }
/** /**
* @param id the feature metadata id * @param id the feature metadata id
* @return {Boolean} returns true if the given id is contained in the metadata array * @return {Boolean} returns true if the given id is contained in the metadata array
*/ */
static isSupported(type: string): boolean { static isSupported(type: string): boolean {
return FeatureModelFactory.modelById.some((elem) => elem.id === type); return FeatureModelFactory.modelById.some((elem) => elem.id === type);
} }

View File

@ -30,7 +30,7 @@ abstract class IMindmap {
abstract setDescription(value: string): void; abstract setDescription(value: string): void;
abstract getId(): string abstract getId(): string;
abstract setId(id: string): void; abstract setId(id: string): void;
@ -58,10 +58,10 @@ abstract class IMindmap {
} }
/** /**
* @param child * @param child
* @throws will throw an error if child is null or undefined * @throws will throw an error if child is null or undefined
* @throws will throw an error if child's parent cannot be found * @throws will throw an error if child's parent cannot be found
*/ */
disconnect(child: INodeModel): void { disconnect(child: INodeModel): void {
const parent = child.getParent(); const parent = child.getParent();
$assert(child, 'Child can not be null.'); $assert(child, 'Child can not be null.');
@ -73,7 +73,7 @@ abstract class IMindmap {
abstract hasAlreadyAdded(node): boolean; abstract hasAlreadyAdded(node): boolean;
abstract createNode(type: NodeType, id: number) abstract createNode(type: NodeType, id: number);
abstract createRelationship(fromNodeId: number, toNodeId: number): void; abstract createRelationship(fromNodeId: number, toNodeId: number): void;
@ -81,7 +81,7 @@ abstract class IMindmap {
abstract deleteRelationship(relationship: RelationshipModel): void; abstract deleteRelationship(relationship: RelationshipModel): void;
inspect():string { inspect(): string {
let result = ''; let result = '';
result = '{ '; result = '{ ';
@ -102,7 +102,7 @@ abstract class IMindmap {
return result; return result;
} }
copyTo(target:IMindmap) { copyTo(target: IMindmap) {
const version = this.getVersion(); const version = this.getVersion();
target.setVersion(version); target.setVersion(version);

View File

@ -24,7 +24,8 @@ import Mindmap from './Mindmap';
export type NodeModelType = 'CentralTopic' | 'MainTopic'; export type NodeModelType = 'CentralTopic' | 'MainTopic';
// regex taken from https://stackoverflow.com/a/34763398/58128 // regex taken from https://stackoverflow.com/a/34763398/58128
const parseJsObject = (str: string) => JSON.parse(str.replace(/(['"])?([a-z0-9A-Z_]+)(['"])?:/g, '"$2": ')); const parseJsObject = (str: string) =>
JSON.parse(str.replace(/(['"])?([a-z0-9A-Z_]+)(['"])?:/g, '"$2": '));
abstract class INodeModel { abstract class INodeModel {
static MAIN_TOPIC_TO_MAIN_TOPIC_DISTANCE = 220; static MAIN_TOPIC_TO_MAIN_TOPIC_DISTANCE = 220;
@ -90,7 +91,7 @@ abstract class INodeModel {
this.putProperty('imageSize', `{width:${width},height:${height}}`); this.putProperty('imageSize', `{width:${width},height:${height}}`);
} }
getImageSize(): { width: number, height: number } { getImageSize(): { width: number; height: number } {
const value = this.getProperty('imageSize') as string; const value = this.getProperty('imageSize') as string;
let result; let result;
if (value != null) { if (value != null) {
@ -120,9 +121,9 @@ abstract class INodeModel {
} }
/** /**
* lets the mindmap handle the disconnect node operation * lets the mindmap handle the disconnect node operation
* @see mindplot.model.IMindmap.disconnect * @see mindplot.model.IMindmap.disconnect
*/ */
disconnect(): void { disconnect(): void {
const mindmap = this.getMindmap(); const mindmap = this.getMindmap();
mindmap.disconnect(this); mindmap.disconnect(this);
@ -233,10 +234,10 @@ abstract class INodeModel {
abstract append(node): void; abstract append(node): void;
/** /**
* lets the mindmap handle the connect node operation * lets the mindmap handle the connect node operation
* @throws will throw an error if parent is null or undefined * @throws will throw an error if parent is null or undefined
* @see mindplot.model.IMindmap.connect * @see mindplot.model.IMindmap.connect
*/ */
connectTo(parent: INodeModel) { connectTo(parent: INodeModel) {
$assert(parent, 'parent can not be null'); $assert(parent, 'parent can not be null');
const mindmap = this.getMindmap(); const mindmap = this.getMindmap();
@ -244,9 +245,9 @@ abstract class INodeModel {
} }
/** /**
* @param target * @param target
* @return target * @return target
*/ */
copyTo(target: INodeModel): INodeModel { copyTo(target: INodeModel): INodeModel {
const source = this; const source = this;
// Copy properties ... // Copy properties ...
@ -270,9 +271,9 @@ abstract class INodeModel {
} }
/** /**
* lets parent handle the delete node operation, or, if none defined, calls the mindmap to * lets parent handle the delete node operation, or, if none defined, calls the mindmap to
* remove the respective branch * remove the respective branch
*/ */
deleteNode(): void { deleteNode(): void {
const mindmap = this.getMindmap(); const mindmap = this.getMindmap();

View File

@ -28,7 +28,7 @@ class IconModel extends FeatureModel {
return this.getAttribute('id') as string; return this.getAttribute('id') as string;
} }
setIconType(iconType: string):void { setIconType(iconType: string): void {
$assert(iconType, 'iconType id can not be null'); $assert(iconType, 'iconType id can not be null');
this.setAttribute('id', iconType); this.setAttribute('id', iconType);
} }

View File

@ -41,16 +41,20 @@ class LinkModel extends FeatureModel {
// url format is already checked in LinkEditor.checkUrl // url format is already checked in LinkEditor.checkUrl
static _fixUrl(url: string): string { static _fixUrl(url: string): string {
let result = url; let result = url;
if (!result.includes('http://') && !result.includes('https://') && !result.includes('mailto://')) { if (
!result.includes('http://') &&
!result.includes('https://') &&
!result.includes('mailto://')
) {
result = `http://${result}`; result = `http://${result}`;
} }
return result; return result;
} }
/** /**
* @param {String} urlType the url type, either 'mail' or 'url' * @param {String} urlType the url type, either 'mail' or 'url'
* @throws will throw an error if urlType is null or undefined * @throws will throw an error if urlType is null or undefined
*/ */
setUrlType(urlType) { setUrlType(urlType) {
$assert(urlType, 'urlType can not be null'); $assert(urlType, 'urlType can not be null');
this.setAttribute('urlType', urlType); this.setAttribute('urlType', urlType);

View File

@ -75,10 +75,10 @@ class Mindmap extends IMindmap {
} }
/** /**
* @param {mindplot.model.NodeModel} nodeModel * @param {mindplot.model.NodeModel} nodeModel
* @throws will throw an error if nodeModel is null, undefined or not a node model object * @throws will throw an error if nodeModel is null, undefined or not a node model object
* @throws will throw an error if * @throws will throw an error if
*/ */
addBranch(nodeModel: INodeModel): void { addBranch(nodeModel: INodeModel): void {
$assert(nodeModel && nodeModel.isNodeModel(), 'Add node must be invoked with model objects'); $assert(nodeModel && nodeModel.isNodeModel(), 'Add node must be invoked with model objects');
const branches = this.getBranches(); const branches = this.getBranches();
@ -93,14 +93,14 @@ class Mindmap extends IMindmap {
} }
/** /**
* @param nodeModel * @param nodeModel
*/ */
removeBranch(nodeModel: INodeModel): void { removeBranch(nodeModel: INodeModel): void {
$assert(nodeModel && nodeModel.isNodeModel(), 'Remove node must be invoked with model objects'); $assert(nodeModel && nodeModel.isNodeModel(), 'Remove node must be invoked with model objects');
this._branches = this._branches.filter((b) => b !== nodeModel); this._branches = this._branches.filter((b) => b !== nodeModel);
} }
getBranches():NodeModel[] { getBranches(): NodeModel[] {
return this._branches; return this._branches;
} }
@ -122,7 +122,7 @@ class Mindmap extends IMindmap {
return result; return result;
} }
createNode(type: NodeModelType = 'MainTopic', id?: number):NodeModel { createNode(type: NodeModelType = 'MainTopic', id?: number): NodeModel {
return new NodeModel(type, this, id); return new NodeModel(type, this, id);
} }
@ -141,8 +141,8 @@ class Mindmap extends IMindmap {
} }
/** /**
* @param relationship * @param relationship
*/ */
deleteRelationship(relationship: RelationshipModel) { deleteRelationship(relationship: RelationshipModel) {
this._relationships = this._relationships.filter((r) => r !== relationship); this._relationships = this._relationships.filter((r) => r !== relationship);
} }

View File

@ -49,18 +49,18 @@ class NodeModel extends INodeModel {
} }
/** /**
* @param type * @param type
* @param attributes * @param attributes
* @return {mindplot.model.FeatureModel} the created feature model * @return {mindplot.model.FeatureModel} the created feature model
*/ */
createFeature(type: FeatureType, attributes): FeatureModel { createFeature(type: FeatureType, attributes): FeatureModel {
return FeatureModelFactory.createModel(type, attributes); return FeatureModelFactory.createModel(type, attributes);
} }
/** /**
* @param feature * @param feature
* @throws will throw an error if feature is null or undefined * @throws will throw an error if feature is null or undefined
*/ */
addFeature(feature: FeatureModel) { addFeature(feature: FeatureModel) {
$assert(feature, 'feature can not be null'); $assert(feature, 'feature can not be null');
this._features.push(feature); this._features.push(feature);
@ -78,20 +78,20 @@ class NodeModel extends INodeModel {
} }
/** /**
* @param {String} type the feature type, e.g. icon or link * @param {String} type the feature type, e.g. icon or link
* @throws will throw an error if type is null or undefined * @throws will throw an error if type is null or undefined
*/ */
findFeatureByType(type: string): FeatureModel[] { findFeatureByType(type: string): FeatureModel[] {
$assert(type, 'type can not be null'); $assert(type, 'type can not be null');
return this._features.filter((feature) => feature.getType() === type); return this._features.filter((feature) => feature.getType() === type);
} }
/** /**
* @param {String} id * @param {String} id
* @throws will throw an error if id is null or undefined * @throws will throw an error if id is null or undefined
* @throws will throw an error if feature could not be found * @throws will throw an error if feature could not be found
* @return the feature with the given id * @return the feature with the given id
*/ */
findFeatureById(id: number): FeatureModel { findFeatureById(id: number): FeatureModel {
$assert($defined(id), 'id can not be null'); $assert($defined(id), 'id can not be null');
const result = this._features.filter((feature) => feature.getId() === id); const result = this._features.filter((feature) => feature.getId() === id);
@ -104,10 +104,10 @@ class NodeModel extends INodeModel {
} }
/** /**
* @param key * @param key
* @param value * @param value
* @throws will throw an error if key is null or undefined * @throws will throw an error if key is null or undefined
*/ */
putProperty(key: string, value: string | number | boolean) { putProperty(key: string, value: string | number | boolean) {
$defined(key, 'key can not be null'); $defined(key, 'key can not be null');
this._properties[key] = value; this._properties[key] = value;

View File

@ -108,8 +108,8 @@ class RelationshipModel {
} }
/** /**
* @return a clone of the relationship model * @return a clone of the relationship model
*/ */
clone() { clone() {
const result = new RelationshipModel(this._sourceTargetId, this._targetTopicId); const result = new RelationshipModel(this._sourceTargetId, this._targetTopicId);
result._id = this._id; result._id = this._id;
@ -122,14 +122,10 @@ class RelationshipModel {
} }
/** /**
* @return {String} textual information about the relationship's source and target node * @return {String} textual information about the relationship's source and target node
*/ */
inspect(): string { inspect(): string {
return ( return `(fromNode:${this.getFromNode()} , toNode: ${this.getToNode()})`;
`(fromNode:${this.getFromNode()
} , toNode: ${this.getToNode()
})`
);
} }
static _nextUUID() { static _nextUUID() {

View File

@ -83,7 +83,7 @@ class Pela2TangoMigrator implements XMLMindmapSerializer {
} }
} }
private _fixNodePosition(node: NodeModel, parentPosition: { x: number, y: number }): void { private _fixNodePosition(node: NodeModel, parentPosition: { x: number; y: number }): void {
// Position was not required in previous versions. Try to synthesize one . // Position was not required in previous versions. Try to synthesize one .
let position = node.getPosition(); let position = node.getPosition();
if (!position) { if (!position) {

View File

@ -19,7 +19,7 @@
import Mindmap from '../model/Mindmap'; import Mindmap from '../model/Mindmap';
interface XMLMindmapSerializer { interface XMLMindmapSerializer {
toXML(mindmap: Mindmap): Document; toXML(mindmap: Mindmap): Document;
loadFromDom(dom: Document, mapId: string): Mindmap; loadFromDom(dom: Document, mapId: string): Mindmap;
} }
export default XMLMindmapSerializer; export default XMLMindmapSerializer;

View File

@ -14,9 +14,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { import { $defined, $assert, createDocument } from '@wisemapping/core-js';
$defined, $assert, createDocument,
} from '@wisemapping/core-js';
import ModelCodeName from './ModelCodeName'; import ModelCodeName from './ModelCodeName';
import Mindmap from '../model/Mindmap'; import Mindmap from '../model/Mindmap';
import FeatureModelFactory from '../model/FeatureModelFactory'; import FeatureModelFactory from '../model/FeatureModelFactory';
@ -99,11 +97,11 @@ class XMLSerializerBeta implements XMLMindmapSerializer {
font += `${fontStyle || ''};`; font += `${fontStyle || ''};`;
if ( if (
$defined(fontFamily) $defined(fontFamily) ||
|| $defined(fontSize) $defined(fontSize) ||
|| $defined(fontColor) $defined(fontColor) ||
|| $defined(fontWeight) $defined(fontWeight) ||
|| $defined(fontStyle) $defined(fontStyle)
) { ) {
parentTopic.setAttribute('fontStyle', font); parentTopic.setAttribute('fontStyle', font);
} }
@ -180,7 +178,8 @@ class XMLSerializerBeta implements XMLMindmapSerializer {
// Is a wisemap?. // Is a wisemap?.
$assert( $assert(
documentElement.tagName === XMLSerializerBeta.MAP_ROOT_NODE, documentElement.tagName === XMLSerializerBeta.MAP_ROOT_NODE,
`This seem not to be a map document. Root Tag: '${documentElement.tagName}',HTML:${dom.innerHTML `This seem not to be a map document. Root Tag: '${documentElement.tagName}',HTML:${
dom.innerHTML
}, XML:,${new XMLSerializer().serializeToString(dom)}`, }, XML:,${new XMLSerializer().serializeToString(dom)}`,
); );
@ -202,9 +201,7 @@ class XMLSerializerBeta implements XMLMindmapSerializer {
} }
_deserializeNode(domElem, mindmap) { _deserializeNode(domElem, mindmap) {
const type = domElem.getAttribute('central') != null const type = domElem.getAttribute('central') != null ? 'CentralTopic' : 'MainTopic';
? 'CentralTopic'
: 'MainTopic';
const topic = mindmap.createNode(type); const topic = mindmap.createNode(type);
// Load attributes... // Load attributes...
@ -275,10 +272,10 @@ class XMLSerializerBeta implements XMLMindmapSerializer {
const child = children[i]; const child = children[i];
if (child.nodeType === 1) { if (child.nodeType === 1) {
$assert( $assert(
child.tagName === 'topic' child.tagName === 'topic' ||
|| child.tagName === 'icon' child.tagName === 'icon' ||
|| child.tagName === 'link' child.tagName === 'link' ||
|| child.tagName === 'note', child.tagName === 'note',
`Illegal node type:${child.tagName}`, `Illegal node type:${child.tagName}`,
); );
if (child.tagName === 'topic') { if (child.tagName === 'topic') {

View File

@ -24,7 +24,7 @@ import XMLSerializerTango from './XMLSerializerTango';
import Mindmap from '../model/Mindmap'; import Mindmap from '../model/Mindmap';
import XMLMindmapSerializer from './XMLMindmapSerializer'; import XMLMindmapSerializer from './XMLMindmapSerializer';
const codeToSerializer: { codeName: string, serializer, migrator }[] = [ const codeToSerializer: { codeName: string; serializer; migrator }[] = [
{ {
codeName: ModelCodeName.BETA, codeName: ModelCodeName.BETA,
serializer: XMLSerializerBeta, serializer: XMLSerializerBeta,
@ -51,8 +51,7 @@ class XMLSerializerFactory {
* mindplot.persistence.XMLSerializer_Tango} serializer corresponding to the mindmap's version * mindplot.persistence.XMLSerializer_Tango} serializer corresponding to the mindmap's version
*/ */
static createInstanceFromMindmap(mindmap: Mindmap) { static createInstanceFromMindmap(mindmap: Mindmap) {
return XMLSerializerFactory return XMLSerializerFactory.getSerializer(mindmap.getVersion());
.getSerializer(mindmap.getVersion());
} }
/** /**
@ -83,7 +82,7 @@ class XMLSerializerFactory {
if (!found) { if (!found) {
found = codeToSerializer[i].codeName === version; found = codeToSerializer[i].codeName === version;
// eslint-disable-next-line new-cap // eslint-disable-next-line new-cap
if (found) result = new (codeToSerializer[i].serializer)(); if (found) result = new codeToSerializer[i].serializer();
} else { } else {
const { migrator } = codeToSerializer[i]; const { migrator } = codeToSerializer[i];
// eslint-disable-next-line new-cap // eslint-disable-next-line new-cap

View File

@ -60,8 +60,8 @@ class XMLSerializerTango implements XMLMindmapSerializer {
const relationships = mindmap.getRelationships(); const relationships = mindmap.getRelationships();
relationships.forEach((relationship) => { relationships.forEach((relationship) => {
if ( if (
mindmap.findNodeById(relationship.getFromNode()) !== null mindmap.findNodeById(relationship.getFromNode()) !== null &&
&& mindmap.findNodeById(relationship.getToNode()) !== null mindmap.findNodeById(relationship.getToNode()) !== null
) { ) {
// Isolated relationships are not persisted .... // Isolated relationships are not persisted ....
const relationDom = XMLSerializerTango._relationshipToXML(document, relationship); const relationDom = XMLSerializerTango._relationshipToXML(document, relationship);
@ -99,14 +99,15 @@ class XMLSerializerTango implements XMLMindmapSerializer {
if (shape === TopicShape.IMAGE) { if (shape === TopicShape.IMAGE) {
const size = topic.getImageSize(); const size = topic.getImageSize();
parentTopic.setAttribute( parentTopic.setAttribute('image', `${size.width},${size.height}:${topic.getImageUrl()}`);
'image',
`${size.width},${size.height}:${topic.getImageUrl()}`,
);
} }
} }
if ((topic.areChildrenShrunken() && topic.getChildren().length > 0) && topic.getType() !== 'CentralTopic') { if (
topic.areChildrenShrunken() &&
topic.getChildren().length > 0 &&
topic.getType() !== 'CentralTopic'
) {
parentTopic.setAttribute('shrink', 'true'); parentTopic.setAttribute('shrink', 'true');
} }
@ -132,11 +133,11 @@ class XMLSerializerTango implements XMLMindmapSerializer {
font += `${fontStyle || ''};`; font += `${fontStyle || ''};`;
if ( if (
$defined(fontFamily) $defined(fontFamily) ||
|| $defined(fontSize) $defined(fontSize) ||
|| $defined(fontColor) $defined(fontColor) ||
|| $defined(fontWeight) $defined(fontWeight) ||
|| $defined(fontStyle) $defined(fontStyle)
) { ) {
parentTopic.setAttribute('fontStyle', font); parentTopic.setAttribute('fontStyle', font);
} }
@ -208,10 +209,7 @@ class XMLSerializerTango implements XMLMindmapSerializer {
if (lineType === ConnectionLine.CURVED || lineType === ConnectionLine.SIMPLE_CURVED) { if (lineType === ConnectionLine.CURVED || lineType === ConnectionLine.SIMPLE_CURVED) {
if ($defined(relationship.getSrcCtrlPoint())) { if ($defined(relationship.getSrcCtrlPoint())) {
const srcPoint = relationship.getSrcCtrlPoint(); const srcPoint = relationship.getSrcCtrlPoint();
result.setAttribute( result.setAttribute('srcCtrlPoint', `${Math.round(srcPoint.x)},${Math.round(srcPoint.y)}`);
'srcCtrlPoint',
`${Math.round(srcPoint.x)},${Math.round(srcPoint.y)}`,
);
} }
if ($defined(relationship.getDestCtrlPoint())) { if ($defined(relationship.getDestCtrlPoint())) {
const destPoint = relationship.getDestCtrlPoint(); const destPoint = relationship.getDestCtrlPoint();
@ -246,9 +244,7 @@ class XMLSerializerTango implements XMLMindmapSerializer {
// Add all the topics nodes ... // Add all the topics nodes ...
const childNodes = Array.from(rootElem.childNodes); const childNodes = Array.from(rootElem.childNodes);
const topicsNodes = childNodes const topicsNodes = childNodes
.filter( .filter((child: ChildNode) => child.nodeType === 1 && (child as Element).tagName === 'topic')
(child: ChildNode) => child.nodeType === 1 && (child as Element).tagName === 'topic',
)
.map((c) => c as Element); .map((c) => c as Element);
topicsNodes.forEach((child) => { topicsNodes.forEach((child) => {
const topic = this._deserializeNode(child, mindmap); const topic = this._deserializeNode(child, mindmap);
@ -488,16 +484,16 @@ class XMLSerializerTango implements XMLMindmapSerializer {
} }
/** /**
* This method ensures that the output String has only * This method ensures that the output String has only
* valid XML unicode characters as specified by the * valid XML unicode characters as specified by the
* XML 1.0 standard. For reference, please see * XML 1.0 standard. For reference, please see
* <a href="http://www.w3.org/TR/2000/REC-xml-20001006#NT-Char">the * <a href="http://www.w3.org/TR/2000/REC-xml-20001006#NT-Char">the
* standard</a>. This method will return an empty * standard</a>. This method will return an empty
* String if the input is null or empty. * String if the input is null or empty.
* *
* @param in The String whose non-valid characters we want to remove. * @param in The String whose non-valid characters we want to remove.
* @return The in String, stripped of non-valid characters. * @return The in String, stripped of non-valid characters.
*/ */
protected _rmXmlInv(str: string) { protected _rmXmlInv(str: string) {
if (str == null || str === undefined) return null; if (str == null || str === undefined) return null;
@ -505,12 +501,12 @@ class XMLSerializerTango implements XMLMindmapSerializer {
for (let i = 0; i < str.length; i++) { for (let i = 0; i < str.length; i++) {
const c = str.charCodeAt(i); const c = str.charCodeAt(i);
if ( if (
c === 0x9 c === 0x9 ||
|| c === 0xa c === 0xa ||
|| c === 0xd c === 0xd ||
|| (c >= 0x20 && c <= 0xd7ff) (c >= 0x20 && c <= 0xd7ff) ||
|| (c >= 0xe000 && c <= 0xfffd) (c >= 0xe000 && c <= 0xfffd) ||
|| (c >= 0x10000 && c <= 0x10ffff) (c >= 0x10000 && c <= 0x10ffff)
) { ) {
result += str.charAt(i); result += str.charAt(i);
} }

View File

@ -73,7 +73,7 @@ class FloatingTip extends Events {
if (this.addEvent) { if (this.addEvent) {
Object.keys(options).forEach((option) => { Object.keys(options).forEach((option) => {
if (options[option] instanceof Function && (/^on[A-Z]/).test(option)) { if (options[option] instanceof Function && /^on[A-Z]/.test(option)) {
this.addEvent(option, options[option]); this.addEvent(option, options[option]);
delete options[option]; delete options[option];
} }

View File

@ -49,7 +49,10 @@ export const parseXMLString = (xmlStr: string, mimeType: DOMParserSupportedType)
return xmlDoc; return xmlDoc;
}; };
export const parseXMLFile = (filePath: fs.PathOrFileDescriptor, mimeType: DOMParserSupportedType) => { export const parseXMLFile = (
filePath: fs.PathOrFileDescriptor,
mimeType: DOMParserSupportedType,
) => {
const stream = fs.readFileSync(filePath, { encoding: 'utf-8' }); const stream = fs.readFileSync(filePath, { encoding: 'utf-8' });
let content = stream.toString(); let content = stream.toString();

View File

@ -7,9 +7,12 @@ import { parseXMLFile, setupBlob, exporterAssert } from './Helper';
setupBlob(); setupBlob();
describe('SVG export test execution', () => { describe('SVG export test execution', () => {
test.each(fs.readdirSync(path.resolve(__dirname, './input/')) test.each(
.filter((f) => f.endsWith('.wxml')) fs
.map((filename: string) => filename.split('.')[0]))('Exporting %p suite', async (testName: string) => { .readdirSync(path.resolve(__dirname, './input/'))
.filter((f) => f.endsWith('.wxml'))
.map((filename: string) => filename.split('.')[0]),
)('Exporting %p suite', async (testName: string) => {
// Load SVG ... // Load SVG ...
const svgPath = path.resolve(__dirname, `./input/${testName}.svg`); const svgPath = path.resolve(__dirname, `./input/${testName}.svg`);
expect(fs.existsSync(svgPath)).toEqual(true); expect(fs.existsSync(svgPath)).toEqual(true);

View File

@ -15,7 +15,10 @@ export const parseXMLString = (xmlStr: string, mimeType: DOMParserSupportedType)
return xmlDoc; return xmlDoc;
}; };
export const parseXMLFile = (filePath: fs.PathOrFileDescriptor, mimeType: DOMParserSupportedType) => { export const parseXMLFile = (
filePath: fs.PathOrFileDescriptor,
mimeType: DOMParserSupportedType,
) => {
const stream = fs.readFileSync(filePath, { encoding: 'utf-8' }); const stream = fs.readFileSync(filePath, { encoding: 'utf-8' });
const content = stream.toString(); const content = stream.toString();

View File

@ -1,21 +1,21 @@
import MapsPage from '../pageObject/MapsPage'; import MapsPage from '../pageObject/MapsPage';
context('Maps Page', () => { context('Maps Page', () => {
beforeEach(() => { beforeEach(() => {
cy.visit('/c/maps'); cy.visit('/c/maps');
}); });
it('should load the maps page', () => { it('should load the maps page', () => {
MapsPage.isLoaded(); MapsPage.isLoaded();
}); });
it('should open the create dialog', () => { it('should open the create dialog', () => {
MapsPage.create(); MapsPage.create();
MapsPage.isCreateDialogVisible(); MapsPage.isCreateDialogVisible();
cy.matchImageSnapshot('maps-create'); cy.matchImageSnapshot('maps-create');
}); });
it('should match the snapshot', () => { it('should match the snapshot', () => {
cy.matchImageSnapshot('maps'); cy.matchImageSnapshot('maps');
}); });
}); });

View File

@ -1,14 +1,14 @@
export default class MapsPage { export default class MapsPage {
static isLoaded() { static isLoaded() {
return cy.findByTestId('create'); return cy.findByTestId('create');
} }
static create() { static create() {
return cy.findByTestId('create').click(); return cy.findByTestId('create').click();
} }
static isCreateDialogVisible() { static isCreateDialogVisible() {
//TODO move to findByText when the double create dialog issue is solved //TODO move to findByText when the double create dialog issue is solved
return cy.findAllByText('Create a new mindmap'); return cy.findAllByText('Create a new mindmap');
} }
} }

View File

@ -4,7 +4,7 @@ const { addMatchImageSnapshotPlugin } = require('cypress-image-snapshot/plugin')
* @type {Cypress.PluginConfig} * @type {Cypress.PluginConfig}
*/ */
module.exports = (on, config) => { module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits // `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config // `config` is the resolved Cypress config
addMatchImageSnapshotPlugin(on, config); addMatchImageSnapshotPlugin(on, config);
}; };

View File

@ -4,16 +4,16 @@ import '@testing-library/cypress/add-commands';
// make matchImageSnapshot() call the real implementation only if CYPRESS_imageSnaphots is set // make matchImageSnapshot() call the real implementation only if CYPRESS_imageSnaphots is set
// otherwise it calls a noop // otherwise it calls a noop
if (Cypress.env('imageSnaphots')) { if (Cypress.env('imageSnaphots')) {
addMatchImageSnapshotCommand({ addMatchImageSnapshotCommand({
failureThreshold: 0.001, failureThreshold: 0.001,
failureThresholdType: 'percent', failureThresholdType: 'percent',
}); });
} else { } else {
Cypress.Commands.add( Cypress.Commands.add(
'matchImageSnapshot', 'matchImageSnapshot',
{ {
prevSubject: ['optional', 'element', 'window', 'document'], prevSubject: ['optional', 'element', 'window', 'document'],
}, },
() => Promise.resolve() () => Promise.resolve(),
); );
} }

View File

@ -2,10 +2,10 @@ declare module '*.png';
declare module '*.svg'; declare module '*.svg';
declare module '*.wxml'; declare module '*.wxml';
declare global { declare global {
const isAuth: boolean; const isAuth: boolean;
const mapId: number; const mapId: number;
const userOptions: { zoom: string | number } | null; const userOptions: { zoom: string | number } | null;
const mindmapLocked: boolean; const mindmapLocked: boolean;
const mindmapLockedMsg: string; const mindmapLockedMsg: string;
const mapTitle: string; const mapTitle: string;
} }

View File

@ -10,10 +10,10 @@ type DateType = string | number | Date | Dayjs;
// @Todo: review if there is a better support for this. // @Todo: review if there is a better support for this.
declare module 'dayjs' { declare module 'dayjs' {
interface Dayjs { interface Dayjs {
fromNow(withoutSuffix?: boolean): string; fromNow(withoutSuffix?: boolean): string;
from(compared: DateType, withoutSuffix?: boolean): string; from(compared: DateType, withoutSuffix?: boolean): string;
toNow(withoutSuffix?: boolean): string; toNow(withoutSuffix?: boolean): string;
to(compared: DateType, withoutSuffix?: boolean): string; to(compared: DateType, withoutSuffix?: boolean): string;
} }
} }

View File

@ -1,78 +1,75 @@
import Client from "../client"; import Client from '../client';
import CacheDecoratorClient from "../client/cache-decorator-client"; import CacheDecoratorClient from '../client/cache-decorator-client';
import MockClient from "../client/mock-client"; import MockClient from '../client/mock-client';
import RestClient from "../client/rest-client"; import RestClient from '../client/rest-client';
interface Config { interface Config {
apiBaseUrl: string; apiBaseUrl: string;
analyticsAccount?: string; analyticsAccount?: string;
recaptcha2Enabled: boolean; recaptcha2Enabled: boolean;
recaptcha2SiteKey?: string; recaptcha2SiteKey?: string;
clientType: 'mock' | 'rest'; clientType: 'mock' | 'rest';
} }
class _AppConfig { class _AppConfig {
private defaultInstance: Config = {
apiBaseUrl: `${window.location.protocol}//${window.location.hostname}:${window.location.port}`,
clientType: 'mock',
recaptcha2Enabled: true,
recaptcha2SiteKey: '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI',
};
private defaultInstance: Config = { isDevelopEnv(): boolean {
apiBaseUrl: `${window.location.protocol}//${window.location.hostname}:${window.location.port}`, const config = this.getInstance();
clientType: 'mock', return config.clientType === 'mock';
recaptcha2Enabled: true, }
recaptcha2SiteKey: '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI'
private getInstance(): Config {
// Config can be inserted in the html page to define the global properties ...
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let result = (window as any).serverconfig;
if (!result) {
result = this.defaultInstance;
} }
isDevelopEnv(): boolean { return result;
const config = this.getInstance(); }
return config.clientType === 'mock';
isRecaptcha2Enabled(): boolean {
const config = this.getInstance();
return config.recaptcha2Enabled;
}
getRecaptcha2SiteKey(): string | undefined {
const config = this.getInstance();
return config.recaptcha2SiteKey;
}
getGoogleAnalyticsAccount(): string | undefined {
const config = this.getInstance();
return config.analyticsAccount;
}
buildClient(): Client {
const config = this.getInstance();
let result: Client;
if (config.clientType == 'rest') {
result = new RestClient(this.getBaseUrl());
console.log('Service using rest client. ' + JSON.stringify(config));
} else {
console.log('Warning:Service using mockservice client');
result = new MockClient();
} }
private getInstance(): Config { // Wrap with a cache decorator ...
// Config can be inserted in the html page to define the global properties ... return new CacheDecoratorClient(result);
// eslint-disable-next-line @typescript-eslint/no-explicit-any }
let result = (window as any).serverconfig;
if (!result) {
result = this.defaultInstance;
}
return result; getBaseUrl(): string {
} const config = this.getInstance();
return config.apiBaseUrl;
isRecaptcha2Enabled(): boolean { }
const config = this.getInstance();
return config.recaptcha2Enabled;
}
getRecaptcha2SiteKey(): string | undefined {
const config = this.getInstance();
return config.recaptcha2SiteKey;
}
getGoogleAnalyticsAccount(): string | undefined {
const config = this.getInstance();
return config.analyticsAccount;
}
buildClient(): Client {
const config = this.getInstance();
let result: Client;
if (config.clientType == 'rest') {
result = new RestClient(this.getBaseUrl());
console.log('Service using rest client. ' + JSON.stringify(config));
} else {
console.log('Warning:Service using mockservice client');
result = new MockClient();
}
// Wrap with a cache decorator ...
return new CacheDecoratorClient(result);
}
getBaseUrl(): string {
const config = this.getInstance();
return config.apiBaseUrl;
}
} }
const AppConfig = new _AppConfig(); const AppConfig = new _AppConfig();
export default AppConfig; export default AppConfig;

View File

@ -7,91 +7,89 @@ import 'dayjs/locale/ru';
import 'dayjs/locale/zh'; import 'dayjs/locale/zh';
export class Locale { export class Locale {
code: LocaleCode; code: LocaleCode;
label: string; label: string;
message: Record<string, string>; message: Record<string, string>;
constructor(code: LocaleCode, label: string, message: unknown) { constructor(code: LocaleCode, label: string, message: unknown) {
this.code = code; this.code = code;
this.label = label; this.label = label;
this.message = message as Record<string, string>; this.message = message as Record<string, string>;
} }
} }
export default abstract class AppI18n { export default abstract class AppI18n {
private static LOCAL_STORAGE_KEY = 'user.locale'; private static LOCAL_STORAGE_KEY = 'user.locale';
public static getUserLocale(): Locale { public static getUserLocale(): Locale {
// @Todo Hack: Try page must not account info. Add this to avoid 403 errors. // @Todo Hack: Try page must not account info. Add this to avoid 403 errors.
const isTryPage = window.location.href.endsWith('/try'); const isTryPage = window.location.href.endsWith('/try');
let result: Locale; let result: Locale;
if (!isTryPage) { if (!isTryPage) {
const account = fetchAccount(); const account = fetchAccount();
result = account?.locale ? account.locale : this.getDefaultLocale(); result = account?.locale ? account.locale : this.getDefaultLocale();
// If the local storage value is different, update ... // If the local storage value is different, update ...
if (account?.locale && result.code !== localStorage.getItem(AppI18n.LOCAL_STORAGE_KEY)) { if (account?.locale && result.code !== localStorage.getItem(AppI18n.LOCAL_STORAGE_KEY)) {
localStorage.setItem(AppI18n.LOCAL_STORAGE_KEY, result.code); localStorage.setItem(AppI18n.LOCAL_STORAGE_KEY, result.code);
} }
} else {
result = this.getDefaultLocale();
}
return result;
}
} else { public static getBrowserLocale(): Locale {
result = this.getDefaultLocale(); let localeCode = (navigator.languages && navigator.languages[0]) || navigator.language;
}
return result; // Just remove the variant ...
localeCode = localeCode.split('-')[0];
let result = Locales.EN;
try {
result = localeFromStr(localeCode);
} catch {
console.warn(`Unsupported languange code ${localeCode}`);
} }
public static getBrowserLocale(): Locale { return result;
let localeCode = (navigator.languages && navigator.languages[0]) || navigator.language; }
// Just remove the variant ... public static getDefaultLocale(): Locale {
localeCode = localeCode.split('-')[0]; // Fetch local from local storage ...
let result: Locale;
let result = Locales.EN; const userLocaleCode: string = localStorage.getItem(AppI18n.LOCAL_STORAGE_KEY);
try { if (userLocaleCode) {
result = localeFromStr(localeCode); result = localeFromStr(userLocaleCode);
} catch {
console.warn(`Unsupported languange code ${localeCode}`);
}
return result;
} }
public static getDefaultLocale(): Locale { // Ok, use browser default ...
// Fetch local from local storage ... if (!result) {
let result: Locale; result = this.getBrowserLocale();
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;
} }
return result;
}
} }
export type LocaleCode = 'en' | 'es' | 'fr' | 'de' | 'ru' | 'zh'; export type LocaleCode = 'en' | 'es' | 'fr' | 'de' | 'ru' | 'zh';
export const Locales = { export const Locales = {
EN: new Locale('en', 'English', require('./../../compiled-lang/en.json')), // eslint-disable-line EN: new Locale('en', 'English', require('./../../compiled-lang/en.json')), // eslint-disable-line
ES: new Locale('es', 'Español', require('./../../compiled-lang/es.json')), // eslint-disable-line ES: new Locale('es', 'Español', require('./../../compiled-lang/es.json')), // eslint-disable-line
DE: new Locale('fr', 'Français', require('./../../compiled-lang/fr.json')), // eslint-disable-line 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 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 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
}; };
export const localeFromStr = (code: string): Locale => { export const localeFromStr = (code: string): Locale => {
const locales: Locale[] = Object.values(Locales); const locales: Locale[] = Object.values(Locales);
const result = locales.find((l) => l.code == code); const result = locales.find((l) => l.code == code);
if (!result) { if (!result) {
throw `Language code could not be found in list of default supported: + ${code}`; throw `Language code could not be found in list of default supported: + ${code}`;
} }
return result; return result;
}; };

View File

@ -1,143 +1,142 @@
import { EditorRenderMode, Mindmap, PersistenceManager } from '@wisemapping/mindplot'; import { EditorRenderMode, Mindmap, PersistenceManager } from '@wisemapping/mindplot';
import Client, { import Client, {
AccountInfo, AccountInfo,
BasicMapInfo, BasicMapInfo,
ChangeHistory, ChangeHistory,
ImportMapInfo, ImportMapInfo,
Label, Label,
MapInfo, MapInfo,
NewUser, NewUser,
Permission, Permission,
} from '..'; } from '..';
import { LocaleCode } from '../../app-i18n'; import { LocaleCode } from '../../app-i18n';
class CacheDecoratorClient implements Client { class CacheDecoratorClient implements Client {
private client: Client; private client: Client;
constructor(client: Client) { constructor(client: Client) {
this.client = client; this.client = client;
} }
onSessionExpired(callback?: () => void): () => void { onSessionExpired(callback?: () => void): () => void {
return this.client.onSessionExpired(callback); return this.client.onSessionExpired(callback);
} }
fetchMindmap(id: number): Mindmap { fetchMindmap(id: number): Mindmap {
return this.client.fetchMindmap(id); return this.client.fetchMindmap(id);
} }
deleteAccount(): Promise<void> { deleteAccount(): Promise<void> {
return this.client.deleteAccount(); return this.client.deleteAccount();
} }
importMap(model: ImportMapInfo): Promise<number> { importMap(model: ImportMapInfo): Promise<number> {
return this.client.importMap(model); return this.client.importMap(model);
} }
createMap(map: BasicMapInfo): Promise<number> { createMap(map: BasicMapInfo): Promise<number> {
return this.client.createMap(map); return this.client.createMap(map);
} }
deleteMaps(ids: number[]): Promise<void> { deleteMaps(ids: number[]): Promise<void> {
return this.client.deleteMaps(ids); return this.client.deleteMaps(ids);
} }
deleteMap(id: number): Promise<void> { deleteMap(id: number): Promise<void> {
return this.client.deleteMap(id); return this.client.deleteMap(id);
} }
renameMap(id: number, basicInfo: BasicMapInfo): Promise<void> { renameMap(id: number, basicInfo: BasicMapInfo): Promise<void> {
return this.client.renameMap(id, basicInfo); return this.client.renameMap(id, basicInfo);
} }
fetchAllMaps(): Promise<MapInfo[]> { fetchAllMaps(): Promise<MapInfo[]> {
return this.client.fetchAllMaps(); return this.client.fetchAllMaps();
} }
fetchMapPermissions(id: number): Promise<Permission[]> { fetchMapPermissions(id: number): Promise<Permission[]> {
return this.client.fetchMapPermissions(id); return this.client.fetchMapPermissions(id);
} }
addMapPermissions(id: number, message: string, permissions: Permission[]): Promise<void> { addMapPermissions(id: number, message: string, permissions: Permission[]): Promise<void> {
return this.client.addMapPermissions(id, message, permissions); return this.client.addMapPermissions(id, message, permissions);
} }
deleteMapPermission(id: number, email: string): Promise<void> { deleteMapPermission(id: number, email: string): Promise<void> {
return this.client.deleteMapPermission(id, email); return this.client.deleteMapPermission(id, email);
} }
duplicateMap(id: number, basicInfo: BasicMapInfo): Promise<number> { duplicateMap(id: number, basicInfo: BasicMapInfo): Promise<number> {
return this.client.duplicateMap(id, basicInfo); return this.client.duplicateMap(id, basicInfo);
} }
updateAccountLanguage(locale: LocaleCode): Promise<void> { updateAccountLanguage(locale: LocaleCode): Promise<void> {
return this.client.updateAccountLanguage(locale); return this.client.updateAccountLanguage(locale);
} }
updateAccountPassword(pasword: string): Promise<void> { updateAccountPassword(pasword: string): Promise<void> {
return this.client.updateAccountPassword(pasword); return this.client.updateAccountPassword(pasword);
} }
updateAccountInfo(firstname: string, lastname: string): Promise<void> { updateAccountInfo(firstname: string, lastname: string): Promise<void> {
return this.client.updateAccountInfo(firstname, lastname); return this.client.updateAccountInfo(firstname, lastname);
} }
updateStarred(id: number, starred: boolean): Promise<void> { updateStarred(id: number, starred: boolean): Promise<void> {
return this.client.updateStarred(id, starred); return this.client.updateStarred(id, starred);
} }
updateMapToPublic(id: number, isPublic: boolean): Promise<void> { updateMapToPublic(id: number, isPublic: boolean): Promise<void> {
return this.client.updateMapToPublic(id, isPublic); return this.client.updateMapToPublic(id, isPublic);
} }
fetchLabels(): Promise<Label[]> { fetchLabels(): Promise<Label[]> {
return this.client.fetchLabels(); return this.client.fetchLabels();
} }
createLabel(title: string, color: string): Promise<number> { createLabel(title: string, color: string): Promise<number> {
return this.client.createLabel(title, color); return this.client.createLabel(title, color);
} }
deleteLabel(id: number): Promise<void> { deleteLabel(id: number): Promise<void> {
return this.client.deleteLabel(id); return this.client.deleteLabel(id);
} }
addLabelToMap(labelId: number, mapId: number): Promise<void> { addLabelToMap(labelId: number, mapId: number): Promise<void> {
return this.client.addLabelToMap(labelId, mapId); return this.client.addLabelToMap(labelId, mapId);
} }
deleteLabelFromMap(labelId: number, mapId: number): Promise<void> { deleteLabelFromMap(labelId: number, mapId: number): Promise<void> {
return this.client.deleteLabelFromMap(labelId, mapId); return this.client.deleteLabelFromMap(labelId, mapId);
} }
fetchAccountInfo(): Promise<AccountInfo> { fetchAccountInfo(): Promise<AccountInfo> {
return this.client.fetchAccountInfo(); return this.client.fetchAccountInfo();
} }
registerNewUser(user: NewUser): Promise<void> { registerNewUser(user: NewUser): Promise<void> {
return this.client.registerNewUser(user); return this.client.registerNewUser(user);
} }
resetPassword(email: string): Promise<void> { resetPassword(email: string): Promise<void> {
return this.client.resetPassword(email); return this.client.resetPassword(email);
} }
fetchHistory(id: number): Promise<ChangeHistory[]> { fetchHistory(id: number): Promise<ChangeHistory[]> {
return this.client.fetchHistory(id); return this.client.fetchHistory(id);
} }
revertHistory(id: number, cid: number): Promise<void> { revertHistory(id: number, cid: number): Promise<void> {
return this.client.revertHistory(id, cid); return this.client.revertHistory(id, cid);
} }
buildPersistenceManager(mode: EditorRenderMode): PersistenceManager { buildPersistenceManager(mode: EditorRenderMode): PersistenceManager {
return this.client.buildPersistenceManager(mode); return this.client.buildPersistenceManager(mode);
} }
removePersistenceManager(): void {
return this.client.removePersistenceManager();
}
removePersistenceManager(): void {
return this.client.removePersistenceManager();
}
} }
export default CacheDecoratorClient; export default CacheDecoratorClient;

View File

@ -2,117 +2,117 @@ import { EditorRenderMode, Mindmap, PersistenceManager } from '@wisemapping/mind
import { Locale, LocaleCode } from '../app-i18n'; import { Locale, LocaleCode } from '../app-i18n';
export type NewUser = { export type NewUser = {
email: string; email: string;
firstname: string; firstname: string;
lastname: string; lastname: string;
password: string; password: string;
recaptcha: string | null; recaptcha: string | null;
}; };
export type ImportMapInfo = { export type ImportMapInfo = {
title: string; title: string;
description?: string; description?: string;
contentType?: string; contentType?: string;
content?: ArrayBuffer | null | string; content?: ArrayBuffer | null | string;
}; };
export type Label = { export type Label = {
id: number; id: number;
title: string; title: string;
color: string; color: string;
}; };
export type Role = 'owner' | 'editor' | 'viewer'; export type Role = 'owner' | 'editor' | 'viewer';
export type MapInfo = { export type MapInfo = {
id: number; id: number;
starred: boolean; starred: boolean;
title: string; title: string;
labels: Label[]; labels: Label[];
createdBy: string; createdBy: string;
creationTime: string; creationTime: string;
lastModificationBy: string; lastModificationBy: string;
lastModificationTime: string; lastModificationTime: string;
description: string; description: string;
isPublic: boolean; isPublic: boolean;
role: Role; role: Role;
}; };
export type ChangeHistory = { export type ChangeHistory = {
id: number; id: number;
lastModificationBy: string; lastModificationBy: string;
lastModificationTime: string; lastModificationTime: string;
}; };
export type BasicMapInfo = { export type BasicMapInfo = {
title: string; title: string;
description?: string; description?: string;
}; };
export type FieldError = { export type FieldError = {
id: string; id: string;
msg: string; msg: string;
}; };
export type ErrorInfo = { export type ErrorInfo = {
msg?: string; msg?: string;
fields?: Map<string, string>; fields?: Map<string, string>;
}; };
export type AccountInfo = { export type AccountInfo = {
firstname: string; firstname: string;
lastname: string; lastname: string;
email: string; email: string;
locale?: Locale; locale?: Locale;
}; };
export type Permission = { export type Permission = {
name?: string; name?: string;
email: string; email: string;
role: Role; role: Role;
}; };
interface Client { interface Client {
deleteAccount(): Promise<void>; deleteAccount(): Promise<void>;
importMap(model: ImportMapInfo): Promise<number>; importMap(model: ImportMapInfo): Promise<number>;
createMap(map: BasicMapInfo): Promise<number>; createMap(map: BasicMapInfo): Promise<number>;
deleteMaps(ids: number[]): Promise<void>; deleteMaps(ids: number[]): Promise<void>;
deleteMap(id: number): Promise<void>; deleteMap(id: number): Promise<void>;
renameMap(id: number, basicInfo: BasicMapInfo): Promise<void>; renameMap(id: number, basicInfo: BasicMapInfo): Promise<void>;
fetchAllMaps(): Promise<MapInfo[]>; fetchAllMaps(): Promise<MapInfo[]>;
fetchMapPermissions(id: number): Promise<Permission[]>; fetchMapPermissions(id: number): Promise<Permission[]>;
addMapPermissions(id: number, message: string, permissions: Permission[]): Promise<void>; addMapPermissions(id: number, message: string, permissions: Permission[]): Promise<void>;
deleteMapPermission(id: number, email: string): Promise<void>; deleteMapPermission(id: number, email: string): Promise<void>;
duplicateMap(id: number, basicInfo: BasicMapInfo): Promise<number>; duplicateMap(id: number, basicInfo: BasicMapInfo): Promise<number>;
updateAccountLanguage(locale: LocaleCode): Promise<void>; updateAccountLanguage(locale: LocaleCode): Promise<void>;
updateAccountPassword(pasword: string): Promise<void>; updateAccountPassword(pasword: string): Promise<void>;
updateAccountInfo(firstname: string, lastname: string): Promise<void>; updateAccountInfo(firstname: string, lastname: string): Promise<void>;
updateStarred(id: number, starred: boolean): Promise<void>; updateStarred(id: number, starred: boolean): Promise<void>;
updateMapToPublic(id: number, isPublic: boolean): Promise<void>; updateMapToPublic(id: number, isPublic: boolean): Promise<void>;
createLabel(title: string, color: string): Promise<number>; createLabel(title: string, color: string): Promise<number>;
fetchLabels(): Promise<Label[]>; fetchLabels(): Promise<Label[]>;
deleteLabel(id: number): Promise<void>; deleteLabel(id: number): Promise<void>;
addLabelToMap(labelId: number, mapId: number): Promise<void>; addLabelToMap(labelId: number, mapId: number): Promise<void>;
deleteLabelFromMap(labelId: number, mapId: number): Promise<void>; deleteLabelFromMap(labelId: number, mapId: number): Promise<void>;
fetchAccountInfo(): Promise<AccountInfo>; fetchAccountInfo(): Promise<AccountInfo>;
registerNewUser(user: NewUser): Promise<void>; registerNewUser(user: NewUser): Promise<void>;
resetPassword(email: string): Promise<void>; resetPassword(email: string): Promise<void>;
fetchHistory(id: number): Promise<ChangeHistory[]>; fetchHistory(id: number): Promise<ChangeHistory[]>;
revertHistory(id: number, cid: number): Promise<void>; revertHistory(id: number, cid: number): Promise<void>;
fetchMindmap(id: number): Mindmap; fetchMindmap(id: number): Mindmap;
buildPersistenceManager(mode: EditorRenderMode): PersistenceManager; buildPersistenceManager(mode: EditorRenderMode): PersistenceManager;
removePersistenceManager(): void; removePersistenceManager(): void;
onSessionExpired(callback?: () => void): () => void; onSessionExpired(callback?: () => void): () => void;
} }
export default Client; export default Client;

View File

@ -1,418 +1,425 @@
import { Mindmap, MockPersistenceManager, PersistenceManager } from '@wisemapping/mindplot'; import { Mindmap, MockPersistenceManager, PersistenceManager } from '@wisemapping/mindplot';
import XMLSerializerTango from '@wisemapping/mindplot/src/components/persistence/XMLSerializerTango'; import XMLSerializerTango from '@wisemapping/mindplot/src/components/persistence/XMLSerializerTango';
import Client, { import Client, {
AccountInfo, AccountInfo,
BasicMapInfo, BasicMapInfo,
ChangeHistory, ChangeHistory,
ImportMapInfo, ImportMapInfo,
Label, Label,
MapInfo, MapInfo,
NewUser, NewUser,
Permission, Permission,
} from '..'; } from '..';
import { LocaleCode, localeFromStr } from '../../app-i18n'; import { LocaleCode, localeFromStr } from '../../app-i18n';
import exampleMap from './example-map.wxml'; import exampleMap from './example-map.wxml';
const label1: Label = { const label1: Label = {
id: 1, id: 1,
title: 'label 1', title: 'label 1',
color: 'black', color: 'black',
} };
const label2: Label = { const label2: Label = {
id: 2, id: 2,
title: 'label 2', title: 'label 2',
color: 'green', color: 'green',
} };
const label3: Label = { const label3: Label = {
id: 3, id: 3,
title: 'label 3', title: 'label 3',
color: 'red', color: 'red',
} };
class MockClient implements Client { class MockClient implements Client {
private maps: MapInfo[] = []; private maps: MapInfo[] = [];
private labels: Label[] = []; private labels: Label[] = [];
private permissionsByMap: Map<number, Permission[]> = new Map(); private permissionsByMap: Map<number, Permission[]> = new Map();
private persistenceManager: PersistenceManager; private persistenceManager: PersistenceManager;
constructor() { constructor() {
// Remove, just for develop .... // Remove, just for develop ....
function createMapInfo( function createMapInfo(
id: number, id: number,
starred: boolean, starred: boolean,
title: string, title: string,
labels: Label[], labels: Label[],
creator: string, creator: string,
creationTime: string, creationTime: string,
modifiedByUser: string, modifiedByUser: string,
modifiedTime: string, modifiedTime: string,
description: string, description: string,
isPublic: boolean, isPublic: boolean,
role: 'owner' | 'viewer' | 'editor' role: 'owner' | 'viewer' | 'editor',
): MapInfo { ): MapInfo {
return { return {
id, id,
title, title,
labels, labels,
createdBy: creator, createdBy: creator,
creationTime, creationTime,
lastModificationBy: modifiedByUser, lastModificationBy: modifiedByUser,
lastModificationTime: modifiedTime, lastModificationTime: modifiedTime,
starred, starred,
description, description,
isPublic, isPublic,
role, role,
}; };
}
this.maps = [
createMapInfo(
1,
true,
'El Mapa',
[],
'Paulo',
'2008-06-02T00:00:00Z',
'Berna',
'2008-06-02T00:00:00Z',
'',
true,
'owner'
),
createMapInfo(
11,
false,
'El Mapa3',
[label1, label2],
'Paulo3',
'2008-06-02T00:00:00Z',
'Berna',
'2008-06-02T00:00:00Z',
'',
false,
'editor'
),
createMapInfo(
12,
false,
'El Mapa3',
[label2, label3],
'Paulo3',
'2008-06-02T00:00:00Z',
'Berna',
'2008-06-02T00:00:00Z',
'',
false,
'editor'
),
];
this.labels = [label1, label2, label3];
} }
onSessionExpired(callback?: () => void): () => void { this.maps = [
return callback; createMapInfo(
} 1,
true,
'El Mapa',
[],
'Paulo',
'2008-06-02T00:00:00Z',
'Berna',
'2008-06-02T00:00:00Z',
'',
true,
'owner',
),
createMapInfo(
11,
false,
'El Mapa3',
[label1, label2],
'Paulo3',
'2008-06-02T00:00:00Z',
'Berna',
'2008-06-02T00:00:00Z',
'',
false,
'editor',
),
createMapInfo(
12,
false,
'El Mapa3',
[label2, label3],
'Paulo3',
'2008-06-02T00:00:00Z',
'Berna',
'2008-06-02T00:00:00Z',
'',
false,
'editor',
),
];
fetchMindmap(id: number): Mindmap { this.labels = [label1, label2, label3];
const parser = new DOMParser(); }
const xmlDoc = parser.parseFromString(`
onSessionExpired(callback?: () => void): () => void {
return callback;
}
fetchMindmap(id: number): Mindmap {
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(
`
<map name="${id}" version="tango"> <map name="${id}" version="tango">
<topic central="true" text="This is the map ${id}" id="1" fontStyle=";;#ffffff;;;"></topic> <topic central="true" text="This is the map ${id}" id="1" fontStyle=";;#ffffff;;;"></topic>
</map> </map>
`, 'text/xml'); `,
'text/xml',
);
const serializer = new XMLSerializerTango(); const serializer = new XMLSerializerTango();
return serializer.loadFromDom(xmlDoc, String(id)); return serializer.loadFromDom(xmlDoc, String(id));
}
deleteMapPermission(id: number, email: string): Promise<void> {
let perm = this.permissionsByMap.get(id) || [];
perm = perm.filter((p) => p.email != email);
this.permissionsByMap.set(id, perm);
return Promise.resolve();
}
addMapPermissions(id: number, message: string, permissions: Permission[]): Promise<void> {
let perm = this.permissionsByMap.get(id) || [];
perm = perm.concat(permissions);
this.permissionsByMap.set(id, perm);
console.debug(`Message ${message}`);
return Promise.resolve();
}
fetchMapPermissions(id: number): Promise<Permission[]> {
let perm = this.permissionsByMap.get(id);
if (!perm) {
perm = [
{
name: 'Cosme Editor',
email: 'pepe@example.com',
role: 'editor',
},
{
name: 'Cosme Owner',
email: 'pepe2@example.com',
role: 'owner',
},
{
name: 'Cosme Viewer',
email: 'pepe3@example.com',
role: 'viewer',
},
];
this.permissionsByMap.set(id, perm);
} }
deleteMapPermission(id: number, email: string): Promise<void> { return Promise.resolve(perm);
let perm = this.permissionsByMap.get(id) || []; }
perm = perm.filter((p) => p.email != email);
this.permissionsByMap.set(id, perm); deleteAccount(): Promise<void> {
return Promise.resolve(); return Promise.resolve();
}
updateAccountInfo(firstname: string, lastname: string): Promise<void> {
console.log('firstname:' + firstname, +lastname);
return Promise.resolve();
}
updateAccountPassword(pasword: string): Promise<void> {
console.log('password:' + pasword);
return Promise.resolve();
}
updateAccountLanguage(locale: LocaleCode): Promise<void> {
localStorage.setItem('locale', locale);
return Promise.resolve();
}
importMap(model: ImportMapInfo): Promise<number> {
console.log('model:' + model);
return Promise.resolve(10);
}
fetchAccountInfo(): Promise<AccountInfo> {
console.log('Fetch account info ...');
const locale: LocaleCode | null = localStorage.getItem('locale') as LocaleCode;
return Promise.resolve({
firstname: 'Costme',
lastname: 'Fulanito',
email: 'test@example.com',
locale: localeFromStr(locale),
});
}
deleteMaps(ids: number[]): Promise<void> {
ids.forEach((id) => this.deleteMap(id));
return Promise.resolve();
}
revertHistory(id: number, cid: number): Promise<void> {
console.log('model:' + id + cid);
return Promise.resolve();
}
createMap(map: BasicMapInfo): Promise<number> {
throw new Error('Method not implemented.' + map);
}
fetchLabels(): Promise<Label[]> {
console.log('Fetching labels from server');
return Promise.resolve(this.labels);
}
updateMapToPublic(id: number, isPublic: boolean): Promise<void> {
const mapInfo = this.maps.find((m) => m.id == id);
if (mapInfo) {
mapInfo.isPublic = isPublic;
} }
return Promise.resolve();
}
addMapPermissions(id: number, message: string, permissions: Permission[]): Promise<void> { updateStarred(id: number, starred: boolean): Promise<void> {
let perm = this.permissionsByMap.get(id) || []; const mapInfo = this.maps.find((m) => m.id == id);
perm = perm.concat(permissions); if (!mapInfo) {
this.permissionsByMap.set(id, perm); console.log(`Could not find the map iwth id ${id}`);
return Promise.reject();
console.debug(`Message ${message}`);
return Promise.resolve();
} }
mapInfo.starred = starred;
return Promise.resolve();
}
fetchMapPermissions(id: number): Promise<Permission[]> { renameMap(id: number, basicInfo: BasicMapInfo): Promise<void> {
let perm = this.permissionsByMap.get(id); const exists = this.maps.find((m) => m.title == basicInfo.title) != undefined;
if (!perm) { if (!exists) {
perm = [ this.maps = this.maps.map((m) => {
{ const result = m;
name: 'Cosme Editor', if (m.id == id) {
email: 'pepe@example.com', result.description = basicInfo.description ? basicInfo.description : '';
role: 'editor', result.title = basicInfo.title;
},
{
name: 'Cosme Owner',
email: 'pepe2@example.com',
role: 'owner',
},
{
name: 'Cosme Viewer',
email: 'pepe3@example.com',
role: 'viewer',
},
];
this.permissionsByMap.set(id, perm);
} }
return Promise.resolve(perm); return result;
} });
return Promise.resolve();
} else {
const fieldErrors: Map<string, string> = new Map<string, string>();
fieldErrors.set('name', 'name already exists ');
deleteAccount(): Promise<void> { return Promise.reject({
return Promise.resolve(); msg: 'Map already exists ...' + basicInfo.title,
fields: fieldErrors,
});
} }
}
updateAccountInfo(firstname: string, lastname: string): Promise<void> { fetchHistory(id: number): Promise<ChangeHistory[]> {
console.log('firstname:' + firstname, +lastname); console.log(`Fetching history for ${id}`);
return Promise.resolve(); const result = [
{
id: 1,
lastModificationBy: 'Paulo',
lastModificationTime: '2008-06-02T00:00:00Z',
},
{
id: 2,
lastModificationBy: 'Paulo',
lastModificationTime: '2008-06-02T00:00:00Z',
},
{
id: 3,
lastModificationBy: 'Paulo',
lastModificationTime: '2008-06-02T00:00:00Z',
},
{
id: 4,
lastModificationBy: 'Paulo',
lastModificationTime: '2008-06-02T00:00:00Z',
},
{
id: 5,
lastModificationBy: 'Paulo',
lastModificationTime: '2008-06-02T00:00:00Z',
},
{
id: 6,
lastModificationBy: 'Paulo',
lastModificationTime: '2008-06-02T00:00:00Z',
},
{
id: 7,
lastModificationBy: 'Paulo',
lastModificationTime: '2008-06-02T00:00:00Z',
},
];
return Promise.resolve(result);
}
duplicateMap(id: number, basicInfo: BasicMapInfo): Promise<number> {
const exists = this.maps.find((m) => m.title == basicInfo.title) != undefined;
if (!exists) {
const newMap: MapInfo = {
id: Math.random() * 1000,
description: String(basicInfo.description),
title: basicInfo.title,
starred: false,
createdBy: 'current user',
labels: [],
lastModificationTime: '2008-06-02T00:00:00Z',
lastModificationBy: 'Berna',
creationTime: '2008-06-02T00:00:00Z',
isPublic: false,
role: 'owner',
};
this.maps.push(newMap);
return Promise.resolve(newMap.id);
} else {
const fieldErrors: Map<string, string> = new Map<string, string>();
fieldErrors.set('name', 'name already exists ');
return Promise.reject({
msg: 'Maps name must be unique:' + basicInfo.title,
fields: fieldErrors,
});
} }
}
updateAccountPassword(pasword: string): Promise<void> { createLabel(title: string, color: string): Promise<number> {
console.log('password:' + pasword); const newId =
return Promise.resolve(); Math.max.apply(
Number,
this.labels.map((l) => l.id),
) + 1;
this.labels.push({
id: newId,
title,
color,
});
return newId;
}
deleteLabel(id: number): Promise<void> {
this.labels = this.labels.filter((l) => l.id != id);
this.maps = this.maps.map((m) => {
return {
...m,
labels: m.labels.filter((l) => l.id != id),
};
});
return Promise.resolve();
}
addLabelToMap(labelId: number, mapId: number): Promise<void> {
const labelToAdd = this.labels.find((l) => l.id === labelId);
if (!labelToAdd) {
return Promise.reject({ msg: `unable to find label with id ${labelId}` });
} }
const map = this.maps.find((m) => m.id === mapId);
updateAccountLanguage(locale: LocaleCode): Promise<void> { if (!map) {
localStorage.setItem('locale', locale); return Promise.reject({ msg: `unable to find map with id ${mapId}` });
return Promise.resolve();
} }
map.labels.push(labelToAdd);
return Promise.resolve();
}
importMap(model: ImportMapInfo): Promise<number> { deleteLabelFromMap(labelId: number, mapId: number): Promise<void> {
console.log('model:' + model); const map = this.maps.find((m) => m.id === mapId);
return Promise.resolve(10); if (!map) {
return Promise.reject({ msg: `unable to find map with id ${mapId}` });
} }
map.labels = map.labels.filter((l) => l.id !== labelId);
return Promise.resolve();
}
fetchAccountInfo(): Promise<AccountInfo> { deleteMap(id: number): Promise<void> {
console.log('Fetch account info ...'); this.maps = this.maps.filter((m) => m.id != id);
const locale: LocaleCode | null = localStorage.getItem('locale') as LocaleCode; return Promise.resolve();
return Promise.resolve({ }
firstname: 'Costme',
lastname: 'Fulanito', registerNewUser(user: NewUser): Promise<void> {
email: 'test@example.com', console.log('user:' + user);
locale: localeFromStr(locale), if (user.email == 'error@example.com') {
}); return Promise.reject({ msg: 'Unexpected error' });
} }
return Promise.resolve();
}
deleteMaps(ids: number[]): Promise<void> { fetchAllMaps(): Promise<MapInfo[]> {
ids.forEach((id) => this.deleteMap(id)); console.log('Fetching maps from server');
return Promise.resolve(); return Promise.resolve(this.maps);
}
resetPassword(email: string): Promise<void> {
console.log('email:' + email);
return Promise.resolve();
}
buildPersistenceManager(): PersistenceManager {
if (this.persistenceManager) {
return this.persistenceManager;
} }
revertHistory(id: number, cid: number): Promise<void> { const persistence: PersistenceManager = new MockPersistenceManager(exampleMap);
console.log('model:' + id + cid); this.persistenceManager = persistence;
return Promise.resolve(); return persistence;
} }
createMap(map: BasicMapInfo): Promise<number> { removePersistenceManager(): void {
throw new Error('Method not implemented.' + map); if (this.persistenceManager) {
} delete this.persistenceManager;
fetchLabels(): Promise<Label[]> {
console.log('Fetching labels from server');
return Promise.resolve(this.labels);
}
updateMapToPublic(id: number, isPublic: boolean): Promise<void> {
const mapInfo = this.maps.find((m) => m.id == id);
if (mapInfo) {
mapInfo.isPublic = isPublic;
}
return Promise.resolve();
}
updateStarred(id: number, starred: boolean): Promise<void> {
const mapInfo = this.maps.find((m) => m.id == id);
if (!mapInfo) {
console.log(`Could not find the map iwth id ${id}`);
return Promise.reject();
}
mapInfo.starred = starred;
return Promise.resolve();
}
renameMap(id: number, basicInfo: BasicMapInfo): Promise<void> {
const exists = this.maps.find((m) => m.title == basicInfo.title) != undefined;
if (!exists) {
this.maps = this.maps.map((m) => {
const result = m;
if (m.id == id) {
result.description = basicInfo.description ? basicInfo.description : '';
result.title = basicInfo.title;
}
return result;
});
return Promise.resolve();
} else {
const fieldErrors: Map<string, string> = new Map<string, string>();
fieldErrors.set('name', 'name already exists ');
return Promise.reject({
msg: 'Map already exists ...' + basicInfo.title,
fields: fieldErrors,
});
}
}
fetchHistory(id: number): Promise<ChangeHistory[]> {
console.log(`Fetching history for ${id}`);
const result = [
{
id: 1,
lastModificationBy: 'Paulo',
lastModificationTime: '2008-06-02T00:00:00Z',
},
{
id: 2,
lastModificationBy: 'Paulo',
lastModificationTime: '2008-06-02T00:00:00Z',
},
{
id: 3,
lastModificationBy: 'Paulo',
lastModificationTime: '2008-06-02T00:00:00Z',
},
{
id: 4,
lastModificationBy: 'Paulo',
lastModificationTime: '2008-06-02T00:00:00Z',
},
{
id: 5,
lastModificationBy: 'Paulo',
lastModificationTime: '2008-06-02T00:00:00Z',
},
{
id: 6,
lastModificationBy: 'Paulo',
lastModificationTime: '2008-06-02T00:00:00Z',
},
{
id: 7,
lastModificationBy: 'Paulo',
lastModificationTime: '2008-06-02T00:00:00Z',
},
];
return Promise.resolve(result);
}
duplicateMap(id: number, basicInfo: BasicMapInfo): Promise<number> {
const exists = this.maps.find((m) => m.title == basicInfo.title) != undefined;
if (!exists) {
const newMap: MapInfo = {
id: Math.random() * 1000,
description: String(basicInfo.description),
title: basicInfo.title,
starred: false,
createdBy: 'current user',
labels: [],
lastModificationTime: '2008-06-02T00:00:00Z',
lastModificationBy: 'Berna',
creationTime: '2008-06-02T00:00:00Z',
isPublic: false,
role: 'owner',
};
this.maps.push(newMap);
return Promise.resolve(newMap.id);
} else {
const fieldErrors: Map<string, string> = new Map<string, string>();
fieldErrors.set('name', 'name already exists ');
return Promise.reject({
msg: 'Maps name must be unique:' + basicInfo.title,
fields: fieldErrors,
});
}
}
createLabel(title: string, color: string): Promise<number> {
const newId = Math.max.apply(Number, this.labels.map(l => l.id)) + 1;
this.labels.push({
id: newId,
title,
color,
});
return newId;
}
deleteLabel(id: number): Promise<void> {
this.labels = this.labels.filter((l) => l.id != id);
this.maps = this.maps.map(m => {
return {
...m,
labels: m.labels.filter((l) => l.id != id)
};
});
return Promise.resolve();
}
addLabelToMap(labelId: number, mapId: number): Promise<void> {
const labelToAdd = this.labels.find((l) => l.id === labelId);
if (!labelToAdd) {
return Promise.reject({ msg: `unable to find label with id ${labelId}` });
}
const map = this.maps.find((m) => m.id === mapId);
if (!map) {
return Promise.reject({ msg: `unable to find map with id ${mapId}` });
}
map.labels.push(labelToAdd);
return Promise.resolve();
}
deleteLabelFromMap(labelId: number, mapId: number): Promise<void> {
const map = this.maps.find((m) => m.id === mapId);
if (!map) {
return Promise.reject({ msg: `unable to find map with id ${mapId}` });
}
map.labels = map.labels.filter((l) => l.id !== labelId);
return Promise.resolve();
}
deleteMap(id: number): Promise<void> {
this.maps = this.maps.filter((m) => m.id != id);
return Promise.resolve();
}
registerNewUser(user: NewUser): Promise<void> {
console.log('user:' + user);
if (user.email == "error@example.com") {
return Promise.reject({ msg: "Unexpected error" });
}
return Promise.resolve();
}
fetchAllMaps(): Promise<MapInfo[]> {
console.log('Fetching maps from server');
return Promise.resolve(this.maps);
}
resetPassword(email: string): Promise<void> {
console.log('email:' + email);
return Promise.resolve();
}
buildPersistenceManager(): PersistenceManager {
if (this.persistenceManager) {
return this.persistenceManager;
}
const persistence: PersistenceManager = new MockPersistenceManager(exampleMap);
this.persistenceManager = persistence;
return persistence;
}
removePersistenceManager(): void {
if (this.persistenceManager) {
delete this.persistenceManager;
}
} }
}
} }
export default MockClient; export default MockClient;

File diff suppressed because it is too large Load Diff

View File

@ -3,43 +3,45 @@ import { EditorRenderMode } from '@wisemapping/mindplot';
import AppConfig from '../../classes/app-config'; import AppConfig from '../../classes/app-config';
class EditorOptionsBuilder { class EditorOptionsBuilder {
static build(locale: string, mode: EditorRenderMode, hotkeys: boolean): EditorOptions { static build(locale: string, mode: EditorRenderMode, hotkeys: boolean): EditorOptions {
let options: EditorOptions = {
enableKeyboardEvents: hotkeys,
locale: locale,
mode: mode,
};
let options: EditorOptions = { if (!AppConfig.isDevelopEnv()) {
enableKeyboardEvents: hotkeys, options = {
locale: locale, zoom:
mode: mode, global.userOptions?.zoom != undefined
}; ? Number.parseFloat(global?.userOptions?.zoom as string)
: 0.8,
if (!AppConfig.isDevelopEnv()) { locked: global.mindmapLocked,
options = { lockedMsg: global.mindmapLockedMsg,
zoom: (global.userOptions?.zoom != undefined mapTitle: global.mapTitle,
? Number.parseFloat(global?.userOptions?.zoom as string) ...options,
: 0.8), };
locked: global.mindmapLocked, } else {
lockedMsg: global.mindmapLockedMsg, // Running in a development mode.
mapTitle: global.mapTitle, console.log('Running editor in development mode');
...options options = {
} zoom: 0.8,
} else { locked: false,
// Running in a development mode. mapTitle: 'Develop Mindnap',
console.log('Running editor in development mode'); ...options,
options = { };
zoom: 0.8,
locked: false,
mapTitle: "Develop Mindnap",
...options
}
}
return options;
} }
return options;
}
static loadMapId(): number { static loadMapId(): number {
const result = !AppConfig.isDevelopEnv() ? global.mapId : 11; const result = !AppConfig.isDevelopEnv() ? global.mapId : 11;
if (result === undefined) { if (result === undefined) {
throw Error(`Could not resolve mapId. Map Id: global.mapId: ${result} , global.mapTitle: ${global.mapTitle}, global.lockSession: ${global.lockSession}`); throw Error(
} `Could not resolve mapId. Map Id: global.mapId: ${result} , global.mapTitle: ${global.mapTitle}, global.lockSession: ${global.lockSession}`,
return result; );
} }
return result;
}
} }
export default EditorOptionsBuilder; export default EditorOptionsBuilder;

View File

@ -2,10 +2,10 @@ import withStyles from '@mui/styles/withStyles';
import Alert from '@mui/material/Alert'; import Alert from '@mui/material/Alert';
export const StyledAlert = withStyles({ export const StyledAlert = withStyles({
root: { root: {
padding: '10px 15px', padding: '10px 15px',
margin: '5px 0px ', margin: '5px 0px ',
}, },
})(Alert); })(Alert);
export default StyledAlert; export default StyledAlert;

View File

@ -2,46 +2,46 @@ import styled from 'styled-components';
/* Footer */ /* Footer */
export const StyledFooter = styled.footer` export const StyledFooter = styled.footer`
height: 250px; height: 250px;
margin-top: 80px; margin-top: 80px;
padding: 30px 40px 10px 50px; padding: 30px 40px 10px 50px;
background-color: #f9a826; background-color: #f9a826;
display: grid; display: grid;
grid-template-columns: 200px 1fr 1fr 1fr 3fr; grid-template-columns: 200px 1fr 1fr 1fr 3fr;
& a { & a {
font-size: 14px; font-size: 14px;
color: white; color: white;
word-wrap: nowrap; word-wrap: nowrap;
} }
& h4 { & h4 {
font-size: 14px; font-size: 14px;
color: white; color: white;
word-wrap: nowrap; word-wrap: nowrap;
font-weight: 500px; font-weight: 500px;
margin: 0px; margin: 0px;
} }
& > svg { & > svg {
grid-column: 1; grid-column: 1;
} }
& div:nth-child(2) { & div:nth-child(2) {
grid-column: 2; grid-column: 2;
} }
& div:nth-child(3) { & div:nth-child(3) {
grid-column: 3; grid-column: 3;
} }
& div:nth-child(4) { & div:nth-child(4) {
grid-column: 4; grid-column: 4;
} }
& div:nth-child(5) { & div:nth-child(5) {
grid-column: 5; grid-column: 5;
text-align: right; text-align: right;
display: inline-block; display: inline-block;
visibility: visible; visibility: visible;
} }
`; `;

View File

@ -1,83 +1,81 @@
import styled from 'styled-components'; import styled from 'styled-components';
export const StyledNav = styled.nav` export const StyledNav = styled.nav`
height: 90px; height: 90px;
position: sticky;
top: -16px;
z-index: 1;
-webkit-backface-visibility: hidden;
&::before,
&::after {
content: '';
display: block;
height: 16px;
position: sticky; position: sticky;
top: -16px; }
z-index: 1;
-webkit-backface-visibility: hidden;
&::before, &::before {
&::after { top: 58px;
content: ''; box-shadow: 0 4px 10px 0 rgba(202, 34, 34, 0.05), 0 5px 30px 0 rgba(0, 0, 0, 0.05);
display: block; }
height: 16px;
position: sticky;
}
&::before { &::after {
top: 58px; background: linear-gradient(white, rgba(255, 255, 255, 0.3));
box-shadow: 0 4px 10px 0 rgba(202, 34, 34, 0.05), 0 5px 30px 0 rgba(0, 0, 0, 0.05); top: 0;
} z-index: 2;
}
&::after { .header-area-right2 {
background: linear-gradient(white, rgba(255, 255, 255, 0.3)); grid-column-start: 3;
top: 0; text-align: right;
z-index: 2; }
}
.header-area-right2 { .header-area-right1 span,
grid-column-start: 3; .header-area-right2 span {
text-align: right; font-size: 15px;
} }
.header-area-right1 span, .header-area-content-span {
.header-area-right2 span { grid-column-start: 2;
font-size: 15px; grid-column-end: 3;
} text-align: right;
font-size: 14px;
padding: 10px;
}
@media only screen and (max-width: 600px) {
.header-area-content-span { .header-area-content-span {
grid-column-start: 2; display: none;
grid-column-end: 3; grid-column-start: 2;
text-align: right; grid-column-end: 3;
font-size: 14px; text-align: right;
padding: 10px; font-size: 14px;
padding: 10px;
} }
}
@media only screen and (max-width: 600px) {
.header-area-content-span {
display: none;
grid-column-start: 2;
grid-column-end: 3;
text-align: right;
font-size: 14px;
padding: 10px;
}
}
`; `;
export const StyledDiv = styled.nav` export const StyledDiv = styled.nav`
background: white; background: white;
height: 74px; height: 74px;
padding: 10px; padding: 10px;
position: sticky; position: sticky;
top: 0px; top: 0px;
margin-top: -16px; margin-top: -16px;
z-index: 3; z-index: 3;
display: grid; display: grid;
white-space: nowrap; white-space: nowrap;
grid-template-columns: 150px 1fr 160px 20px; grid-template-columns: 150px 1fr 160px 20px;
`; `;
export const Logo = styled.span` export const Logo = styled.span`
grid-column-start: 1; grid-column-start: 1;
margin-left: 20px; margin-left: 20px;
margin-top: 0px; margin-top: 0px;
.header-logo a { .header-logo a {
padding: 0px; padding: 0px;
} }
`; `;

View File

@ -2,7 +2,7 @@ import MenuItem from '@mui/material/MenuItem';
import withStyles from '@mui/styles/withStyles'; import withStyles from '@mui/styles/withStyles';
export const StyledMenuItem = withStyles({ export const StyledMenuItem = withStyles({
root: { root: {
width: '300px', width: '300px',
}, },
})(MenuItem); })(MenuItem);

View File

@ -3,23 +3,23 @@ import IconButton from '@mui/material/IconButton';
import LabelTwoTone from '@mui/icons-material/LabelTwoTone'; import LabelTwoTone from '@mui/icons-material/LabelTwoTone';
export const StyledButton = styled(IconButton)` export const StyledButton = styled(IconButton)`
margin: 4px; margin: 4px;
`; `;
export const NewLabelContainer = styled.div` export const NewLabelContainer = styled.div`
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
`; `;
export const NewLabelColor = styled(LabelTwoTone)` export const NewLabelColor = styled(LabelTwoTone)`
margin-right: 12px; margin-right: 12px;
cursor: pointer; cursor: pointer;
`; `;
export const CreateLabel = styled.div` export const CreateLabel = styled.div`
padding-top: 10px; padding-top: 10px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: flex-end; justify-content: flex-end;
`; `;

View File

@ -5,25 +5,25 @@ import DialogTitle from '@mui/material/DialogTitle';
import withStyles from '@mui/styles/withStyles'; import withStyles from '@mui/styles/withStyles';
export const StyledDialogContent = withStyles({ export const StyledDialogContent = withStyles({
root: { root: {
padding: '0px 39px', padding: '0px 39px',
}, },
})(DialogContent); })(DialogContent);
export const StyledDialogTitle = withStyles({ export const StyledDialogTitle = withStyles({
root: { root: {
padding: '39px 39px 10px 39px', padding: '39px 39px 10px 39px',
}, },
})(DialogTitle); })(DialogTitle);
export const StyledDialogActions = withStyles({ export const StyledDialogActions = withStyles({
root: { root: {
padding: '39px 39px 39px 39px', padding: '39px 39px 39px 39px',
}, },
})(DialogActions); })(DialogActions);
export const StyledDialog = withStyles({ export const StyledDialog = withStyles({
root: { root: {
borderRadius: '9px', borderRadius: '9px',
}, },
})(Dialog); })(Dialog);

View File

@ -2,19 +2,19 @@ import createStyles from '@mui/styles/createStyles';
import makeStyles from '@mui/styles/makeStyles'; import makeStyles from '@mui/styles/makeStyles';
export const useStyles = makeStyles(() => export const useStyles = makeStyles(() =>
createStyles({ createStyles({
select: { select: {
height: '40px', height: '40px',
borderRadius: '9px', borderRadius: '9px',
width: '300px', width: '300px',
fontSize: '14px', fontSize: '14px',
margin: '0px 40px', margin: '0px 40px',
}, },
menu: { menu: {
fontSize: '14px', fontSize: '14px',
}, },
label: { label: {
margin: '5px 0px', margin: '5px 0px',
}, },
}) }),
); );

View File

@ -2,14 +2,14 @@ import createStyles from '@mui/styles/createStyles';
import makeStyles from '@mui/styles/makeStyles'; import makeStyles from '@mui/styles/makeStyles';
export const useStyles = makeStyles(() => export const useStyles = makeStyles(() =>
createStyles({ createStyles({
textarea: { textarea: {
width: '100%', width: '100%',
padding: '15px 15px', padding: '15px 15px',
marging: '0px 10px', marging: '0px 10px',
}, },
textDesc: { textDesc: {
width: '150px', width: '150px',
}, },
}) }),
); );

View File

@ -2,9 +2,9 @@ import createStyles from '@mui/styles/createStyles';
import makeStyles from '@mui/styles/makeStyles'; import makeStyles from '@mui/styles/makeStyles';
export const useStyles = makeStyles(() => export const useStyles = makeStyles(() =>
createStyles({ createStyles({
paper: { paper: {
maxWidth: '420px', maxWidth: '420px',
}, },
}) }),
); );

View File

@ -2,11 +2,11 @@ import createStyles from '@mui/styles/createStyles';
import makeStyles from '@mui/styles/makeStyles'; import makeStyles from '@mui/styles/makeStyles';
export const useStyles = makeStyles(() => export const useStyles = makeStyles(() =>
createStyles({ createStyles({
textarea: { textarea: {
width: '100%', width: '100%',
padding: '15px 15px', padding: '15px 15px',
marging: '0px 10px', marging: '0px 10px',
}, },
}) }),
); );

View File

@ -2,25 +2,25 @@ import createStyles from '@mui/styles/createStyles';
import makeStyles from '@mui/styles/makeStyles'; import makeStyles from '@mui/styles/makeStyles';
export const useStyles = makeStyles(() => export const useStyles = makeStyles(() =>
createStyles({ createStyles({
actionContainer: { actionContainer: {
padding: '10px 0px', padding: '10px 0px',
border: '1px solid rgba(0, 0, 0, 0.12)', border: '1px solid rgba(0, 0, 0, 0.12)',
borderRadius: '8px 8px 0px 0px', borderRadius: '8px 8px 0px 0px',
textAlign: 'center', textAlign: 'center',
}, },
textArea: { textArea: {
width: '730px', width: '730px',
margin: '5px 0px', margin: '5px 0px',
padding: '10px', padding: '10px',
}, },
listPaper: { listPaper: {
maxHeight: 200, maxHeight: 200,
overflowY: 'scroll', overflowY: 'scroll',
}, },
paper: { paper: {
width: '850px', width: '850px',
minWidth: '850px', minWidth: '850px',
}, },
}) }),
); );

View File

@ -2,7 +2,7 @@ import FormGroup from '@mui/material/FormGroup';
import styled from 'styled-components'; import styled from 'styled-components';
export const LabelListContainer = styled(FormGroup)` export const LabelListContainer = styled(FormGroup)`
max-height: 400px; max-height: 400px;
flex-wrap: nowrap; flex-wrap: nowrap;
overflow-y: scroll; overflow-y: scroll;
`; `;

View File

@ -8,8 +8,8 @@ export const LabelContainer = styled.div`
align-items: center; align-items: center;
font-size: smaller; font-size: smaller;
`; `;
export const LabelText = styled.span` export const LabelText = styled.span`
margin-left: 4px; margin-left: 4px;
margin-right: 2px; margin-right: 2px;
`; `;

View File

@ -8,8 +8,8 @@ export const LabelContainer = styled.div`
align-items: center; align-items: center;
font-size: smaller; font-size: smaller;
`; `;
export const LabelText = styled.span` export const LabelText = styled.span`
margin-left: 4px; margin-left: 4px;
margin-right: 2px; margin-right: 2px;
`; `;

View File

@ -4,108 +4,108 @@ import createStyles from '@mui/styles/createStyles';
import makeStyles from '@mui/styles/makeStyles'; import makeStyles from '@mui/styles/makeStyles';
export const useStyles = makeStyles((theme: Theme) => export const useStyles = makeStyles((theme: Theme) =>
createStyles({ createStyles({
root: { root: {
width: '100%', width: '100%',
},
paper: {
width: '100%',
marginBottom: theme.spacing(2),
},
table: {
minWidth: 750,
'& tr:nth-child(even)': {
background: 'white',
},
'& tr:nth-child(odd)': {
background: 'rgba(221, 221, 221, 0.35)',
},
// '&:hover tr': {
// backgroundColor: 'rgba(150, 150, 150, 0.7)',
// }
},
headerCell: {
background: 'white',
fontWeight: 'bold',
color: 'rgba(0, 0, 0, 0.44)',
border: 0,
},
bodyCell: {
border: '0px',
},
labelsCell: {
maxWidth: '300px',
overflow: 'hidden',
textAlign: 'right',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
},
visuallyHidden: {
border: 0,
clip: 'rect(0 0 0 0)',
height: 1,
margin: -1,
overflow: 'hidden',
padding: 0,
position: 'absolute',
top: 20,
width: 1,
},
toolbar: {
display: 'flex',
borderBottom: '1px solid #cccccc',
padding: '0',
marging: '0',
},
toolbarActions: {
flexGrow: 1,
paddingLeft: '23px;',
},
toolbarListActions: {
flexGrow: 1,
},
search: {
borderRadius: 9,
backgroundColor: alpha(theme.palette.common.white, 0.15),
'&:hover': {
backgroundColor: alpha(theme.palette.common.white, 0.25),
},
margin: '10px 0px',
width: '100%',
[theme.breakpoints.up('sm')]: {
marginLeft: theme.spacing(1),
width: 'auto',
},
float: 'right',
},
searchIcon: {
padding: '6px 0 0 5px',
height: '100%',
position: 'absolute',
pointerEvents: 'none',
alignItems: 'center',
justifyContent: 'center',
},
searchInputRoot: {
color: 'inherit',
},
toolbalLeft: {
float: 'right',
},
searchInputInput: {
// padding: theme.spacing(1, 1, 1, 0),
// vertical padding + font size from searchIcon
border: '1px solid #ffa800',
borderRadius: 4,
paddingLeft: `calc(1em + ${theme.spacing(4)})`,
transition: theme.transitions.create('width'),
width: '100%',
[theme.breakpoints.up('sm')]: {
width: '12ch',
'&:focus': {
width: '20ch',
}, },
paper: { },
width: '100%', },
marginBottom: theme.spacing(2), }),
},
table: {
minWidth: 750,
'& tr:nth-child(even)': {
background: 'white',
},
'& tr:nth-child(odd)': {
background: 'rgba(221, 221, 221, 0.35)',
},
// '&:hover tr': {
// backgroundColor: 'rgba(150, 150, 150, 0.7)',
// }
},
headerCell: {
background: 'white',
fontWeight: 'bold',
color: 'rgba(0, 0, 0, 0.44)',
border: 0,
},
bodyCell: {
border: '0px',
},
labelsCell: {
maxWidth: '300px',
overflow: 'hidden',
textAlign: 'right',
whiteSpace: 'nowrap',
textOverflow: 'ellipsis'
},
visuallyHidden: {
border: 0,
clip: 'rect(0 0 0 0)',
height: 1,
margin: -1,
overflow: 'hidden',
padding: 0,
position: 'absolute',
top: 20,
width: 1,
},
toolbar: {
display: 'flex',
borderBottom: '1px solid #cccccc',
padding: '0',
marging: '0',
},
toolbarActions: {
flexGrow: 1,
paddingLeft: '23px;'
},
toolbarListActions: {
flexGrow: 1,
},
search: {
borderRadius: 9,
backgroundColor: alpha(theme.palette.common.white, 0.15),
'&:hover': {
backgroundColor: alpha(theme.palette.common.white, 0.25),
},
margin: '10px 0px',
width: '100%',
[theme.breakpoints.up('sm')]: {
marginLeft: theme.spacing(1),
width: 'auto',
},
float: 'right',
},
searchIcon: {
padding: '6px 0 0 5px',
height: '100%',
position: 'absolute',
pointerEvents: 'none',
alignItems: 'center',
justifyContent: 'center',
},
searchInputRoot: {
color: 'inherit',
},
toolbalLeft: {
float: 'right',
},
searchInputInput: {
// padding: theme.spacing(1, 1, 1, 0),
// vertical padding + font size from searchIcon
border: '1px solid #ffa800',
borderRadius: 4,
paddingLeft: `calc(1em + ${theme.spacing(4)})`,
transition: theme.transitions.create('width'),
width: '100%',
[theme.breakpoints.up('sm')]: {
width: '12ch',
'&:focus': {
width: '20ch',
},
},
},
})
); );

View File

@ -6,61 +6,61 @@ import makeStyles from '@mui/styles/makeStyles';
const drawerWidth = 300; const drawerWidth = 300;
export const useStyles = makeStyles((theme: Theme) => export const useStyles = makeStyles((theme: Theme) =>
createStyles({ createStyles({
root: { root: {
display: 'flex', display: 'flex',
}, },
appBar: { appBar: {
zIndex: theme.zIndex.drawer + 1, zIndex: theme.zIndex.drawer + 1,
transition: theme.transitions.create(['width', 'margin'], { transition: theme.transitions.create(['width', 'margin'], {
easing: theme.transitions.easing.sharp, easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen, duration: theme.transitions.duration.leavingScreen,
}), }),
background: '#ffffff', background: '#ffffff',
}, },
appBarShift: { appBarShift: {
marginLeft: drawerWidth, marginLeft: drawerWidth,
width: `calc(100% - ${drawerWidth}px)`, width: `calc(100% - ${drawerWidth}px)`,
transition: theme.transitions.create(['width', 'margin'], { transition: theme.transitions.create(['width', 'margin'], {
easing: theme.transitions.easing.sharp, easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen, duration: theme.transitions.duration.enteringScreen,
}), }),
}, },
newMapButton: { newMapButton: {
marginRight: 10, marginRight: 10,
minWidth: '130px', minWidth: '130px',
}, },
importButton: { importButton: {
marginRight: 10, marginRight: 10,
minWidth: '130px', minWidth: '130px',
}, },
rightButtonGroup: { rightButtonGroup: {
marginRight: 10, marginRight: 10,
flexGrow: 10, flexGrow: 10,
textAlign: 'right', textAlign: 'right',
minWidth: '280px', minWidth: '280px',
}, },
drawer: { drawer: {
width: drawerWidth, width: drawerWidth,
flexShrink: 0, flexShrink: 0,
whiteSpace: 'nowrap', whiteSpace: 'nowrap',
}, },
drawerOpen: { drawerOpen: {
background: '#ffa800', background: '#ffa800',
width: drawerWidth, width: drawerWidth,
transition: theme.transitions.create('width', { transition: theme.transitions.create('width', {
easing: theme.transitions.easing.sharp, easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen, duration: theme.transitions.duration.enteringScreen,
}), }),
}, },
toolbar: { toolbar: {
display: 'flex', display: 'flex',
justifyContent: 'flex-end', justifyContent: 'flex-end',
minHeight: '44px', minHeight: '44px',
}, },
content: { content: {
flexGrow: 1, flexGrow: 1,
padding: '24px 0px', padding: '24px 0px',
}, },
}) }),
); );

View File

@ -6,79 +6,82 @@ import { useSelector } from 'react-redux';
import AppConfig from '../classes/app-config'; import AppConfig from '../classes/app-config';
import { RootState } from './rootReducer'; import { RootState } from './rootReducer';
export interface ClientStatus { export interface ClientStatus {
state: 'healthy' | 'session-expired'; state: 'healthy' | 'session-expired';
msg?: string; msg?: string;
} }
export interface ClientState { export interface ClientState {
instance: Client; instance: Client;
status: ClientStatus; status: ClientStatus;
} }
const initialState: ClientState = { const initialState: ClientState = {
instance: AppConfig.buildClient(), instance: AppConfig.buildClient(),
status: { state: 'healthy' }, status: { state: 'healthy' },
}; };
export const clientSlice = createSlice({ export const clientSlice = createSlice({
name: 'client', name: 'client',
initialState: initialState, initialState: initialState,
reducers: { reducers: {
sessionExpired(state) { sessionExpired(state) {
state.status = { state.status = {
state: 'session-expired', state: 'session-expired',
msg: 'Sessions has expired. You need to login again', msg: 'Sessions has expired. You need to login again',
}; };
},
}, },
},
}); });
type MapLoadResult = { type MapLoadResult = {
isLoading: boolean; isLoading: boolean;
error: ErrorInfo | null; error: ErrorInfo | null;
map: MapInfo | null; map: MapInfo | null;
}; };
export const fetchMapById = (id: number): MapLoadResult => { export const fetchMapById = (id: number): MapLoadResult => {
const client: Client = useSelector(activeInstance); const client: Client = useSelector(activeInstance);
const { isLoading, error, data } = useQuery<unknown, ErrorInfo, MapInfo[]>(`maps-${id}`, () => { const { isLoading, error, data } = useQuery<unknown, ErrorInfo, MapInfo[]>(`maps-${id}`, () => {
return client.fetchAllMaps(); return client.fetchAllMaps();
}); });
// If the map can not be loaded, create an error object. // If the map can not be loaded, create an error object.
let map: MapInfo; let map: MapInfo;
let errorMsg: ErrorInfo = error; let errorMsg: ErrorInfo = error;
if (!isLoading) { if (!isLoading) {
// Sanitize error structure ... // Sanitize error structure ...
if (errorMsg) { if (errorMsg) {
errorMsg = Object.keys(error).length !== 0 ? error : null; errorMsg = Object.keys(error).length !== 0 ? error : null;
}
// Seach for object...
map = data?.find((m) => m.id == id);
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 }; // Seach for object...
map = data?.find((m) => m.id == id);
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 };
}; };
export const fetchAccount = (): AccountInfo | undefined => { export const fetchAccount = (): AccountInfo | undefined => {
const client: Client = useSelector(activeInstance); const client: Client = useSelector(activeInstance);
const { data } = useQuery<unknown, ErrorInfo, AccountInfo>('account', () => { const { data } = useQuery<unknown, ErrorInfo, AccountInfo>('account', () => {
return client.fetchAccountInfo(); return client.fetchAccountInfo();
}); });
return data; return data;
}; };
export const activeInstance = (state: RootState): Client => { export const activeInstance = (state: RootState): Client => {
return state.client.instance; return state.client.instance;
}; };
export const activeInstanceStatus = (state: RootState): ClientStatus => { export const activeInstanceStatus = (state: RootState): ClientStatus => {
return state.client.status; return state.client.status;
}; };
export const { sessionExpired } = clientSlice.actions; export const { sessionExpired } = clientSlice.actions;
export default clientSlice.reducer; export default clientSlice.reducer;

View File

@ -1,30 +1,30 @@
import { createSlice } from "@reduxjs/toolkit"; import { createSlice } from '@reduxjs/toolkit';
import { RootState } from "./rootReducer"; import { RootState } from './rootReducer';
export interface EditorState { export interface EditorState {
hotkeysEnabled: boolean; hotkeysEnabled: boolean;
} }
const initialState: EditorState = { const initialState: EditorState = {
hotkeysEnabled: true, hotkeysEnabled: true,
}; };
export const editorSlice = createSlice({ export const editorSlice = createSlice({
name: 'editor', name: 'editor',
initialState: initialState, initialState: initialState,
reducers: { reducers: {
disableHotkeys(state) { disableHotkeys(state) {
state.hotkeysEnabled = false; state.hotkeysEnabled = false;
},
enableHotkeys(state) {
state.hotkeysEnabled = true;
},
}, },
enableHotkeys(state) {
state.hotkeysEnabled = true;
},
},
}); });
export const hotkeysEnabled = (state: RootState): boolean => { export const hotkeysEnabled = (state: RootState): boolean => {
return state.editor.hotkeysEnabled; return state.editor.hotkeysEnabled;
}; };
export const { disableHotkeys, enableHotkeys } = editorSlice.actions; export const { disableHotkeys, enableHotkeys } = editorSlice.actions;
export default editorSlice.reducer; export default editorSlice.reducer;

Some files were not shown because too many files have changed in this diff Show More