wisemapping-frontend/packages/mindplot/src/components/Topic.ts

1358 lines
36 KiB
TypeScript
Raw Normal View History

2021-07-16 16:41:58 +02:00
/*
2021-12-25 23:39:34 +01:00
* Copyright [2021] [wisemapping]
2021-07-16 16:41:58 +02:00
*
* 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.
*/
2021-12-05 18:25:16 +01:00
import $ from 'jquery';
2022-01-26 20:25:11 +01:00
import { $assert, $defined } from '@wisemapping/core-js';
2022-02-06 06:28:35 +01:00
import {
2022-02-10 04:26:44 +01:00
Rect, Image, Line, Text, Group, ElementClass, Point,
} from '@wisemapping/web2d';
import NodeGraph from './NodeGraph';
import TopicConfig from './TopicConfig';
import TopicStyle from './TopicStyle';
import TopicFeatureFactory from './TopicFeature';
import ConnectionLine from './ConnectionLine';
import IconGroup from './IconGroup';
import FadeEffect from './util/FadeEffect';
import EventBus from './layout/EventBus';
import ShirinkConnector from './ShrinkConnector';
import NoteEditor from './widget/NoteEditor';
import ActionDispatcher from './ActionDispatcher';
import LinkEditor from './widget/LinkEditor';
2021-12-14 16:08:54 +01:00
2022-01-26 20:25:11 +01:00
import TopicEventDispatcher, { TopicEvent } from './TopicEventDispatcher';
import { TopicShape } from './model/INodeModel';
2022-02-06 06:28:35 +01:00
import NodeModel from './model/NodeModel';
import Relationship from './Relationship';
import Workspace from './Workspace';
import LayoutManager from './layout/LayoutManager';
import NoteModel from './model/NoteModel';
import LinkModel from './model/LinkModel';
import SizeType from './SizeType';
import FeatureModel from './model/FeatureModel';
import Icon from './Icon';
2021-12-27 20:42:32 +01:00
2021-12-28 23:12:38 +01:00
const ICON_SCALING_FACTOR = 1.3;
2021-07-16 16:41:58 +02:00
2022-02-06 06:28:35 +01:00
abstract class Topic extends NodeGraph {
private _innerShape: ElementClass;
2022-02-10 04:26:44 +01:00
2022-02-06 06:28:35 +01:00
private _relationships: Relationship[];
2022-02-10 04:26:44 +01:00
2022-02-06 06:28:35 +01:00
private _isInWorkspace: boolean;
2022-02-10 04:26:44 +01:00
// eslint-disable-next-line no-use-before-define
2022-02-06 06:28:35 +01:00
private _children: Topic[];
2022-02-10 04:26:44 +01:00
// eslint-disable-next-line no-use-before-define
2022-02-06 06:28:35 +01:00
private _parent: Topic | null;
2022-02-10 04:26:44 +01:00
2022-02-06 06:28:35 +01:00
private _outerShape: ElementClass;
2022-02-10 04:26:44 +01:00
2022-02-06 06:28:35 +01:00
private _text: Text | null;
2022-02-10 04:26:44 +01:00
2022-02-06 06:28:35 +01:00
private _iconsGroup: IconGroup;
2022-02-10 04:26:44 +01:00
private _connector: ShirinkConnector;
2022-02-06 06:28:35 +01:00
private _outgoingLine: Line;
constructor(model: NodeModel, options) {
2021-12-05 00:39:20 +01:00
super(model, options);
this._children = [];
this._parent = null;
this._relationships = [];
this._isInWorkspace = false;
this._buildTopicShape();
// Position a topic ....
const pos = model.getPosition();
if (pos != null && this.isCentralTopic()) {
this.setPosition(pos);
}
// Register events for the topic ...
if (!this.isReadOnly()) {
this._registerEvents();
}
}
2022-02-06 06:28:35 +01:00
protected _registerEvents(): void {
2021-12-05 00:39:20 +01:00
this.setMouseEventsEnabled(true);
// Prevent click on the topics being propagated ...
2022-02-06 06:28:35 +01:00
this.addEvent('click', (event: Event) => {
2021-12-05 00:39:20 +01:00
event.stopPropagation();
});
const me = this;
2022-02-06 06:28:35 +01:00
this.addEvent('dblclick', (event: Event) => {
2021-12-05 00:39:20 +01:00
me._getTopicEventDispatcher().show(me);
event.stopPropagation();
});
}
2022-02-12 08:38:20 +01:00
setShapeType(type: string): void {
2021-12-05 00:39:20 +01:00
this._setShapeType(type, true);
}
2022-02-06 06:28:35 +01:00
getParent(): Topic | null {
2021-12-05 00:39:20 +01:00
return this._parent;
}
2022-02-06 06:28:35 +01:00
protected _setShapeType(type: string, updateModel: boolean) {
2021-12-05 00:39:20 +01:00
// Remove inner shape figure ...
const model = this.getModel();
if ($defined(updateModel) && updateModel) {
model.setShapeType(type);
}
// If shape is line, reset background color to default.
if (type === TopicShape.LINE) {
const color = TopicStyle.defaultBackgroundColor(this);
this.setBackgroundColor(color);
}
2021-12-05 00:39:20 +01:00
const oldInnerShape = this.getInnerShape();
if (oldInnerShape != null) {
this._removeInnerShape();
// Create a new one ...
2021-10-05 02:05:34 +02:00
const innerShape = this.getInnerShape();
2021-12-05 00:39:20 +01:00
// Update figure size ...
const size = this.getSize();
this.setSize(size, true);
2021-10-05 02:05:34 +02:00
2021-12-05 00:39:20 +01:00
const group = this.get2DElement();
group.append(innerShape);
2021-10-05 02:05:34 +02:00
2021-12-05 00:39:20 +01:00
// Move text to the front ...
const text = this.getTextShape();
text.moveToFront();
2021-10-05 02:05:34 +02:00
2021-12-05 00:39:20 +01:00
// Move iconGroup to front ...
const iconGroup = this.getIconGroup();
if ($defined(iconGroup)) {
iconGroup.moveToFront();
2021-10-05 02:05:34 +02:00
}
2021-12-05 00:39:20 +01:00
// Move connector to front
const connector = this.getShrinkConnector();
if ($defined(connector)) {
connector.moveToFront();
2021-10-05 02:05:34 +02:00
}
2021-12-05 00:39:20 +01:00
}
}
2022-02-12 08:38:20 +01:00
getShapeType(): string {
2021-12-05 00:39:20 +01:00
const model = this.getModel();
let result = model.getShapeType();
if (!$defined(result)) {
result = TopicStyle.defaultShapeType(this);
}
return result;
}
private _removeInnerShape(): ElementClass {
2021-12-05 00:39:20 +01:00
const group = this.get2DElement();
const innerShape = this.getInnerShape();
group.removeChild(innerShape);
this._innerShape = null;
return innerShape;
}
2022-02-06 06:28:35 +01:00
getInnerShape(): ElementClass {
2021-12-05 00:39:20 +01:00
if (!$defined(this._innerShape)) {
// Create inner box.
this._innerShape = this._buildShape(
TopicConfig.INNER_RECT_ATTRIBUTES,
this.getShapeType(),
);
2021-10-05 02:05:34 +02:00
2021-12-05 00:39:20 +01:00
// Update bgcolor ...
const bgColor = this.getBackgroundColor();
this._setBackgroundColor(bgColor, false);
2021-10-05 02:05:34 +02:00
2021-12-05 00:39:20 +01:00
// Update border color ...
const brColor = this.getBorderColor();
this._setBorderColor(brColor, false);
2021-10-05 02:05:34 +02:00
2021-12-05 00:39:20 +01:00
// Define the pointer ...
if (!this.isCentralTopic() && !this.isReadOnly()) {
this._innerShape.setCursor('move');
} else {
this._innerShape.setCursor('default');
2021-10-05 02:05:34 +02:00
}
2021-12-05 00:39:20 +01:00
}
return this._innerShape;
}
2021-10-05 02:05:34 +02:00
2022-02-06 06:28:35 +01:00
_buildShape(attributes, shapeType: string) {
2021-12-05 00:39:20 +01:00
$assert(attributes, 'attributes can not be null');
$assert(shapeType, 'shapeType can not be null');
2021-10-05 02:05:34 +02:00
2021-12-05 00:39:20 +01:00
let result;
if (shapeType === TopicShape.RECTANGLE) {
2021-12-19 17:31:29 +01:00
result = new Rect(0, attributes);
2021-12-05 00:39:20 +01:00
} else if (shapeType === TopicShape.IMAGE) {
2021-10-05 02:05:34 +02:00
const model = this.getModel();
2021-12-05 00:39:20 +01:00
const url = model.getImageUrl();
const size = model.getImageSize();
2021-10-05 02:05:34 +02:00
2021-12-19 17:31:29 +01:00
result = new Image();
2021-12-05 00:39:20 +01:00
result.setHref(url);
result.setSize(size.width, size.height);
2021-10-05 02:05:34 +02:00
2021-12-15 03:28:15 +01:00
result.getSize = function getSize() {
2021-12-05 00:39:20 +01:00
return model.getImageSize();
};
2021-10-05 02:05:34 +02:00
2022-01-24 20:24:16 +01:00
result.setPosition = function setPosition() {
// Ignore ...
};
2021-12-05 00:39:20 +01:00
} else if (shapeType === TopicShape.ELLIPSE) {
2021-12-19 17:31:29 +01:00
result = new Rect(0.9, attributes);
2021-12-05 00:39:20 +01:00
} else if (shapeType === TopicShape.ROUNDED_RECT) {
2021-12-19 17:31:29 +01:00
result = new Rect(0.3, attributes);
2021-12-05 00:39:20 +01:00
} else if (shapeType === TopicShape.LINE) {
2021-12-27 20:42:32 +01:00
result = new Line({
strokeColor: '#495879',
strokeWidth: 1,
});
2022-02-06 06:28:35 +01:00
result.setSize = function setSize(width: number, height: number) {
2021-12-27 20:42:32 +01:00
this.size = {
width,
height,
};
2021-12-05 00:39:20 +01:00
result.setFrom(0, height);
result.setTo(width, height);
// Lines will have the same color of the default connection lines...
const stokeColor = ConnectionLine.getStrokeColor();
result.setStroke(1, 'solid', stokeColor);
};
2021-10-05 02:05:34 +02:00
2022-02-10 04:26:44 +01:00
result.getSize = function getSize() { return this.size; };
2022-01-24 20:24:16 +01:00
result.setPosition = () => {
// Overwrite behaviour ...
2021-12-05 00:39:20 +01:00
};
2021-10-05 02:05:34 +02:00
2022-01-24 20:24:16 +01:00
result.setFill = () => {
// Overwrite behaviour ...
};
result.setStroke = () => {
// Overwrite behaviour ...
};
2021-12-05 00:39:20 +01:00
} else {
$assert(false, `Unsupported figure shapeType:${shapeType}`);
}
result.setPosition(0, 0);
return result;
}
2021-10-05 02:05:34 +02:00
2022-02-06 06:28:35 +01:00
setCursor(type: string) {
2021-12-05 00:39:20 +01:00
const innerShape = this.getInnerShape();
innerShape.setCursor(type);
2021-10-05 02:05:34 +02:00
2021-12-05 00:39:20 +01:00
const outerShape = this.getOuterShape();
outerShape.setCursor(type);
2021-10-05 02:05:34 +02:00
2021-12-05 00:39:20 +01:00
const textShape = this.getTextShape();
textShape.setCursor(type);
}
2021-10-05 02:05:34 +02:00
2022-02-06 06:28:35 +01:00
getOuterShape(): ElementClass {
2021-12-05 00:39:20 +01:00
if (!$defined(this._outerShape)) {
const rect = this._buildShape(
TopicConfig.OUTER_SHAPE_ATTRIBUTES,
TopicShape.ROUNDED_RECT,
);
rect.setPosition(-2, -3);
rect.setOpacity(0);
this._outerShape = rect;
}
return this._outerShape;
}
2022-02-06 06:28:35 +01:00
getTextShape(): Text {
2021-12-05 00:39:20 +01:00
if (!$defined(this._text)) {
this._text = this._buildTextShape(false);
// Set Text ...
const text = this.getText();
this._setText(text, false);
}
return this._text;
}
getOrBuildIconGroup(): Group {
2021-12-05 00:39:20 +01:00
if (!$defined(this._iconsGroup)) {
this._iconsGroup = this._buildIconGroup();
const group = this.get2DElement();
group.append(this._iconsGroup.getNativeElement());
this._iconsGroup.moveToFront();
}
return this._iconsGroup;
}
/** */
2022-02-06 06:28:35 +01:00
getIconGroup(): IconGroup {
2021-12-05 00:39:20 +01:00
return this._iconsGroup;
}
2022-02-06 06:28:35 +01:00
private _buildIconGroup(): Group {
2021-12-05 00:39:20 +01:00
const textHeight = this.getTextShape().getFontHeight();
2021-12-27 20:42:32 +01:00
const iconSize = textHeight * ICON_SCALING_FACTOR;
const result = new IconGroup(this.getId(), iconSize);
2021-12-05 00:39:20 +01:00
const padding = TopicStyle.getInnerPadding(this);
result.setPosition(padding, padding);
// Load topic features ...
const model = this.getModel();
const featuresModel = model.getFeatures();
2021-12-27 20:42:32 +01:00
featuresModel.forEach((f) => {
const icon = TopicFeatureFactory.createIcon(this, f, this.isReadOnly());
result.addIcon(icon, f.getType() === TopicFeatureFactory.Icon.id && !this.isReadOnly());
2021-12-27 20:42:32 +01:00
});
2021-12-05 00:39:20 +01:00
return result;
}
/**
2022-01-26 20:25:11 +01:00
* assigns the new feature model to the topic's node model and adds the respective icon
* @param {mindplot.model.FeatureModel} featureModel
* @return {mindplot.Icon} the icon corresponding to the feature model
*/
addFeature(featureModel: FeatureModel): Icon {
2021-12-05 00:39:20 +01:00
const iconGroup = this.getOrBuildIconGroup();
this.closeEditors();
// Update model ...
const model = this.getModel();
model.addFeature(featureModel);
const result = TopicFeatureFactory.createIcon(this, featureModel, this.isReadOnly());
2021-12-05 00:39:20 +01:00
iconGroup.addIcon(
result,
featureModel.getType() === TopicFeatureFactory.Icon.id && !this.isReadOnly(),
2021-12-05 00:39:20 +01:00
);
2022-02-06 06:28:35 +01:00
this.adjustShapes();
2021-12-05 00:39:20 +01:00
return result;
}
/** */
findFeatureById(id: number) {
2021-12-05 00:39:20 +01:00
const model = this.getModel();
return model.findFeatureById(id);
}
/** */
removeFeature(featureModel: FeatureModel): void {
2021-12-05 00:39:20 +01:00
$assert(featureModel, 'featureModel could not be null');
// Removing the icon from MODEL
const model = this.getModel();
model.removeFeature(featureModel);
// Removing the icon from UI
const iconGroup = this.getIconGroup();
if ($defined(iconGroup)) {
iconGroup.removeIconByModel(featureModel);
}
2022-02-06 06:28:35 +01:00
this.adjustShapes();
2021-12-05 00:39:20 +01:00
}
/** */
addRelationship(relationship: Relationship) {
2021-12-05 00:39:20 +01:00
this._relationships.push(relationship);
}
/** */
deleteRelationship(relationship: Rect) {
2021-12-14 18:06:09 +01:00
this._relationships = this._relationships.filter((r) => r !== relationship);
2021-12-05 00:39:20 +01:00
}
/** */
getRelationships(): Relationship[] {
2021-12-05 00:39:20 +01:00
return this._relationships;
}
protected _buildTextShape(readOnly: boolean): Text {
2021-12-19 17:31:29 +01:00
const result = new Text();
2021-12-05 00:39:20 +01:00
const family = this.getFontFamily();
const size = this.getFontSize();
const weight = this.getFontWeight();
const style = this.getFontStyle();
result.setFont(family, size, style, weight);
const color = this.getFontColor();
result.setColor(color);
if (!readOnly) {
// Propagate mouse events ...
if (!this.isCentralTopic()) {
result.setCursor('move');
} else {
result.setCursor('default');
2021-10-05 02:05:34 +02:00
}
2021-12-05 00:39:20 +01:00
}
2021-10-05 02:05:34 +02:00
2021-12-05 00:39:20 +01:00
return result;
}
2021-10-05 02:05:34 +02:00
2021-12-05 00:39:20 +01:00
/** */
setFontFamily(value: string, updateModel?: boolean) {
2021-12-05 00:39:20 +01:00
const textShape = this.getTextShape();
textShape.setFontName(value);
2021-12-05 00:39:20 +01:00
if ($defined(updateModel) && updateModel) {
2021-10-05 02:05:34 +02:00
const model = this.getModel();
2021-12-05 00:39:20 +01:00
model.setFontFamily(value);
}
2022-02-06 06:28:35 +01:00
this.adjustShapes();
2021-12-05 00:39:20 +01:00
}
2021-10-05 02:05:34 +02:00
2021-12-05 00:39:20 +01:00
/** */
setFontSize(value: number, updateModel?: boolean) {
2021-12-05 00:39:20 +01:00
const textShape = this.getTextShape();
textShape.setSize(value);
2021-10-05 02:05:34 +02:00
2021-12-05 00:39:20 +01:00
if ($defined(updateModel) && updateModel) {
2021-10-05 02:05:34 +02:00
const model = this.getModel();
2021-12-05 00:39:20 +01:00
model.setFontSize(value);
}
2022-02-06 06:28:35 +01:00
this.adjustShapes();
2021-12-05 00:39:20 +01:00
}
/** */
setFontStyle(value, updateModel) {
const textShape = this.getTextShape();
textShape.setStyle(value);
if ($defined(updateModel) && updateModel) {
2021-10-05 02:05:34 +02:00
const model = this.getModel();
2021-12-05 00:39:20 +01:00
model.setFontStyle(value);
}
2022-02-06 06:28:35 +01:00
this.adjustShapes();
2021-12-05 00:39:20 +01:00
}
/** */
setFontWeight(value, updateModel) {
const textShape = this.getTextShape();
textShape.setWeight(value);
if ($defined(updateModel) && updateModel) {
2021-10-05 02:05:34 +02:00
const model = this.getModel();
2021-12-05 00:39:20 +01:00
model.setFontWeight(value);
}
2022-02-06 06:28:35 +01:00
this.adjustShapes();
2021-12-05 00:39:20 +01:00
}
/** */
getFontWeight() {
const model = this.getModel();
let result = model.getFontWeight();
if (!$defined(result)) {
const font = TopicStyle.defaultFontStyle(this);
result = font.weight;
}
return result;
}
/** */
getFontFamily() {
const model = this.getModel();
let result = model.getFontFamily();
if (!$defined(result)) {
const font = TopicStyle.defaultFontStyle(this);
result = font.font;
}
return result;
}
/** */
getFontColor() {
const model = this.getModel();
let result = model.getFontColor();
if (!$defined(result)) {
const font = TopicStyle.defaultFontStyle(this);
result = font.color;
}
return result;
}
/** */
getFontStyle() {
const model = this.getModel();
let result = model.getFontStyle();
if (!$defined(result)) {
const font = TopicStyle.defaultFontStyle(this);
result = font.style;
}
return result;
}
/** */
getFontSize() {
const model = this.getModel();
let result = model.getFontSize();
if (!$defined(result)) {
const font = TopicStyle.defaultFontStyle(this);
result = font.size;
}
return result;
}
/** */
setFontColor(value, updateModel) {
const textShape = this.getTextShape();
textShape.setColor(value);
if ($defined(updateModel) && updateModel) {
2021-10-05 02:05:34 +02:00
const model = this.getModel();
2021-12-05 00:39:20 +01:00
model.setFontColor(value);
}
}
2021-10-05 02:05:34 +02:00
2021-12-05 00:39:20 +01:00
_setText(text, updateModel) {
const textShape = this.getTextShape();
textShape.setText(text == null ? TopicStyle.defaultText(this) : text);
2021-10-05 02:05:34 +02:00
2021-12-05 00:39:20 +01:00
if ($defined(updateModel) && updateModel) {
2021-10-05 02:05:34 +02:00
const model = this.getModel();
2021-12-05 00:39:20 +01:00
model.setText(text);
}
}
/** */
setText(text) {
// Avoid empty nodes ...
if (!text || $.trim(text).length === 0) {
this._setText(null, true);
} else {
this._setText(text, true);
2021-12-05 00:39:20 +01:00
}
2022-02-06 06:28:35 +01:00
this.adjustShapes();
2021-12-05 00:39:20 +01:00
}
/** */
getText() {
const model = this.getModel();
let result = model.getText();
if (!$defined(result)) {
result = TopicStyle.defaultText(this);
}
return result;
}
/** */
setBackgroundColor(color) {
this._setBackgroundColor(color, true);
}
_setBackgroundColor(color, updateModel) {
const innerShape = this.getInnerShape();
innerShape.setFill(color);
const connector = this.getShrinkConnector();
if (connector) {
connector.setFill(color);
}
if ($defined(updateModel) && updateModel) {
2021-10-05 02:05:34 +02:00
const model = this.getModel();
2021-12-05 00:39:20 +01:00
model.setBackgroundColor(color);
}
}
/** */
getBackgroundColor() {
const model = this.getModel();
let result = model.getBackgroundColor();
if (!$defined(result)) {
result = TopicStyle.defaultBackgroundColor(this);
}
return result;
}
/** */
setBorderColor(color) {
this._setBorderColor(color, true);
}
_setBorderColor(color, updateModel) {
const innerShape = this.getInnerShape();
innerShape.setAttribute('strokeColor', color);
const connector = this.getShrinkConnector();
if (connector) {
connector.setAttribute('strokeColor', color);
}
if ($defined(updateModel) && updateModel) {
2021-10-05 02:05:34 +02:00
const model = this.getModel();
2021-12-05 00:39:20 +01:00
model.setBorderColor(color);
}
}
/** */
getBorderColor() {
const model = this.getModel();
let result = model.getBorderColor();
if (!$defined(result)) {
result = TopicStyle.defaultBorderColor(this);
}
return result;
}
_buildTopicShape() {
const groupAttributes = {
width: 100,
height: 100,
coordSizeWidth: 100,
coordSizeHeight: 100,
};
2021-12-19 17:31:29 +01:00
const group = new Group(groupAttributes);
2021-12-05 00:39:20 +01:00
this._set2DElement(group);
// Shape must be build based on the model width ...
const outerShape = this.getOuterShape();
const innerShape = this.getInnerShape();
const textShape = this.getTextShape();
// Add to the group ...
group.append(outerShape);
group.append(innerShape);
group.append(textShape);
// Update figure size ...
const model = this.getModel();
if (model.getFeatures().length !== 0) {
this.getOrBuildIconGroup();
}
const shrinkConnector = this.getShrinkConnector();
if ($defined(shrinkConnector)) {
shrinkConnector.addToWorkspace(group);
}
// Register listeners ...
this._registerDefaultListenersToElement(group, this);
2022-01-26 20:25:11 +01:00
// Set test id
group.setTestId(model.getId());
2021-12-05 00:39:20 +01:00
}
_registerDefaultListenersToElement(elem, topic) {
2021-12-15 03:28:15 +01:00
const mouseOver = function mouseOver(event) {
2021-12-05 00:39:20 +01:00
if (topic.isMouseEventsEnabled()) {
topic.handleMouseOver(event);
}
};
elem.addEvent('mouseover', mouseOver);
2021-12-15 03:28:15 +01:00
const outout = function outout(event) {
2021-12-05 00:39:20 +01:00
if (topic.isMouseEventsEnabled()) {
topic.handleMouseOut(event);
}
};
elem.addEvent('mouseout', outout);
const me = this;
// Focus events ...
elem.addEvent('mousedown', (event) => {
2021-12-23 18:56:36 +01:00
const isMac = window.navigator.platform.toUpperCase().indexOf('MAC') >= 0;
2021-12-05 00:39:20 +01:00
if (!me.isReadOnly()) {
// Disable topic selection of readOnly mode ...
let value = true;
2021-12-23 18:56:36 +01:00
if ((event.metaKey && isMac) || (event.ctrlKey && !isMac)) {
2021-12-05 00:39:20 +01:00
value = !me.isOnFocus();
event.stopPropagation();
event.preventDefault();
2021-10-05 02:05:34 +02:00
}
2021-12-05 00:39:20 +01:00
topic.setOnFocus(value);
}
const eventDispatcher = me._getTopicEventDispatcher();
eventDispatcher.process(TopicEvent.CLICK, me);
event.stopPropagation();
});
}
/** */
areChildrenShrunken() {
const model = this.getModel();
return model.areChildrenShrunken() && !this.isCentralTopic();
}
/** */
isCollapsed() {
let result = false;
let current = this.getParent();
while (current && !result) {
result = current.areChildrenShrunken();
current = current.getParent();
}
return result;
}
/** */
setChildrenShrunken(value) {
// Update Model ...
const model = this.getModel();
model.setChildrenShrunken(value);
// Change render base on the state.
const shrinkConnector = this.getShrinkConnector();
if ($defined(shrinkConnector)) {
shrinkConnector.changeRender(value);
}
// Do some fancy animation ....
const elements = this._flatten2DElements(this);
const fade = new FadeEffect(elements, !value);
const me = this;
fade.addEvent('complete', () => {
// Set focus on the parent node ...
if (value) {
me.setOnFocus(true);
}
// Set focus in false for all the children ...
elements.forEach((elem) => {
if (elem.setOnFocus) {
elem.setOnFocus(false);
2021-10-05 02:05:34 +02:00
}
});
2021-12-05 00:39:20 +01:00
});
fade.start();
EventBus.instance.fireEvent(EventBus.events.NodeShrinkEvent, model);
}
/** */
2022-02-06 06:28:35 +01:00
getShrinkConnector(): ShirinkConnector {
2021-12-05 00:39:20 +01:00
let result = this._connector;
if (this._connector == null) {
this._connector = new ShirinkConnector(this);
this._connector.setVisibility(false);
result = this._connector;
}
return result;
}
2022-02-06 06:28:35 +01:00
handleMouseOver(): void {
2021-12-05 00:39:20 +01:00
const outerShape = this.getOuterShape();
outerShape.setOpacity(1);
}
2022-02-06 06:28:35 +01:00
handleMouseOut(): void {
2021-12-05 00:39:20 +01:00
const outerShape = this.getOuterShape();
if (!this.isOnFocus()) {
outerShape.setOpacity(0);
}
}
2022-02-06 06:28:35 +01:00
showTextEditor(text: string) {
2021-12-27 20:42:32 +01:00
this._getTopicEventDispatcher().show(this, {
text,
});
2021-12-05 00:39:20 +01:00
}
2022-02-06 06:28:35 +01:00
showNoteEditor(): void {
2021-12-05 00:39:20 +01:00
const topicId = this.getId();
const model = this.getModel();
const editorModel = {
2022-02-06 06:28:35 +01:00
getValue(): string {
const notes = model.findFeatureByType(TopicFeatureFactory.Note.id);
2021-12-05 00:39:20 +01:00
let result;
2022-02-06 06:28:35 +01:00
if (notes.length > 0) {
result = (notes[0] as NoteModel).getText();
}
2021-12-05 00:39:20 +01:00
return result;
},
2022-02-06 06:28:35 +01:00
setValue(value: string) {
2021-12-05 00:39:20 +01:00
const dispatcher = ActionDispatcher.getInstance();
const notes = model.findFeatureByType(TopicFeatureFactory.Note.id);
2021-12-05 00:39:20 +01:00
if (!$defined(value)) {
const featureId = notes[0].getId();
dispatcher.removeFeatureFromTopic(topicId, featureId);
} else if (notes.length > 0) {
dispatcher.changeFeatureToTopic(topicId, notes[0].getId(), {
text: value,
});
} else {
dispatcher.addFeatureToTopic(topicId, TopicFeatureFactory.Note.id, {
2021-12-05 00:39:20 +01:00
text: value,
});
2021-10-05 02:05:34 +02:00
}
2021-12-14 16:08:54 +01:00
},
2021-12-05 00:39:20 +01:00
};
const editor = new NoteEditor(editorModel);
this.closeEditors();
editor.show();
}
/** opens a dialog where the user can enter or edit an existing link associated with this topic */
showLinkEditor() {
const topicId = this.getId();
const model = this.getModel();
const editorModel = {
2022-02-06 06:28:35 +01:00
getValue(): string {
2021-12-05 00:39:20 +01:00
// @param {mindplot.model.LinkModel[]} links
const links = model.findFeatureByType(TopicFeatureFactory.Link.id);
2021-12-05 00:39:20 +01:00
let result;
2022-02-06 06:28:35 +01:00
if (links.length > 0) {
result = (links[0] as LinkModel).getUrl();
}
2021-12-05 00:39:20 +01:00
return result;
},
2022-02-06 06:28:35 +01:00
setValue(value: string) {
2021-12-05 00:39:20 +01:00
const dispatcher = ActionDispatcher.getInstance();
const links = model.findFeatureByType(TopicFeatureFactory.Link.id);
2021-12-05 00:39:20 +01:00
if (!$defined(value)) {
const featureId = links[0].getId();
dispatcher.removeFeatureFromTopic(topicId, featureId);
} else if (links.length > 0) {
dispatcher.changeFeatureToTopic(topicId, links[0].getId(), {
url: value,
});
} else {
dispatcher.addFeatureToTopic(topicId, TopicFeatureFactory.Link.id, {
2021-12-05 00:39:20 +01:00
url: value,
});
2021-10-05 02:05:34 +02:00
}
2021-12-14 16:08:54 +01:00
},
2021-12-05 00:39:20 +01:00
};
this.closeEditors();
const editor = new LinkEditor(editorModel);
editor.show();
}
closeEditors() {
this._getTopicEventDispatcher().close(true);
}
2022-02-06 06:28:35 +01:00
private _getTopicEventDispatcher() {
2021-12-05 00:39:20 +01:00
return TopicEventDispatcher.getInstance();
}
/**
2022-01-26 20:25:11 +01:00
* Point: references the center of the rect shape.!!!
*/
2022-02-06 06:28:35 +01:00
setPosition(point: Point) {
2021-12-05 00:39:20 +01:00
$assert(point, 'position can not be null');
// allowed param reassign to avoid risks of existing code relying in this side-effect
// eslint-disable-next-line no-param-reassign
2021-12-05 00:39:20 +01:00
point.x = Math.ceil(point.x);
// eslint-disable-next-line no-param-reassign
2021-12-05 00:39:20 +01:00
point.y = Math.ceil(point.y);
// Update model's position ...
const model = this.getModel();
model.setPosition(point.x, point.y);
// Elements are positioned in the center.
// All topic element must be positioned based on the innerShape.
const size = this.getSize();
const cx = point.x - size.width / 2;
const cy = point.y - size.height / 2;
// Update visual position.
2022-02-06 06:28:35 +01:00
this.get2DElement().setPosition(cx, cy);
2021-12-05 00:39:20 +01:00
// Update connection lines ...
this._updateConnectionLines();
// Check object state.
this.invariant();
}
/** */
2022-02-06 06:28:35 +01:00
getOutgoingLine(): Line {
2021-12-05 00:39:20 +01:00
return this._outgoingLine;
}
getIncomingLines() {
const children = this.getChildren();
2022-01-26 20:25:11 +01:00
return children
.filter((node) => $defined(node.getOutgoingLine()))
.map((node) => node.getOutgoingLine());
2021-12-05 00:39:20 +01:00
}
2022-02-06 06:28:35 +01:00
getOutgoingConnectedTopic(): Topic {
2021-12-05 00:39:20 +01:00
let result = null;
const line = this.getOutgoingLine();
if ($defined(line)) {
result = line.getTargetTopic();
}
return result;
}
2022-02-06 06:28:35 +01:00
private _updateConnectionLines(): void {
2021-12-05 00:39:20 +01:00
// Update this to parent line ...
const outgoingLine = this.getOutgoingLine();
if ($defined(outgoingLine)) {
outgoingLine.redraw();
}
// Update all the incoming lines ...
const incomingLines = this.getIncomingLines();
2021-12-27 20:42:32 +01:00
incomingLines.forEach((line) => line.redraw());
2021-12-05 00:39:20 +01:00
// Update relationship lines
2021-12-27 20:42:32 +01:00
this._relationships.forEach((r) => r.redraw());
2021-12-05 00:39:20 +01:00
}
/** */
2022-02-06 06:28:35 +01:00
setBranchVisibility(value: boolean): void {
let current: Topic = this;
let parent: Topic = this;
2021-12-05 00:39:20 +01:00
while (parent != null && !parent.isCentralTopic()) {
current = parent;
parent = current.getParent();
}
current.setVisibility(value);
}
/** */
2022-02-06 06:28:35 +01:00
setVisibility(value: boolean): void {
2021-12-05 00:39:20 +01:00
this._setTopicVisibility(value);
// Hide all children...
this._setChildrenVisibility(value);
// If there there are connection to the node, topic must be hidden.
this._setRelationshipLinesVisibility(value);
// If it's connected, the connection must be rendered.
const outgoingLine = this.getOutgoingLine();
if (outgoingLine) {
outgoingLine.setVisibility(value);
}
}
/** */
2022-02-06 06:28:35 +01:00
moveToBack(): void {
2021-12-05 00:39:20 +01:00
// Update relationship lines
2021-12-27 20:42:32 +01:00
this._relationships.forEach((r) => r.moveToBack());
2021-12-05 00:39:20 +01:00
const connector = this.getShrinkConnector();
if ($defined(connector)) {
connector.moveToBack();
}
this.get2DElement().moveToBack();
}
/** */
2022-02-06 06:28:35 +01:00
moveToFront(): void {
2021-12-05 00:39:20 +01:00
this.get2DElement().moveToFront();
const connector = this.getShrinkConnector();
if ($defined(connector)) {
connector.moveToFront();
}
// Update relationship lines
2021-12-27 20:42:32 +01:00
this._relationships.forEach((r) => r.moveToFront());
2021-12-05 00:39:20 +01:00
}
/** */
2022-02-06 06:28:35 +01:00
isVisible(): boolean {
2021-12-05 00:39:20 +01:00
const elem = this.get2DElement();
return elem.isVisible();
}
2022-02-06 06:28:35 +01:00
private _setRelationshipLinesVisibility(value: boolean): void {
2021-12-05 17:14:15 +01:00
this._relationships.forEach((relationship) => {
2021-12-05 00:39:20 +01:00
const sourceTopic = relationship.getSourceTopic();
const targetTopic = relationship.getTargetTopic();
const targetParent = targetTopic.getModel().getParent();
const sourceParent = sourceTopic.getModel().getParent();
relationship.setVisibility(
value
2022-02-06 06:28:35 +01:00
&& (targetParent == null || !targetParent.areChildrenShrunken())
&& (sourceParent == null || !sourceParent.areChildrenShrunken()),
2021-12-05 00:39:20 +01:00
);
});
}
2021-10-05 02:05:34 +02:00
2022-02-06 06:28:35 +01:00
private _setTopicVisibility(value: boolean) {
2021-12-05 00:39:20 +01:00
const elem = this.get2DElement();
elem.setVisibility(value);
2021-10-05 02:05:34 +02:00
2021-12-05 00:39:20 +01:00
if (this.getIncomingLines().length > 0) {
2021-10-05 02:05:34 +02:00
const connector = this.getShrinkConnector();
if ($defined(connector)) {
2021-12-05 00:39:20 +01:00
connector.setVisibility(value);
}
}
const textShape = this.getTextShape();
2021-12-15 03:28:15 +01:00
textShape.setVisibility(this.getShapeType() !== TopicShape.IMAGE ? value : false);
2021-12-05 00:39:20 +01:00
}
/** */
2022-02-06 06:28:35 +01:00
setOpacity(opacity: number): void {
2021-12-05 00:39:20 +01:00
const elem = this.get2DElement();
elem.setOpacity(opacity);
const connector = this.getShrinkConnector();
if ($defined(connector)) {
connector.setOpacity(opacity);
}
const textShape = this.getTextShape();
textShape.setOpacity(opacity);
}
2022-02-06 06:28:35 +01:00
private _setChildrenVisibility(isVisible: boolean) {
2021-12-05 00:39:20 +01:00
// Hide all children.
const children = this.getChildren();
const model = this.getModel();
const visibility = isVisible ? !model.areChildrenShrunken() : isVisible;
2021-12-15 03:28:15 +01:00
children.forEach((child) => {
child.setVisibility(visibility);
2021-12-05 00:39:20 +01:00
const outgoingLine = child.getOutgoingLine();
outgoingLine.setVisibility(visibility);
2021-12-15 03:28:15 +01:00
});
2021-12-05 00:39:20 +01:00
}
/** */
invariant() {
const line = this._outgoingLine;
const model = this.getModel();
const isConnected = model.isConnected();
// Check consistency...
if ((isConnected && !line) || (!isConnected && line)) {
// $assert(false,'Illegal state exception.');
}
}
2022-02-12 08:11:59 +01:00
setSize(size: SizeType, force?: boolean): void {
2021-12-05 00:39:20 +01:00
$assert(size, 'size can not be null');
$assert($defined(size.width), 'size seem not to be a valid element');
2021-12-27 20:42:32 +01:00
const roundedSize = {
width: Math.ceil(size.width),
height: Math.ceil(size.height),
};
2021-12-05 00:39:20 +01:00
const oldSize = this.getSize();
2022-01-26 20:25:11 +01:00
const hasSizeChanged = oldSize.width !== roundedSize.width || oldSize.height !== roundedSize.height;
2021-12-05 00:39:20 +01:00
if (hasSizeChanged || force) {
NodeGraph.prototype.setSize.call(this, roundedSize);
2021-10-05 02:05:34 +02:00
2021-12-05 00:39:20 +01:00
const outerShape = this.getOuterShape();
const innerShape = this.getInnerShape();
2021-10-05 02:05:34 +02:00
outerShape.setSize(roundedSize.width + 4, roundedSize.height + 6);
innerShape.setSize(roundedSize.width, roundedSize.height);
2021-10-05 02:05:34 +02:00
2021-12-05 00:39:20 +01:00
// Update the figure position(ej: central topic must be centered) and children position.
this._updatePositionOnChangeSize(oldSize, roundedSize);
2021-10-05 02:05:34 +02:00
2021-12-05 00:39:20 +01:00
if (hasSizeChanged) {
EventBus.instance.fireEvent(EventBus.events.NodeResizeEvent, {
node: this.getModel(),
size: roundedSize,
2021-12-05 00:39:20 +01:00
});
2021-10-05 02:05:34 +02:00
}
2021-12-05 00:39:20 +01:00
}
}
2021-10-05 02:05:34 +02:00
2022-02-06 06:28:35 +01:00
protected abstract _updatePositionOnChangeSize(oldSize: SizeType, roundedSize: SizeType): void;
2021-10-05 02:05:34 +02:00
2022-02-06 06:28:35 +01:00
disconnect(workspace: Workspace): void {
2021-12-05 00:39:20 +01:00
const outgoingLine = this.getOutgoingLine();
if ($defined(outgoingLine)) {
$assert(workspace, 'workspace can not be null');
2021-10-05 02:05:34 +02:00
2021-12-05 00:39:20 +01:00
this._outgoingLine = null;
2021-10-05 02:05:34 +02:00
2021-12-05 00:39:20 +01:00
// Disconnect nodes ...
const targetTopic = outgoingLine.getTargetTopic();
targetTopic.removeChild(this);
2021-10-05 02:05:34 +02:00
// Update model ...
const childModel = this.getModel();
2021-12-05 00:39:20 +01:00
childModel.disconnect();
2021-10-05 02:05:34 +02:00
2021-12-05 00:39:20 +01:00
this._parent = null;
2021-10-05 02:05:34 +02:00
2021-12-05 00:39:20 +01:00
// Remove graphical element from the workspace...
outgoingLine.removeFromWorkspace(workspace);
2021-10-05 02:05:34 +02:00
2021-12-05 00:39:20 +01:00
// Remove from workspace.
EventBus.instance.fireEvent(EventBus.events.NodeDisconnectEvent, this.getModel());
2021-10-05 02:05:34 +02:00
// Change text based on the current connection ...
const model = this.getModel();
if (!model.getText()) {
const text = this.getText();
this._setText(text, false);
}
if (!model.getFontSize()) {
const size = this.getFontSize();
this.setFontSize(size, false);
}
2021-12-05 00:39:20 +01:00
// Hide connection line?.
2021-12-15 03:28:15 +01:00
if (targetTopic.getChildren().length === 0) {
2021-12-05 00:39:20 +01:00
const connector = targetTopic.getShrinkConnector();
if ($defined(connector)) {
connector.setVisibility(false);
}
2021-10-05 02:05:34 +02:00
}
2021-12-05 00:39:20 +01:00
}
}
2022-02-06 06:28:35 +01:00
getOrder(): number {
2021-12-05 00:39:20 +01:00
const model = this.getModel();
return model.getOrder();
}
/** */
2022-02-06 06:28:35 +01:00
setOrder(value: number) {
2021-12-05 00:39:20 +01:00
const model = this.getModel();
model.setOrder(value);
}
/** */
2022-02-06 06:28:35 +01:00
connectTo(targetTopic: Topic, workspace: Workspace) {
2021-12-05 00:39:20 +01:00
$assert(!this._outgoingLine, 'Could not connect an already connected node');
2021-12-15 03:28:15 +01:00
$assert(targetTopic !== this, 'Circular connection are not allowed');
2021-12-05 00:39:20 +01:00
$assert(targetTopic, 'Parent Graph can not be null');
$assert(workspace, 'Workspace can not be null');
// Connect Graphical Nodes ...
targetTopic.append(this);
this._parent = targetTopic;
// Update model ...
const targetModel = targetTopic.getModel();
const childModel = this.getModel();
childModel.connectTo(targetModel);
// Create a connection line ...
const outgoingLine = new ConnectionLine(this, targetTopic);
outgoingLine.setVisibility(false);
this._outgoingLine = outgoingLine;
workspace.append(outgoingLine);
// Update figure is necessary.
this.updateTopicShape(targetTopic);
// Change text based on the current connection ...
const model = this.getModel();
if (!model.getText()) {
const text = this.getText();
this._setText(text, false);
}
if (!model.getFontSize()) {
const size = this.getFontSize();
this.setFontSize(size, false);
}
this.getTextShape();
// Display connection node...
const connector = targetTopic.getShrinkConnector();
if ($defined(connector)) {
connector.setVisibility(true);
}
// Redraw line ...
outgoingLine.redraw();
// Fire connection event ...
if (this.isInWorkspace()) {
EventBus.instance.fireEvent(EventBus.events.NodeConnectEvent, {
parentNode: targetTopic.getModel(),
childNode: this.getModel(),
});
}
}
2022-02-06 06:28:35 +01:00
abstract updateTopicShape(targetTopic: Topic);
append(child: Topic) {
2021-12-05 00:39:20 +01:00
const children = this.getChildren();
children.push(child);
}
/** */
2022-02-06 06:28:35 +01:00
removeChild(child: Topic) {
2021-12-05 00:39:20 +01:00
const children = this.getChildren();
2021-12-14 18:06:09 +01:00
this._children = children.filter((c) => c !== child);
2021-12-05 00:39:20 +01:00
}
/** */
2022-02-06 06:28:35 +01:00
getChildren(): Topic[] {
2021-12-05 00:39:20 +01:00
let result = this._children;
if (!$defined(result)) {
this._children = [];
result = this._children;
}
return result;
}
2022-02-06 06:28:35 +01:00
removeFromWorkspace(workspace: Workspace) {
2021-12-05 00:39:20 +01:00
const elem2d = this.get2DElement();
workspace.removeChild(elem2d);
const line = this.getOutgoingLine();
if ($defined(line)) {
workspace.removeChild(line);
}
this._isInWorkspace = false;
EventBus.instance.fireEvent(EventBus.events.NodeRemoved, this.getModel());
}
2022-02-06 06:28:35 +01:00
addToWorkspace(workspace: Workspace) {
2021-12-05 00:39:20 +01:00
const elem = this.get2DElement();
workspace.append(elem);
if (!this.isInWorkspace()) {
if (!this.isCentralTopic()) {
EventBus.instance.fireEvent(EventBus.events.NodeAdded, this.getModel());
}
if (this.getModel().isConnected()) {
2021-10-05 02:05:34 +02:00
EventBus.instance.fireEvent(EventBus.events.NodeConnectEvent, {
2021-12-05 00:39:20 +01:00
parentNode: this.getOutgoingConnectedTopic().getModel(),
2021-10-05 02:05:34 +02:00
childNode: this.getModel(),
});
}
2021-12-05 00:39:20 +01:00
}
this._isInWorkspace = true;
2022-02-06 06:28:35 +01:00
this.adjustShapes();
2021-12-05 00:39:20 +01:00
}
2021-10-05 02:05:34 +02:00
2021-12-05 00:39:20 +01:00
/** */
2022-02-06 06:28:35 +01:00
isInWorkspace(): boolean {
2021-12-05 00:39:20 +01:00
return this._isInWorkspace;
}
2021-10-05 02:05:34 +02:00
2021-12-05 00:39:20 +01:00
/** */
2022-02-06 06:28:35 +01:00
createDragNode(layoutManager: LayoutManager) {
2021-12-05 18:25:16 +01:00
const result = super.createDragNode(layoutManager);
2021-10-05 02:05:34 +02:00
2021-12-05 00:39:20 +01:00
// Is the node already connected ?
const targetTopic = this.getOutgoingConnectedTopic();
if ($defined(targetTopic)) {
result.connectTo(targetTopic);
result.setVisibility(false);
}
2021-10-05 02:05:34 +02:00
2021-12-05 00:39:20 +01:00
// If a drag node is create for it, let's hide the editor.
this._getTopicEventDispatcher().close();
2021-10-05 02:05:34 +02:00
2021-12-05 00:39:20 +01:00
return result;
}
2021-10-05 02:05:34 +02:00
2022-02-06 06:28:35 +01:00
adjustShapes(): void {
2021-12-05 00:39:20 +01:00
if (this._isInWorkspace) {
const textShape = this.getTextShape();
2021-12-15 03:28:15 +01:00
if (this.getShapeType() !== TopicShape.IMAGE) {
2021-12-27 20:42:32 +01:00
// Calculate topic size and adjust elements ...
2021-12-05 00:39:20 +01:00
const textWidth = textShape.getWidth();
2021-12-27 20:42:32 +01:00
const textHeight = textShape.getHeight();
const padding = TopicStyle.getInnerPadding(this);
2021-10-05 02:05:34 +02:00
2021-12-27 20:42:32 +01:00
// Adjust icons group based on the font size ...
2021-12-05 00:39:20 +01:00
const iconGroup = this.getOrBuildIconGroup();
const fontHeight = this.getTextShape().getFontHeight();
2021-12-27 20:42:32 +01:00
const iconHeight = ICON_SCALING_FACTOR * fontHeight;
iconGroup.seIconSize(iconHeight, iconHeight);
// Calculate size and adjust ...
const topicHeight = Math.max(iconHeight, textHeight) + padding * 2;
const textIconSpacing = Math.round(fontHeight / 4);
const iconGroupWith = iconGroup.getSize().width;
const topicWith = iconGroupWith + textIconSpacing + textWidth + padding * 2;
this.setSize({
width: topicWith,
height: topicHeight,
2022-02-06 06:28:35 +01:00
}, false);
2021-10-05 02:05:34 +02:00
2021-12-27 20:42:32 +01:00
// Adjust all topic elements positions ...
2021-12-27 21:29:24 +01:00
const yPosition = Math.round((topicHeight - textHeight) / 2);
iconGroup.setPosition(padding, yPosition);
textShape.setPosition(padding + iconGroupWith + textIconSpacing, yPosition);
2021-12-05 00:39:20 +01:00
} else {
2021-12-27 20:42:32 +01:00
// In case of images, the size is fixed ...
2021-12-05 00:39:20 +01:00
const size = this.getModel().getImageSize();
2022-02-06 06:28:35 +01:00
this.setSize(size, false);
2021-12-05 00:39:20 +01:00
}
}
}
2022-02-06 06:28:35 +01:00
private _flatten2DElements(topic: Topic) {
2021-12-05 00:39:20 +01:00
let result = [];
const children = topic.getChildren();
2021-12-15 03:28:15 +01:00
children.forEach((child) => {
2021-12-05 00:39:20 +01:00
result.push(child);
result.push(child.getOutgoingLine());
const relationships = child.getRelationships();
result = result.concat(relationships);
if (!child.areChildrenShrunken()) {
const innerChilds = this._flatten2DElements(child);
result = result.concat(innerChilds);
}
2021-12-15 03:28:15 +01:00
});
2021-12-05 00:39:20 +01:00
return result;
}
2022-02-15 04:01:48 +01:00
abstract workoutOutgoingConnectionPoint(position: Point): Point;
abstract workoutIncomingConnectionPoint(position: Point): Point;
2022-02-06 06:28:35 +01:00
isChildTopic(childTopic: Topic): boolean {
2021-12-15 03:28:15 +01:00
let result = this.getId() === childTopic.getId();
2021-12-05 00:39:20 +01:00
if (!result) {
const children = this.getChildren();
for (let i = 0; i < children.length; i++) {
const parent = children[i];
result = parent.isChildTopic(childTopic);
if (result) {
break;
2021-10-05 02:05:34 +02:00
}
}
2021-12-05 00:39:20 +01:00
}
return result;
}
isCentralTopic() {
2022-01-02 23:16:18 +01:00
return this.getModel().getType() === 'CentralTopic';
2021-12-05 00:39:20 +01:00
}
}
2021-07-16 16:41:58 +02:00
export default Topic;