UNPKG

webgme

Version:

Web-based Generic Modeling Environment

484 lines (403 loc) 19.2 kB
/*globals define, _*/ /*jshint browser: true*/ /** * @author rkereskenyi / https://github.com/rkereskenyi */ define([ './Connection', './DiagramDesignerWidget.Constants' ], function (Connection, DiagramDesignerWidgetConstants) { 'use strict'; var DiagramDesignerWidget, CONNECTION_IN_DRAW_CLASS = 'connection-drawing'; DiagramDesignerWidget = function () { }; DiagramDesignerWidget.prototype.createConnection = function (objD) { var connectionId = this._getGuid('C_'), objDescriptor = _.extend({}, objD), sourceId = objDescriptor.srcObjId, sourceSubcomponentId = objDescriptor.srcSubCompId, targetId = objDescriptor.dstObjId, targetSubcomponentId = objDescriptor.dstSubCompId, newComponent; this.logger.debug('Creating connection component with parameters:', objDescriptor); objDescriptor.designerCanvas = this; this.connectionIds.push(connectionId); //add to accounting queues for performance optimization this._insertedConnectionIDs.push(connectionId); //accounting connection info this.connectionEndIDs[connectionId] = { srcObjId: sourceId, srcSubCompId: sourceSubcomponentId, dstObjId: targetId, dstSubCompId: targetSubcomponentId }; this._saveConnectionIDbyEndID(connectionId, sourceId, sourceSubcomponentId); this._saveConnectionIDbyEndID(connectionId, targetId, targetSubcomponentId); newComponent = this.items[connectionId] = new Connection(connectionId); newComponent._initialize(objDescriptor); return newComponent; }; DiagramDesignerWidget.prototype.updateConnection = function (id, objDescriptor) { var srcObjId = objDescriptor.srcObjId, srcSubCompId = objDescriptor.srcSubCompId, dstObjId = objDescriptor.dstObjId, dstSubCompId = objDescriptor.dstSubCompId; this.logger.debug('Updating connection component with ID: "' + id + '"'); //add to accounting queues for performance optimization this._updatedConnectionIDs.push(id); /* check if any endpoint of the connection has been changed */ //check SOURCE if (srcObjId !== this.connectionEndIDs[id].srcObjId || srcSubCompId !== this.connectionEndIDs[id].srcSubCompId) { //remove connection from source list this._removeConnectionIDfromEnd(id, true); //account the new this._saveConnectionIDbyEndID(id, srcObjId, srcSubCompId); } //check TARGET if (dstObjId !== this.connectionEndIDs[id].dstObjId || dstSubCompId !== this.connectionEndIDs[id].dstSubCompId) { //remove connection from target list this._removeConnectionIDfromEnd(id, false); //account the new this._saveConnectionIDbyEndID(id, dstObjId, dstSubCompId); } //accounting connection info this.connectionEndIDs[id] = { srcObjId: srcObjId, srcSubCompId: srcSubCompId, dstObjId: dstObjId, dstSubCompId: dstSubCompId }; this.items[id].update(objDescriptor); }; DiagramDesignerWidget.prototype.updateConnectionTexts = function (id, texts) { this.logger.debug('Updating connection texts with ID: "' + id + '"'); this.items[id].updateTexts(texts); }; DiagramDesignerWidget.prototype.deleteConnection = function (id) { var idx; this.logger.debug('Deleting connection component with ID: "' + id + '"'); //keep up accounting this._deletedConnectionIDs.push(id); //remove connection from source list this._removeConnectionIDfromEnd(id, true); //remove connection from target list this._removeConnectionIDfromEnd(id, false); //remove connection from connection endpoint list delete this.connectionEndIDs[id]; //remove ID from connection ID list idx = this.connectionIds.indexOf(id); this.connectionIds.splice(idx, 1); //get rid of the connection itself this.items[id].destroy(); delete this.items[id]; }; DiagramDesignerWidget.prototype._saveConnectionIDbyEndID = function (connId, objId, subCompId) { subCompId = subCompId || DiagramDesignerWidgetConstants.SELF; this.connectionIDbyEndID[objId] = this.connectionIDbyEndID[objId] || {}; this.connectionIDbyEndID[objId][subCompId] = this.connectionIDbyEndID[objId][subCompId] || []; this.connectionIDbyEndID[objId][subCompId].push(connId); }; DiagramDesignerWidget.prototype._removeConnectionIDfromEnd = function (connId, isSource) { var objId = isSource ? this.connectionEndIDs[connId].srcObjId : this.connectionEndIDs[connId].dstObjId, subComponentId = isSource ? this.connectionEndIDs[connId].srcSubCompId : this.connectionEndIDs[connId].dstSubCompId, idx; subComponentId = subComponentId || DiagramDesignerWidgetConstants.SELF; idx = this.connectionIDbyEndID[objId][subComponentId].indexOf(connId); if (idx !== -1) { this.connectionIDbyEndID[objId][subComponentId].splice(idx, 1); } }; /* * Called when a new connection is being created in the widget by the user */ DiagramDesignerWidget.prototype.onCreateNewConnection = function (params) { this.logger.warn('onCreateNewConnection with parameters: ' + JSON.stringify(params)); }; DiagramDesignerWidget.prototype._onModifyConnectionEnd = function (params) { var oConnectionDesc = _.extend({}, this.connectionEndIDs[params.id]), nConnectionDesc = _.extend({}, this.connectionEndIDs[params.id]); this.logger.debug('Modifying connection with parameters: ' + JSON.stringify(params)); if (params.endPoint === DiagramDesignerWidgetConstants.CONNECTION_END_SRC) { nConnectionDesc.srcObjId = params.endId; nConnectionDesc.srcSubCompId = params.endSubCompId; } else { nConnectionDesc.dstObjId = params.endId; nConnectionDesc.dstSubCompId = params.endSubCompId; } if (_.isEqual(oConnectionDesc, nConnectionDesc) === false) { this.onModifyConnectionEnd({ id: params.id, old: oConnectionDesc, new: nConnectionDesc }); } }; /* * Called when a new connection is being created in the widget by the user */ DiagramDesignerWidget.prototype.onModifyConnectionEnd = function (params) { this.logger.warn('onModifyConnectionEnd with parameters: ' + JSON.stringify(params)); }; /*************** NO CONNECTION START / END UI CLASS ADD/REMOVE ***********/ DiagramDesignerWidget.prototype._connectionDrawStartAddClass = function () { this.skinParts.$itemsContainer.addClass(CONNECTION_IN_DRAW_CLASS); }; DiagramDesignerWidget.prototype._connectionDrawEndRemoveClass = function () { this.skinParts.$itemsContainer.removeClass(CONNECTION_IN_DRAW_CLASS); }; /**************** ON_END_CONNECTION_DRAW EVENT HANDLER *******************/ DiagramDesignerWidget.prototype._onEndConnectionDraw = function () { var i; this._connectionDrawEndRemoveClass(); i = this.itemIds.length; while (i--) { this.items[this.itemIds[i]].hideEndConnectors(); } i = this.connectionIds.length; while (i--) { this.items[this.connectionIds[i]].hideEndConnectors(); } }; /**************** ON _TART_CONNECTION_CREATE EVENT HANDLER *******************/ DiagramDesignerWidget.prototype._onStartConnectionCreate = function (params) { var srcItemID = params.srcId, srcSubCompID = params.srcSubCompId, availableEndPoints = [], srcItemMetaInfo = this.items[srcItemID]._decoratorInstance ? this.items[srcItemID]._decoratorInstance.getConnectorMetaInfo() : undefined, srcSubCompMetaInfo = srcSubCompID ? this.items[srcItemID]._decoratorInstance.getConnectorMetaInfo(srcSubCompID) : undefined, i, objID, filteredDroppableEnds; //clear out selection this.selectionManager.setSelection([]); //hide all the source connectors on the 'src' item this.items[srcItemID].hideSourceConnectors(); //iterate through all the known items to build the available connection end list i = this.itemIds.length; while (i--) { availableEndPoints.push({ 'dstItemID': this.itemIds[i], 'dstSubCompID': undefined }); } //iterate through all the known items' subcomponents to build the available connection end list for (objID in this._itemSubcomponentsMap) { if (this._itemSubcomponentsMap.hasOwnProperty(objID)) { i = this._itemSubcomponentsMap[objID].length; while (i--) { availableEndPoints.push({ 'dstItemID': objID, 'dstSubCompID': this._itemSubcomponentsMap[objID][i] }); } } } //if connecting to connections are enabled if (this._connectToConnection === true) { //iterate through all the known connections to build the available connection end list i = this.connectionIds.length; while (i--) { availableEndPoints.push({ 'dstItemID': this.connectionIds[i], 'dstSubCompID': undefined }); } } //all available items and their subcomponent is a valid connection-destination by default params.availableConnectionEnds = availableEndPoints; //call optional filtering filteredDroppableEnds = this.onFilterNewConnectionDroppableEnds(params) || []; this.logger.debug('_onStartConnectionCreate filteredDroppableEnds: ' + JSON.stringify(filteredDroppableEnds)); //iterate through all the filteredDroppableEnds and //ask the decorators to display the connectors for the given item/subcomponent var processedIndices = []; var decoratorPackages = []; while (filteredDroppableEnds.length > 0) { i = filteredDroppableEnds.length; objID = filteredDroppableEnds[0].dstItemID; var decoratorUpdatePackage = []; processedIndices = []; while (i--) { if (objID === filteredDroppableEnds[i].dstItemID) { processedIndices.push(i); decoratorUpdatePackage.push(filteredDroppableEnds[i].dstSubCompID); } } decoratorPackages.push([objID, srcItemMetaInfo, srcSubCompMetaInfo, decoratorUpdatePackage]); processedIndices.sort(function (a, b) { return a - b; }); i = processedIndices.length; while (i--) { filteredDroppableEnds.splice(processedIndices[i], 1); } } this.logger.debug('_onStartConnectionCreate decorator update package: ' + JSON.stringify(decoratorPackages)); i = decoratorPackages.length; while (i--) { objID = decoratorPackages[i][0]; this.items[objID].showEndConnectors({ 'srcItemMetaInfo': decoratorPackages[i][1], 'srcSubCompMetaInfo': decoratorPackages[i][2], 'connectors': decoratorPackages[i][3] }); } //add class to items container this._connectionDrawStartAddClass(); }; DiagramDesignerWidget.prototype.onFilterNewConnectionDroppableEnds = function (params) { this.logger.warn('DiagramDesignerWidget.prototype.onFilterNewConnectionDroppableEnds not overridden ' + 'in controller. params: ' + JSON.stringify(params)); return params.availableConnectionEnds; }; /**************** ON_START_CONNECTION_RECONNECT EVENT HANDLER *******************/ DiagramDesignerWidget.prototype._onStartConnectionReconnect = function (params) { var connID = params.connId, srcDragged = params.draggedEnd === DiagramDesignerWidgetConstants.CONNECTION_END_SRC, srcItemID, srcSubCompID, dstItemID, dstSubCompID, availableEndPoints = [], availableSourcePoints = [], srcItemMetaInfo, srcSubCompMetaInfo, dstItemMetaInfo, dstSubCompMetaInfo, i, objID, filteredResult; //don't clear the selection but remove the highlight this.selectionManager.hideSelectionOutline(); //based on 'src' or 'dst' end of the connection is being dragged, //set src/dst values and meta descriptors if (srcDragged === true) { //source end of the connection is dragged //destination is fix if (this.connectionEndIDs[connID]) { dstItemID = this.connectionEndIDs[connID].dstObjId; dstSubCompID = this.connectionEndIDs[connID].dstSubCompId; dstItemMetaInfo = this.items[dstItemID]._decoratorInstance ? this.items[dstItemID]._decoratorInstance.getConnectorMetaInfo() : undefined; dstSubCompMetaInfo = dstSubCompID ? this.items[dstItemID]._decoratorInstance.getConnectorMetaInfo(dstSubCompID) : undefined; } } else { //destination end of the connection is dragged //source is fix if (this.connectionEndIDs[connID]) { srcItemID = this.connectionEndIDs[connID].srcObjId; srcSubCompID = this.connectionEndIDs[connID].srcSubCompId; srcItemMetaInfo = this.items[srcItemID]._decoratorInstance ? this.items[srcItemID]._decoratorInstance.getConnectorMetaInfo() : undefined; srcSubCompMetaInfo = srcSubCompID ? this.items[srcItemID]._decoratorInstance.getConnectorMetaInfo(srcSubCompID) : undefined; } } //iterate through all the known items to build the available connection src/dst list i = this.itemIds.length; while (i--) { if (srcDragged === true) { availableSourcePoints.push({ 'srcItemID': this.itemIds[i], 'srcSubCompID': undefined }); } else { availableEndPoints.push({ 'dstItemID': this.itemIds[i], 'dstSubCompID': undefined }); } } //iterate through all the known items' subcomponents to build the available connection src/dst list for (objID in this._itemSubcomponentsMap) { if (this._itemSubcomponentsMap.hasOwnProperty(objID)) { i = this._itemSubcomponentsMap[objID].length; while (i--) { if (srcDragged === true) { availableSourcePoints.push({ 'srcItemID': objID, 'srcSubCompID': this._itemSubcomponentsMap[objID][i] }); } else { availableEndPoints.push({ 'dstItemID': objID, 'dstSubCompID': this._itemSubcomponentsMap[objID][i] }); } } } } //all available items and their subcomponent is a valid connection destination by default params.availableConnectionEnds = availableEndPoints; params.availableConnectionSources = availableSourcePoints; params.srcItemID = srcItemID; params.srcSubCompID = srcSubCompID; params.dstItemID = dstItemID; params.dstSubCompID = dstSubCompID; filteredResult = this.onFilterReconnectionDroppableEnds(params) || []; this.logger.debug('_onStartConnectionReconnect filteredResult:' + JSON.stringify(filteredResult)); // Iterate through all the filteredResult and ask the decorators to // highlight the given connection endpoint's connector. var processedIndices = []; var decoratorPackages = []; var prefix = srcDragged ? 'src' : 'dst'; while (filteredResult.length > 0) { i = filteredResult.length; objID = filteredResult[0][prefix + 'ItemID']; var decoratorUpdatePackage = []; processedIndices = []; while (i--) { if (objID === filteredResult[i][prefix + 'ItemID']) { processedIndices.push(i); decoratorUpdatePackage.push(filteredResult[i][prefix + 'SubCompID']); } } decoratorPackages.push([objID, srcDragged ? srcItemMetaInfo : dstItemMetaInfo, srcDragged ? srcSubCompMetaInfo : dstSubCompMetaInfo, decoratorUpdatePackage]); processedIndices.sort(function (a, b) { return a - b; }); i = processedIndices.length; while (i--) { filteredResult.splice(processedIndices[i], 1); } } this.logger.debug('_onStartConnectionReconnect decorator update package: ' + JSON.stringify(decoratorPackages)); i = decoratorPackages.length; while (i--) { objID = decoratorPackages[i][0]; if (srcDragged) { this.items[objID].showSourceConnectors({ 'dstItemMetaInfo': decoratorPackages[i][1], 'dstSubCompMetaInfo': decoratorPackages[i][2], 'connectors': decoratorPackages[i][3] }); } else { this.items[objID].showEndConnectors({ 'srcItemMetaInfo': decoratorPackages[i][1], 'srcSubCompMetaInfo': decoratorPackages[i][2], 'connectors': decoratorPackages[i][3] }); } } this._connectionDrawStartAddClass(); }; DiagramDesignerWidget.prototype.onFilterReconnectionDroppableEnds = function (params) { var srcDragged = params.draggedEnd === DiagramDesignerWidgetConstants.CONNECTION_END_SRC; this.logger.warn('DiagramDesignerWidget.prototype.onFilterReconnectionDroppableEnds not overridden in ' + 'controller. params: ' + JSON.stringify(params)); if (srcDragged === true) { return params.availableConnectionSources; } else { return params.availableConnectionEnds; } }; return DiagramDesignerWidget; });