wisemapping-frontend/packages/mindplot/lib/components/Designer.js
2021-09-29 17:24:07 -03:00

1049 lines
37 KiB
JavaScript

/*
* Copyright [2015] [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.
*/
const Events = require('./Events').default;
const Messages = require('./Messages').default;
const { StandaloneActionDispatcher, CommandContext } = require('./StandaloneActionDispatcher');
const ActionDispatcher = require('./ActionDispatcher').default;
const DesignerModel = require('./DesignerModel').default;
const DesignerKeyboard = require('./DesignerKeyboard').default;
const ScreenManager = require('./ScreenManager').default;
const Workspace = require('./Workspace').default;
const DragConnector = require('./DragConnector').default;
const DragManager = require('./DragManager').default;
const RelationshipPivot = require('./RelationshipPivot').default;
const Relationship = require('./Relationship').default;
const TopicEventDispatcher = require('./TopicEventDispatcher').default;
const TopicFeature = require('./TopicFeature').default;
const { TopicEvent } = require('./TopicEventDispatcher');
const NodeGraph = require('./NodeGraph').default;
const EventBusDispatcher = require('./layout/EventBusDispatcher').default;
const LayoutManager = require('./layout/LayoutManager').default;
const INodeModel = require('./model/INodeModel').default;
const { TopicShape } = require('./model/INodeModel');
const Designer = new Class(
/** @lends Designer */ {
Extends: Events,
/**
* @constructs
* @param {Object} options
* @param {HTMLElement} divElement
* @extends mindplot.Events
*/
initialize: function (options, divElement) {
$assert(options, 'options must be defined');
$assert(options.zoom, 'zoom must be defined');
$assert(options.size, 'size must be defined');
$assert(divElement, 'divElement must be defined');
// Set up i18n location ...
Messages.init(options.locale);
this._options = options;
// Set full div elem render area ...
divElement.css(options.size);
// Dispatcher manager ...
var commandContext = new CommandContext(this);
this._actionDispatcher = new StandaloneActionDispatcher(commandContext);
var me = this;
this._actionDispatcher.addEvent('modelUpdate', function (event) {
me.fireEvent('modelUpdate', event);
});
ActionDispatcher.setInstance(this._actionDispatcher);
this._model = new DesignerModel(options);
// Init Screen manager..
var screenManager = new ScreenManager(divElement);
this._workspace = new Workspace(screenManager, this._model.getZoom());
// Init layout manager ...
this._eventBussDispatcher = new EventBusDispatcher(this.getModel());
// Register events
if (!this.isReadOnly()) {
// Register mouse events ...
this._registerMouseEvents();
// Register keyboard events ...
DesignerKeyboard.register(this);
this._dragManager = this._buildDragManager(this._workspace);
}
this._registerWheelEvents();
this._relPivot = new RelationshipPivot(this._workspace, this);
// Set editor working area ...
this.setViewPort(options.viewPort);
TopicEventDispatcher.configure(this.isReadOnly());
this._clipboard = [];
},
/**
* @private
*/
_registerWheelEvents: function () {
var zoomFactor = 1.006;
var me = this;
// Zoom In and Zoom Out must active event
$(document).on('mousewheel', function (event) {
if (event.deltaY > 0) {
me.zoomIn(zoomFactor);
} else {
me.zoomOut(zoomFactor);
}
event.preventDefault();
});
},
/**
* @param {String} type the event type
* @param {Function} listener
* forwards to the TopicEventDispatcher or the parent Events class, depending on the type
*/
addEvent: function (type, listener) {
if (type == TopicEvent.EDIT || type == TopicEvent.CLICK) {
var editor = TopicEventDispatcher.getInstance();
editor.addEvent(type, listener);
} else {
this.parent(type, listener);
}
},
/**
* @private
*/
_registerMouseEvents: function () {
var workspace = this._workspace;
var screenManager = workspace.getScreenManager();
var me = this;
// Initialize workspace event listeners.
screenManager.addEvent('update', function () {
// Topic must be set to his original state. All editors must be closed.
var topics = me.getModel().getTopics();
_.each(topics, function (object) {
object.closeEditors();
});
// Clean some selected nodes on event ..
if (me._cleanScreen) me._cleanScreen();
});
// Deselect on click ...
screenManager.addEvent('click', function (event) {
me.onObjectFocusEvent(null, event);
});
// Create nodes on double click...
screenManager.addEvent(
'dblclick',
function (event) {
if (workspace.isWorkspaceEventsEnabled()) {
var mousePos = screenManager.getWorkspaceMousePosition(event);
var centralTopic = me.getModel().getCentralTopic();
var model = me._createChildModel(centralTopic, mousePos);
this._actionDispatcher.addTopics([model], [centralTopic.getId()]);
}
}.bind(this)
);
// Register mouse drag and drop event ...
function noopHandler(evt) {
evt.stopPropagation();
evt.preventDefault();
}
},
/**
* @private
* @param {mindplot.Workspace} workspace
* @return {mindplot.DragManager} the new dragManager for the workspace with events
* registered
*/
_buildDragManager: function (workspace) {
var designerModel = this.getModel();
var dragConnector = new DragConnector(designerModel, this._workspace);
var dragManager = new DragManager(workspace, this._eventBussDispatcher);
var topics = designerModel.getTopics();
dragManager.addEvent('startdragging', function () {
// Enable all mouse events.
for (var i = 0; i < topics.length; i++) {
topics[i].setMouseEventsEnabled(false);
}
});
dragManager.addEvent('dragging', function (event, dragTopic) {
dragTopic.updateFreeLayout(event);
if (!dragTopic.isFreeLayoutOn(event)) {
// The node is being drag. Is the connection still valid ?
dragConnector.checkConnection(dragTopic);
if (!dragTopic.isVisible() && dragTopic.isConnected()) {
dragTopic.setVisibility(true);
}
}
});
dragManager.addEvent('enddragging', function (event, dragTopic) {
for (var i = 0; i < topics.length; i++) {
topics[i].setMouseEventsEnabled(true);
}
dragTopic.applyChanges(workspace);
});
return dragManager;
},
/**
* @param {{width:Number, height:Number}} size
* sets width and height of the workspace
*/
setViewPort: function (size) {
this._workspace.setViewPort(size);
var model = this.getModel();
this._workspace.setZoom(model.getZoom(), true);
},
/**
* @private
* @param {mindplot.model.NodeModel} model
* @param {Boolean} readOnly
* @return {mindplot.CentralTopic|mindplot.MainTopic} the topic to the given model,
* connected, added to the drag manager, with events registered - complying type & read mode
*/
_buildNodeGraph: function (model, readOnly) {
// Create node graph ...
var topic = NodeGraph.create(model, { readOnly: readOnly });
this.getModel().addTopic(topic);
var me = this;
// Add Topic events ...
if (!readOnly) {
// If a node had gained focus, clean the rest of the nodes ...
topic.addEvent('mousedown', function (event) {
me.onObjectFocusEvent(topic, event);
});
// Register node listeners ...
if (topic.getType() != INodeModel.CENTRAL_TOPIC_TYPE) {
// Central Topic doesn't support to be dragged
this._dragManager.add(topic);
}
}
// Connect Topic ...
var isConnected = model.isConnected();
if (isConnected) {
// Improve this ...
var targetTopicModel = model.getParent();
var targetTopic = null;
var topics = this.getModel().getTopics();
for (var i = 0; i < topics.length; i++) {
var t = topics[i];
if (t.getModel() == targetTopicModel) {
targetTopic = t;
// Disconnect the node. It will be connected again later ...
model.disconnect();
break;
}
}
$assert(targetTopic, 'Could not find a topic to connect');
topic.connectTo(targetTopic, this._workspace);
}
topic.addEvent('ontblur', function () {
var topics = me.getModel().filterSelectedTopics();
var rels = me.getModel().filterSelectedRelationships();
if (topics.length == 0 || rels.length == 0) {
me.fireEvent('onblur');
}
});
topic.addEvent('ontfocus', function () {
var topics = me.getModel().filterSelectedTopics();
var rels = me.getModel().filterSelectedRelationships();
if (topics.length == 1 || rels.length == 1) {
me.fireEvent('onfocus');
}
});
return topic;
},
/**
* @param {?mindplot.Topic} currentObject
* @param {Event=} event
* sets focus to the given currentObject and removes it from any other objects if not
* triggered with Ctrl pressed
*/
onObjectFocusEvent: function (currentObject, event) {
// Close node editors ..
var topics = this.getModel().getTopics();
_.each(topics, function (topic) {
topic.closeEditors();
});
var model = this.getModel();
var objects = model.getEntities();
_.each(objects, function (object) {
// Disable all nodes on focus but not the current if Ctrl key isn't being pressed
if (!$defined(event) || (!event.ctrlKey && !event.metaKey)) {
if (object.isOnFocus() && object != currentObject) {
object.setOnFocus(false);
}
}
});
},
/** sets focus to all model entities, i.e. relationships and topics */
selectAll: function () {
var model = this.getModel();
var objects = model.getEntities();
_.each(objects, function (object) {
object.setOnFocus(true);
});
},
/** removes focus from all model entities, i.e. relationships and topics */
deselectAll: function () {
var objects = this.getModel().getEntities();
_.each(objects, function (object) {
object.setOnFocus(false);
});
},
/**
* Set the zoom of the map
* @param {Number} zoom number between 0.3 and 1.9
*/
setZoom: function (zoom) {
if (zoom > 1.9 || zoom < 0.3) {
$notify($msg('ZOOM_IN_ERROR'));
return;
}
this.getModel().setZoom(zoom);
this._workspace.setZoom(zoom);
},
/**
* @param {Number=} factor
* zoom out by the given factor, or 1.2, if undefined
*/
zoomOut: function (factor) {
if (!factor) factor = 1.2;
var model = this.getModel();
var scale = model.getZoom() * factor;
if (scale <= 1.9) {
model.setZoom(scale);
this._workspace.setZoom(scale);
} else {
$notify($msg('ZOOM_ERROR'));
}
},
/**
* @param {Number=} factor
* zoom in by the given factor, or 1.2, if undefined
*/
zoomIn: function (factor) {
if (!factor) factor = 1.2;
var model = this.getModel();
var scale = model.getZoom() / factor;
if (scale >= 0.3) {
model.setZoom(scale);
this._workspace.setZoom(scale);
} else {
$notify($msg('ZOOM_ERROR'));
}
},
/** copy selected topics to a private clipboard */
copyToClipboard: function () {
var topics = this.getModel().filterSelectedTopics();
if (topics.length <= 0) {
// If there are more than one node selected,
$notify($msg('AT_LEAST_ONE_TOPIC_MUST_BE_SELECTED'));
return;
}
// Exclude central topic ..
topics = topics.filter(function (topic) {
return !topic.isCentralTopic();
});
this._clipboard = topics.map(function (topic) {
var nodeModel = topic.getModel().deepCopy();
// Change position to make the new topic evident...
var pos = nodeModel.getPosition();
nodeModel.setPosition(pos.x + 60 * Math.sign(pos.x), pos.y + 30);
return nodeModel;
});
$notify($msg('SELECTION_COPIED_TO_CLIPBOARD'));
},
/** paste clipboard contents to the mindmap */
pasteClipboard: function () {
if (this._clipboard.length == 0) {
$notify($msg('CLIPBOARD_IS_EMPTY'));
return;
}
this._actionDispatcher.addTopics(this._clipboard);
this._clipboard = [];
},
/** @return {mindplot.DesignerModel} model */
getModel: function () {
return this._model;
},
/** collapse the subtree of the selected topic */
shrinkSelectedBranch: function () {
var nodes = this.getModel().filterSelectedTopics();
if (nodes.length <= 0 || nodes.length != 1) {
// If there are more than one node selected,
$notify($msg('ONLY_ONE_TOPIC_MUST_BE_SELECTED_COLLAPSE'));
return;
}
// Execute event ...
var topic = nodes[0];
if (topic.getType() != INodeModel.CENTRAL_TOPIC_TYPE) {
this._actionDispatcher.shrinkBranch([topic.getId()], !topic.areChildrenShrunken());
}
},
/** create a NodeModel for the selected node's child and add it via the ActionDispatcher */
createChildForSelectedNode: function () {
var nodes = this.getModel().filterSelectedTopics();
if (nodes.length <= 0) {
// If there are more than one node selected,
$notify($msg('ONE_TOPIC_MUST_BE_SELECTED'));
return;
}
if (nodes.length != 1) {
// If there are more than one node selected,
$notify($msg('ONLY_ONE_TOPIC_MUST_BE_SELECTED'));
return;
}
// Add new node ...
var parentTopic = nodes[0];
var parentTopicId = parentTopic.getId();
var childModel = this._createChildModel(parentTopic);
// Execute event ...
this._actionDispatcher.addTopics([childModel], [parentTopicId]);
},
/**
* @private
*/
_copyNodeProps: function (sourceModel, targetModel) {
// I don't copy the font size if the target is the source is the central topic.
if (sourceModel.getType() != INodeModel.CENTRAL_TOPIC_TYPE) {
var fontSize = sourceModel.getFontSize();
if (fontSize) {
targetModel.setFontSize(fontSize);
}
}
var fontFamily = sourceModel.getFontFamily();
if (fontFamily) {
targetModel.setFontFamily(fontFamily);
}
var fontColor = sourceModel.getFontColor();
if (fontColor) {
targetModel.setFontColor(fontColor);
}
var fontWeight = sourceModel.getFontWeight();
if (fontWeight) {
targetModel.setFontWeight(fontWeight);
}
var fontStyle = sourceModel.getFontStyle();
if (fontStyle) {
targetModel.setFontStyle(fontStyle);
}
var shape = sourceModel.getShapeType();
if (shape) {
targetModel.setShapeType(shape);
}
var borderColor = sourceModel.getBorderColor();
if (borderColor) {
targetModel.setBorderColor(borderColor);
}
var backgroundColor = sourceModel.getBackgroundColor();
if (backgroundColor) {
targetModel.setBackgroundColor(backgroundColor);
}
},
/**
* @private
* @param {mindplot.Topic} topic the parent topic of the child to create the NodeModel for
* @param {core.Point} mousePos the mouse position
* @return {mindplot.NodeModel} the node model for the new child
*/
_createChildModel: function (topic, mousePos) {
// Create a new node ...
var parentModel = topic.getModel();
var mindmap = parentModel.getMindmap();
var childModel = mindmap.createNode();
// Create a new node ...
var layoutManager = this._eventBussDispatcher.getLayoutManager();
var result = layoutManager.predict(topic.getId(), null, mousePos);
childModel.setOrder(result.order);
var position = result.position;
childModel.setPosition(position.x, position.y);
this._copyNodeProps(parentModel, childModel);
return childModel;
},
/**
* @param {Events} event
* @param {mindplot.model.NodeModel} model
* @todo not used
*/
addDraggedNode: function (event, model) {
$assert(event, 'event can not be null');
$assert(model, 'model can not be null');
// Position far from the visual area ...
model.setPosition(1000, 1000);
this._actionDispatcher.addTopics([model]);
var topic = this.getModel().findTopicById(model.getId());
// Simulate a mouse down event to start the dragging ...
topic.fireEvent('mousedown', event);
},
/**
* creates a sibling or child node of the selected node, if the selected node is the
* central topic
*/
createSiblingForSelectedNode: function () {
var nodes = this.getModel().filterSelectedTopics();
if (nodes.length <= 0) {
// If there are no nodes selected,
$notify($msg('ONE_TOPIC_MUST_BE_SELECTED'));
return;
}
if (nodes.length > 1) {
// If there are more than one node selected,
$notify($msg('ONLY_ONE_TOPIC_MUST_BE_SELECTED'));
return;
}
var topic = nodes[0];
if (!topic.getOutgoingConnectedTopic()) {
// Central topic and isolated topics ....
// Central topic doesn't have siblings ...
this.createChildForSelectedNode();
} else {
var parentTopic = topic.getOutgoingConnectedTopic();
var siblingModel = this._createSiblingModel(topic);
// Hack: if parent is central topic, add node below not on opposite side.
// This should be done in the layout
if (parentTopic.getType() == INodeModel.CENTRAL_TOPIC_TYPE) {
siblingModel.setOrder(topic.getOrder() + 2);
}
var parentTopicId = parentTopic.getId();
this._actionDispatcher.addTopics([siblingModel], [parentTopicId]);
}
},
/**
* @private
* @param {mindplot.Topic} topic the topic to create the sibling to
* @return {mindplot.NodeModel} the node model of the sibling
*/
_createSiblingModel: function (topic) {
var result = null;
var parentTopic = topic.getOutgoingConnectedTopic();
if (parentTopic != null) {
// Create a new node ...
var model = topic.getModel();
var mindmap = model.getMindmap();
result = mindmap.createNode();
// Create a new node ...
var order = topic.getOrder() + 1;
result.setOrder(order);
result.setPosition(10, 10); // Set a dummy position ...
}
this._copyNodeProps(model, result);
return result;
},
/**
* @param {Event} event
*/
showRelPivot: function (event) {
var nodes = this.getModel().filterSelectedTopics();
if (nodes.length <= 0) {
// This could not happen ...
$notify($msg('RELATIONSHIP_COULD_NOT_BE_CREATED'));
return;
}
// Current mouse position ....
var screen = this._workspace.getScreenManager();
var pos = screen.getWorkspaceMousePosition(event);
// create a connection ...
this._relPivot.start(nodes[0], pos);
},
/** @return {{zoom:Number}} the zoom */
getMindmapProperties: function () {
var model = this.getModel();
return { zoom: model.getZoom() };
},
/**
* @param {mindplot.Mindmap} mindmapModel
* @throws will throw an error if mindmapModel is null or undefined
*/
loadMap: function (mindmapModel) {
$assert(mindmapModel, 'mindmapModel can not be null');
this._mindmap = mindmapModel;
// Init layout manager ...
var size = { width: 25, height: 25 };
var layoutManager = new LayoutManager(mindmapModel.getCentralTopic().getId(), size);
var me = this;
layoutManager.addEvent('change', function (event) {
var id = event.getId();
var topic = me.getModel().findTopicById(id);
topic.setPosition(event.getPosition());
topic.setOrder(event.getOrder());
});
this._eventBussDispatcher.setLayoutManager(layoutManager);
// Building node graph ...
var branches = mindmapModel.getBranches();
for (var i = 0; i < branches.length; i++) {
// NodeModel -> NodeGraph ...
var nodeModel = branches[i];
var nodeGraph = this.nodeModelToNodeGraph(nodeModel);
// Update shrink render state...
nodeGraph.setBranchVisibility(true);
}
var relationships = mindmapModel.getRelationships();
for (var j = 0; j < relationships.length; j++) {
this._relationshipModelToRelationship(relationships[j]);
}
// Place the focus on the Central Topic
var centralTopic = this.getModel().getCentralTopic();
this.goToNode(centralTopic);
// Finally, sort the map ...
EventBus.instance.fireEvent(EventBus.events.DoLayout);
this.fireEvent('loadSuccess');
},
/** */
getMindmap: function () {
return this._mindmap;
},
/** */
undo: function () {
// @Todo: This is a hack...
this._actionDispatcher._actionRunner.undo();
},
/** */
redo: function () {
this._actionDispatcher._actionRunner.redo();
},
/** */
isReadOnly: function () {
return this._options.readOnly;
},
/**
* @param {mindplot.model.NodeModel} nodeModel
* @return {mindplot.Topic} the topic (extends mindplot.NodeGraph) created to the model
*/
nodeModelToNodeGraph: function (nodeModel) {
$assert(nodeModel, 'Node model can not be null');
var children = nodeModel.getChildren().slice();
children = children.sort(function (a, b) {
return a.getOrder() - b.getOrder();
});
var nodeGraph = this._buildNodeGraph(nodeModel, this.isReadOnly());
nodeGraph.setVisibility(false);
this._workspace.append(nodeGraph);
for (var i = 0; i < children.length; i++) {
var child = children[i];
if ($defined(child)) this.nodeModelToNodeGraph(child);
}
return nodeGraph;
},
/**
* @private
* @param {mindplot.model.RelationshipModel} model
* @return {mindplot.Relationship} the relationship created to the model
* @throws will throw an error if model is null or undefined
*/
_relationshipModelToRelationship: function (model) {
$assert(model, 'Node model can not be null');
var result = this._buildRelationshipShape(model);
var sourceTopic = result.getSourceTopic();
sourceTopic.addRelationship(result);
var targetTopic = result.getTargetTopic();
targetTopic.addRelationship(result);
result.setVisibility(sourceTopic.isVisible() && targetTopic.isVisible());
this._workspace.append(result);
return result;
},
/**
* @param {mindplot.model.RelationshipModel} model
* @return {mindplot.Relationship} the relationship added to the mindmap
*/
addRelationship: function (model) {
var mindmap = this.getMindmap();
mindmap.addRelationship(model);
return this._relationshipModelToRelationship(model);
},
/**
* deletes the relationship from the linked topics, DesignerModel, Workspace and Mindmap
* @param {mindplot.Relationship} rel the relationship to delete
*/
deleteRelationship: function (rel) {
var sourceTopic = rel.getSourceTopic();
sourceTopic.deleteRelationship(rel);
var targetTopic = rel.getTargetTopic();
targetTopic.deleteRelationship(rel);
this.getModel().removeRelationship(rel);
this._workspace.removeChild(rel);
var mindmap = this.getMindmap();
mindmap.deleteRelationship(rel.getModel());
},
/**
* @private
* @param {mindplot.model.RelationshipModel} model
* @return {mindplot.Relationship} the new relationship with events registered
* @throws will throw an error if the target topic cannot be found
*/
_buildRelationshipShape: function (model) {
var dmodel = this.getModel();
var sourceTopicId = model.getFromNode();
var sourceTopic = dmodel.findTopicById(sourceTopicId);
var targetTopicId = model.getToNode();
var targetTopic = dmodel.findTopicById(targetTopicId);
$assert(
targetTopic,
'targetTopic could not be found:' +
targetTopicId +
dmodel.getTopics().map(function (e) {
return e.getId();
})
);
// Build relationship line ....
var result = new Relationship(sourceTopic, targetTopic, model);
var me = this;
result.addEvent('ontblur', function () {
var topics = me.getModel().filterSelectedTopics();
var rels = me.getModel().filterSelectedRelationships();
if (topics.length == 0 || rels.length == 0) {
me.fireEvent('onblur');
}
});
result.addEvent('ontfocus', function () {
var topics = me.getModel().filterSelectedTopics();
var rels = me.getModel().filterSelectedRelationships();
if (topics.length == 1 || rels.length == 1) {
me.fireEvent('onfocus');
}
});
// Append it to the workspace ...
dmodel.addRelationship(result);
return result;
},
/**
* @param {mindplot.Topic} node the topic to remove
* removes the given topic and its children from Workspace, DesignerModel and NodeModel
*/
removeTopic: function (node) {
if (!node.isCentralTopic()) {
var parent = node._parent;
node.disconnect(this._workspace);
//remove children
while (node.getChildren().length > 0) {
this.removeTopic(node.getChildren()[0]);
}
this._workspace.removeChild(node);
this.getModel().removeTopic(node);
// Delete this node from the model...
var model = node.getModel();
model.deleteNode();
if ($defined(parent)) {
this.goToNode(parent);
}
}
},
/**
* @private
*/
_resetEdition: function () {
var screenManager = this._workspace.getScreenManager();
screenManager.fireEvent('update');
screenManager.fireEvent('mouseup');
this._relPivot.dispose();
},
/** */
deleteSelectedEntities: function () {
// Is there some action in progress ?.
this._resetEdition();
var topics = this.getModel().filterSelectedTopics();
var relation = this.getModel().filterSelectedRelationships();
if (topics.length <= 0 && relation.length <= 0) {
// If there are more than one node selected,
$notify($msg('ENTITIES_COULD_NOT_BE_DELETED'));
return;
} else if (topics.length == 1 && topics[0].isCentralTopic()) {
$notify($msg('CENTRAL_TOPIC_CAN_NOT_BE_DELETED'));
return;
}
// If the central topic has been selected, I must filter ir
var topicIds = topics
.filter(function (topic) {
return !topic.isCentralTopic();
})
.map(function (topic) {
return topic.getId();
});
var relIds = relation.map(function (rel) {
return rel.getId();
});
// Finally delete the topics ...
if (topicIds.length > 0 || relIds.length > 0) {
this._actionDispatcher.deleteEntities(topicIds, relIds);
}
},
/** */
changeFontFamily: function (font) {
var topicsIds = this.getModel().filterTopicsIds();
if (topicsIds.length > 0) {
this._actionDispatcher.changeFontFamilyToTopic(topicsIds, font);
}
},
/** */
changeFontStyle: function () {
var topicsIds = this.getModel().filterTopicsIds();
if (topicsIds.length > 0) {
this._actionDispatcher.changeFontStyleToTopic(topicsIds);
}
},
/** */
changeFontColor: function (color) {
$assert(color, 'color can not be null');
var topicsIds = this.getModel().filterTopicsIds();
if (topicsIds.length > 0) {
this._actionDispatcher.changeFontColorToTopic(topicsIds, color);
}
},
/** */
changeBackgroundColor: function (color) {
var validateFunc = function (topic) {
return topic.getShapeType() != TopicShape.LINE;
};
var validateError = 'Color can not be set to line topics.';
var topicsIds = this.getModel().filterTopicsIds(validateFunc, validateError);
if (topicsIds.length > 0) {
this._actionDispatcher.changeBackgroundColorToTopic(topicsIds, color);
}
},
/** */
changeBorderColor: function (color) {
var validateFunc = function (topic) {
return topic.getShapeType() != TopicShape.LINE;
};
var validateError = 'Color can not be set to line topics.';
var topicsIds = this.getModel().filterTopicsIds(validateFunc, validateError);
if (topicsIds.length > 0) {
this._actionDispatcher.changeBorderColorToTopic(topicsIds, color);
}
},
/** */
changeFontSize: function (size) {
var topicsIds = this.getModel().filterTopicsIds();
if (topicsIds.length > 0) {
this._actionDispatcher.changeFontSizeToTopic(topicsIds, size);
}
},
/** */
changeTopicShape: function (shape) {
var validateFunc = function (topic) {
return !(
topic.getType() == INodeModel.CENTRAL_TOPIC_TYPE && shape == TopicShape.LINE
);
};
var validateError = 'Central Topic shape can not be changed to line figure.';
var topicsIds = this.getModel().filterTopicsIds(validateFunc, validateError);
if (topicsIds.length > 0) {
this._actionDispatcher.changeShapeTypeToTopic(topicsIds, shape);
}
},
/** */
changeFontWeight: function () {
var topicsIds = this.getModel().filterTopicsIds();
if (topicsIds.length > 0) {
this._actionDispatcher.changeFontWeightToTopic(topicsIds);
}
},
/** */
addIconType: function (iconType) {
var topicsIds = this.getModel().filterTopicsIds();
if (topicsIds.length > 0) {
this._actionDispatcher.addFeatureToTopic(topicsIds[0], TopicFeature.Icon.id, {
id: iconType,
});
}
},
/**
* lets the selected topic open the link editor where the user can define or modify an
* existing link
*/
addLink: function () {
var model = this.getModel();
var topic = model.selectedTopic();
if (topic) {
topic.showLinkEditor();
this.onObjectFocusEvent();
}
},
/** */
addNote: function () {
var model = this.getModel();
var topic = model.selectedTopic();
if (topic) {
topic.showNoteEditor();
this.onObjectFocusEvent();
}
},
/**
* @param {mindplot.Topic} node
* sets the focus to the given node
*/
goToNode: function (node) {
node.setOnFocus(true);
this.onObjectFocusEvent(node);
},
/** @return {mindplot.Workspace} */
getWorkSpace: function () {
return this._workspace;
},
}
);
export default Designer;