Type INodeModel interface

This commit is contained in:
Paulo Gustavo Veiga 2022-01-03 07:12:12 -08:00
parent b1809816b0
commit 954ee444ca
7 changed files with 127 additions and 169 deletions

View File

@ -22,7 +22,7 @@ class FeatureModelFactory {
model: NoteModel,
}];
static createModel(type: string, attributes): FeatureModel {
static createModel(type: FeatureType, attributes): FeatureModel {
$assert(type, 'type can not be null');
$assert(attributes, 'attributes can not be null');

View File

@ -74,7 +74,7 @@ abstract class IMindmap {
abstract hasAlreadyAdded(node: INodeModel): boolean;
abstract createNode(type: NodeType, id: number):void;
abstract createNode(type: NodeType, id: number): INodeModel
abstract createRelationship(fromNode: NodeModel, toNode: NodeModel): void;

View File

@ -18,6 +18,7 @@
*/
import { $assert, $defined } from '@wisemapping/core-js';
import FeatureModel from './FeatureModel';
import IMindmap from './IMindmap';
import Mindmap from './Mindmap';
// regex taken from https://stackoverflow.com/a/34763398/58128
@ -37,7 +38,7 @@ abstract class INodeModel {
getId(): number {
return this.getProperty('id');
}
abstract getFeatures(): Array<FeatureModel>;
abstract getFeatures(): FeatureModel[];
/** */
setId(id: number): void {
@ -54,33 +55,26 @@ abstract class INodeModel {
}
getType(): NodeModelType {
return this.getProperty('type');
return this.getProperty('type') as NodeModelType;
}
/** */
setType(type: NodeModelType): void {
this.putProperty('type', type);
}
/** */
setText(text: string): void {
this.putProperty('text', text);
}
/** */
getText() {
getText(): string {
return this.getProperty('text');
}
/** */
setPosition(x, y) {
$assert(!Number.isNaN(parseInt(x, 10)), `x position is not valid:${x}`);
$assert(!Number.isNaN(parseInt(y, 10)), `y position is not valid:${y}`);
this.putProperty('position', `{x:${parseInt(x, 10)},y:${parseInt(y, 10)}}`);
setPosition(x: number, y: number): void {
this.putProperty('position', `{x:${x},y:${y}}`);
}
/** */
getPosition() {
getPosition(): { x: number, y: number } {
const value = this.getProperty('position');
let result = null;
if (value != null) {
@ -89,13 +83,11 @@ abstract class INodeModel {
return result;
}
/** */
setImageSize(width, height) {
setImageSize(width: number, height: number) {
this.putProperty('imageSize', `{width:${width},height:${height}}`);
}
/** */
getImageSize() {
getImageSize(): {width: number, height: number} {
const value = this.getProperty('imageSize');
let result = null;
if (value != null) {
@ -104,28 +96,23 @@ abstract class INodeModel {
return result;
}
/** */
setImageUrl(url) {
setImageUrl(url: string) {
this.putProperty('imageUrl', url);
}
/** */
getMetadata() {
getMetadata(): string {
return this.getProperty('metadata');
}
/** */
setMetadata(json) {
setMetadata(json: string): void {
this.putProperty('metadata', json);
}
/** */
getImageUrl() {
getImageUrl(): string {
return this.getProperty('imageUrl');
}
/** */
getMindmap() {
getMindmap(): IMindmap {
return this._mindmap;
}
@ -133,23 +120,22 @@ abstract class INodeModel {
* lets the mindmap handle the disconnect node operation
* @see mindplot.model.IMindmap.disconnect
*/
disconnect() {
disconnect(): void {
const mindmap = this.getMindmap();
mindmap.disconnect(this);
}
/** */
getShapeType() {
getShapeType(): string {
return this.getProperty('shapeType');
}
/** */
setShapeType(type) {
setShapeType(type: string) {
this.putProperty('shapeType', type);
}
/** */
setOrder(value) {
setOrder(value: number) {
$assert(
(typeof value === 'number' && Number.isFinite(value)) || value == null,
'Order must be null or a number',
@ -157,120 +143,98 @@ abstract class INodeModel {
this.putProperty('order', value);
}
/** */
getOrder() {
getOrder(): number {
return this.getProperty('order');
}
/** */
setFontFamily(fontFamily) {
setFontFamily(fontFamily: string): void {
this.putProperty('fontFamily', fontFamily);
}
/** */
getFontFamily() {
getFontFamily(): string {
return this.getProperty('fontFamily');
}
/** */
setFontStyle(fontStyle) {
setFontStyle(fontStyle: string) {
this.putProperty('fontStyle', fontStyle);
}
/** */
getFontStyle() {
getFontStyle(): string {
return this.getProperty('fontStyle');
}
/** */
setFontWeight(weight) {
this.putProperty('fontWeight', weight);
}
/** */
getFontWeight() {
return this.getProperty('fontWeight');
}
/** */
setFontColor(color) {
setFontColor(color: string) {
this.putProperty('fontColor', color);
}
/** */
getFontColor() {
getFontColor(): string {
return this.getProperty('fontColor');
}
/** */
setFontSize(size) {
setFontSize(size: number) {
this.putProperty('fontSize', size);
}
/** */
getFontSize() {
getFontSize(): number {
return this.getProperty('fontSize');
}
/** */
getBorderColor() {
getBorderColor(): string {
return this.getProperty('borderColor');
}
/** */
setBorderColor(color) {
setBorderColor(color: string): void {
this.putProperty('borderColor', color);
}
/** */
getBackgroundColor() {
getBackgroundColor(): string {
return this.getProperty('backgroundColor');
}
/** */
setBackgroundColor(color) {
setBackgroundColor(color: string) {
this.putProperty('backgroundColor', color);
}
/** */
areChildrenShrunken() {
areChildrenShrunken(): boolean {
const result = this.getProperty('shrunken');
return $defined(result) ? result : false;
}
/**
* @return {Boolean} true if the children nodes are hidden by the shrink option
*/
setChildrenShrunken(value) {
* @return {Boolean} true if the children nodes are hidden by the shrink option
*/
setChildrenShrunken(value: boolean) {
this.putProperty('shrunken', value);
}
/**
* @return {Boolean} true
*/
isNodeModel() {
isNodeModel(): boolean {
return true;
}
/**
* @return {Boolean} true if the node model has a parent assigned to it
*/
isConnected() {
* @return {Boolean} true if the node model has a parent assigned to it
*/
isConnected(): boolean {
return this.getParent() != null;
}
/** @abstract */
// eslint-disable-next-line no-unused-vars
append(node) {
throw new Error('Unsupported operation');
}
abstract append(node): void;
/**
* lets the mindmap handle the connect node operation
* @throws will throw an error if parent is null or undefined
* @see mindplot.model.IMindmap.connect
*/
connectTo(parent) {
connectTo(parent: INodeModel) {
$assert(parent, 'parent can not be null');
const mindmap = this.getMindmap();
mindmap.connect(parent, this);
@ -280,7 +244,7 @@ abstract class INodeModel {
* @param target
* @return target
*/
copyTo(target) {
copyTo(target: INodeModel): INodeModel {
const source = this;
// Copy properties ...
const keys = source.getPropertiesKeys();
@ -306,7 +270,7 @@ abstract class INodeModel {
* lets parent handle the delete node operation, or, if none defined, calls the mindmap to
* remove the respective branch
*/
deleteNode() {
deleteNode(): void {
const mindmap = this.getMindmap();
// console.log("Before:" + mindmap.inspect());
@ -323,7 +287,7 @@ abstract class INodeModel {
abstract getPropertiesKeys(): string[];
abstract getProperty(key: string);
abstract getProperty(key: string): any;
abstract putProperty(key: string, value: any): void;

View File

@ -19,14 +19,14 @@ import { $assert, $defined } from '@wisemapping/core-js';
import cloneDeep from 'lodash/cloneDeep';
import INodeModel, { NodeModelType } from './INodeModel';
import FeatureModelFactory from './FeatureModelFactory';
import FeatureModel from './FeatureModel';
import FeatureModel, { FeatureType } from './FeatureModel';
import Mindmap from './Mindmap';
class NodeModel extends INodeModel {
private _properties: {};
private _children: INodeModel[];
private _children: NodeModel[];
private _features: FeatureModel[];
private _parent: INodeModel;
private _parent: NodeModel;
constructor(type: NodeModelType, mindmap: Mindmap, id: number) {
$assert(type, 'Node type can not be null');
@ -46,7 +46,7 @@ class NodeModel extends INodeModel {
* @param attributes
* @return {mindplot.model.FeatureModel} the created feature model
*/
createFeature(type, attributes) {
createFeature(type: FeatureType, attributes: any): FeatureModel {
return FeatureModelFactory.createModel(type, attributes);
}
@ -54,12 +54,11 @@ class NodeModel extends INodeModel {
* @param feature
* @throws will throw an error if feature is null or undefined
*/
addFeature(feature) {
addFeature(feature: FeatureModel) {
$assert(feature, 'feature can not be null');
this._features.push(feature);
}
/** */
getFeatures() {
return this._features;
}
@ -69,7 +68,7 @@ class NodeModel extends INodeModel {
* @throws will throw an error if feature is null or undefined
* @throws will throw an error if the feature could not be removed
*/
removeFeature(feature) {
removeFeature(feature: FeatureModel) {
$assert(feature, 'feature can not be null');
const size = this._features.length;
this._features = this._features.filter((f) => feature.getId() !== f.getId());
@ -80,7 +79,7 @@ class NodeModel extends INodeModel {
* @param {String} type the feature type, e.g. icon or link
* @throws will throw an error if type is null or undefined
*/
findFeatureByType(type) {
findFeatureByType(type: string) {
$assert(type, 'type can not be null');
return this._features.filter((feature) => feature.getType() === type);
}
@ -91,7 +90,7 @@ class NodeModel extends INodeModel {
* @throws will throw an error if feature could not be found
* @return the feature with the given id
*/
findFeatureById(id) {
findFeatureById(id: number) {
$assert($defined(id), 'id can not be null');
const result = this._features.filter((feature) => feature.getId() === id);
$assert(result.length === 1, `Feature could not be found:${id}`);
@ -108,7 +107,7 @@ class NodeModel extends INodeModel {
* @param value
* @throws will throw an error if key is null or undefined
*/
putProperty(key, value) {
putProperty(key: string, value: string | number | boolean) {
$defined(key, 'key can not be null');
this._properties[key] = value;
}
@ -176,25 +175,22 @@ class NodeModel extends INodeModel {
* @param {mindplot.model.NodeModel} child
* @throws will throw an error if child is null, undefined or not a NodeModel object
*/
removeChild(child): void {
removeChild(child: NodeModel): void {
$assert(child && child.isNodeModel(), 'Only NodeModel can be appended to Mindmap object.');
this._children = this._children.filter((c) => c !== child);
// eslint-disable-next-line no-param-reassign
child._parent = null;
}
/** */
getChildren() {
getChildren(): NodeModel[] {
return this._children;
}
/** */
getParent() {
getParent(): NodeModel {
return this._parent;
}
/** */
setParent(parent) {
setParent(parent: NodeModel): void {
$assert(parent !== this, 'The same node can not be parent and child if itself.');
this._parent = parent;
}

View File

@ -19,11 +19,13 @@ import {
} from '@wisemapping/core-js';
import ModelCodeName from './ModelCodeName';
import Mindmap from '../model/Mindmap';
import INodeModel from '../model/INodeModel';
import FeatureModelFactory from '../model/FeatureModelFactory';
import NodeModel from '../model/NodeModel';
class XMLSerializerBeta {
toXML(mindmap) {
private static MAP_ROOT_NODE = 'map';
toXML(mindmap: Mindmap) {
$assert(mindmap, 'Can not save a null mindmap');
const document = createDocument();
@ -38,21 +40,20 @@ class XMLSerializerBeta {
// Create branches ...
const topics = mindmap.getBranches();
for (let i = 0; i < topics.length; i++) {
const topic = topics[i];
topics.forEach((topic) => {
const topicDom = this._topicToXML(document, topic);
mapElem.append(topicDom);
}
});
return document;
}
_topicToXML(document, topic) {
_topicToXML(document: Document, topic: NodeModel) {
const parentTopic = document.createElement('topic');
// Set topic attributes...
if (topic.getType() === 'CentralTopic') {
parentTopic.setAttribute('central', true);
parentTopic.setAttribute('central', new Boolean(true).toString());
} else {
const parent = topic.getParent();
if (parent == null || parent.getType() === 'CentralTopic') {
@ -60,7 +61,7 @@ class XMLSerializerBeta {
parentTopic.setAttribute('position', `${pos.x},${pos.y}`);
} else {
const order = topic.getOrder();
parentTopic.setAttribute('order', order);
parentTopic.setAttribute('order', order.toString());
}
}
@ -75,7 +76,7 @@ class XMLSerializerBeta {
}
if (topic.areChildrenShrunken()) {
parentTopic.setAttribute('shrink', true);
parentTopic.setAttribute('shrink', new Boolean(true).toString());
}
// Font properties ...
@ -117,36 +118,31 @@ class XMLSerializerBeta {
}
// ICONS
let i;
const icons = topic.getIcons();
for (i = 0; i < icons.length; i++) {
const icon = icons[i];
const icons = topic.findFeatureByType('icons');
icons.forEach((icon)=>{
const iconDom = this._iconToXML(document, icon);
parentTopic.append(iconDom);
}
});
// LINKS
const links = topic.getLinks();
for (i = 0; i < links.length; i++) {
const link = links[i];
const links = topic.findFeatureByType('links');
icons.forEach((link)=>{
const linkDom = this._linkToXML(document, link);
parentTopic.append(linkDom);
}
});
const notes = topic.getNotes();
for (i = 0; i < notes.length; i++) {
const note = notes[i];
const notes = topic.findFeatureByType('note');
notes.forEach((note)=>{
const noteDom = this._noteToXML(document, note);
parentTopic.append(noteDom);
}
});
// CHILDREN TOPICS
const childTopics = topic.getChildren();
for (i = 0; i < childTopics.length; i++) {
const childTopic = childTopics[i];
childTopics.forEach((childTopic)=>{
const childDom = this._topicToXML(document, childTopic);
parentTopic.append(childDom);
}
});
return parentTopic;
}
@ -288,13 +284,13 @@ class XMLSerializerBeta {
const childTopic = this._deserializeNode(child, mindmap);
childTopic.connectTo(topic);
} else if (child.tagName === 'icon') {
const icon = this._deserializeIcon(child, topic);
const icon = this._deserializeIcon(child);
topic.addFeature(icon);
} else if (child.tagName === 'link') {
const link = this._deserializeLink(child, topic);
const link = this._deserializeLink(child);
topic.addFeature(link);
} else if (child.tagName === 'note') {
const note = this._deserializeNote(child, topic);
const note = this._deserializeNote(child);
topic.addFeature(note);
}
}
@ -303,23 +299,21 @@ class XMLSerializerBeta {
return topic;
}
_deserializeIcon(domElem) {
_deserializeIcon(domElem: Element) {
let icon = domElem.getAttribute('id');
icon = icon.replace('images/', 'icons/legacy/');
return FeatureModelFactory.createModel(FeatureModelFactory.Icon.id, { id: icon });
return FeatureModelFactory.createModel('icon', { id: icon });
}
_deserializeLink(domElem) {
return FeatureModelFactory.createModel(FeatureModelFactory.Link.id, { url: domElem.getAttribute('url') });
_deserializeLink(domElem: Element) {
return FeatureModelFactory.createModel('link', { url: domElem.getAttribute('url') });
}
_deserializeNote(domElem) {
_deserializeNote(domElem: Element) {
const text = domElem.getAttribute('text');
return FeatureModelFactory.createModel(FeatureModelFactory.Note.id, { text: text == null ? ' ' : text });
return FeatureModelFactory.createModel('note', { text: text == null ? ' ' : text });
}
}
XMLSerializerBeta.MAP_ROOT_NODE = 'map';
// eslint-disable-next-line camelcase
export default XMLSerializerBeta;

View File

@ -18,12 +18,17 @@
import { $assert, $defined, createDocument } from '@wisemapping/core-js';
import { Point } from '@wisemapping/web2d';
import Mindmap from '../model/Mindmap';
import INodeModel, { TopicShape } from '../model/INodeModel';
import { TopicShape } from '../model/INodeModel';
import ConnectionLine from '../ConnectionLine';
import FeatureModelFactory from '../model/FeatureModelFactory';
import NodeModel from '../model/NodeModel';
import { FeatureType } from '../model/FeatureModel';
class XMLSerializerPela {
toXML(mindmap) {
private static MAP_ROOT_NODE = 'map';
private _idsMap: {};
toXML(mindmap: Mindmap) {
$assert(mindmap, 'Can not save a null mindmap');
const document = createDocument();
@ -64,7 +69,7 @@ class XMLSerializerPela {
return document;
}
_topicToXML(document, topic) {
_topicToXML(document: Document, topic: NodeModel) {
const parentTopic = document.createElement('topic');
// Set topic attributes...
@ -75,7 +80,7 @@ class XMLSerializerPela {
parentTopic.setAttribute('position', `${pos.x},${pos.y}`);
const order = topic.getOrder();
if (typeof order === 'number' && Number.isFinite(order)) { parentTopic.setAttribute('order', order); }
if (typeof order === 'number' && Number.isFinite(order)) { parentTopic.setAttribute('order', order.toString()); }
}
const text = topic.getText();
@ -88,9 +93,10 @@ class XMLSerializerPela {
parentTopic.setAttribute('shape', shape);
if (shape === TopicShape.IMAGE) {
const size = topic.getImageSize();
parentTopic.setAttribute(
'image',
`${topic.getImageSize().width},${topic.getImageSize().height
`${size.width},${size.height
}:${topic.getImageUrl()}`,
);
}
@ -102,7 +108,7 @@ class XMLSerializerPela {
// Font properties ...
const id = topic.getId();
parentTopic.setAttribute('id', id);
parentTopic.setAttribute('id', id.toString());
let font = '';
@ -243,14 +249,18 @@ class XMLSerializerPela {
// Add all the topics nodes ...
const childNodes = Array.from(rootElem.childNodes);
const topicsNodes = childNodes.filter((child) => (child.nodeType === 1 && child.tagName === 'topic'));
const topicsNodes = childNodes.
filter((child: ChildNode) => (child.nodeType === 1 && (child as Element).tagName === 'topic'))
.map((c) => c as Element);
topicsNodes.forEach((child) => {
const topic = this._deserializeNode(child, mindmap);
mindmap.addBranch(topic);
});
// Then all relationshops, they are connected to topics ...
const relationshipsNodes = childNodes.filter((child) => (child.nodeType === 1 && child.tagName === 'relationship'));
const relationshipsNodes = childNodes.
filter((child: ChildNode) => (child.nodeType === 1 && (child as Element).tagName === 'relationship'))
.map((c) => c as Element);
relationshipsNodes.forEach((child) => {
try {
const relationship = XMLSerializerPela._deserializeRelationship(child, mindmap);
@ -266,15 +276,15 @@ class XMLSerializerPela {
return mindmap;
}
_deserializeNode(domElem, mindmap) {
_deserializeNode(domElem: Element, mindmap: Mindmap) {
const type = domElem.getAttribute('central') != null
? 'CentralTopic'
: 'MainTopic';
// Load attributes...
let id = domElem.getAttribute('id');
if ($defined(id)) {
id = parseInt(id, 10);
let id = null;
if ($defined(domElem.getAttribute('id'))) {
id = Number.parseInt(domElem.getAttribute('id'), 10);
}
if (this._idsMap[id]) {
@ -300,7 +310,7 @@ class XMLSerializerPela {
}
if (font[1]) {
topic.setFontSize(font[1]);
topic.setFontSize(Number.parseInt(font[1], 10));
}
if (font[2]) {
@ -327,7 +337,7 @@ class XMLSerializerPela {
topic.setImageUrl(url);
const split = size.split(',');
topic.setImageSize(split[0], split[1]);
topic.setImageSize(Number.parseInt(split[0], 10), Number.parseInt(split[1], 10));
}
}
@ -350,13 +360,13 @@ class XMLSerializerPela {
const isShrink = domElem.getAttribute('shrink');
// Hack: Some production maps has been stored with the central topic collapsed. This is a bug.
if ($defined(isShrink) && type !== 'CentralTopic') {
topic.setChildrenShrunken(isShrink);
topic.setChildrenShrunken(Boolean(isShrink));
}
const position = domElem.getAttribute('position');
if ($defined(position)) {
const pos = position.split(',');
topic.setPosition(pos[0], pos[1]);
topic.setPosition(Number.parseInt(pos[0]), Number.parseInt(pos[1]));
}
const metadata = domElem.getAttribute('metadata');
@ -368,29 +378,31 @@ class XMLSerializerPela {
const children = Array.from(domElem.childNodes);
children.forEach((child) => {
if (child.nodeType === Node.ELEMENT_NODE) {
if (child.tagName === 'topic') {
const childTopic = this._deserializeNode(child, mindmap);
const elem = child as Element;
if (elem.tagName === 'topic') {
const childTopic = this._deserializeNode(elem, mindmap);
childTopic.connectTo(topic);
} else if (FeatureModelFactory.isSupported(child.tagName)) {
} else if (FeatureModelFactory.isSupported(elem.tagName)) {
// Load attributes ...
const namedNodeMap = child.attributes;
const namedNodeMap = elem.attributes;
const attributes = {};
for (let j = 0; j < namedNodeMap.length; j++) {
const attribute = namedNodeMap.item(j);
attributes[attribute.name] = attribute.value;
}
// Has text node ?.
const textAttr = XMLSerializerPela._deserializeTextAttr(child);
const textAttr = XMLSerializerPela._deserializeTextAttr(elem);
if (textAttr) {
attributes.text = textAttr;
attributes['text'] = textAttr;
}
// Create a new element ....
const featureType = child.tagName;
const featureType = elem.tagName as FeatureType;
const feature = FeatureModelFactory.createModel(featureType, attributes);
topic.addFeature(feature);
} else if (child.tagName === 'text') {
} else if (elem.tagName === 'text') {
const nodeText = XMLSerializerPela._deserializeNodeText(child);
topic.setText(nodeText);
}
@ -400,7 +412,7 @@ class XMLSerializerPela {
return topic;
}
static _deserializeTextAttr(domElem) {
static _deserializeTextAttr(domElem: Element): string {
let value = domElem.getAttribute('text');
if (!$defined(value)) {
const children = domElem.childNodes;
@ -497,13 +509,5 @@ class XMLSerializerPela {
}
}
/**
* a wisemap's root element tag name
* @constant
* @type {String}
* @default
*/
XMLSerializerPela.MAP_ROOT_NODE = 'map';
// eslint-disable-next-line camelcase
export default XMLSerializerPela;