Merge 'origin/develop' into feature/map-actions

This commit is contained in:
Matias Arriola 2022-01-25 11:35:20 -03:00
commit dd8b40bf6d
43 changed files with 614 additions and 565 deletions

View File

@ -7,23 +7,23 @@
image: cypress/included:8.4.1 image: cypress/included:8.4.1
pipelines: pipelines:
default: branches:
- parallel: '{master,develop}':
- step: - step:
name: Build and test name: Build and test
caches: caches:
- node - node
- npm - npm
- cypress - cypress
script: script:
- export CYPRESS_imageSnaphots="true" - export CYPRESS_imageSnaphots="true"
- yarn install - yarn install
- yarn bootstrap - yarn bootstrap
- yarn build - yarn build
- yarn lint - yarn lint
- yarn test - yarn test
artifacts: artifacts:
- packages/**/cypress/snapshots/**/__diff_output__/*.diff.png - packages/**/cypress/snapshots/**/__diff_output__/*.diff.png
definitions: definitions:
caches: caches:
npm: $HOME/.npm npm: $HOME/.npm

View File

@ -37,7 +37,6 @@
// no-unused-vars already used // no-unused-vars already used
"@typescript-eslint/no-unused-vars": "off", "@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/ban-ts-comment": "warn", "@typescript-eslint/ban-ts-comment": "warn",
"@typescript-eslint/no-empty-function": "warn",
"import/no-extraneous-dependencies": ["warn", {"packageDir": "./", "devDependencies": false, "optionalDependencies": false, "peerDependencies": false}] "import/no-extraneous-dependencies": ["warn", {"packageDir": "./", "devDependencies": false, "optionalDependencies": false, "peerDependencies": false}]
}, },
"settings": { "settings": {

View File

@ -1,6 +1,6 @@
{ {
"name": "@wisemapping/mindplot", "name": "@wisemapping/mindplot",
"version": "0.4.15", "version": "5.0.1",
"description": "WiseMapping - Mindplot Canvas Library", "description": "WiseMapping - Mindplot Canvas Library",
"homepage": "http://www.wisemapping.org/", "homepage": "http://www.wisemapping.org/",
"main": "dist/mindplot.js", "main": "dist/mindplot.js",

View File

@ -1,111 +0,0 @@
/* eslint-disable no-unused-vars */
/*
* Copyright [2021] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { $assert } from '@wisemapping/core-js';
import Events from './Events';
class ActionDispatcher extends Events {
constructor(commandContext) {
$assert(commandContext, 'commandContext can not be null');
super();
}
addRelationship(model, mindmap) {
throw new Error('method must be implemented.');
}
addTopics(models, parentTopicId) {
throw new Error('method must be implemented.');
}
deleteEntities(topicsIds, relIds) {
throw new Error('method must be implemented.');
}
dragTopic(topicId, position, order, parentTopic) {
throw new Error('method must be implemented.');
}
moveTopic(topicId, position) {
throw new Error('method must be implemented.');
}
moveControlPoint(ctrlPoint, point) {
throw new Error('method must be implemented.');
}
changeFontFamilyToTopic(topicIds, fontFamily) {
throw new Error('method must be implemented.');
}
changeFontStyleToTopic(topicsIds) {
throw new Error('method must be implemented.');
}
changeFontColorToTopic(topicsIds, color) {
throw new Error('method must be implemented.');
}
changeFontSizeToTopic(topicsIds, size) {
throw new Error('method must be implemented.');
}
changeBackgroundColorToTopic(topicsIds, color) {
throw new Error('method must be implemented.');
}
changeBorderColorToTopic(topicsIds, color) {
throw new Error('method must be implemented.');
}
changeShapeTypeToTopic(topicsIds, shapeType) {
throw new Error('method must be implemented.');
}
changeFontWeightToTopic(topicsIds) {
throw new Error('method must be implemented.');
}
changeTextToTopic(topicsIds, text) {
throw new Error('method must be implemented.');
}
shrinkBranch(topicsIds, collapse) {
throw new Error('method must be implemented.');
}
addFeatureToTopic(topicId, type, attributes) {
throw new Error('method must be implemented.');
}
changeFeatureToTopic(topicId, featureId, attributes) {
throw new Error('method must be implemented.');
}
removeFeatureFromTopic(topicId, featureId) {
throw new Error('method must be implemented.');
}
}
ActionDispatcher.setInstance = (dispatcher) => {
ActionDispatcher._instance = dispatcher;
};
ActionDispatcher.getInstance = () => ActionDispatcher._instance;
export default ActionDispatcher;

View File

@ -0,0 +1,82 @@
/* eslint-disable import/no-cycle */
/* eslint-disable no-use-before-define */
/*
* Copyright [2021] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { $assert } from '@wisemapping/core-js';
import Point from '@wisemapping/web2d';
import { Mindmap } from '..';
import CommandContext from './CommandContext';
import Events from './Events';
import NodeModel from './model/NodeModel';
import RelationshipModel from './model/RelationshipModel';
import Topic from './Topic';
abstract class ActionDispatcher extends Events {
static _instance: ActionDispatcher;
constructor(commandContext: CommandContext) {
$assert(commandContext, 'commandContext can not be null');
super();
}
abstract addRelationship(model: RelationshipModel, mindmap: Mindmap);
abstract addTopics(models: NodeModel[], parentTopicId: any[]);
abstract deleteEntities(topicsIds: number[], relIds: number[]);
abstract dragTopic(topicId: number, position: Point, order: number, parentTopic: Topic);
abstract moveTopic(topicId: number, position: any);
abstract moveControlPoint(ctrlPoint: this, point: any);
abstract changeFontFamilyToTopic(topicIds: number[], fontFamily: string);
abstract changeFontStyleToTopic(topicsIds: number[]);
abstract changeFontColorToTopic(topicsIds: number[], color: string);
abstract changeFontSizeToTopic(topicsIds: number[], size: number);
abstract changeBackgroundColorToTopic(topicsIds: number[], color: string);
abstract changeBorderColorToTopic(topicsIds: number[], color: string);
abstract changeShapeTypeToTopic(topicsIds: number[], shapeType: string);
abstract changeFontWeightToTopic(topicsIds: number[]);
abstract changeTextToTopic(topicsIds: number[], text: string);
abstract shrinkBranch(topicsIds: number[], collapse: boolean);
abstract addFeatureToTopic(topicId: number, type: string, attributes: object);
abstract changeFeatureToTopic(topicId: number, featureId: any, attributes: object);
abstract removeFeatureFromTopic(topicId: number, featureId: number);
static setInstance = (dispatcher: ActionDispatcher) => {
this._instance = dispatcher;
};
static getInstance = (): ActionDispatcher => ActionDispatcher._instance;
}
export default ActionDispatcher;

View File

@ -42,7 +42,9 @@ class CentralTopic extends Topic {
} }
/** */ /** */
updateTopicShape() { } updateTopicShape() {
// Overwite behaviour ...
}
_updatePositionOnChangeSize() { _updatePositionOnChangeSize() {
// Center main topic ... // Center main topic ...

View File

@ -16,42 +16,32 @@
* limitations under the License. * limitations under the License.
*/ */
import { $defined } from '@wisemapping/core-js'; import { $defined } from '@wisemapping/core-js';
import CommandContext from './CommandContext';
abstract class Command {
private _id: number;
static _uuid: number;
class Command {
/**
* @classdesc The command base class for handling do/undo mindmap operations
* @constructs
*/
constructor() { constructor() {
this._id = Command._nextUUID(); this._id = Command._nextUUID();
} }
// eslint-disable-next-line no-unused-vars abstract execute(commandContext:CommandContext):void;
execute(commandContext) {
throw new Error('execute must be implemented.');
}
// eslint-disable-next-line no-unused-vars abstract undoExecute(commandContext:CommandContext):void;
undoExecute(commandContext) {
throw new Error('undo must be implemented.');
}
/** getId():number {
* Returns the unique id of this command
* @returns {Number} command id
*/
getId() {
return this._id; return this._id;
} }
static _nextUUID() {
if (!$defined(this._uuid)) {
this._uuid = 1;
}
this._uuid += 1;
return this._uuid;
}
} }
Command._nextUUID = function _nextUUID() {
if (!$defined(Command._uuid)) {
Command._uuid = 1;
}
Command._uuid += 1;
return Command._uuid;
};
export default Command; export default Command;

View File

@ -16,16 +16,32 @@
* limitations under the License. * limitations under the License.
*/ */
import { $assert, $defined } from '@wisemapping/core-js'; import { $assert, $defined } from '@wisemapping/core-js';
import Point from '@wisemapping/web2d';
import { Designer } from '..';
import EventBus from './layout/EventBus'; import EventBus from './layout/EventBus';
import NodeModel from './model/NodeModel';
import RelationshipModel from './model/RelationshipModel';
import Relationship from './Relationship';
import Topic from './Topic';
class CommandContext { class CommandContext {
constructor(designer) { private _designer: Designer;
constructor(designer: Designer) {
$assert(designer, 'designer can not be null'); $assert(designer, 'designer can not be null');
this._designer = designer; this._designer = designer;
} }
public get designer(): Designer {
return this._designer;
}
public set designer(value: Designer) {
this._designer = value;
}
/** */ /** */
findTopics(topicIds) { findTopics(topicIds: number[]): Topic[] {
$assert($defined(topicIds), 'topicsIds can not be null'); $assert($defined(topicIds), 'topicsIds can not be null');
const topicsIds = Array.isArray(topicIds) ? topicIds : [topicIds]; const topicsIds = Array.isArray(topicIds) ? topicIds : [topicIds];
const designerTopics = this._designer.getModel().getTopics(); const designerTopics = this._designer.getModel().getTopics();
@ -45,51 +61,51 @@ class CommandContext {
} }
/** */ /** */
deleteTopic(topic) { deleteTopic(topic: Topic) {
this._designer.removeTopic(topic); this._designer.removeTopic(topic);
} }
/** */ /** */
createTopic(model) { createTopic(model: NodeModel) {
$assert(model, 'model can not be null'); $assert(model, 'model can not be null');
return this._designer.nodeModelToTopic(model); return this._designer.nodeModelToTopic(model);
} }
/** */ // /** */
createModel() { // createModel() {
const mindmap = this._designer.getMindmap(); // const mindmap = this._designer.getMindmap();
return mindmap.createNode('MainTopic'); // return mindmap.createNode('MainTopic');
} // }
/** */ /** */
addTopic(topic) { addTopic(topic: Topic) {
const mindmap = this._designer.getMindmap(); const mindmap = this._designer.getMindmap();
return mindmap.addBranch(topic.getModel()); return mindmap.addBranch(topic.getModel());
} }
/** */ /** */
connect(childTopic, parentTopic) { connect(childTopic: Topic, parentTopic: Topic) {
childTopic.connectTo(parentTopic, this._designer._workspace); childTopic.connectTo(parentTopic, this._designer.getWorkSpace());
} }
/** */ /** */
disconnect(topic) { disconnect(topic: Topic) {
topic.disconnect(this._designer._workspace); topic.disconnect(this._designer.getWorkSpace());
} }
/** */ /** */
addRelationship(model) { addRelationship(model: RelationshipModel) {
$assert(model, 'model cannot be null'); $assert(model, 'model cannot be null');
return this._designer.addRelationship(model); return this._designer.addRelationship(model);
} }
/** */ /** */
deleteRelationship(relationship) { deleteRelationship(relationship: Relationship) {
this._designer.deleteRelationship(relationship); this._designer.deleteRelationship(relationship);
} }
/** */ /** */
findRelationships(relationshipIds) { findRelationships(relationshipIds: number[]) {
$assert($defined(relationshipIds), 'relId can not be null'); $assert($defined(relationshipIds), 'relId can not be null');
const relIds = Array.isArray(relationshipIds) ? relationshipIds : [relationshipIds]; const relIds = Array.isArray(relationshipIds) ? relationshipIds : [relationshipIds];
@ -98,7 +114,7 @@ class CommandContext {
} }
/** */ /** */
moveTopic(topic, position) { moveTopic(topic: Topic, position: Point) {
$assert(topic, 'topic cannot be null'); $assert(topic, 'topic cannot be null');
$assert(position, 'position cannot be null'); $assert(position, 'position cannot be null');
EventBus.instance.fireEvent(EventBus.events.NodeMoveEvent, { EventBus.instance.fireEvent(EventBus.events.NodeMoveEvent, {
@ -107,5 +123,4 @@ class CommandContext {
}); });
} }
} }
// eslint-disable-next-line import/prefer-default-export
export default CommandContext; export default CommandContext;

View File

@ -112,7 +112,9 @@ class ControlPoint {
); );
} }
_removeLine() { } _removeLine() {
// Overwrite default behaviour ...
}
_mouseDown(event, point, me) { _mouseDown(event, point, me) {
if (!this._isBinded) { if (!this._isBinded) {

View File

@ -77,9 +77,9 @@ class Designer extends Events {
private _relPivot: RelationshipPivot; private _relPivot: RelationshipPivot;
private _clipboard: any[]; private _clipboard: NodeModel[];
private _cleanScreen: any; private _cleanScreen: () => void;
constructor(options: DesignerOptions, divElement: JQuery) { constructor(options: DesignerOptions, divElement: JQuery) {
super(); super();
@ -148,9 +148,12 @@ class Designer extends Events {
}, { passive: false }); }, { passive: false });
} }
getActionDispatcher(): StandaloneActionDispatcher {
return this._actionDispatcher;
}
// @ts-ignore // @ts-ignore
// eslint-disable-next-line @typescript-eslint/ban-types addEvent(type: string, listener: any): void {
addEvent(type: string, listener: Function): void {
if (type === TopicEvent.EDIT || type === TopicEvent.CLICK) { if (type === TopicEvent.EDIT || type === TopicEvent.CLICK) {
const editor = TopicEventDispatcher.getInstance(); const editor = TopicEventDispatcher.getInstance();
editor.addEvent(type, listener); editor.addEvent(type, listener);
@ -280,11 +283,11 @@ class Designer extends Events {
} }
/** /**
* @param {?mindplot.Topic} currentObject * @param {?mindplot.Topic} currentObject
* @param {Event=} event * @param {Event=} event
* sets focus to the given currentObject and removes it from any other objects if not * sets focus to the given currentObject and removes it from any other objects if not
* triggered with Ctrl pressed * triggered with Ctrl pressed
*/ */
onObjectFocusEvent(currentObject: Topic = null, event = null): void { onObjectFocusEvent(currentObject: Topic = null, event = null): void {
// Close node editors .. // Close node editors ..
const topics = this.getModel().getTopics(); const topics = this.getModel().getTopics();
@ -581,9 +584,9 @@ class Designer extends Events {
} }
/** /**
* @param {mindplot.Mindmap} mindmap * @param {mindplot.Mindmap} mindmap
* @throws will throw an error if mindmapModel is null or undefined * @throws will throw an error if mindmapModel is null or undefined
*/ */
loadMap(mindmap: Mindmap): void { loadMap(mindmap: Mindmap): void {
$assert(mindmap, 'mindmapModel can not be null'); $assert(mindmap, 'mindmapModel can not be null');
this._mindmap = mindmap; this._mindmap = mindmap;
@ -626,11 +629,11 @@ class Designer extends Events {
} }
undo(): void { undo(): void {
this._actionDispatcher._actionRunner.undo(); this._actionDispatcher.actionRunner.undo();
} }
redo(): void { redo(): void {
this._actionDispatcher._actionRunner.redo(); this._actionDispatcher.actionRunner.redo();
} }
/** */ /** */
@ -638,7 +641,7 @@ class Designer extends Events {
return this._options.readOnly; return this._options.readOnly;
} }
nodeModelToTopic(nodeModel: NodeModel):Topic { nodeModelToTopic(nodeModel: NodeModel): Topic {
$assert(nodeModel, 'Node model can not be null'); $assert(nodeModel, 'Node model can not be null');
let children = nodeModel.getChildren().slice(); let children = nodeModel.getChildren().slice();
children = children.sort((a, b) => a.getOrder() - b.getOrder()); children = children.sort((a, b) => a.getOrder() - b.getOrder());
@ -656,12 +659,12 @@ class Designer extends Events {
} }
/** /**
* @private * @private
* @param {mindplot.model.RelationshipModel} model * @param {mindplot.model.RelationshipModel} model
* @return {mindplot.Relationship} the relationship created to the model * @return {mindplot.Relationship} the relationship created to the model
* @throws will throw an error if model is null or undefined * @throws will throw an error if model is null or undefined
*/ */
private _relationshipModelToRelationship(model: RelationshipModel):Relationship { private _relationshipModelToRelationship(model: RelationshipModel): Relationship {
$assert(model, 'Node model can not be null'); $assert(model, 'Node model can not be null');
const result = this._buildRelationshipShape(model); const result = this._buildRelationshipShape(model);
@ -679,20 +682,20 @@ class Designer extends Events {
} }
/** /**
* @param {mindplot.model.RelationshipModel} model * @param {mindplot.model.RelationshipModel} model
* @return {mindplot.Relationship} the relationship added to the mindmap * @return {mindplot.Relationship} the relationship added to the mindmap
*/ */
addRelationship(model: RelationshipModel):Relationship { addRelationship(model: RelationshipModel): Relationship {
const mindmap = this.getMindmap(); const mindmap = this.getMindmap();
mindmap.addRelationship(model); mindmap.addRelationship(model);
return this._relationshipModelToRelationship(model); return this._relationshipModelToRelationship(model);
} }
/** /**
* deletes the relationship from the linked topics, DesignerModel, Workspace and Mindmap * deletes the relationship from the linked topics, DesignerModel, Workspace and Mindmap
* @param {mindplot.Relationship} rel the relationship to delete * @param {mindplot.Relationship} rel the relationship to delete
*/ */
deleteRelationship(rel: Relationship):void { deleteRelationship(rel: Relationship): void {
const sourceTopic = rel.getSourceTopic(); const sourceTopic = rel.getSourceTopic();
sourceTopic.deleteRelationship(rel); sourceTopic.deleteRelationship(rel);
@ -707,12 +710,12 @@ class Designer extends Events {
} }
/** /**
* @private * @private
* @param {mindplot.model.RelationshipModel} model * @param {mindplot.model.RelationshipModel} model
* @return {mindplot.Relationship} the new relationship with events registered * @return {mindplot.Relationship} the new relationship with events registered
* @throws will throw an error if the target topic cannot be found * @throws will throw an error if the target topic cannot be found
*/ */
private _buildRelationshipShape(model: RelationshipModel):Relationship { private _buildRelationshipShape(model: RelationshipModel): Relationship {
const dmodel = this.getModel(); const dmodel = this.getModel();
const sourceTopicId = model.getFromNode(); const sourceTopicId = model.getFromNode();
@ -756,9 +759,9 @@ class Designer extends Events {
} }
/** /**
* @param {mindplot.Topic} node the topic to remove * @param {mindplot.Topic} node the topic to remove
* removes the given topic and its children from Workspace, DesignerModel and NodeModel * removes the given topic and its children from Workspace, DesignerModel and NodeModel
*/ */
removeTopic(node) { removeTopic(node) {
if (!node.isCentralTopic()) { if (!node.isCentralTopic()) {
const parent = node._parent; const parent = node._parent;
@ -783,8 +786,8 @@ class Designer extends Events {
} }
/** /**
* @private * @private
*/ */
_resetEdition() { _resetEdition() {
const screenManager = this._workspace.getScreenManager(); const screenManager = this._workspace.getScreenManager();
screenManager.fireEvent('update'); screenManager.fireEvent('update');
@ -840,18 +843,19 @@ class Designer extends Events {
} }
/** */ /** */
changeFontColor(color) { changeFontColor(color: string) {
$assert(color, 'color can not be null'); $assert(color, 'color can not be null');
const topicsIds = this.getModel() const topicsIds = this.getModel()
.filterTopicsIds(); .filterTopicsIds();
if (topicsIds.length > 0) { if (topicsIds.length > 0) {
this._actionDispatcher.changeFontColorToTopic(topicsIds, color); this._actionDispatcher.changeFontColorToTopic(topicsIds, color);
} }
} }
/** */ /** */
changeBackgroundColor(color) { changeBackgroundColor(color: string) {
const validateFunc = (topic) => topic.getShapeType() !== TopicShape.LINE; const validateFunc = (topic) => topic.getShapeType() !== TopicShape.LINE;
const validateError = 'Color can not be set to line topics.'; const validateError = 'Color can not be set to line topics.';
@ -911,9 +915,9 @@ class Designer extends Events {
} }
/** /**
* lets the selected topic open the link editor where the user can define or modify an * lets the selected topic open the link editor where the user can define or modify an
* existing link * existing link
*/ */
addLink() { addLink() {
const model = this.getModel(); const model = this.getModel();
const topic = model.selectedTopic(); const topic = model.selectedTopic();
@ -934,9 +938,9 @@ class Designer extends Events {
} }
/** /**
* @param {mindplot.Topic} node * @param {mindplot.Topic} node
* sets the focus to the given node * sets the focus to the given node
*/ */
goToNode(node) { goToNode(node) {
node.setOnFocus(true); node.setOnFocus(true);
this.onObjectFocusEvent(node); this.onObjectFocusEvent(node);

View File

@ -106,7 +106,7 @@ class DesignerModel extends Events {
this._relationships.push(rel); this._relationships.push(rel);
} }
filterTopicsIds(validate: (topic: Topic) => boolean = null, errorMsg = null): Topic[] { filterTopicsIds(validate: (topic: Topic) => boolean = null, errorMsg = null): number[] {
const result = []; const result = [];
const topics = this.filterSelectedTopics(); const topics = this.filterSelectedTopics();

View File

@ -92,8 +92,8 @@ class DragManager {
event.preventDefault(); event.preventDefault();
}; };
// 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
// eslint-disable-next-line no-param-reassign
dragManager._mouseMoveListener = result; dragManager._mouseMoveListener = result;
return result; return result;
} }
@ -110,10 +110,8 @@ class DragManager {
// Help GC // Help GC
// 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
/* eslint-disable no-param-reassign */
dragManager._mouseMoveListener = null; dragManager._mouseMoveListener = null;
dragManager._mouseUpListener = null; dragManager._mouseUpListener = null;
/* eslint-enable no-param-reassign */
workspace.enableWorkspaceEvents(true); workspace.enableWorkspaceEvents(true);
// Change the cursor to the default. // Change the cursor to the default.
@ -130,7 +128,6 @@ class DragManager {
me._isDragInProcess = false; me._isDragInProcess = false;
} }
}; };
// eslint-disable-next-line no-param-reassign
dragManager._mouseUpListener = result; dragManager._mouseUpListener = result;
return result; return result;
} }

View File

@ -15,16 +15,34 @@
* 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 { Arrow, Point } from '@wisemapping/web2d';
import { $assert, $defined } from '@wisemapping/core-js'; import { $assert, $defined } from '@wisemapping/core-js';
import { Arrow, Point, ElementClass } from '@wisemapping/web2d';
import ConnectionLine from './ConnectionLine'; import ConnectionLine from './ConnectionLine';
import ControlPoint from './ControlPoint'; import ControlPoint from './ControlPoint';
import RelationshipModel from './model/RelationshipModel';
import NodeGraph from './NodeGraph';
import Shape from './util/Shape'; import Shape from './util/Shape';
class Relationship extends ConnectionLine { class Relationship extends ConnectionLine {
constructor(sourceNode, targetNode, model) { private _focusShape: ElementClass;
private _onFocus: boolean;
private _isInWorkspace: boolean;
private _controlPointsController: ControlPoint;
private _startArrow: Arrow;
private _showEndArrow: Arrow;
private _endArrow: Arrow;
private _controlPointControllerListener: any;
private _showStartArrow: Arrow;
constructor(sourceNode: NodeGraph, targetNode: NodeGraph, model: RelationshipModel) {
$assert(sourceNode, 'sourceNode can not be null'); $assert(sourceNode, 'sourceNode can not be null');
$assert(targetNode, 'targetNode can not be null'); $assert(targetNode, 'targetNode can not be null');
@ -72,12 +90,12 @@ class Relationship extends ConnectionLine {
} }
} }
setStroke(color, style, opacity) { setStroke(color: string, style: string, opacity: number): void {
super.setStroke(color, style, opacity); super.setStroke(color, style, opacity);
this._startArrow.setStrokeColor(color); this._startArrow.setStrokeColor(color);
} }
redraw() { redraw(): void {
const line2d = this._line2d; const line2d = this._line2d;
const sourceTopic = this._sourceTopic; const sourceTopic = this._sourceTopic;
const sourcePosition = sourceTopic.getPosition(); const sourcePosition = sourceTopic.getPosition();
@ -131,7 +149,7 @@ class Relationship extends ConnectionLine {
this._controlPointsController.redraw(); this._controlPointsController.redraw();
} }
_positionArrows() { private _positionArrows(): void {
const tpos = this._line2d.getTo(); const tpos = this._line2d.getTo();
const spos = this._line2d.getFrom(); const spos = this._line2d.getFrom();
@ -167,7 +185,7 @@ class Relationship extends ConnectionLine {
workspace.append(this._controlPointsController); workspace.append(this._controlPointsController);
this._controlPointControllerListener = this._initializeControlPointController.bind(this); this._controlPointControllerListener = this._initializeControlPointController.bind(this);
if (workspace.isReadOnly) { if (workspace.isReadOnly()) {
this._line2d.setCursor('default'); this._line2d.setCursor('default');
} else { } else {
this._line2d.addEvent('click', this._controlPointControllerListener); this._line2d.addEvent('click', this._controlPointControllerListener);
@ -182,7 +200,7 @@ class Relationship extends ConnectionLine {
this.redraw(); this.redraw();
} }
_initializeControlPointController() { _initializeControlPointController(): void {
this.setOnFocus(true); this.setOnFocus(true);
} }
@ -199,12 +217,11 @@ class Relationship extends ConnectionLine {
super.removeFromWorkspace(workspace); super.removeFromWorkspace(workspace);
} }
// eslint-disable-next-line class-methods-use-this
getType() { getType() {
return Relationship.type; return 'Relationship';
} }
setOnFocus(focus) { setOnFocus(focus: boolean): void {
// Change focus shape // Change focus shape
if (this.isOnFocus() !== focus) { if (this.isOnFocus() !== focus) {
if (focus) { if (focus) {
@ -219,7 +236,7 @@ class Relationship extends ConnectionLine {
} }
} }
_refreshShape() { private _refreshShape() {
const sPos = this._line2d.getFrom(); const sPos = this._line2d.getFrom();
const tPos = this._line2d.getTo(); const tPos = this._line2d.getTo();
const ctrlPoints = this._line2d.getControlPoints(); const ctrlPoints = this._line2d.getControlPoints();
@ -233,7 +250,8 @@ class Relationship extends ConnectionLine {
this._focusShape.updateLine(); this._focusShape.updateLine();
} }
addEvent(eventType, listener) { // @typescript-eslint/ban-types
addEvent(eventType: string, listener: any) {
let type = eventType; let type = eventType;
// Translate to web 2d events ... // Translate to web 2d events ...
if (type === 'onfocus') { if (type === 'onfocus') {
@ -244,37 +262,37 @@ class Relationship extends ConnectionLine {
line.addEvent(type, listener); line.addEvent(type, listener);
} }
isOnFocus() { isOnFocus(): boolean {
return this._onFocus; return this._onFocus;
} }
isInWorkspace() { isInWorkspace(): boolean {
return this._isInWorkspace; return this._isInWorkspace;
} }
setVisibility(value) { setVisibility(value: boolean) {
super.setVisibility(value); super.setVisibility(value);
if (this._showEndArrow) this._endArrow.setVisibility(this._showEndArrow); if (this._showEndArrow) this._endArrow.setVisibility(this._showEndArrow);
this._startArrow.setVisibility(this._showStartArrow && value); this._startArrow.setVisibility(this._showStartArrow && value);
} }
setOpacity(opacity) { setOpacity(opacity: number) {
super.setOpacity(opacity); super.setOpacity(opacity);
if (this._showEndArrow) this._endArrow.setOpacity(opacity); if (this._showEndArrow) this._endArrow.setOpacity(opacity);
if (this._showStartArrow) this._startArrow.setOpacity(opacity); if (this._showStartArrow) this._startArrow.setOpacity(opacity);
} }
setShowEndArrow(visible) { setShowEndArrow(visible: boolean) {
this._showEndArrow = visible; this._showEndArrow = visible;
if (this._isInWorkspace) this.redraw(); if (this._isInWorkspace) this.redraw();
} }
setShowStartArrow(visible) { setShowStartArrow(visible: boolean) {
this._showStartArrow = visible; this._showStartArrow = visible;
if (this._isInWorkspace) this.redraw(); if (this._isInWorkspace) this.redraw();
} }
setFrom(x, y) { setFrom(x: number, y: number) {
$assert($defined(x), 'x must be defined'); $assert($defined(x), 'x must be defined');
$assert($defined(y), 'y must be defined'); $assert($defined(y), 'y must be defined');
@ -282,7 +300,7 @@ class Relationship extends ConnectionLine {
this._startArrow.setFrom(x, y); this._startArrow.setFrom(x, y);
} }
setTo(x, y) { setTo(x: number, y: number) {
$assert($defined(x), 'x must be defined'); $assert($defined(x), 'x must be defined');
$assert($defined(y), 'y must be defined'); $assert($defined(y), 'y must be defined');
@ -312,11 +330,11 @@ class Relationship extends ConnectionLine {
return this._line2d.isDestControlPointCustom(); return this._line2d.isDestControlPointCustom();
} }
setIsSrcControlPointCustom(isCustom) { setIsSrcControlPointCustom(isCustom: boolean) {
this._line2d.setIsSrcControlPointCustom(isCustom); this._line2d.setIsSrcControlPointCustom(isCustom);
} }
setIsDestControlPointCustom(isCustom) { setIsDestControlPointCustom(isCustom: boolean) {
this._line2d.setIsDestControlPointCustom(isCustom); this._line2d.setIsDestControlPointCustom(isCustom);
} }
@ -324,16 +342,14 @@ class Relationship extends ConnectionLine {
return this._model.getId(); return this._model.getId();
} }
fireEvent(type, event) { fireEvent(type: string, event: any): void {
const elem = this._line2d; const elem = this._line2d;
elem.trigger(type, event); elem.trigger(type, event);
} }
static getStrokeColor() {
return '#9b74e6';
}
} }
Relationship.getStrokeColor = function getStrokeColor() {
return '#9b74e6';
};
Relationship.type = 'Relationship';
export default Relationship; export default Relationship;

View File

@ -19,21 +19,39 @@ import { CurvedLine, Arrow, Point } from '@wisemapping/web2d';
import { $assert } from '@wisemapping/core-js'; import { $assert } from '@wisemapping/core-js';
import Relationship from './Relationship'; import Relationship from './Relationship';
import Shape from './util/Shape'; import Shape from './util/Shape';
import Workspace from './Workspace';
import { Designer } from '..';
import Topic from './Topic';
class RelationshipPivot { class RelationshipPivot {
constructor(workspace, designer) { private _workspace: Workspace;
private _designer: Designer;
private _mouseMoveEvent: MouseEvent;
private _onClickEvent: (event: MouseEvent) => void;
private _onTopicClick: (event: MouseEvent) => void;;
private _sourceTopic: Topic;
private _pivot: any;
private _startArrow: Arrow;
constructor(workspace: Workspace, designer: Designer) {
$assert(workspace, 'workspace can not be null'); $assert(workspace, 'workspace can not be null');
$assert(designer, 'designer can not be null'); $assert(designer, 'designer can not be null');
this._workspace = workspace; this._workspace = workspace;
this._designer = designer; this._designer = designer;
// FIXME: the aim of the migration is remove .bind mootools method, please remove these!
this._mouseMoveEvent = this._mouseMove.bind(this); this._mouseMoveEvent = this._mouseMove.bind(this);
this._onClickEvent = this._cleanOnMouseClick.bind(this); this._onClickEvent = this._cleanOnMouseClick.bind(this);
this._onTopicClick = this._connectOnFocus.bind(this); this._onTopicClick = this._connectOnFocus.bind(this);
} }
start(sourceTopic, targetPos) { start(sourceTopic: Topic, targetPos: Point) {
$assert(sourceTopic, 'sourceTopic can not be null'); $assert(sourceTopic, 'sourceTopic can not be null');
$assert(targetPos, 'targetPos can not be null'); $assert(targetPos, 'targetPos can not be null');
@ -75,7 +93,7 @@ class RelationshipPivot {
} }
} }
dispose() { dispose(): void {
const workspace = this._workspace; const workspace = this._workspace;
if (this._isActive()) { if (this._isActive()) {
@ -99,7 +117,7 @@ class RelationshipPivot {
} }
} }
_mouseMove(event) { _mouseMove(event: MouseEvent): boolean {
const screen = this._workspace.getScreenManager(); const screen = this._workspace.getScreenManager();
const pos = screen.getWorkspaceMousePosition(event); const pos = screen.getWorkspaceMousePosition(event);
@ -121,13 +139,13 @@ class RelationshipPivot {
return false; return false;
} }
_cleanOnMouseClick(event) { _cleanOnMouseClick(event: MouseEvent): void {
// The user clicks on a desktop on in other element that is not a node. // The user clicks on a desktop on in other element that is not a node.
this.dispose(); this.dispose();
event.stopPropagation(); event.stopPropagation();
} }
_calculateFromPosition(toPosition) { private _calculateFromPosition(toPosition: Point): Point {
// Calculate origin position ... // Calculate origin position ...
let sourcePosition = this._sourceTopic.getPosition(); let sourcePosition = this._sourceTopic.getPosition();
if (this._sourceTopic.getType() === 'CentralTopic') { if (this._sourceTopic.getType() === 'CentralTopic') {
@ -141,19 +159,21 @@ class RelationshipPivot {
return Shape.calculateRelationShipPointCoordinates(this._sourceTopic, spoint); return Shape.calculateRelationShipPointCoordinates(this._sourceTopic, spoint);
} }
_connectOnFocus(event, targetTopic) { private _connectOnFocus(event: string, targetTopic: Topic): void {
const sourceTopic = this._sourceTopic; const sourceTopic = this._sourceTopic;
const mindmap = this._designer.getMindmap(); const mindmap = this._designer.getMindmap();
// Avoid circular connections ... // Avoid circular connections ...
if (targetTopic.getId() !== sourceTopic.getId()) { if (targetTopic.getId() !== sourceTopic.getId()) {
const relModel = mindmap.createRelationship(targetTopic.getId(), sourceTopic.getId()); const relModel = mindmap.createRelationship(targetTopic.getId(), sourceTopic.getId());
this._designer._actionDispatcher.addRelationship(relModel); this._designer
.getActionDispatcher()
.addRelationship(relModel);
} }
this.dispose(); this.dispose();
} }
_isActive() { private _isActive() {
return this._pivot != null; return this._pivot != null;
} }
} }

View File

@ -17,13 +17,14 @@
*/ */
import { $assert } from '@wisemapping/core-js'; import { $assert } from '@wisemapping/core-js';
import { Point } from '@wisemapping/web2d'; import { Point } from '@wisemapping/web2d';
import Topic from './Topic';
class ScreenManager { class ScreenManager {
private _divContainer: JQuery; private _divContainer: JQuery;
private _padding: { x: number; y: number; }; private _padding: { x: number; y: number; };
private _clickEvents: ((event: UIEvent)=>void)[]; private _clickEvents: ((event: UIEvent) => void)[];
private _scale: number; private _scale: number;
@ -47,7 +48,7 @@ class ScreenManager {
/** /**
* Return the current visibile area in the browser. * Return the current visibile area in the browser.
*/ */
getVisibleBrowserSize():{width:number, height:number} { getVisibleBrowserSize(): { width: number, height: number } {
return { return {
width: window.innerWidth, width: window.innerWidth,
height: window.innerHeight - Number.parseInt(this._divContainer.css('top'), 10), height: window.innerHeight - Number.parseInt(this._divContainer.css('top'), 10),
@ -59,7 +60,7 @@ class ScreenManager {
this._scale = scale; this._scale = scale;
} }
addEvent(eventType: string, listener:any) { addEvent(eventType: string, listener: any) {
if (eventType === 'click') this._clickEvents.push(listener); if (eventType === 'click') this._clickEvents.push(listener);
else this._divContainer.bind(eventType, listener); else this._divContainer.bind(eventType, listener);
} }
@ -83,7 +84,7 @@ class ScreenManager {
} }
} }
_getElementPosition(elem: { getPosition: () => any; }) { private _getElementPosition(elem: Topic) {
// Retrieve current element position. // Retrieve current element position.
const elementPosition = elem.getPosition(); const elementPosition = elem.getPosition();
let { x } = elementPosition; let { x } = elementPosition;

View File

@ -16,6 +16,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { $defined, $assert } from '@wisemapping/core-js'; import { $defined, $assert } from '@wisemapping/core-js';
import { Point } from '@wisemapping/web2d';
import ActionDispatcher from './ActionDispatcher'; import ActionDispatcher from './ActionDispatcher';
import DesignerActionRunner from './DesignerActionRunner'; import DesignerActionRunner from './DesignerActionRunner';
import AddTopicCommand from './commands/AddTopicCommand'; import AddTopicCommand from './commands/AddTopicCommand';
@ -28,39 +29,52 @@ import GenericFunctionCommand from './commands/GenericFunctionCommand';
import MoveControlPointCommand from './commands/MoveControlPointCommand'; import MoveControlPointCommand from './commands/MoveControlPointCommand';
import ChangeFeatureToTopicCommand from './commands/ChangeFeatureToTopicCommand'; import ChangeFeatureToTopicCommand from './commands/ChangeFeatureToTopicCommand';
import EventBus from './layout/EventBus'; import EventBus from './layout/EventBus';
import CommandContext from './CommandContext';
import NodeModel from './model/NodeModel';
import RelationshipModel from './model/RelationshipModel';
import Topic from './Topic';
import Command from './Command';
class StandaloneActionDispatcher extends ActionDispatcher { class StandaloneActionDispatcher extends ActionDispatcher {
constructor(commandContext) { private _actionRunner: DesignerActionRunner;
public get actionRunner(): DesignerActionRunner {
return this._actionRunner;
}
public set actionRunner(value: DesignerActionRunner) {
this._actionRunner = value;
}
constructor(commandContext: CommandContext) {
super(commandContext); super(commandContext);
this._actionRunner = new DesignerActionRunner(commandContext, this); this._actionRunner = new DesignerActionRunner(commandContext, this);
} }
/** */ addTopics(models: NodeModel[], parentTopicsId: number[] = undefined) {
addTopics(models, parentTopicsId) {
const command = new AddTopicCommand(models, parentTopicsId); const command = new AddTopicCommand(models, parentTopicsId);
this.execute(command); this.execute(command);
} }
/** */ addRelationship(model: RelationshipModel) {
addRelationship(model) {
const command = new AddRelationshipCommand(model); const command = new AddRelationshipCommand(model);
this.execute(command); this.execute(command);
} }
/** */ /** */
deleteEntities(topicsIds, relIds) { deleteEntities(topicsIds: number[], relIds: number[]) {
const command = new DeleteCommand(topicsIds, relIds); const command = new DeleteCommand(topicsIds, relIds);
this.execute(command); this.execute(command);
} }
/** */ /** */
dragTopic(topicId, position, order, parentTopic) { dragTopic(topicId: number, position: Point, order: number, parentTopic: Topic) {
const command = new DragTopicCommand(topicId, position, order, parentTopic); const command = new DragTopicCommand(topicId, position, order, parentTopic);
this.execute(command); this.execute(command);
} }
/** */ /** */
moveTopic(topicId, position) { moveTopic(topicId: number, position: Point) {
$assert($defined(topicId), 'topicsId can not be null'); $assert($defined(topicId), 'topicsId can not be null');
$assert($defined(position), 'position can not be null'); $assert($defined(position), 'position can not be null');
@ -73,19 +87,19 @@ class StandaloneActionDispatcher extends ActionDispatcher {
return result; return result;
}; };
const command = new GenericFunctionCommand(commandFunc, topicId, position); const command = new GenericFunctionCommand(commandFunc, [topicId], position);
this.execute(command); this.execute(command);
} }
/** */ /** */
moveControlPoint(ctrlPoint, point) { moveControlPoint(ctrlPoint: Point, point: Point) {
const command = new MoveControlPointCommand(ctrlPoint, point); const command = new MoveControlPointCommand(ctrlPoint, point);
this.execute(command); this.execute(command);
} }
/** */ /** */
changeFontStyleToTopic(topicsIds) { changeFontStyleToTopic(topicsIds: number[]) {
const commandFunc = (topic) => { const commandFunc = (topic: Topic) => {
const result = topic.getFontStyle(); const result = topic.getFontStyle();
const style = result === 'italic' ? 'normal' : 'italic'; const style = result === 'italic' ? 'normal' : 'italic';
topic.setFontStyle(style, true); topic.setFontStyle(style, true);
@ -96,10 +110,10 @@ class StandaloneActionDispatcher extends ActionDispatcher {
} }
/** */ /** */
changeTextToTopic(topicsIds, text) { changeTextToTopic(topicsIds: number[], text: string) {
$assert($defined(topicsIds), 'topicsIds can not be null'); $assert($defined(topicsIds), 'topicsIds can not be null');
const commandFunc = (topic, value) => { const commandFunc = (topic: Topic, value: object) => {
const result = topic.getText(); const result = topic.getText();
topic.setText(value); topic.setText(value);
return result; return result;
@ -111,11 +125,11 @@ class StandaloneActionDispatcher extends ActionDispatcher {
} }
/** */ /** */
changeFontFamilyToTopic(topicIds, fontFamily) { changeFontFamilyToTopic(topicIds: number[], fontFamily: string) {
$assert(topicIds, 'topicIds can not be null'); $assert(topicIds, 'topicIds can not be null');
$assert(fontFamily, 'fontFamily can not be null'); $assert(fontFamily, 'fontFamily can not be null');
const commandFunc = (topic, commandFontFamily) => { const commandFunc = (topic: Topic, commandFontFamily: string) => {
const result = topic.getFontFamily(); const result = topic.getFontFamily();
topic.setFontFamily(commandFontFamily, true); topic.setFontFamily(commandFontFamily, true);
@ -128,7 +142,7 @@ class StandaloneActionDispatcher extends ActionDispatcher {
} }
/** */ /** */
changeFontColorToTopic(topicsIds, color) { changeFontColorToTopic(topicsIds: number[], color: string) {
$assert(topicsIds, 'topicIds can not be null'); $assert(topicsIds, 'topicIds can not be null');
$assert(color, 'color can not be null'); $assert(color, 'color can not be null');
@ -144,7 +158,7 @@ class StandaloneActionDispatcher extends ActionDispatcher {
} }
/** */ /** */
changeBackgroundColorToTopic(topicsIds, color) { changeBackgroundColorToTopic(topicsIds: number[], color: string) {
$assert(topicsIds, 'topicIds can not be null'); $assert(topicsIds, 'topicIds can not be null');
$assert(color, 'color can not be null'); $assert(color, 'color can not be null');
@ -160,7 +174,7 @@ class StandaloneActionDispatcher extends ActionDispatcher {
} }
/** */ /** */
changeBorderColorToTopic(topicsIds, color) { changeBorderColorToTopic(topicsIds: number[], color: string): void {
$assert(topicsIds, 'topicIds can not be null'); $assert(topicsIds, 'topicIds can not be null');
$assert(color, 'topicIds can not be null'); $assert(color, 'topicIds can not be null');
@ -176,7 +190,7 @@ class StandaloneActionDispatcher extends ActionDispatcher {
} }
/** */ /** */
changeFontSizeToTopic(topicsIds, size) { changeFontSizeToTopic(topicsIds: number[], size: number) {
$assert(topicsIds, 'topicIds can not be null'); $assert(topicsIds, 'topicIds can not be null');
$assert(size, 'size can not be null'); $assert(size, 'size can not be null');
@ -193,7 +207,7 @@ class StandaloneActionDispatcher extends ActionDispatcher {
} }
/** */ /** */
changeShapeTypeToTopic(topicsIds, shapeType) { changeShapeTypeToTopic(topicsIds: number[], shapeType: string) {
$assert(topicsIds, 'topicsIds can not be null'); $assert(topicsIds, 'topicsIds can not be null');
$assert(shapeType, 'shapeType can not be null'); $assert(shapeType, 'shapeType can not be null');
@ -208,7 +222,7 @@ class StandaloneActionDispatcher extends ActionDispatcher {
} }
/** */ /** */
changeFontWeightToTopic(topicsIds) { changeFontWeightToTopic(topicsIds: number[]) {
$assert(topicsIds, 'topicsIds can not be null'); $assert(topicsIds, 'topicsIds can not be null');
const commandFunc = (topic) => { const commandFunc = (topic) => {
@ -225,38 +239,38 @@ class StandaloneActionDispatcher extends ActionDispatcher {
} }
/** */ /** */
shrinkBranch(topicsIds, collapse) { shrinkBranch(topicsIds: number[], collapse: boolean) {
$assert(topicsIds, 'topicsIds can not be null'); $assert(topicsIds, 'topicsIds can not be null');
const commandFunc = (topic, isShrink) => { const commandFunc = (topic: Topic, isShrink: boolean) => {
topic.setChildrenShrunken(isShrink); topic.setChildrenShrunken(isShrink);
return !isShrink; return !isShrink;
}; };
const command = new GenericFunctionCommand(commandFunc, topicsIds, collapse); const command = new GenericFunctionCommand(commandFunc, topicsIds, collapse);
this.execute(command, false); this.execute(command);
} }
/** */ /** */
addFeatureToTopic(topicId, featureType, attributes) { addFeatureToTopic(topicId: number, featureType: string, attributes) {
const command = new AddFeatureToTopicCommand(topicId, featureType, attributes); const command = new AddFeatureToTopicCommand(topicId, featureType, attributes);
this.execute(command); this.execute(command);
} }
/** */ /** */
changeFeatureToTopic(topicId, featureId, attributes) { changeFeatureToTopic(topicId: number, featureId: number, attributes) {
const command = new ChangeFeatureToTopicCommand(topicId, featureId, attributes); const command = new ChangeFeatureToTopicCommand(topicId, featureId, attributes);
this.execute(command); this.execute(command);
} }
/** */ /** */
removeFeatureFromTopic(topicId, featureId) { removeFeatureFromTopic(topicId: number, featureId: number) {
const command = new RemoveFeatureFromTopicCommand(topicId, featureId); const command = new RemoveFeatureFromTopicCommand(topicId, featureId);
this.execute(command); this.execute(command);
} }
/** */ /** */
execute(command) { execute(command: Command) {
this._actionRunner.execute(command); this._actionRunner.execute(command);
} }
} }

View File

@ -212,7 +212,9 @@ class Topic extends NodeGraph {
return model.getImageSize(); return model.getImageSize();
}; };
result.setPosition = function setPosition() {}; result.setPosition = function setPosition() {
// Ignore ...
};
} else if (shapeType === TopicShape.ELLIPSE) { } else if (shapeType === TopicShape.ELLIPSE) {
result = new Rect(0.9, attributes); result = new Rect(0.9, attributes);
} else if (shapeType === TopicShape.ROUNDED_RECT) { } else if (shapeType === TopicShape.ROUNDED_RECT) {
@ -235,13 +237,19 @@ class Topic extends NodeGraph {
result.setStroke(1, 'solid', stokeColor); result.setStroke(1, 'solid', stokeColor);
}; };
result.getSize = function getSize() { result.getSize = () => this.size;
return this.size;
result.setPosition = () => {
// Overwrite behaviour ...
}; };
result.setPosition = function setPosition() {}; result.setFill = () => {
result.setFill = function setFill() {}; // Overwrite behaviour ...
result.setStroke = function setStroke() {}; };
result.setStroke = () => {
// Overwrite behaviour ...
};
} else { } else {
$assert(false, `Unsupported figure shapeType:${shapeType}`); $assert(false, `Unsupported figure shapeType:${shapeType}`);
} }

View File

@ -17,8 +17,17 @@
*/ */
import { $assert, $defined } from '@wisemapping/core-js'; import { $assert, $defined } from '@wisemapping/core-js';
import Command from '../Command'; import Command from '../Command';
import CommandContext from '../CommandContext';
class AddFeatureToTopicCommand extends Command { class AddFeatureToTopicCommand extends Command {
private _topicId: number;
private _featureType: string;
private _attributes: object;
private _featureModel: any;
/* /*
* @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}
@ -29,7 +38,7 @@ class AddFeatureToTopicCommand extends Command {
* @extends mindplot.Command * @extends mindplot.Command
* @see mindplot.model.FeatureModel and subclasses * @see mindplot.model.FeatureModel and subclasses
*/ */
constructor(topicId, featureType, attributes) { constructor(topicId: number, featureType: string, 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');
$assert(attributes, 'attributes can not be null'); $assert(attributes, 'attributes can not be null');
@ -44,8 +53,8 @@ class AddFeatureToTopicCommand extends Command {
/** /**
* Overrides abstract parent method * Overrides abstract parent method
*/ */
execute(commandContext) { execute(commandContext: CommandContext) {
const topic = commandContext.findTopics(this._topicId)[0]; const topic = commandContext.findTopics([this._topicId])[0];
// Feature must be created only one time. // Feature must be created only one time.
if (!this._featureModel) { if (!this._featureModel) {
@ -59,8 +68,8 @@ class AddFeatureToTopicCommand extends Command {
* Overrides abstract parent method * Overrides abstract parent method
* @see {@link mindplot.Command.undoExecute} * @see {@link mindplot.Command.undoExecute}
*/ */
undoExecute(commandContext) { undoExecute(commandContext: CommandContext) {
const topic = commandContext.findTopics(this._topicId)[0]; const topic = commandContext.findTopics([this._topicId])[0];
topic.removeFeature(this._featureModel); topic.removeFeature(this._featureModel);
} }
} }

View File

@ -17,15 +17,15 @@
*/ */
import { $assert } from '@wisemapping/core-js'; import { $assert } from '@wisemapping/core-js';
import Command from '../Command'; import Command from '../Command';
import RelationshipModel from '../model/RelationshipModel';
class AddRelationshipCommand extends Command { class AddRelationshipCommand extends Command {
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.
* @constructs
* @param {XMLDOM} model
* @extends mindplot.Command
*/ */
constructor(model) { constructor(model:RelationshipModel) {
$assert(model, 'Relationship model can not be null'); $assert(model, 'Relationship model can not be null');
super(); super();

View File

@ -17,18 +17,19 @@
*/ */
import { $assert, $defined } from '@wisemapping/core-js'; import { $assert, $defined } from '@wisemapping/core-js';
import Command from '../Command'; import Command from '../Command';
import CommandContext from '../CommandContext';
import NodeModel from '../model/NodeModel';
class AddTopicCommand extends Command { class AddTopicCommand extends Command {
private _models: NodeModel[];
private _parentsIds: number[];
/** /**
* @classdesc This command class handles do/undo of adding one or multiple topics to * @classdesc This command class handles do/undo of adding one or multiple topics to
* the mindmap. * the mindmap.
* @constructs
* @param {Array<mindplot.model.NodeModel>} models one or multiple models
* @param {Array<String>} parentTopicsId ids of the parent topics to add the children to, or null
* when attaching a dragged node or a node/branch from clipboard
* @extends mindplot.Command
*/ */
constructor(models, parentTopicsId) { 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');
@ -40,7 +41,7 @@ class AddTopicCommand extends Command {
/** /**
* Overrides abstract parent method * Overrides abstract parent method
*/ */
execute(commandContext) { execute(commandContext: CommandContext) {
const me = this; const me = this;
this._models.forEach((model, index) => { this._models.forEach((model, index) => {
// Add a new topic ... // Add a new topic ...
@ -50,7 +51,7 @@ class AddTopicCommand extends Command {
if (me._parentsIds) { if (me._parentsIds) {
const parentId = me._parentsIds[index]; const parentId = me._parentsIds[index];
if ($defined(parentId)) { if ($defined(parentId)) {
const parentTopic = commandContext.findTopics(parentId)[0]; const parentTopic = commandContext.findTopics([parentId])[0];
commandContext.connect(topic, parentTopic); commandContext.connect(topic, parentTopic);
} }
} else { } else {
@ -58,7 +59,7 @@ class AddTopicCommand extends Command {
} }
// Select just created node ... // Select just created node ...
const designer = commandContext._designer; const { designer } = commandContext;
designer.onObjectFocusEvent(topic); designer.onObjectFocusEvent(topic);
topic.setOnFocus(true); topic.setOnFocus(true);
@ -71,7 +72,7 @@ class AddTopicCommand extends Command {
* Overrides abstract parent method * Overrides abstract parent method
* @see {@link mindplot.Command.undoExecute} * @see {@link mindplot.Command.undoExecute}
*/ */
undoExecute(commandContext) { undoExecute(commandContext: CommandContext) {
// Delete disconnected the nodes. Create a copy of the topics ... // Delete disconnected the nodes. Create a copy of the topics ...
const clonedModel = []; const clonedModel = [];
this._models.forEach((model) => { this._models.forEach((model) => {
@ -79,9 +80,9 @@ class AddTopicCommand extends Command {
}); });
// Finally, remove the nodes ... // Finally, remove the nodes ...
this._models.forEach((model) => { this._models.forEach((model: NodeModel) => {
const topicId = model.getId(); const topicId = model.getId();
const topic = commandContext.findTopics(topicId)[0]; const topic = commandContext.findTopics([topicId])[0];
commandContext.deleteTopic(topic); commandContext.deleteTopic(topic);
}); });

View File

@ -17,19 +17,16 @@
*/ */
import { $assert, $defined } from '@wisemapping/core-js'; import { $assert, $defined } from '@wisemapping/core-js';
import Command from '../Command'; import Command from '../Command';
import CommandContext from '../CommandContext';
class ChangeFeatureToTopicCommand extends Command { class ChangeFeatureToTopicCommand extends Command {
/** private _featureId: number;
* @extends mindplot.Command
* @constructs private _topicId: number;
* @param topicId
* @param featureId private _attributes: any;
* @param attributes
* @throws will throw an error if topicId is null or undefined constructor(topicId: number, featureId: number, attributes: any) {
* @throws will throw an error if featureId is null or undefined
* @throws will throw an error if attributes is null or undefined
*/
constructor(topicId, featureId, attributes) {
$assert($defined(topicId), 'topicId can not be null'); $assert($defined(topicId), 'topicId can not be null');
$assert($defined(featureId), 'featureId can not be null'); $assert($defined(featureId), 'featureId can not be null');
$assert($defined(attributes), 'attributes can not be null'); $assert($defined(attributes), 'attributes can not be null');
@ -43,8 +40,8 @@ class ChangeFeatureToTopicCommand extends Command {
/** /**
* Overrides abstract parent method * Overrides abstract parent method
*/ */
execute(commandContext) { execute(commandContext: CommandContext) {
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);
const oldAttributes = feature.getAttributes(); const oldAttributes = feature.getAttributes();
@ -56,7 +53,7 @@ class ChangeFeatureToTopicCommand extends Command {
* Overrides abstract parent method * Overrides abstract parent method
* @see {@link mindplot.Command.undoExecute} * @see {@link mindplot.Command.undoExecute}
*/ */
undoExecute(commandContext) { undoExecute(commandContext: any) {
this.execute(commandContext); this.execute(commandContext);
} }
} }

View File

@ -17,16 +17,20 @@
*/ */
import { $assert, $defined } from '@wisemapping/core-js'; import { $assert, $defined } from '@wisemapping/core-js';
import Command from '../Command'; import Command from '../Command';
import CommandContext from '../CommandContext';
class DeleteCommand extends Command { class DeleteCommand extends Command {
/** private _relIds: number[];
* @classdesc This command class handles do/undo of deleting a topic.
* @constructs private _topicIds: number[];
* @param {Array<String>} topicIds ids of the topics to delete
* @param {Array<String>} relIds ids of the relationships connected to the topics private _deletedTopicModels: any[];
* @extends mindplot.Command
*/ private _deletedRelModel: any[];
constructor(topicIds, relIds) {
private _parentTopicIds: any[];
constructor(topicIds: number[], relIds: number[]) {
$assert($defined(relIds), 'topicIds can not be null'); $assert($defined(relIds), 'topicIds can not be null');
super(); super();
@ -40,7 +44,7 @@ class DeleteCommand extends Command {
/** /**
* Overrides abstract parent method * Overrides abstract parent method
*/ */
execute(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);
@ -89,7 +93,7 @@ class DeleteCommand extends Command {
* Overrides abstract parent method * Overrides abstract parent method
* @see {@link mindplot.Command.undoExecute} * @see {@link mindplot.Command.undoExecute}
*/ */
undoExecute(commandContext) { undoExecute(commandContext: CommandContext) {
// Add all the topics ... // Add all the topics ...
this._deletedTopicModels.forEach((model) => { this._deletedTopicModels.forEach((model) => {
commandContext.createTopic(model); commandContext.createTopic(model);

View File

@ -16,19 +16,25 @@
* limitations under the License. * limitations under the License.
*/ */
import { $assert, $defined } from '@wisemapping/core-js'; import { $assert, $defined } from '@wisemapping/core-js';
import Point from '@wisemapping/web2d';
import Command from '../Command'; import Command from '../Command';
import CommandContext from '../CommandContext';
import Topic from '../Topic';
class DragTopicCommand extends Command { class DragTopicCommand extends Command {
private _topicsId: number;
private _parentId: any;
private _position: Point;
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
* @param {String} topicId id of the topic to drag
* @param {Object} position
* @param {Number} order the order property (children are displayed in order from 0 to n)
* @param {mindplot.Topic} parentTopic the topic to be made the dragged topic's new parent
* @extends mindplot.Command
*/ */
constructor(topicId, position, order, parentTopic) { constructor(topicId: number, position: Point, order: number, parentTopic: Topic) {
$assert(topicId, 'topicId must be defined'); $assert(topicId, 'topicId must be defined');
super(); super();
@ -44,8 +50,8 @@ class DragTopicCommand extends Command {
/** /**
* Overrides abstract parent method * Overrides abstract parent method
*/ */
execute(commandContext) { execute(commandContext: CommandContext): void {
const topic = commandContext.findTopics(this._topicsId)[0]; const topic = commandContext.findTopics([this._topicsId])[0];
topic.setVisibility(false); topic.setVisibility(false);
// Save old position ... // Save old position ...
@ -89,11 +95,7 @@ class DragTopicCommand extends Command {
this._position = origPosition; this._position = origPosition;
} }
/** undoExecute(commandContext: CommandContext): void {
* Overrides abstract parent method
* @see {@link mindplot.Command.undoExecute}
*/
undoExecute(commandContext) {
this.execute(commandContext); this.execute(commandContext);
} }
} }

View File

@ -17,20 +17,23 @@
*/ */
import { $assert, $defined } from '@wisemapping/core-js'; import { $assert, $defined } from '@wisemapping/core-js';
import Command from '../Command'; import Command from '../Command';
import CommandContext from '../CommandContext';
import Topic from '../Topic';
class GenericFunctionCommand extends Command { class GenericFunctionCommand extends Command {
/** private _discardDuplicated: string;
* @classdesc This command handles do/undo of different actions, e.g. moving topics to
* a different position, changing text or font,... (for full reference check the private _value: string | object | boolean | number;
* StandaloneActionDispatcher i.e. the ActionDispatcher subclass in use)
* @constructs private _topicsId: number[];
* @param {Function} commandFunc the function the command shall execute
* @param {String|Array<String>} topicsIds the ids of the topics affected private _commandFunc: (topic: Topic, value: string | object | boolean | number) => string | object | boolean;
* @param {Object} [value] value arbitrary value necessary for the execution of the function,
* e.g. color, font family or text private _oldValues: any[];
* @extends mindplot.Command
*/ private _applied: boolean;
constructor(commandFunc, topicsIds, value) {
constructor(commandFunc: (topic: Topic, value: string | object | boolean) => string | object | boolean, topicsIds: number[], value: string | object | boolean | number = 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');
@ -39,58 +42,51 @@ class GenericFunctionCommand extends Command {
this._topicsId = topicsIds; this._topicsId = topicsIds;
this._commandFunc = commandFunc; this._commandFunc = commandFunc;
this._oldValues = []; this._oldValues = [];
this.discardDuplicated = undefined;
} }
/** /**
* Overrides abstract parent method * Overrides abstract parent method
*/ */
execute(commandContext) { execute(commandContext: CommandContext) {
if (!this.applied) { if (!this._applied) {
let topics = null; const topics = commandContext.findTopics(this._topicsId);
try {
topics = commandContext.findTopics(this._topicsId);
} catch (e) {
if (this._commandFunc.commandType !== 'changeTextToTopic') {
// Workaround: For some reason, there is a combination of events that involves
// making some modification and firing out of focus event. This is causing
// that a remove node try to be removed.
// In some other life, I will come with the solution. Almost aways occurs with IE9.
// I could be related with some change of order in sets o something similar.
throw e;
}
}
if (topics != null) { if (topics != null) {
const me = this; const me = this;
topics.forEach((topic) => { topics.forEach((topic: Topic) => {
const oldValue = me._commandFunc(topic, me._value); const oldValue = me._commandFunc(topic, me._value);
me._oldValues.push(oldValue); me._oldValues.push(oldValue);
}); });
} }
this.applied = true; this._applied = true;
} else { } else {
throw new Error('Command can not be applied two times in a row.'); throw new Error('Command can not be applied two times in a row.');
} }
} }
/** undoExecute(commandContext: CommandContext): void {
* Overrides abstract parent method if (this._applied) {
* @see {@link mindplot.Command.undoExecute}
*/
undoExecute(commandContext) {
if (this.applied) {
const topics = commandContext.findTopics(this._topicsId); const topics = commandContext.findTopics(this._topicsId);
topics.forEach(((topic, index) => { 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 = [];
} else { } else {
throw new Error('undo can not be applied.'); throw new Error('undo can not be applied.');
} }
} }
public get disardDuplicated(): string {
return this._discardDuplicated;
}
public set discardDuplicated(value: string) {
this._discardDuplicated = value;
}
} }
export default GenericFunctionCommand; export default GenericFunctionCommand;

View File

@ -17,20 +17,32 @@
*/ */
import { $assert, $defined } from '@wisemapping/core-js'; import { $assert, $defined } from '@wisemapping/core-js';
import Command from '../Command'; import Command from '../Command';
import ControlPoint from '../ControlPoint';
class MoveControlPointCommand extends Command { class MoveControlPointCommand extends Command {
private _ctrlPointControler: ControlPoint;
private _line: any;
private _controlPoint: any;
private _oldControlPoint: any;
private _originalEndPoint: any;
private _wasCustom: any;
private _endPoint: any;
private _point: number;
/** /**
* @classdesc This command handles do/undo of changing the control points of a relationship * @classdesc This command handles do/undo of changing the control points of a relationship
* arrow. These are the two points that appear when the relationship is on focus. They * arrow. These are the two points that appear when the relationship is on focus. They
* influence how the arrow is drawn (not the source or the destination topic nor the arrow * influence how the arrow is drawn (not the source or the destination topic nor the arrow
* direction) * direction)
* @constructs */
* @param {ControlPoint} ctrlPointController constructor(ctrlPointController: ControlPoint, point: number) {
* @param {Number} point 0 for the destination control point, 1 for the source control point
* @param ctrlPointController {ControlPoint}
* @param point {Number} 0 for the destination control point, 1 for the source control point
*/
constructor(ctrlPointController, point) {
$assert(ctrlPointController, 'line can not be null'); $assert(ctrlPointController, 'line can not be null');
$assert($defined(point), 'point can not be null'); $assert($defined(point), 'point can not be null');

View File

@ -17,17 +17,20 @@
*/ */
import { $assert, $defined } from '@wisemapping/core-js'; import { $assert, $defined } from '@wisemapping/core-js';
import Command from '../Command'; import Command from '../Command';
import CommandContext from '../CommandContext';
class RemoveFeatureFromTopicCommand extends Command { class RemoveFeatureFromTopicCommand extends Command {
private _topicId: number;
private _featureId: number;
private _oldFeature: any;
/** /**
* @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}.
* @constructs
* @param {String} topicId id of the topic to remove the feature from
* @param {String} featureId id of the feature to remove
* @extends mindplot.Command
*/ */
constructor(topicId, featureId) { 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');
@ -40,8 +43,8 @@ class RemoveFeatureFromTopicCommand extends Command {
/** /**
* Overrides abstract parent method * Overrides abstract parent method
*/ */
execute(commandContext) { 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);
topic.removeFeature(feature); topic.removeFeature(feature);
this._oldFeature = feature; this._oldFeature = feature;
@ -51,8 +54,8 @@ class RemoveFeatureFromTopicCommand extends Command {
* Overrides abstract parent method * Overrides abstract parent method
* @see {@link mindplot.Command.undoExecute} * @see {@link mindplot.Command.undoExecute}
*/ */
undoExecute(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);
this._oldFeature = null; this._oldFeature = null;
} }

View File

@ -30,7 +30,7 @@ const Bundle = {
es: ES, es: ES,
en: EN, en: EN,
de: DE, de: DE,
fe: FR, fr: FR,
pt_BR: PT_BR, pt_BR: PT_BR,
zh_CN: ZH_CN, zh_CN: ZH_CN,
zh_TW: ZH_TW, zh_TW: ZH_TW,

View File

@ -100,7 +100,9 @@ class BootstrapDialog extends Options {
throw new Error('Unsupported operation'); throw new Error('Unsupported operation');
} }
onDialogShown() {} onDialogShown() {
// Overwrite default behaviour ...
}
onRemoveClick(event) { onRemoveClick(event) {
throw new Error('Unsupported operation'); throw new Error('Unsupported operation');

View File

@ -19,7 +19,6 @@
*/ */
import { $assert } from '@wisemapping/core-js'; import { $assert } from '@wisemapping/core-js';
import INodeModel, { NodeModelType as NodeType } from './INodeModel'; import INodeModel, { NodeModelType as NodeType } from './INodeModel';
import NodeModel from './NodeModel';
import RelationshipModel from './RelationshipModel'; import RelationshipModel from './RelationshipModel';
abstract class IMindmap { abstract class IMindmap {
@ -76,14 +75,13 @@ abstract class IMindmap {
abstract createNode(type: NodeType, id: number): INodeModel abstract createNode(type: NodeType, id: number): INodeModel
abstract createRelationship(fromNode: NodeModel, toNode: NodeModel): void; abstract createRelationship(fromNodeId: number, toNodeId: number): void;
abstract addRelationship(rel: RelationshipModel): void; abstract addRelationship(rel: RelationshipModel): void;
abstract deleteRelationship(relationship: RelationshipModel): void; abstract deleteRelationship(relationship: RelationshipModel): void;
/** */ inspect():string {
inspect() {
let result = ''; let result = '';
result = '{ '; result = '{ ';
@ -104,19 +102,15 @@ abstract class IMindmap {
return result; return result;
} }
/** copyTo(target:IMindmap) {
* @param target const version = this.getVersion();
*/
copyTo(target) {
const source = this;
const version = source.getVersion();
target.setVersion(version); target.setVersion(version);
const desc = this.getDescription(); const desc = this.getDescription();
target.setDescription(desc); target.setDescription(desc);
// Then the rest of the branches ... // Then the rest of the branches ...
const sbranchs = source.getBranches(); const sbranchs = this.getBranches();
sbranchs.forEach((snode) => { sbranchs.forEach((snode) => {
const tnode = target.createNode(snode.getType(), snode.getId()); const tnode = target.createNode(snode.getType(), snode.getId());
snode.copyTo(tnode); snode.copyTo(tnode);

View File

@ -18,7 +18,6 @@
*/ */
import { $assert, $defined } from '@wisemapping/core-js'; import { $assert, $defined } from '@wisemapping/core-js';
import FeatureModel from './FeatureModel'; import FeatureModel from './FeatureModel';
import IMindmap from './IMindmap';
import Mindmap from './Mindmap'; import Mindmap from './Mindmap';
export type NodeModelType = 'CentralTopic' | 'MainTopic'; export type NodeModelType = 'CentralTopic' | 'MainTopic';
@ -39,7 +38,7 @@ abstract class INodeModel {
} }
getId(): number { getId(): number {
return this.getProperty('id'); return this.getProperty('id') as number;
} }
abstract getFeatures(): FeatureModel[]; abstract getFeatures(): FeatureModel[];
@ -71,7 +70,7 @@ abstract class INodeModel {
} }
getText(): string { getText(): string {
return this.getProperty('text'); return this.getProperty('text') as string;
} }
setPosition(x: number, y: number): void { setPosition(x: number, y: number): void {
@ -79,7 +78,7 @@ abstract class INodeModel {
} }
getPosition(): { x: number, y: number } { getPosition(): { x: number, y: number } {
const value = this.getProperty('position'); const value = this.getProperty('position') as string;
let result = null; let result = null;
if (value != null) { if (value != null) {
result = parseJsObject(value); result = parseJsObject(value);
@ -92,7 +91,7 @@ abstract class INodeModel {
} }
getImageSize(): {width: number, height: number} { getImageSize(): {width: number, height: number} {
const value = this.getProperty('imageSize'); const value = this.getProperty('imageSize') as string;
let result = null; let result = null;
if (value != null) { if (value != null) {
result = parseJsObject(value); result = parseJsObject(value);
@ -105,7 +104,7 @@ abstract class INodeModel {
} }
getMetadata(): string { getMetadata(): string {
return this.getProperty('metadata'); return this.getProperty('metadata') as string;
} }
setMetadata(json: string): void { setMetadata(json: string): void {
@ -113,10 +112,10 @@ abstract class INodeModel {
} }
getImageUrl(): string { getImageUrl(): string {
return this.getProperty('imageUrl'); return this.getProperty('imageUrl') as string;
} }
getMindmap(): IMindmap { getMindmap(): Mindmap {
return this._mindmap; return this._mindmap;
} }
@ -131,7 +130,7 @@ abstract class INodeModel {
/** */ /** */
getShapeType(): string { getShapeType(): string {
return this.getProperty('shapeType'); return this.getProperty('shapeType') as string;
} }
/** */ /** */
@ -148,7 +147,7 @@ abstract class INodeModel {
} }
getOrder(): number { getOrder(): number {
return this.getProperty('order'); return this.getProperty('order') as number;
} }
setFontFamily(fontFamily: string): void { setFontFamily(fontFamily: string): void {
@ -156,7 +155,7 @@ abstract class INodeModel {
} }
getFontFamily(): string { getFontFamily(): string {
return this.getProperty('fontFamily'); return this.getProperty('fontFamily') as string;
} }
/** */ /** */
@ -165,7 +164,7 @@ abstract class INodeModel {
} }
getFontStyle(): string { getFontStyle(): string {
return this.getProperty('fontStyle'); return this.getProperty('fontStyle') as string;
} }
setFontWeight(weight) { setFontWeight(weight) {
@ -181,7 +180,7 @@ abstract class INodeModel {
} }
getFontColor(): string { getFontColor(): string {
return this.getProperty('fontColor'); return this.getProperty('fontColor') as string;
} }
setFontSize(size: number) { setFontSize(size: number) {
@ -189,11 +188,11 @@ abstract class INodeModel {
} }
getFontSize(): number { getFontSize(): number {
return this.getProperty('fontSize'); return this.getProperty('fontSize') as number;
} }
getBorderColor(): string { getBorderColor(): string {
return this.getProperty('borderColor'); return this.getProperty('borderColor') as string;
} }
setBorderColor(color: string): void { setBorderColor(color: string): void {
@ -201,7 +200,7 @@ abstract class INodeModel {
} }
getBackgroundColor(): string { getBackgroundColor(): string {
return this.getProperty('backgroundColor'); return this.getProperty('backgroundColor') as string;
} }
setBackgroundColor(color: string) { setBackgroundColor(color: string) {
@ -209,7 +208,7 @@ abstract class INodeModel {
} }
areChildrenShrunken(): boolean { areChildrenShrunken(): boolean {
const result = this.getProperty('shrunken'); const result = this.getProperty('shrunken') as boolean;
return $defined(result) ? result : false; return $defined(result) ? result : false;
} }
@ -291,9 +290,9 @@ abstract class INodeModel {
abstract getPropertiesKeys(): string[]; abstract getPropertiesKeys(): string[];
abstract getProperty(key: string): any; abstract getProperty(key: string): number | string | boolean;
abstract putProperty(key: string, value: any): void; abstract putProperty(key: string, value: number | string| boolean): void;
abstract setParent(parent: INodeModel): void; abstract setParent(parent: INodeModel): void;

View File

@ -126,14 +126,7 @@ class Mindmap extends IMindmap {
return new NodeModel(type, this, id); return new NodeModel(type, this, id);
} }
/** createRelationship(sourceNodeId: number, targetNodeId: number):RelationshipModel {
* @param sourceNodeId
* @param targetNodeId
* @throws will throw an error if source node is null or undefined
* @throws will throw an error if target node is null or undefined
* @return the relationship model created
*/
createRelationship(sourceNodeId: any, targetNodeId: any) {
$assert($defined(sourceNodeId), 'from node cannot be null'); $assert($defined(sourceNodeId), 'from node cannot be null');
$assert($defined(targetNodeId), 'to node cannot be null'); $assert($defined(targetNodeId), 'to node cannot be null');
@ -154,7 +147,7 @@ class Mindmap extends IMindmap {
this._relationships = this._relationships.filter((r) => r !== relationship); this._relationships = this._relationships.filter((r) => r !== relationship);
} }
findNodeById(id: any) { findNodeById(id: number) {
let result = null; let result = null;
for (let i = 0; i < this._branches.length; i++) { for (let i = 0; i < this._branches.length; i++) {
const branch = this._branches[i]; const branch = this._branches[i];

View File

@ -37,6 +37,7 @@ class NodeModel extends INodeModel {
$assert(type, 'Node type can not be null'); $assert(type, 'Node type can not be null');
$assert(mindmap, 'mindmap can not be null'); $assert(mindmap, 'mindmap can not be null');
super(mindmap); super(mindmap);
this._properties = {}; this._properties = {};
this.setId(id); this.setId(id);
this.setType(type); this.setType(type);

View File

@ -83,7 +83,7 @@ class Pela2TangoMigrator implements XMLMindmapSerializer {
} }
} }
_fixNodePosition(node: { getPosition: () => any; setPosition: (arg0: any, arg1: any) => void; getChildren: () => any; }, parentPosition: { x: number; y: any; }) { _fixNodePosition(node: NodeModel, parentPosition: {x:number, y:number}) {
// 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

@ -30,6 +30,7 @@ const codeToSerializer = [
codeName: ModelCodeName.BETA, codeName: ModelCodeName.BETA,
serializer: XMLSerializerBeta, serializer: XMLSerializerBeta,
migrator() { migrator() {
// Ignore ..
}, },
}, },
{ {

View File

@ -22,6 +22,7 @@ class AccountSettingsPanel extends ListToolbarPanel {
constructor(elemId) { constructor(elemId) {
const model = { const model = {
getValue() { getValue() {
// Overwite default behaviour ...
}, },
setValue() { setValue() {
window.location = '/c/logout'; window.location = '/c/logout';

View File

@ -15,7 +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.
*/ */
/* eslint-disable import/no-unresolved */
import jquery from 'jquery'; import jquery from 'jquery';
import * as DesignerBuilder from './components/DesignerBuilder'; import * as DesignerBuilder from './components/DesignerBuilder';
import Mindmap from './components/model/Mindmap'; import Mindmap from './components/model/Mindmap';

View File

@ -121,7 +121,7 @@
w: a.w, w: a.w,
k: {}, k: {},
d: a.d && `M${a.d.replace(/[mlcxtrv]/g, (t) => ({ d: a.d && `M${a.d.replace(/[mlcxtrv]/g, (t) => ({
l: 'L', c: 'C', x: 'z', t: 'm', r: 'l', v: 'c', l: 'L', c: 'C', x: 'z', t: 'm', r: 'l', v: 'c',
}[t] || 'M'))}z`, }[t] || 'M'))}z`,
}, a.k) for (const s in a.k)a[o](s) && (e.glyphs[n].k[s] = a.k[s]); }, a.k) for (const s in a.k)a[o](s) && (e.glyphs[n].k[s] = a.k[s]);
} }
@ -149,29 +149,29 @@
}; var y = function (t) { if ((e = document.documentMode) && (e === 9 || e === 10)) return `url('#${t}')`; let e; const r = document.location; return `url('${r.protocol}//${r.host}${r.pathname}${r.search}#${t}')`; }; const m = function (t) { const e = t.getBBox(1); x(t.pattern, { patternTransform: `${t.matrix.invert()} translate(${e.x},${e.y})` }); }; const b = function (i, n, a) { }; var y = function (t) { if ((e = document.documentMode) && (e === 9 || e === 10)) return `url('#${t}')`; let e; const r = document.location; return `url('${r.protocol}//${r.host}${r.pathname}${r.search}#${t}')`; }; const m = function (t) { const e = t.getBBox(1); x(t.pattern, { patternTransform: `${t.matrix.invert()} translate(${e.x},${e.y})` }); }; const b = function (i, n, a) {
if (i.type == 'path') { if (i.type == 'path') {
for (var s, o, l, h, u, f = r(n).toLowerCase().split('-'), p = i.paper, v = a ? 'end' : 'start', y = i.node, m = i.attrs, b = m['stroke-width'], _ = f.length, w = 'classic', k = 3, B = 3, C = 5; _--;) switch (f[_]) { case 'block': case 'classic': case 'oval': case 'diamond': case 'open': case 'none': w = f[_]; break; case 'wide': B = 5; break; case 'narrow': B = 2; break; case 'long': k = 5; break; case 'short': k = 2; } if (w == 'open' ? (k += 2, B += 2, C += 2, l = 1, h = a ? 4 : 1, u = { fill: 'none', stroke: m.stroke }) : (h = l = k / 2, u = { fill: m.stroke, stroke: 'none' }), i._.arrows ? a ? (i._.arrows.endPath && g[i._.arrows.endPath]--, i._.arrows.endMarker && g[i._.arrows.endMarker]--) : (i._.arrows.startPath && g[i._.arrows.startPath]--, i._.arrows.startMarker && g[i._.arrows.startMarker]--) : i._.arrows = {}, w != 'none') { for (var s, o, l, h, u, f = r(n).toLowerCase().split('-'), p = i.paper, v = a ? 'end' : 'start', y = i.node, m = i.attrs, b = m['stroke-width'], _ = f.length, w = 'classic', k = 3, B = 3, C = 5; _--;) switch (f[_]) { case 'block': case 'classic': case 'oval': case 'diamond': case 'open': case 'none': w = f[_]; break; case 'wide': B = 5; break; case 'narrow': B = 2; break; case 'long': k = 5; break; case 'short': k = 2; } if (w == 'open' ? (k += 2, B += 2, C += 2, l = 1, h = a ? 4 : 1, u = { fill: 'none', stroke: m.stroke }) : (h = l = k / 2, u = { fill: m.stroke, stroke: 'none' }), i._.arrows ? a ? (i._.arrows.endPath && g[i._.arrows.endPath]--, i._.arrows.endMarker && g[i._.arrows.endMarker]--) : (i._.arrows.startPath && g[i._.arrows.startPath]--, i._.arrows.startMarker && g[i._.arrows.startMarker]--) : i._.arrows = {}, w != 'none') {
const S = `raphael-marker-${ w}`; const T = `raphael-marker-${ v }${w }${k }${B }-obj${ i.id}`; t._g.doc.getElementById(S) ? g[S]++ : (p.defs.appendChild(x(x('path'), { 'stroke-linecap': 'round', d: d[w], id: S })), g[S] = 1); let A; let M = t._g.doc.getElementById(T); M ? (g[T]++, A = M.getElementsByTagName('use')[0]) : (M = x(x('marker'), { const S = `raphael-marker-${w}`; const T = `raphael-marker-${v}${w}${k}${B}-obj${i.id}`; t._g.doc.getElementById(S) ? g[S]++ : (p.defs.appendChild(x(x('path'), { 'stroke-linecap': 'round', d: d[w], id: S })), g[S] = 1); let A; let M = t._g.doc.getElementById(T); M ? (g[T]++, A = M.getElementsByTagName('use')[0]) : (M = x(x('marker'), {
id: T, markerHeight: B, markerWidth: k, orient: 'auto', refX: h, refY: B / 2, id: T, markerHeight: B, markerWidth: k, orient: 'auto', refX: h, refY: B / 2,
}), A = x(x('use'), { 'xlink:href': `#${S}`, transform: `${a ? `rotate(180 ${ k / 2 } ${ B / 2 }) ` : c}scale(${k / C},${B / C})`, 'stroke-width': (1 / ((k / C + B / C) / 2)).toFixed(4) }), M.appendChild(A), p.defs.appendChild(M), g[T] = 1), x(A, u); const E = l * (w != 'diamond' && w != 'oval'); a ? (s = i._.arrows.startdx * b || 0, o = t.getTotalLength(m.path) - E * b) : (s = E * b, o = t.getTotalLength(m.path) - (i._.arrows.enddx * b || 0)), (u = {})[`marker-${v}`] = `url(#${T})`, (o || s) && (u.d = t.getSubpath(m.path, s, o)), x(y, u), i._.arrows[`${v}Path`] = S, i._.arrows[`${v}Marker`] = T, i._.arrows[`${v}dx`] = E, i._.arrows[`${v}Type`] = w, i._.arrows[`${v}String`] = n; }), A = x(x('use'), { 'xlink:href': `#${S}`, transform: `${a ? `rotate(180 ${k / 2} ${B / 2}) ` : c}scale(${k / C},${B / C})`, 'stroke-width': (1 / ((k / C + B / C) / 2)).toFixed(4) }), M.appendChild(A), p.defs.appendChild(M), g[T] = 1), x(A, u); const E = l * (w != 'diamond' && w != 'oval'); a ? (s = i._.arrows.startdx * b || 0, o = t.getTotalLength(m.path) - E * b) : (s = E * b, o = t.getTotalLength(m.path) - (i._.arrows.enddx * b || 0)), (u = {})[`marker-${v}`] = `url(#${T})`, (o || s) && (u.d = t.getSubpath(m.path, s, o)), x(y, u), i._.arrows[`${v}Path`] = S, i._.arrows[`${v}Marker`] = T, i._.arrows[`${v}dx`] = E, i._.arrows[`${v}Type`] = w, i._.arrows[`${v}String`] = n;
} else a ? (s = i._.arrows.startdx * b || 0, o = t.getTotalLength(m.path) - s) : (s = 0, o = t.getTotalLength(m.path) - (i._.arrows.enddx * b || 0)), i._.arrows[`${v}Path`] && x(y, { d: t.getSubpath(m.path, s, o) }), delete i._.arrows[`${v}Path`], delete i._.arrows[`${v}Marker`], delete i._.arrows[`${v}dx`], delete i._.arrows[`${v}Type`], delete i._.arrows[`${v}String`]; for (u in g) if (g[e](u) && !g[u]) { const N = t._g.doc.getElementById(u); N && N.parentNode.removeChild(N); } } else a ? (s = i._.arrows.startdx * b || 0, o = t.getTotalLength(m.path) - s) : (s = 0, o = t.getTotalLength(m.path) - (i._.arrows.enddx * b || 0)), i._.arrows[`${v}Path`] && x(y, { d: t.getSubpath(m.path, s, o) }), delete i._.arrows[`${v}Path`], delete i._.arrows[`${v}Marker`], delete i._.arrows[`${v}dx`], delete i._.arrows[`${v}Type`], delete i._.arrows[`${v}String`]; for (u in g) if (g[e](u) && !g[u]) { const N = t._g.doc.getElementById(u); N && N.parentNode.removeChild(N); }
} }
}; const _ = { }; const _ = {
'-': [3, 1], '.': [1, 1], '-.': [3, 1, 1, 1], '-..': [3, 1, 1, 1, 1, 1], '. ': [1, 3], '- ': [4, 3], '--': [8, 3], '- .': [4, 3, 1, 3], '--.': [8, 3, 1, 3], '--..': [8, 3, 1, 3, 1, 3], '-': [3, 1], '.': [1, 1], '-.': [3, 1, 1, 1], '-..': [3, 1, 1, 1, 1, 1], '. ': [1, 3], '- ': [4, 3], '--': [8, 3], '- .': [4, 3, 1, 3], '--.': [8, 3, 1, 3], '--..': [8, 3, 1, 3, 1, 3],
}; const w = function (t, e, i) { if (e = _[r(e).toLowerCase()]) { for (var n = t.attrs['stroke-width'] || '1', a = { round: n, square: n, butt: 0 }[t.attrs['stroke-linecap'] || i['stroke-linecap']] || 0, s = [], o = e.length; o--;)s[o] = e[o] * n + (o % 2 ? 1 : -1) * a; x(t.node, { 'stroke-dasharray': s.join(',') }); } else x(t.node, { 'stroke-dasharray': 'none' }); }; const k = function (i, a) { }; const w = function (t, e, i) { if (e = _[r(e).toLowerCase()]) { for (var n = t.attrs['stroke-width'] || '1', a = { round: n, square: n, butt: 0 }[t.attrs['stroke-linecap'] || i['stroke-linecap']] || 0, s = [], o = e.length; o--;)s[o] = e[o] * n + (o % 2 ? 1 : -1) * a; x(t.node, { 'stroke-dasharray': s.join(',') }); } else x(t.node, { 'stroke-dasharray': 'none' }); }; const k = function (i, a) {
const l = i.node; const u = i.attrs; const f = l.style.visibility; for (let d in l.style.visibility = 'hidden', a) { const l = i.node; const u = i.attrs; const f = l.style.visibility; for (let d in l.style.visibility = 'hidden', a) {
if (a[e](d)) { if (a[e](d)) {
if (!t._availableAttrs[e](d)) continue; let g = a[d]; switch (u[d] = g, d) { if (!t._availableAttrs[e](d)) continue; let g = a[d]; switch (u[d] = g, d) {
case 'blur': i.blur(g); break; case 'title': var y = l.getElementsByTagName('title'); if (y.length && (y = y[0]))y.firstChild.nodeValue = g; else { y = x('title'); const _ = t._g.doc.createTextNode(g); y.appendChild(_), l.appendChild(y); } break; case 'href': case 'target': var k = l.parentNode; if (k.tagName.toLowerCase() != 'a') { const C = x('a'); k.insertBefore(C, l), C.appendChild(l), k = C; }d == 'target' ? k.setAttributeNS(p, 'show', g == 'blank' ? 'new' : g) : k.setAttributeNS(p, d, g); break; case 'cursor': l.style.cursor = g; break; case 'transform': i.transform(g); break; case 'arrow-start': b(i, g); break; case 'arrow-end': b(i, g, 1); break; case 'clip-rect': var S = r(g).split(h); if (S.length == 4) { case 'blur': i.blur(g); break; case 'title': var y = l.getElementsByTagName('title'); if (y.length && (y = y[0]))y.firstChild.nodeValue = g; else { y = x('title'); const _ = t._g.doc.createTextNode(g); y.appendChild(_), l.appendChild(y); } break; case 'href': case 'target': var k = l.parentNode; if (k.tagName.toLowerCase() != 'a') { const C = x('a'); k.insertBefore(C, l), C.appendChild(l), k = C; }d == 'target' ? k.setAttributeNS(p, 'show', g == 'blank' ? 'new' : g) : k.setAttributeNS(p, d, g); break; case 'cursor': l.style.cursor = g; break; case 'transform': i.transform(g); break; case 'arrow-start': b(i, g); break; case 'arrow-end': b(i, g, 1); break; case 'clip-rect': var S = r(g).split(h); if (S.length == 4) {
i.clip && i.clip.parentNode.parentNode.removeChild(i.clip.parentNode); var T = x('clipPath'); const A = x('rect'); T.id = t.createUUID(), x(A, { i.clip && i.clip.parentNode.parentNode.removeChild(i.clip.parentNode); var T = x('clipPath'); const A = x('rect'); T.id = t.createUUID(), x(A, {
x: S[0], y: S[1], width: S[2], height: S[3], x: S[0], y: S[1], width: S[2], height: S[3],
}), T.appendChild(A), i.paper.defs.appendChild(T), x(l, { 'clip-path': `url(#${ T.id })` }), i.clip = A; }), T.appendChild(A), i.paper.defs.appendChild(T), x(l, { 'clip-path': `url(#${T.id})` }), i.clip = A;
} if (!g) { const M = l.getAttribute('clip-path'); if (M) { const E = t._g.doc.getElementById(M.replace(/(^url\(#|\)$)/g, c)); E && E.parentNode.removeChild(E), x(l, { 'clip-path': c }), delete i.clip; } } break; case 'path': i.type == 'path' && (x(l, { d: g ? u.path = t._pathToAbsolute(g) : 'M0,0' }), i._.dirty = 1, i._.arrows && ('startString' in i._.arrows && b(i, i._.arrows.startString), 'endString' in i._.arrows && b(i, i._.arrows.endString, 1))); break; case 'width': if (l.setAttribute(d, g), i._.dirty = 1, !u.fx) break; d = 'x', g = u.x; case 'x': u.fx && (g = -u.x - (u.width || 0)); case 'rx': if (d == 'rx' && i.type == 'rect') break; case 'cx': l.setAttribute(d, g), i.pattern && m(i), i._.dirty = 1; break; case 'height': if (l.setAttribute(d, g), i._.dirty = 1, !u.fy) break; d = 'y', g = u.y; case 'y': u.fy && (g = -u.y - (u.height || 0)); case 'ry': if (d == 'ry' && i.type == 'rect') break; case 'cy': l.setAttribute(d, g), i.pattern && m(i), i._.dirty = 1; break; case 'r': i.type == 'rect' ? x(l, { rx: g, ry: g }) : l.setAttribute(d, g), i._.dirty = 1; break; case 'src': i.type == 'image' && l.setAttributeNS(p, 'href', g); break; case 'stroke-width': i._.sx == 1 && i._.sy == 1 || (g /= s(o(i._.sx), o(i._.sy)) || 1), l.setAttribute(d, g), u['stroke-dasharray'] && w(i, u['stroke-dasharray'], a), i._.arrows && ('startString' in i._.arrows && b(i, i._.arrows.startString), 'endString' in i._.arrows && b(i, i._.arrows.endString, 1)); break; case 'stroke-dasharray': w(i, g, a); break; case 'fill': var N = r(g).match(t._ISURL); if (N) { } if (!g) { const M = l.getAttribute('clip-path'); if (M) { const E = t._g.doc.getElementById(M.replace(/(^url\(#|\)$)/g, c)); E && E.parentNode.removeChild(E), x(l, { 'clip-path': c }), delete i.clip; } } break; case 'path': i.type == 'path' && (x(l, { d: g ? u.path = t._pathToAbsolute(g) : 'M0,0' }), i._.dirty = 1, i._.arrows && ('startString' in i._.arrows && b(i, i._.arrows.startString), 'endString' in i._.arrows && b(i, i._.arrows.endString, 1))); break; case 'width': if (l.setAttribute(d, g), i._.dirty = 1, !u.fx) break; d = 'x', g = u.x; case 'x': u.fx && (g = -u.x - (u.width || 0)); case 'rx': if (d == 'rx' && i.type == 'rect') break; case 'cx': l.setAttribute(d, g), i.pattern && m(i), i._.dirty = 1; break; case 'height': if (l.setAttribute(d, g), i._.dirty = 1, !u.fy) break; d = 'y', g = u.y; case 'y': u.fy && (g = -u.y - (u.height || 0)); case 'ry': if (d == 'ry' && i.type == 'rect') break; case 'cy': l.setAttribute(d, g), i.pattern && m(i), i._.dirty = 1; break; case 'r': i.type == 'rect' ? x(l, { rx: g, ry: g }) : l.setAttribute(d, g), i._.dirty = 1; break; case 'src': i.type == 'image' && l.setAttributeNS(p, 'href', g); break; case 'stroke-width': i._.sx == 1 && i._.sy == 1 || (g /= s(o(i._.sx), o(i._.sy)) || 1), l.setAttribute(d, g), u['stroke-dasharray'] && w(i, u['stroke-dasharray'], a), i._.arrows && ('startString' in i._.arrows && b(i, i._.arrows.startString), 'endString' in i._.arrows && b(i, i._.arrows.endString, 1)); break; case 'stroke-dasharray': w(i, g, a); break; case 'fill': var N = r(g).match(t._ISURL); if (N) {
T = x('pattern'); var L = x('image'); T.id = t.createUUID(), x(T, { T = x('pattern'); var L = x('image'); T.id = t.createUUID(), x(T, {
x: 0, y: 0, patternUnits: 'userSpaceOnUse', height: 1, width: 1, x: 0, y: 0, patternUnits: 'userSpaceOnUse', height: 1, width: 1,
}), x(L, { x: 0, y: 0, 'xlink:href': N[1] }), T.appendChild(L), (function (e) { t._preload(N[1], function () { const t = this.offsetWidth; const r = this.offsetHeight; x(e, { width: t, height: r }), x(L, { width: t, height: r }); }); }(T)), i.paper.defs.appendChild(T), x(l, { fill: `url(#${ T.id })` }), i.pattern = T, i.pattern && m(i); break; }), x(L, { x: 0, y: 0, 'xlink:href': N[1] }), T.appendChild(L), (function (e) { t._preload(N[1], function () { const t = this.offsetWidth; const r = this.offsetHeight; x(e, { width: t, height: r }), x(L, { width: t, height: r }); }); }(T)), i.paper.defs.appendChild(T), x(l, { fill: `url(#${T.id})` }), i.pattern = T, i.pattern && m(i); break;
} var P = t.getRGB(g); if (P.error) { if ((i.type == 'circle' || i.type == 'ellipse' || r(g).charAt() != 'r') && v(i, g)) { if ('opacity' in u || 'fill-opacity' in u) { var z = t._g.doc.getElementById(l.getAttribute('fill').replace(/^url\(#|\)$/g, c)); if (z) { var F = z.getElementsByTagName('stop'); x(F[F.length - 1], { 'stop-opacity': ('opacity' in u ? u.opacity : 1) * ('fill-opacity' in u ? u['fill-opacity'] : 1) }); } }u.gradient = g, u.fill = 'none'; break; } } else delete a.gradient, delete u.gradient, !t.is(u.opacity, 'undefined') && t.is(a.opacity, 'undefined') && x(l, { opacity: u.opacity }), !t.is(u['fill-opacity'], 'undefined') && t.is(a['fill-opacity'], 'undefined') && x(l, { 'fill-opacity': u['fill-opacity'] }); P[e]('opacity') && x(l, { 'fill-opacity': P.opacity > 1 ? P.opacity / 100 : P.opacity }); case 'stroke': P = t.getRGB(g), l.setAttribute(d, P.hex), d == 'stroke' && P[e]('opacity') && x(l, { 'stroke-opacity': P.opacity > 1 ? P.opacity / 100 : P.opacity }), d == 'stroke' && i._.arrows && ('startString' in i._.arrows && b(i, i._.arrows.startString), 'endString' in i._.arrows && b(i, i._.arrows.endString, 1)); break; case 'gradient': (i.type == 'circle' || i.type == 'ellipse' || r(g).charAt() != 'r') && v(i, g); break; case 'opacity': u.gradient && !u[e]('stroke-opacity') && x(l, { 'stroke-opacity': g > 1 ? g / 100 : g }); case 'fill-opacity': if (u.gradient) { (z = t._g.doc.getElementById(l.getAttribute('fill').replace(/^url\(#|\)$/g, c))) && (F = z.getElementsByTagName('stop'), x(F[F.length - 1], { 'stop-opacity': g })); break; } default: d == 'font-size' && (g = `${n(g, 10)}px`); var R = d.replace(/(\-.)/g, (t) => t.substring(1).toUpperCase()); l.style[R] = g, i._.dirty = 1, l.setAttribute(d, g); } var P = t.getRGB(g); if (P.error) { if ((i.type == 'circle' || i.type == 'ellipse' || r(g).charAt() != 'r') && v(i, g)) { if ('opacity' in u || 'fill-opacity' in u) { var z = t._g.doc.getElementById(l.getAttribute('fill').replace(/^url\(#|\)$/g, c)); if (z) { var F = z.getElementsByTagName('stop'); x(F[F.length - 1], { 'stop-opacity': ('opacity' in u ? u.opacity : 1) * ('fill-opacity' in u ? u['fill-opacity'] : 1) }); } }u.gradient = g, u.fill = 'none'; break; } } else delete a.gradient, delete u.gradient, !t.is(u.opacity, 'undefined') && t.is(a.opacity, 'undefined') && x(l, { opacity: u.opacity }), !t.is(u['fill-opacity'], 'undefined') && t.is(a['fill-opacity'], 'undefined') && x(l, { 'fill-opacity': u['fill-opacity'] }); P[e]('opacity') && x(l, { 'fill-opacity': P.opacity > 1 ? P.opacity / 100 : P.opacity }); case 'stroke': P = t.getRGB(g), l.setAttribute(d, P.hex), d == 'stroke' && P[e]('opacity') && x(l, { 'stroke-opacity': P.opacity > 1 ? P.opacity / 100 : P.opacity }), d == 'stroke' && i._.arrows && ('startString' in i._.arrows && b(i, i._.arrows.startString), 'endString' in i._.arrows && b(i, i._.arrows.endString, 1)); break; case 'gradient': (i.type == 'circle' || i.type == 'ellipse' || r(g).charAt() != 'r') && v(i, g); break; case 'opacity': u.gradient && !u[e]('stroke-opacity') && x(l, { 'stroke-opacity': g > 1 ? g / 100 : g }); case 'fill-opacity': if (u.gradient) { (z = t._g.doc.getElementById(l.getAttribute('fill').replace(/^url\(#|\)$/g, c))) && (F = z.getElementsByTagName('stop'), x(F[F.length - 1], { 'stop-opacity': g })); break; } default: d == 'font-size' && (g = `${n(g, 10)}px`); var R = d.replace(/(\-.)/g, (t) => t.substring(1).toUpperCase()); l.style[R] = g, i._.dirty = 1, l.setAttribute(d, g);
}
} }
} }B(i, a), l.style.visibility = f;
}B(i, a), l.style.visibility = f;
}; var B = function (i, a) { if (i.type == 'text' && (a[e]('text') || a[e]('font') || a[e]('font-size') || a[e]('x') || a[e]('y'))) { const s = i.attrs; const o = i.node; const l = o.firstChild ? n(t._g.doc.defaultView.getComputedStyle(o.firstChild, c).getPropertyValue('font-size'), 10) : 10; if (a[e]('text')) { for (s.text = a.text; o.firstChild;)o.removeChild(o.firstChild); for (var h, u = r(a.text).split('\n'), f = [], p = 0, d = u.length; p < d; p++)h = x('tspan'), p && x(h, { dy: 1.2 * l, x: s.x }), h.appendChild(t._g.doc.createTextNode(u[p])), o.appendChild(h), f[p] = h; } else for (p = 0, d = (f = o.getElementsByTagName('tspan')).length; p < d; p++)p ? x(f[p], { dy: 1.2 * l, x: s.x }) : x(f[0], { dy: 0 }); x(o, { x: s.x, y: s.y }), i._.dirty = 1; const g = i._getBBox(); const v = s.y - (g.y + g.height / 2); v && t.is(v, 'finite') && x(f[0], { dy: v }); } }; const C = function (t) { return t.parentNode && t.parentNode.tagName.toLowerCase() === 'a' ? t.parentNode : t; }; const S = function (e, r) { }; var B = function (i, a) { if (i.type == 'text' && (a[e]('text') || a[e]('font') || a[e]('font-size') || a[e]('x') || a[e]('y'))) { const s = i.attrs; const o = i.node; const l = o.firstChild ? n(t._g.doc.defaultView.getComputedStyle(o.firstChild, c).getPropertyValue('font-size'), 10) : 10; if (a[e]('text')) { for (s.text = a.text; o.firstChild;)o.removeChild(o.firstChild); for (var h, u = r(a.text).split('\n'), f = [], p = 0, d = u.length; p < d; p++)h = x('tspan'), p && x(h, { dy: 1.2 * l, x: s.x }), h.appendChild(t._g.doc.createTextNode(u[p])), o.appendChild(h), f[p] = h; } else for (p = 0, d = (f = o.getElementsByTagName('tspan')).length; p < d; p++)p ? x(f[p], { dy: 1.2 * l, x: s.x }) : x(f[0], { dy: 0 }); x(o, { x: s.x, y: s.y }), i._.dirty = 1; const g = i._getBBox(); const v = s.y - (g.y + g.height / 2); v && t.is(v, 'finite') && x(f[0], { dy: v }); } }; const C = function (t) { return t.parentNode && t.parentNode.tagName.toLowerCase() === 'a' ? t.parentNode : t; }; const S = function (e, r) {
this[0] = this.node = e, e.raphael = !0, this.id = (`0000${(Math.random() * Math.pow(36, 5) << 0).toString(36)}`).slice(-5), e.raphaelid = this.id, this.matrix = t.matrix(), this.realPath = null, this.paper = r, this.attrs = this.attrs || {}, this._ = { this[0] = this.node = e, e.raphael = !0, this.id = (`0000${(Math.random() * Math.pow(36, 5) << 0).toString(36)}`).slice(-5), e.raphaelid = this.id, this.matrix = t.matrix(), this.realPath = null, this.paper = r, this.attrs = this.attrs || {}, this._ = {
transform: [], sx: 1, sy: 1, deg: 0, dx: 0, dy: 0, dirty: 1, transform: [], sx: 1, sy: 1, deg: 0, dx: 0, dy: 0, dirty: 1,
@ -217,7 +217,7 @@
const e = 'hasOwnProperty'; const r = String; const i = parseFloat; const n = Math; const a = n.round; const s = n.max; const o = n.min; const l = n.abs; const h = /[, ]+/; const u = t.eve; const c = ' '; const f = ''; const p = { const e = 'hasOwnProperty'; const r = String; const i = parseFloat; const n = Math; const a = n.round; const s = n.max; const o = n.min; const l = n.abs; const h = /[, ]+/; const u = t.eve; const c = ' '; const f = ''; const p = {
M: 'm', L: 'l', C: 'c', Z: 'x', m: 't', l: 'r', c: 'v', z: 'x', M: 'm', L: 'l', C: 'c', Z: 'x', m: 't', l: 'r', c: 'v', z: 'x',
}; const d = /([clmz]),?([^clmz]*)/gi; const g = / progid:\S+Blur\([^\)]+\)/g; const x = /-?[^,\s-]+/g; const v = 'position:absolute;left:0;top:0;width:1px;height:1px;behavior:url(#default#VML)'; const y = 21600; const m = { path: 1, rect: 1, image: 1 }; const b = { circle: 1, ellipse: 1 }; const _ = function (e, r, i) { const n = t.matrix(); return n.rotate(-e, 0.5, 0.5), { dx: n.x(r, i), dy: n.y(r, i) }; }; const w = function (t, e, r, i, n, a) { const s = t._; const o = t.matrix; const h = s.fillpos; const u = t.node; const f = u.style; let p = 1; let d = ''; const g = y / e; const x = y / r; if (f.visibility = 'hidden', e && r) { if (u.coordsize = l(g) + c + l(x), f.rotation = a * (e * r < 0 ? -1 : 1), a) { var v = _(a, i, n); i = v.dx, n = v.dy; } if (e < 0 && (d += 'x'), r < 0 && (d += ' y') && (p = -1), f.flip = d, u.coordorigin = i * -g + c + n * -x, h || s.fillsize) { let m = u.getElementsByTagName('fill'); m = m && m[0], u.removeChild(m), h && (v = _(a, o.x(h[0], h[1]), o.y(h[0], h[1])), m.position = v.dx * p + c + v.dy * p), s.fillsize && (m.size = s.fillsize[0] * l(e) + c + s.fillsize[1] * l(r)), u.appendChild(m); }f.visibility = 'visible'; } }; t.toString = function () { return `Your browser doesnt support SVG. Falling down to VML.\nYou are running Raphaël ${this.version}`; }; let k; const B = function (t, e, i) { for (var n = r(e).toLowerCase().split('-'), a = i ? 'end' : 'start', s = n.length, o = 'classic', l = 'medium', h = 'medium'; s--;) switch (n[s]) { case 'block': case 'classic': case 'oval': case 'diamond': case 'open': case 'none': o = n[s]; break; case 'wide': case 'narrow': h = n[s]; break; case 'long': case 'short': l = n[s]; } const u = t.node.getElementsByTagName('stroke')[0]; u[`${a}arrow`] = o, u[`${a}arrowlength`] = l, u[`${a}arrowwidth`] = h; }; const C = function (n, l) { }; const d = /([clmz]),?([^clmz]*)/gi; const g = / progid:\S+Blur\([^\)]+\)/g; const x = /-?[^,\s-]+/g; const v = 'position:absolute;left:0;top:0;width:1px;height:1px;behavior:url(#default#VML)'; const y = 21600; const m = { path: 1, rect: 1, image: 1 }; const b = { circle: 1, ellipse: 1 }; const _ = function (e, r, i) { const n = t.matrix(); return n.rotate(-e, 0.5, 0.5), { dx: n.x(r, i), dy: n.y(r, i) }; }; const w = function (t, e, r, i, n, a) { const s = t._; const o = t.matrix; const h = s.fillpos; const u = t.node; const f = u.style; let p = 1; let d = ''; const g = y / e; const x = y / r; if (f.visibility = 'hidden', e && r) { if (u.coordsize = l(g) + c + l(x), f.rotation = a * (e * r < 0 ? -1 : 1), a) { var v = _(a, i, n); i = v.dx, n = v.dy; } if (e < 0 && (d += 'x'), r < 0 && (d += ' y') && (p = -1), f.flip = d, u.coordorigin = i * -g + c + n * -x, h || s.fillsize) { let m = u.getElementsByTagName('fill'); m = m && m[0], u.removeChild(m), h && (v = _(a, o.x(h[0], h[1]), o.y(h[0], h[1])), m.position = v.dx * p + c + v.dy * p), s.fillsize && (m.size = s.fillsize[0] * l(e) + c + s.fillsize[1] * l(r)), u.appendChild(m); }f.visibility = 'visible'; } }; t.toString = function () { return `Your browser doesnt support SVG. Falling down to VML.\nYou are running Raphaël ${this.version}`; }; let k; const B = function (t, e, i) { for (var n = r(e).toLowerCase().split('-'), a = i ? 'end' : 'start', s = n.length, o = 'classic', l = 'medium', h = 'medium'; s--;) switch (n[s]) { case 'block': case 'classic': case 'oval': case 'diamond': case 'open': case 'none': o = n[s]; break; case 'wide': case 'narrow': h = n[s]; break; case 'long': case 'short': l = n[s]; } const u = t.node.getElementsByTagName('stroke')[0]; u[`${a}arrow`] = o, u[`${a}arrowlength`] = l, u[`${a}arrowwidth`] = h; }; const C = function (n, l) {
n.attrs = n.attrs || {}; const u = n.node; const g = n.attrs; let v = u.style; const _ = m[n.type] && (l.x != g.x || l.y != g.y || l.width != g.width || l.height != g.height || l.cx != g.cx || l.cy != g.cy || l.rx != g.rx || l.ry != g.ry || l.r != g.r); const C = b[n.type] && (g.cx != l.cx || g.cy != l.cy || g.r != l.r || g.rx != l.rx || g.ry != l.ry); const T = n; for (const A in l)l[e](A) && (g[A] = l[A]); if (_ && (g.path = t._getPath[n.type](n), n._.dirty = 1), l.href && (u.href = l.href), l.title && (u.title = l.title), l.target && (u.target = l.target), l.cursor && (v.cursor = l.cursor), 'blur' in l && n.blur(l.blur), (l.path && n.type == 'path' || _) && (u.path = (function (e) { let i = /[ahqstv]/gi; let n = t._pathToAbsolute; if (r(e).match(i) && (n = t._path2curve), i = /[clmz]/g, n == t._pathToAbsolute && !r(e).match(i)) { var s = r(e).replace(d, (t, e, r) => { let i = []; const n = 'm' == e.toLowerCase(); let s = p[e]; return r.replace(x, (t) => { n && i.length == 2 && (s += i + p[e == 'm' ? 'l' : 'L'], i = []), i.push(a(t * y)); }), s + i; }); return s; } let o; let l; const h = n(e); s = []; for (let u = 0, g = h.length; u < g; u++) { o = h[u], (l = h[u][0].toLowerCase()) == 'z' && (l = 'x'); for (let v = 1, m = o.length; v < m; v++)l += a(o[v] * y) + (v != m - 1 ? ',' : f); s.push(l); } return s.join(c); }(~r(g.path).toLowerCase().indexOf('r') ? t._pathToAbsolute(g.path) : g.path)), n._.dirty = 1, n.type == 'image' && (n._.fillpos = [g.x, g.y], n._.fillsize = [g.width, g.height], w(n, 1, 1, 0, 0, 0))), 'transform' in l && n.transform(l.transform), C) { const M = +g.cx; const E = +g.cy; const N = +g.rx || +g.r || 0; const L = +g.ry || +g.r || 0; u.path = t.format('ar{0},{1},{2},{3},{4},{1},{4},{1}x', a((M - N) * y), a((E - L) * y), a((M + N) * y), a((E + L) * y), a(M * y)), n._.dirty = 1; } if ('clip-rect' in l) { const P = r(l['clip-rect']).split(h); if (P.length == 4) { P[2] = +P[2] + +P[0], P[3] = +P[3] + +P[1]; const z = u.clipRect || t._g.doc.createElement('div'); const F = z.style; F.clip = t.format('rect({1}px {2}px {3}px {0}px)', P), u.clipRect || (F.position = 'absolute', F.top = 0, F.left = 0, F.width = `${n.paper.width}px`, F.height = `${n.paper.height}px`, u.parentNode.insertBefore(z, u), z.appendChild(u), u.clipRect = z); }l['clip-rect'] || u.clipRect && (u.clipRect.style.clip = 'auto'); } if (n.textpath) { const R = n.textpath.style; l.font && (R.font = l.font), l['font-family'] && (R.fontFamily = `"${l['font-family'].split(',')[0].replace(/^['"]+|['"]+$/g, f)}"`), l['font-size'] && (R.fontSize = l['font-size']), l['font-weight'] && (R.fontWeight = l['font-weight']), l['font-style'] && (R.fontStyle = l['font-style']); } if ('arrow-start' in l && B(T, l['arrow-start']), 'arrow-end' in l && B(T, l['arrow-end'], 1), l.opacity != null || l.fill != null || l.src != null || l.stroke != null || l['stroke-width'] != null || l['stroke-opacity'] != null || l['fill-opacity'] != null || l['stroke-dasharray'] != null || l['stroke-miterlimit'] != null || l['stroke-linejoin'] != null || l['stroke-linecap'] != null) { n.attrs = n.attrs || {}; const u = n.node; const g = n.attrs; let v = u.style; const _ = m[n.type] && (l.x != g.x || l.y != g.y || l.width != g.width || l.height != g.height || l.cx != g.cx || l.cy != g.cy || l.rx != g.rx || l.ry != g.ry || l.r != g.r); const C = b[n.type] && (g.cx != l.cx || g.cy != l.cy || g.r != l.r || g.rx != l.rx || g.ry != l.ry); const T = n; for (const A in l)l[e](A) && (g[A] = l[A]); if (_ && (g.path = t._getPath[n.type](n), n._.dirty = 1), l.href && (u.href = l.href), l.title && (u.title = l.title), l.target && (u.target = l.target), l.cursor && (v.cursor = l.cursor), 'blur' in l && n.blur(l.blur), (l.path && n.type == 'path' || _) && (u.path = (function (e) { let i = /[ahqstv]/gi; let n = t._pathToAbsolute; if (r(e).match(i) && (n = t._path2curve), i = /[clmz]/g, n == t._pathToAbsolute && !r(e).match(i)) { var s = r(e).replace(d, (t, e, r) => { let i = []; const n = e.toLowerCase() == 'm'; let s = p[e]; return r.replace(x, (t) => { n && i.length == 2 && (s += i + p[e == 'm' ? 'l' : 'L'], i = []), i.push(a(t * y)); }), s + i; }); return s; } let o; let l; const h = n(e); s = []; for (let u = 0, g = h.length; u < g; u++) { o = h[u], (l = h[u][0].toLowerCase()) == 'z' && (l = 'x'); for (let v = 1, m = o.length; v < m; v++)l += a(o[v] * y) + (v != m - 1 ? ',' : f); s.push(l); } return s.join(c); }(~r(g.path).toLowerCase().indexOf('r') ? t._pathToAbsolute(g.path) : g.path)), n._.dirty = 1, n.type == 'image' && (n._.fillpos = [g.x, g.y], n._.fillsize = [g.width, g.height], w(n, 1, 1, 0, 0, 0))), 'transform' in l && n.transform(l.transform), C) { const M = +g.cx; const E = +g.cy; const N = +g.rx || +g.r || 0; const L = +g.ry || +g.r || 0; u.path = t.format('ar{0},{1},{2},{3},{4},{1},{4},{1}x', a((M - N) * y), a((E - L) * y), a((M + N) * y), a((E + L) * y), a(M * y)), n._.dirty = 1; } if ('clip-rect' in l) { const P = r(l['clip-rect']).split(h); if (P.length == 4) { P[2] = +P[2] + +P[0], P[3] = +P[3] + +P[1]; const z = u.clipRect || t._g.doc.createElement('div'); const F = z.style; F.clip = t.format('rect({1}px {2}px {3}px {0}px)', P), u.clipRect || (F.position = 'absolute', F.top = 0, F.left = 0, F.width = `${n.paper.width}px`, F.height = `${n.paper.height}px`, u.parentNode.insertBefore(z, u), z.appendChild(u), u.clipRect = z); }l['clip-rect'] || u.clipRect && (u.clipRect.style.clip = 'auto'); } if (n.textpath) { const R = n.textpath.style; l.font && (R.font = l.font), l['font-family'] && (R.fontFamily = `"${l['font-family'].split(',')[0].replace(/^['"]+|['"]+$/g, f)}"`), l['font-size'] && (R.fontSize = l['font-size']), l['font-weight'] && (R.fontWeight = l['font-weight']), l['font-style'] && (R.fontStyle = l['font-style']); } if ('arrow-start' in l && B(T, l['arrow-start']), 'arrow-end' in l && B(T, l['arrow-end'], 1), l.opacity != null || l.fill != null || l.src != null || l.stroke != null || l['stroke-width'] != null || l['stroke-opacity'] != null || l['fill-opacity'] != null || l['stroke-dasharray'] != null || l['stroke-miterlimit'] != null || l['stroke-linejoin'] != null || l['stroke-linecap'] != null) {
let j = u.getElementsByTagName('fill'); if (!(j = j && j[0]) && (j = k('fill')), n.type == 'image' && l.src && (j.src = l.src), l.fill && (j.on = !0), j.on != null && l.fill != 'none' && l.fill !== null || (j.on = !1), j.on && l.fill) { const I = r(l.fill).match(t._ISURL); if (I) { j.parentNode == u && u.removeChild(j), j.rotate = !0, j.src = I[1], j.type = 'tile'; const D = n.getBBox(1); j.position = D.x + c + D.y, n._.fillpos = [D.x, D.y], t._preload(I[1], function () { n._.fillsize = [this.offsetWidth, this.offsetHeight]; }); } else j.color = t.getRGB(l.fill).hex, j.src = f, j.type = 'solid', t.getRGB(l.fill).error && (T.type in { circle: 1, ellipse: 1 } || r(l.fill).charAt() != 'r') && S(T, l.fill, j) && (g.fill = 'none', g.gradient = l.fill, j.rotate = !1); } if ('fill-opacity' in l || 'opacity' in l) { var q = ((+g['fill-opacity'] + 1 || 2) - 1) * ((+g.opacity + 1 || 2) - 1) * ((+t.getRGB(l.fill).o + 1 || 2) - 1); q = o(s(q, 0), 1), j.opacity = q, j.src && (j.color = 'none'); }u.appendChild(j); let O = u.getElementsByTagName('stroke') && u.getElementsByTagName('stroke')[0]; let V = !1; !O && (V = O = k('stroke')), (l.stroke && l.stroke != 'none' || l['stroke-width'] || l['stroke-opacity'] != null || l['stroke-dasharray'] || l['stroke-miterlimit'] || l['stroke-linejoin'] || l['stroke-linecap']) && (O.on = !0), (l.stroke == 'none' || l.stroke === null || O.on == null || l.stroke == 0 || l['stroke-width'] == 0) && (O.on = !1); const W = t.getRGB(l.stroke); O.on && l.stroke && (O.color = W.hex), q = ((+g['stroke-opacity'] + 1 || 2) - 1) * ((+g.opacity + 1 || 2) - 1) * ((+W.o + 1 || 2) - 1); let Y = 0.75 * (i(l['stroke-width']) || 1); if (q = o(s(q, 0), 1), l['stroke-width'] == null && (Y = g['stroke-width']), l['stroke-width'] && (O.weight = Y), Y && Y < 1 && (q *= Y) && (O.weight = 1), O.opacity = q, l['stroke-linejoin'] && (O.joinstyle = l['stroke-linejoin'] || 'miter'), O.miterlimit = l['stroke-miterlimit'] || 8, l['stroke-linecap'] && (O.endcap = l['stroke-linecap'] == 'butt' ? 'flat' : l['stroke-linecap'] == 'square' ? 'square' : 'round'), 'stroke-dasharray' in l) { let j = u.getElementsByTagName('fill'); if (!(j = j && j[0]) && (j = k('fill')), n.type == 'image' && l.src && (j.src = l.src), l.fill && (j.on = !0), j.on != null && l.fill != 'none' && l.fill !== null || (j.on = !1), j.on && l.fill) { const I = r(l.fill).match(t._ISURL); if (I) { j.parentNode == u && u.removeChild(j), j.rotate = !0, j.src = I[1], j.type = 'tile'; const D = n.getBBox(1); j.position = D.x + c + D.y, n._.fillpos = [D.x, D.y], t._preload(I[1], function () { n._.fillsize = [this.offsetWidth, this.offsetHeight]; }); } else j.color = t.getRGB(l.fill).hex, j.src = f, j.type = 'solid', t.getRGB(l.fill).error && (T.type in { circle: 1, ellipse: 1 } || r(l.fill).charAt() != 'r') && S(T, l.fill, j) && (g.fill = 'none', g.gradient = l.fill, j.rotate = !1); } if ('fill-opacity' in l || 'opacity' in l) { var q = ((+g['fill-opacity'] + 1 || 2) - 1) * ((+g.opacity + 1 || 2) - 1) * ((+t.getRGB(l.fill).o + 1 || 2) - 1); q = o(s(q, 0), 1), j.opacity = q, j.src && (j.color = 'none'); }u.appendChild(j); let O = u.getElementsByTagName('stroke') && u.getElementsByTagName('stroke')[0]; let V = !1; !O && (V = O = k('stroke')), (l.stroke && l.stroke != 'none' || l['stroke-width'] || l['stroke-opacity'] != null || l['stroke-dasharray'] || l['stroke-miterlimit'] || l['stroke-linejoin'] || l['stroke-linecap']) && (O.on = !0), (l.stroke == 'none' || l.stroke === null || O.on == null || l.stroke == 0 || l['stroke-width'] == 0) && (O.on = !1); const W = t.getRGB(l.stroke); O.on && l.stroke && (O.color = W.hex), q = ((+g['stroke-opacity'] + 1 || 2) - 1) * ((+g.opacity + 1 || 2) - 1) * ((+W.o + 1 || 2) - 1); let Y = 0.75 * (i(l['stroke-width']) || 1); if (q = o(s(q, 0), 1), l['stroke-width'] == null && (Y = g['stroke-width']), l['stroke-width'] && (O.weight = Y), Y && Y < 1 && (q *= Y) && (O.weight = 1), O.opacity = q, l['stroke-linejoin'] && (O.joinstyle = l['stroke-linejoin'] || 'miter'), O.miterlimit = l['stroke-miterlimit'] || 8, l['stroke-linecap'] && (O.endcap = l['stroke-linecap'] == 'butt' ? 'flat' : l['stroke-linecap'] == 'square' ? 'square' : 'round'), 'stroke-dasharray' in l) {
const G = { const G = {
'-': 'shortdash', '.': 'shortdot', '-.': 'shortdashdot', '-..': 'shortdashdotdot', '. ': 'dot', '- ': 'dash', '--': 'longdash', '- .': 'dashdot', '--.': 'longdashdot', '--..': 'longdashdotdot', '-': 'shortdash', '.': 'shortdot', '-.': 'shortdashdot', '-..': 'shortdashdotdot', '. ': 'dot', '- ': 'dash', '--': 'longdash', '- .': 'dashdot', '--.': 'longdashdot', '--..': 'longdashdotdot',

View File

@ -16,11 +16,11 @@
* limitations under the License. * limitations under the License.
*/ */
import { Blob } from 'blob-polyfill'; import { Blob } from 'blob-polyfill';
import Exporter from '../../../src/components/export/Exporter';
import path from 'path'; import path from 'path';
import fs from 'fs'; import fs from 'fs';
import { diff } from 'jest-diff'; import { diff } from 'jest-diff';
import { expect } from '@jest/globals'; import { expect } from '@jest/globals';
import Exporter from '../../../src/components/export/Exporter';
const saveOutputRecord = false; const saveOutputRecord = false;
@ -40,31 +40,31 @@ export const parseXMLFile = (filePath: fs.PathOrFileDescriptor, mimeType: DOMPar
let content = stream.toString(); let content = stream.toString();
// Hack for SVG exported from the browser ... // Hack for SVG exported from the browser ...
if(mimeType=="image/svg+xml"){ if (mimeType == 'image/svg+xml') {
content = content.replace('<svg ', '<svg xmlns:xlink="http://www.w3.org/1999/xlink" ') content = content.replace('<svg ', '<svg xmlns:xlink="http://www.w3.org/1999/xlink" ');
} }
return parseXMLString(content, mimeType); return parseXMLString(content, mimeType);
} };
export const parseXMLString = (xmlStr: string, mimeType: DOMParserSupportedType) => { export const parseXMLString = (xmlStr: string, mimeType: DOMParserSupportedType) => {
const parser = new DOMParser(); const parser = new DOMParser();
const xmlDoc = parser.parseFromString(xmlStr, mimeType); const xmlDoc = parser.parseFromString(xmlStr, mimeType);
// Is there any parsing error ?. // Is there any parsing error ?.
if (xmlDoc.getElementsByTagName("parsererror").length > 0) { if (xmlDoc.getElementsByTagName('parsererror').length > 0) {
const xmmStr = new XMLSerializer().serializeToString(xmlDoc); const xmmStr = new XMLSerializer().serializeToString(xmlDoc);
console.log(xmmStr); console.log(xmmStr);
throw new Error(`Unexpected error parsing: ${xmlStr}. Error: ${xmmStr}`); throw new Error(`Unexpected error parsing: ${xmlStr}. Error: ${xmmStr}`);
} }
return xmlDoc; return xmlDoc;
} };
export const exporterAssert = async (testName: string, exporter: Exporter) => { export const exporterAssert = async (testName: string, exporter: Exporter) => {
const actualStr = await exporter.export(); const actualStr = await exporter.export();
//Compared with expected ... // Compared with expected ...
const expectedPath = path.resolve(__dirname, `./expected/${testName}.${exporter.extension()}`); const expectedPath = path.resolve(__dirname, `./expected/${testName}.${exporter.extension()}`);
if (saveOutputRecord) { if (saveOutputRecord) {
fs.writeFileSync(expectedPath, actualStr); fs.writeFileSync(expectedPath, actualStr);
@ -73,8 +73,8 @@ export const exporterAssert = async (testName: string, exporter: Exporter) => {
// compare with expected ... // compare with expected ...
const expectedStr = fs.readFileSync(expectedPath).toString(); const expectedStr = fs.readFileSync(expectedPath).toString();
if (actualStr !== expectedStr) { if (actualStr !== expectedStr) {
const diffResult = diff(actualStr, expectedStr); const diffResult = diff(actualStr, expectedStr);
console.log(diffResult); console.log(diffResult);
expect(actualStr).toEqual(expectedStr); expect(actualStr).toEqual(expectedStr);
} }
} };

View File

@ -1,7 +1,7 @@
import Mindmap from '../../../src/components/model/Mindmap';
import path from 'path'; import path from 'path';
import fs from 'fs'; import fs from 'fs';
import { expect, test } from '@jest/globals'; // Workaround for cypress conflict import { expect, test } from '@jest/globals'; // Workaround for cypress conflict
import Mindmap from '../../../src/components/model/Mindmap';
import XMLSerializerFactory from '../../../src/components/persistence/XMLSerializerFactory'; import XMLSerializerFactory from '../../../src/components/persistence/XMLSerializerFactory';
import SVGExporter from '../../../src/components/export/SVGExporter'; import SVGExporter from '../../../src/components/export/SVGExporter';
import { parseXMLFile, setupBlob, exporterAssert } from './Helper'; import { parseXMLFile, setupBlob, exporterAssert } from './Helper';
@ -11,23 +11,22 @@ setupBlob();
describe('SVG export test execution', () => { describe('SVG export test execution', () => {
test.each(fs.readdirSync(path.resolve(__dirname, './input/')) test.each(fs.readdirSync(path.resolve(__dirname, './input/'))
.filter((f) => f.endsWith('.wxml')) .filter((f) => f.endsWith('.wxml'))
.map((filename: string) => filename.split('.')[0])) .map((filename: string) => filename.split('.')[0]))('Exporting %p suite', async (testName: string) => {
(`Exporting %p suite`, async (testName: string) => { // Load mindmap DOM ...
// Load mindmap DOM ... const mindmapPath = path.resolve(__dirname, `./input/${testName}.wxml`);
const mindmapPath = path.resolve(__dirname, `./input/${testName}.wxml`); const mapDocument = parseXMLFile(mindmapPath, 'text/xml');
const mapDocument = parseXMLFile(mindmapPath, 'text/xml');
// Convert to mindmap ... // Convert to mindmap ...
const serializer = XMLSerializerFactory.createInstanceFromDocument(mapDocument); const serializer = XMLSerializerFactory.createInstanceFromDocument(mapDocument);
const mindmap: Mindmap = serializer.loadFromDom(mapDocument, testName); const mindmap: Mindmap = serializer.loadFromDom(mapDocument, testName);
// 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);
const svgDocument = parseXMLFile(svgPath, 'image/svg+xml'); const svgDocument = parseXMLFile(svgPath, 'image/svg+xml');
// Generate output ... // Generate output ...
const exporter = new SVGExporter(mindmap, svgDocument.documentElement); const exporter = new SVGExporter(mindmap, svgDocument.documentElement);
await exporterAssert(testName, exporter); await exporterAssert(testName, exporter);
}); });
}); });

View File

@ -1,61 +1,58 @@
import Mindmap from '../../../src/components/model/Mindmap';
import path from 'path'; import path from 'path';
import fs from 'fs';
import { test } from '@jest/globals'; // Workaround for cypress conflict
import Mindmap from '../../../src/components/model/Mindmap';
import XMLSerializerFactory from '../../../src/components/persistence/XMLSerializerFactory'; import XMLSerializerFactory from '../../../src/components/persistence/XMLSerializerFactory';
import TextExporterFactory from '../../../src/components/export/TextExporterFactory'; import TextExporterFactory from '../../../src/components/export/TextExporterFactory';
import { parseXMLFile, setupBlob, exporterAssert } from './Helper'; import { parseXMLFile, setupBlob, exporterAssert } from './Helper';
import fs from 'fs';
import { test } from '@jest/globals'; // Workaround for cypress conflict
setupBlob(); setupBlob();
const testNames = fs.readdirSync(path.resolve(__dirname, './input/')) const testNames = fs.readdirSync(path.resolve(__dirname, './input/'))
.filter((f) => f.endsWith('.wxml')) .filter((f) => f.endsWith('.wxml'))
.map((filename: string) => filename.split('.')[0]); .map((filename: string) => filename.split('.')[0]);
describe('WXML export test execution', () => { describe('WXML export test execution', () => {
test.each(testNames) test.each(testNames)('Exporting %p suite', async (testName: string) => {
(`Exporting %p suite`, async (testName: string) => { // Load mindmap DOM ...
// Load mindmap DOM ... const mindmapPath = path.resolve(__dirname, `./input/${testName}.wxml`);
const mindmapPath = path.resolve(__dirname, `./input/${testName}.wxml`); const mapDocument = parseXMLFile(mindmapPath, 'text/xml');
const mapDocument = parseXMLFile(mindmapPath, 'text/xml');
// Convert to mindmap ... // Convert to mindmap ...
const serializer = XMLSerializerFactory.createInstanceFromDocument(mapDocument); const serializer = XMLSerializerFactory.createInstanceFromDocument(mapDocument);
const mindmap: Mindmap = serializer.loadFromDom(mapDocument, testName); const mindmap: Mindmap = serializer.loadFromDom(mapDocument, testName);
const exporter = TextExporterFactory.create('wxml', mindmap); const exporter = TextExporterFactory.create('wxml', mindmap);
await exporterAssert(testName, exporter); await exporterAssert(testName, exporter);
});
}); });
});
describe('Txt export test execution', () => { describe('Txt export test execution', () => {
test.each(testNames) test.each(testNames)('Exporting %p suite', async (testName: string) => {
(`Exporting %p suite`, async (testName: string) => { // Load mindmap DOM ...
// Load mindmap DOM ... const mindmapPath = path.resolve(__dirname, `./input/${testName}.wxml`);
const mindmapPath = path.resolve(__dirname, `./input/${testName}.wxml`); const mapDocument = parseXMLFile(mindmapPath, 'text/xml');
const mapDocument = parseXMLFile(mindmapPath, 'text/xml');
// Convert to mindmap ...
const serializer = XMLSerializerFactory.createInstanceFromDocument(mapDocument);
const mindmap: Mindmap = serializer.loadFromDom(mapDocument, testName);
const exporter = TextExporterFactory.create('txt', mindmap);
await exporterAssert(testName, exporter);
});
});
describe('MD export test execution', () => { // Convert to mindmap ...
test.each(testNames) const serializer = XMLSerializerFactory.createInstanceFromDocument(mapDocument);
(`Exporting %p suite`, async (testName: string) => { const mindmap: Mindmap = serializer.loadFromDom(mapDocument, testName);
// Load mindmap DOM ...
const mindmapPath = path.resolve(__dirname, `./input/${testName}.wxml`); const exporter = TextExporterFactory.create('txt', mindmap);
const mapDocument = parseXMLFile(mindmapPath, 'text/xml'); await exporterAssert(testName, exporter);
});
// Convert to mindmap ... });
const serializer = XMLSerializerFactory.createInstanceFromDocument(mapDocument);
const mindmap: Mindmap = serializer.loadFromDom(mapDocument, testName); describe('MD export test execution', () => {
test.each(testNames)('Exporting %p suite', async (testName: string) => {
const exporter = TextExporterFactory.create('md', mindmap); // Load mindmap DOM ...
await exporterAssert(testName, exporter); const mindmapPath = path.resolve(__dirname, `./input/${testName}.wxml`);
}); const mapDocument = parseXMLFile(mindmapPath, 'text/xml');
});
// Convert to mindmap ...
const serializer = XMLSerializerFactory.createInstanceFromDocument(mapDocument);
const mindmap: Mindmap = serializer.loadFromDom(mapDocument, testName);
const exporter = TextExporterFactory.create('md', mindmap);
await exporterAssert(testName, exporter);
});
});

View File

@ -1,5 +1,5 @@
const Constants = { const Constants = {
NODE_SIZE: { width: 80, height: 30 }, NODE_SIZE: { width: 80, height: 30 },
ROOT_NODE_SIZE: { width: 120, height: 40 } ROOT_NODE_SIZE: { width: 120, height: 40 },
} };
export default Constants; export default Constants;

View File

@ -2,8 +2,8 @@ const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin'); const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin'); const CopyPlugin = require('copy-webpack-plugin');
const common = require('./webpack.common');
const { merge } = require('webpack-merge'); const { merge } = require('webpack-merge');
const common = require('./webpack.common');
const playgroundConfig = { const playgroundConfig = {
mode: 'development', mode: 'development',

View File

@ -1,6 +1,6 @@
{ {
"name": "@wisemapping/webapp", "name": "@wisemapping/webapp",
"version": "0.4.9", "version": "5.0.1",
"main": "app.jsx", "main": "app.jsx",
"scripts": { "scripts": {
"start": "webpack serve --config webpack.dev.js ", "start": "webpack serve --config webpack.dev.js ",