From acb91416172cdc63bc39db2e3e174a5c549bd81c Mon Sep 17 00:00:00 2001 From: lakhoune Date: Wed, 12 Apr 2023 17:04:06 +0200 Subject: [PATCH 1/2] bump version --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index f71bd369..ba8cc408 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@rwth-acis/syncmeta-widgets", - "version": "2.1.2", + "version": "2.1.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@rwth-acis/syncmeta-widgets", - "version": "2.1.2", + "version": "2.1.4", "license": "SEE LICENSE IN LICENSE", "dependencies": { "@jsplumb/browser-ui": "^5.13.2", diff --git a/package.json b/package.json index 1f79f394..5d576cc0 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@rwth-acis/syncmeta-widgets", "description": "SyncMeta is a near real-time collaborative modeling framework. This package only contains the used widgets. If you want to use the SyncMeta app in a docker container, see https://github.com/rwth-acis/syncmeta.", - "version": "2.1.3", + "version": "2.1.4", "author": { "name": "ACIS Group, RWTH Aachen", "email": "acis@dbis.rwth-aachen.de" From abcc4129d1b095a808841ff2d7e5e6fe0cb9356f Mon Sep 17 00:00:00 2001 From: lakhoune Date: Wed, 12 Apr 2023 17:05:03 +0200 Subject: [PATCH 2/2] update build --- build/widgets/partials/activity.widget.js | 58 +- build/widgets/partials/activity.widget.js.map | 2 +- build/widgets/partials/attribute.widget.js | 227 +- .../widgets/partials/attribute.widget.js.map | 2 +- build/widgets/partials/debug.widget.js | 42404 ++++++------- build/widgets/partials/debug.widget.js.map | 2 +- build/widgets/partials/guidance.widget.js | 42 +- build/widgets/partials/heatmap.widget.js | 42 +- build/widgets/partials/imsld.export.widget.js | 40 +- build/widgets/partials/json.export.widget.js | 40 +- build/widgets/partials/main.widget.js | 50221 ++++++++-------- build/widgets/partials/main.widget.js.map | 2 +- build/widgets/partials/palette.widget.js | 52 +- build/widgets/partials/test.widget.js | 40 +- build/widgets/partials/viewcontrol.widget.js | 41612 ++++++------- .../partials/viewcontrol.widget.js.map | 2 +- .../widgets/partials/activity.widget.d.ts | 3 + .../widgets/partials/debug.widget.d.ts | 6 + build/widgets/widget.container.min.js | 29 +- build/widgets/widget.container.min.js.map | 2 +- 20 files changed, 67455 insertions(+), 67373 deletions(-) diff --git a/build/widgets/partials/activity.widget.js b/build/widgets/partials/activity.widget.js index 670402c3..4c6fc1b5 100644 --- a/build/widgets/partials/activity.widget.js +++ b/build/widgets/partials/activity.widget.js @@ -4,26 +4,26 @@ import { LitElement, html, css } from 'lit'; import { Doc } from 'yjs'; import { WebsocketProvider } from 'y-websocket'; -/****************************************************************************** -Copyright (c) Microsoft Corporation. - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. -***************************************************************************** */ - -function __decorate(decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; +/****************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */ + +function __decorate(decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; } /** @@ -24149,7 +24149,7 @@ class IWCW { } } -const activityBoxHtml = "\"\r\n>\r\n
\r\n \r\n \">\r\n \r\n <%= heading %>\r\n <%= timestamp %>\r\n
\r\n
<%= text %>
\r\n\r\n"; // replaced by importmap.plugin.js +const activityBoxHtml = "\"\n>\n
\n \n \">\n \n <%= heading %>\n <%= timestamp %>\n
\n
<%= text %>
\n\n"; // replaced by importmap.plugin.js /** * An abstract user activity issued by one of the users * @class activity_widget.Activity @@ -24892,7 +24892,7 @@ class ReloadWidgetActivity extends Activity { } } -const userBoxHtml = "\"\r\n>\r\n
\r\n
<%= heading %>
\r\n <%= text %> ago\r\n
\r\n \r\n\r\n"; // replaced by importmap.plugin.js +const userBoxHtml = "\"\n>\n
\n
<%= heading %>
\n <%= text %> ago\n
\n \n\n"; // replaced by importmap.plugin.js /** * A user working on the model @@ -26089,6 +26089,10 @@ const SyncMetaWidget = (superClass, widgetName) => { }; let ActivityWidget = class ActivityWidget extends SyncMetaWidget(LitElement, getWidgetTagName(CONFIG.WIDGET.NAME.ACTIVITY)) { + constructor() { + super(...arguments); + this.widgetName = getWidgetTagName(CONFIG.WIDGET.NAME.ACTIVITY); + } firstUpdated(_changedProperties) { super.firstUpdated(_changedProperties); yjsSync() @@ -26133,11 +26137,19 @@ let ActivityWidget = class ActivityWidget extends SyncMetaWidget(LitElement, get console.error("ACTIVITY: Error while waiting for CANVAS: ", err); }); }) - .catch(function (err) { + .catch((err) => { console.error("ACTIVITY: Error while initializing Yjs: " + err); this.showErrorAlert("Cannot connect to Yjs server."); }); } + hideErrorAlert() { + $(this.widgetName).find("#alert-message").text(""); + $(this.widgetName).find("error-alert").hide(); + } + showErrorAlert(message) { + $(this.widgetName).find("#alert-message").text(message); + $(this.widgetName).find("error-alert").show(); + } render() { return html ` - - -
- - -
-
Select a JSON file
- -
- -
-
-
-
- (Meta- or Guidance-)Model -
- - - -
-
-
-
Metamodel (Model Editor only)
- - - -
-
-
-
- Logical Guidancemodel (Model Editor only) -
- - - -
-
-
-
Activity list
- - -
-
- -
-
- - - `; - } - connectedCallback() { - super.connectedCallback(); - init(); - } - disconnectedCallback() { - super.disconnectedCallback(); - } -}; -DebugWidget = __decorate([ - e(getWidgetTagName(CONFIG.WIDGET.NAME.DEBUG)) +const guidance = getGuidanceModeling(); +let DebugWidget = class DebugWidget extends SyncMetaWidget(LitElement, getWidgetTagName(CONFIG.WIDGET.NAME.DEBUG)) { + constructor() { + super(...arguments); + this.widgetName = getWidgetTagName(CONFIG.WIDGET.NAME.DEBUG); + } + firstUpdated(_changedProperties) { + super.firstUpdated(_changedProperties); + this.$spinner = $(getWidgetTagName(CONFIG.WIDGET.NAME.DEBUG)).find("loading-spinner"); + yjsSync() + .then((y) => { + const dataMap = y.getMap("data"); + console.info("DEBUG: Yjs successfully initialized in room " + + window.spaceTitle + + " with y-user-id: " + + y.clientID); + var $deleteMetamodel = $("#delete-meta-model").prop("disabled", false), $exportMetamodel = $("#export-meta-model").prop("disabled", false), $importMetamodel = $("#import-meta-model"), $exportModel = $("#export-model").prop("disabled", false), $importModel = $("#import-model"), $deleteGuidancemodel = $("#delete-guidance-model").prop("disabled", true), $exportGuidancemodel = $("#export-guidance-model").prop("disabled", true), $importGuidancemodel = $("#import-guidance-model"), $fileObject = $("#file-object"), $activityExport = $("#export-activity-list").prop("disabled", false), $activityDelete = $("#delete-activity-list").prop("disabled", false); + $importGuidancemodel.hide(); + $importMetamodel.hide(); + $importModel.hide(); + var getFileContent = function () { + var fileReader, files = $fileObject[0].files, file, deferred = $.Deferred(); + if (!files || files.length === 0) + deferred.reject("No files selected"); + file = files[0]; + fileReader = new FileReader(); + fileReader.onload = function (e) { + var data = e.target.result; + try { + data = JSON.parse(data); + } + catch (e) { + deferred.reject("Incorrect file type. Please make sure that your file is in JSON format"); + } + deferred.resolve(data); + }; + try { + fileReader.readAsText(file); + return deferred.promise(); + } + catch (error) { + return deferred.reject("Incorrect file type. Please make sure that your file is in JSON format"); + } + }; + $deleteGuidancemodel.click(() => { + const retVal = confirm("Are you sure you want to delete the Guidancemodel ?"); + if (retVal) { + this.$spinner.show(); + $exportGuidancemodel.prop("disabled", true); + $deleteGuidancemodel.prop("disabled", true); + const dataMap = y.getMap("data"); + dataMap.set("guidancemodel", null); + this.feedback("The guidance model was deleted. The page will be reloaded."); + location.reload(); + } + }); + $activityDelete.click(() => { + const retVal = confirm("Are you sure you want to delete the activity list ?"); + if (retVal) { + this.$spinner.show(); + const activityMap = y.getMap("activity"); + activityMap.set("log", null); + this.feedback("The activity log has been deleted. The page will be reloaded."); + location.reload(); + } + }); + $exportModel.click(() => { + this.$spinner.show(); + const dataMap = y.getMap("data"); + var link = document.createElement("a"); + link.download = "model.json"; + link.href = + "data:," + + encodeURIComponent(JSON.stringify(dataMap.get("model"), null, 4)); + link.click(); + this.$spinner.hide(); + }); + $exportMetamodel.click(() => { + this.$spinner.show(); + const dataMap = y.getMap("data"); + var link = document.createElement("a"); + link.download = "vls.json"; + link.href = + "data:," + + encodeURIComponent(JSON.stringify(dataMap.get("metamodel"), null, 4)); + link.click(); + this.$spinner.hide(); + }); + $exportGuidancemodel.click(() => { + this.$spinner.show(); + const dataMap = y.getMap("data"); + var link = document.createElement("a"); + link.download = "guidance_model.json"; + link.href = + "data:," + + encodeURI(JSON.stringify(dataMap.get("guidancemodel"), null, 4)); + link.click(); + this.$spinner.hide(); + }); + $activityExport.click(() => { + this.$spinner.show(); + const activityMap = y.getMap("activity"); + var link = document.createElement("a"); + link.download = "activityList.json"; + link.href = + "data:," + + encodeURI(JSON.stringify(activityMap.get("log"), null, 4)); + link.click(); + this.$spinner.hide(); + }); + $importMetamodel.click(() => { + this.$spinner.show(); + $importMetamodel.prop("disabled", true); + getFileContent() + .then((data) => { + const dataMap = y.getMap("data"); + try { + var vls = GenerateViewpointModel(data, y); + if (lodash.keys(vls.nodes).length === 0 && + lodash.keys(vls.edges).length === 0 && + lodash.keys(vls.attributes).length === 0) { + dataMap.set("metamodel", data); + } + else { + dataMap.set("metamodel", vls); + } + dataMap.set("model", null); + this.feedback("Imported Meta Model, the page will reload now"); + setTimeout(() => { + location.reload(); + }, 1000); + } + catch (e) { + this.feedback("Error: " + e); + throw e; + } + $importMetamodel.prop("disabled", false); + this.$spinner.hide(); + }) + .catch((err) => { + console.error(err); + this.feedback("Error: " + err); + $importMetamodel.prop("disabled", false); + this.$spinner.hide(); + }); + }); + $importGuidancemodel.click(() => { + this.$spinner.show(); + getFileContent() + .then((data) => { + const dataMap = y.getMap("data"); + $exportGuidancemodel.prop("disabled", false); + $deleteGuidancemodel.prop("disabled", false); + EntityManagerInstance.setGuidance(guidance); + dataMap.set("guidancemodel", EntityManagerInstance.generateLogicalGuidanceRepresentation(data)); + this.feedback("Done!"); + this.$spinner.hide(); + }) + .catch((e) => { + this.feedback("Error: " + e); + this.$spinner.hide(); + }); + }); + var checkExistence = function () { + if (!dataMap.get("model")) { + $exportModel.prop("disabled", true); + } + else { + $exportModel.prop("disabled", false); + } + if (!dataMap.get("metamodel")) { + $exportMetamodel.prop("disabled", true); + $deleteMetamodel.prop("disabled", true); + } + else { + $exportMetamodel.prop("disabled", false); + $deleteMetamodel.prop("disabled", false); + } + const activityMap = y.getMap("activity"); + if (!activityMap.get("log")) { + $activityExport.prop("disabled", true); + $activityDelete.prop("disabled", true); + } + else { + $activityExport.prop("disabled", false); + $activityDelete.prop("disabled", false); + } + if (!dataMap.get("guidancemodel")) { + $exportGuidancemodel.prop("disabled", true); + $deleteGuidancemodel.prop("disabled", true); + } + else { + $exportGuidancemodel.prop("disabled", false); + $deleteGuidancemodel.prop("disabled", false); + } + }; + checkExistence(); + setInterval(checkExistence, 10000); + this.$spinner.hide(); + $("input:file").change(() => { + $importGuidancemodel.show(); + $importMetamodel.show(); + $importModel.show(); + }); + }) + .catch((err) => { + console.error(err); + this.showErrorAlert("Cannot connect to Yjs server."); + }); + } + hideErrorAlert() { + $(this.widgetName).find("#alert-message").text(""); + $(this.widgetName).find("error-alert").hide(); + } + showErrorAlert(message) { + $(this.widgetName).find("#alert-message").text(message); + $(this.widgetName).find("error-alert").hide(); + } + render() { + return html ` + + + + +
+ + +
+
Select a JSON file
+ +
+ +
+
+
+
+ (Meta- or Guidance-)Model +
+ + + +
+
+
+
Metamodel (Model Editor only)
+ + + +
+
+
+
+ Logical Guidancemodel (Model Editor only) +
+ + + +
+
+
+
Activity list
+ + +
+
+ +
+
+ + + `; + } + importModel() { + this.$spinner.show(); + getFileContent() + .then((data) => { + var initAttributes = function (attrs, map) { + if (attrs.hasOwnProperty("[attributes]")) { + var attr = attrs["[attributes]"].list; + for (var key in attr) { + if (attr.hasOwnProperty(key)) { + if (attr[key].hasOwnProperty("key")) { + var ytext = map.set(attr[key].key.id, new Text()); + ytext.insert(0, attr[key].key.value); + } + else { + var ytext = map.set(attr[key].value.id, new Text()); + ytext.insert(0, attr[key].value.value); + } + } + } + } + else { + for (var key in attrs) { + if (attrs.hasOwnProperty(key)) { + var value = attrs[key].value; + if (!value.hasOwnProperty("option")) { + if (value.value instanceof String) { + var ytext = map.set(value.id, new Text()); + ytext.insert(0, value.value); + } + } + } + } + } + }; + const dataMap = window.y.getMap("data"); + if (guidance.isGuidanceEditor()) { + dataMap.set("guidancemodel", data); + } + else + dataMap.set("model", data); + for (var key in data.nodes) { + if (data.nodes.hasOwnProperty(key)) { + var entity = data.nodes[key]; + const nodesMap = window.y.getMap("nodes"); + nodesMap.set(key, new Map$2()); + var attrs = entity.attributes; + if (entity.hasOwnProperty("label")) { + var ytext = new Text(entity.label.value.id); + nodesMap.set(entity.label.value.id, ytext); + ytext.insert(0, entity.label.value.value); + } + initAttributes(attrs, nodesMap); + } + } + for (var key in data.edges) { + if (data.edges.hasOwnProperty(key)) { + var entity = data.edges[key]; + const edgeMap = window.y.getMap("edges"); + const map = new Map$2(); + edgeMap.set(key, map); + var attrs = entity.attributes; + if (entity.hasOwnProperty("label")) { + const ytext = new Text(); + map.set(entity.label.value.id, ytext); + ytext.insert(0, entity.label.value.value); + } + initAttributes(attrs, map); + } + } + const canvasMap = window.y.getMap("canvas"); + canvasMap.set("ReloadWidgetOperation", "import"); + this.feedback("Imported model successfully! The page will be reloaded."); + location.reload(); + }) + .catch((err) => { + console.error(err); + this.feedback("Error: " + err); + this.$spinner.hide(); + }); + } + deleteModel() { + if (!confirm("Are you sure you want to delete the model ?")) + return; + this.$spinner.show(); + const dataMap = window.y.getMap("data"); + dataMap.set("model", null); + const canvasMap = window.y.getMap("canvas"); + canvasMap.set("ReloadWidgetOperation", "delete"); + this.feedback("The model was deleted. The page will be reloaded."); + location.reload(); + } + deleteMetamodel() { + if (!confirm("Are you sure you want to delete the Metamodel ?")) + return; + this.$spinner.show(); + const dataMap = window.y.getMap("data"); + dataMap.delete("metamodel"); + const canvasMap = window.y.getMap("canvas"); + canvasMap.set("ReloadWidgetOperation", "meta_delete"); + this.feedback("The meta model was deleted. The page will be reloaded."); + location.reload(); + } + feedback(msg) { + alert(msg); + this.$spinner.hide(); + } + connectedCallback() { + super.connectedCallback(); + init(); + } + disconnectedCallback() { + super.disconnectedCallback(); + } +}; +DebugWidget = __decorate([ + e(getWidgetTagName(CONFIG.WIDGET.NAME.DEBUG)) ], DebugWidget); +function getFileContent() { + var fileReader, files = $("#file-object").get(0).files, file, deferred = $.Deferred(); + if (!files || files.length === 0) + deferred.reject("No files selected"); + file = files[0]; + fileReader = new FileReader(); + fileReader.onload = function (e) { + var data = e.target.result.toString(); + try { + data = JSON.parse(data); + } + catch (e) { + deferred.reject("Incorrect file type. Please make sure that your file is in JSON format"); + } + deferred.resolve(data); + }; + try { + fileReader.readAsText(file); + return deferred.promise(); + } + catch (error) { + return deferred.reject("Incorrect file type. Please make sure that your file is in JSON format"); + } +} -/** - * The closed-view-generation(CVG) algorithm - * Searches for neighbors of a referenced object/relationship node and adds the neighbors to the viewpoint model - * @param viewType the view type node - * @constructor - */ -function CVG(viewType) { - //the metamodel as json from the y-space - const dataMap = y.getMap("data"); - var metamodel = dataMap.get("model"); - //initilaize the current metamodel using the graphlib.Graph - var metaGraph = new graphlib.Graph(); - lodash.forEach(metamodel.nodes, function (value, index) { - metaGraph.setNode(index, value); - }); - lodash.forEach(metamodel.edges, function (value, index) { - value.id = index; - metaGraph.setEdge(value.source, value.target, value); - }); - - var originId = viewType - .getAttribute(viewType.getEntityId() + "[target]") - .getValue() - .getValue(); - var neighborsOfOrigin = metaGraph.neighbors(originId); - var canvas = viewType.getCanvas(); - var viewpointName = $("#lblCurrentView").text().replace("View:", ""); - - lodash.forEach(neighborsOfOrigin, function (neighborId) { - var node = metaGraph.node(neighborId); - var newNodeId; - //if neighbor is shape or relation just add it and the corresponding assocation - if ( - node.type === "Node Shape" || - node.type === "Edge Shape" || - node.type === "Relation" - ) { - newNodeId = viewpointName + "_" + neighborId; - if (!EntityManagerInstance.findNode(newNodeId)) - canvas.createNode( - node.type, - node.left, - node.top, - node.width, - node.height, - node.zIndex, - node.containment, - node, - newNodeId - ); - } else if ( - viewType.getType() === "ViewObject" && - node.type === "Relationship" - ) { - var viewtypes = EntityManagerInstance.getNodesByType("ViewRelationship"); - for (var key in viewtypes) { - if (viewtypes.hasOwnProperty(key)) { - var viewType2 = viewtypes[key]; - if ( - viewType2 - .getAttribute(viewType2.getEntityId() + "[target]") - .getValue() - .getValue() === neighborId - ) - newNodeId = viewType2.getEntityId(); - } - } - } else if ( - viewType.getType() === "ViewRelationship" && - node.type === "Object" - ) { - var viewtypes = EntityManagerInstance.getNodesByType("ViewObject"); - for (var key in viewtypes) { - if (viewtypes.hasOwnProperty(key)) { - var viewType2 = viewtypes[key]; - if ( - viewType2 - .getAttribute(viewType2.getEntityId() + "[target]") - .getValue() - .getValue() === neighborId - ) - newNodeId = viewType2.getEntityId(); - } - } - } - if (newNodeId) { - var edge = metaGraph.edge(originId, neighborId); - if (!edge) { - //try the other direction - edge = metaGraph.edge(neighborId, originId); - canvas.createEdge( - edge.type, - newNodeId, - viewType.getEntityId(), - edge, - viewpointName + "_" + edge.id, - viewpointName - ); - } else { - canvas.createEdge( - edge.type, - viewType.getEntityId(), - newNodeId, - edge, - viewpointName + "_" + edge.id, - viewpointName - ); - } - } - }); +/** + * The closed-view-generation(CVG) algorithm + * Searches for neighbors of a referenced object/relationship node and adds the neighbors to the viewpoint model + * @param viewType the view type node + * @constructor + */ +function CVG(viewType) { + //the metamodel as json from the y-space + const dataMap = y.getMap("data"); + var metamodel = dataMap.get("model"); + //initilaize the current metamodel using the graphlib.Graph + var metaGraph = new graphlib.Graph(); + lodash.forEach(metamodel.nodes, function (value, index) { + metaGraph.setNode(index, value); + }); + lodash.forEach(metamodel.edges, function (value, index) { + value.id = index; + metaGraph.setEdge(value.source, value.target, value); + }); + + var originId = viewType + .getAttribute(viewType.getEntityId() + "[target]") + .getValue() + .getValue(); + var neighborsOfOrigin = metaGraph.neighbors(originId); + var canvas = viewType.getCanvas(); + var viewpointName = $("#lblCurrentView").text().replace("View:", ""); + + lodash.forEach(neighborsOfOrigin, function (neighborId) { + var node = metaGraph.node(neighborId); + var newNodeId; + //if neighbor is shape or relation just add it and the corresponding assocation + if ( + node.type === "Node Shape" || + node.type === "Edge Shape" || + node.type === "Relation" + ) { + newNodeId = viewpointName + "_" + neighborId; + if (!EntityManagerInstance.findNode(newNodeId)) + canvas.createNode( + node.type, + node.left, + node.top, + node.width, + node.height, + node.zIndex, + node.containment, + node, + newNodeId + ); + } else if ( + viewType.getType() === "ViewObject" && + node.type === "Relationship" + ) { + var viewtypes = EntityManagerInstance.getNodesByType("ViewRelationship"); + for (var key in viewtypes) { + if (viewtypes.hasOwnProperty(key)) { + var viewType2 = viewtypes[key]; + if ( + viewType2 + .getAttribute(viewType2.getEntityId() + "[target]") + .getValue() + .getValue() === neighborId + ) + newNodeId = viewType2.getEntityId(); + } + } + } else if ( + viewType.getType() === "ViewRelationship" && + node.type === "Object" + ) { + var viewtypes = EntityManagerInstance.getNodesByType("ViewObject"); + for (var key in viewtypes) { + if (viewtypes.hasOwnProperty(key)) { + var viewType2 = viewtypes[key]; + if ( + viewType2 + .getAttribute(viewType2.getEntityId() + "[target]") + .getValue() + .getValue() === neighborId + ) + newNodeId = viewType2.getEntityId(); + } + } + } + if (newNodeId) { + var edge = metaGraph.edge(originId, neighborId); + if (!edge) { + //try the other direction + edge = metaGraph.edge(neighborId, originId); + canvas.createEdge( + edge.type, + newNodeId, + viewType.getEntityId(), + edge, + viewpointName + "_" + edge.id, + viewpointName + ); + } else { + canvas.createEdge( + edge.type, + viewType.getEntityId(), + newNodeId, + edge, + viewpointName + "_" + edge.id, + viewpointName + ); + } + } + }); } var ClosedViewGeneration = /*#__PURE__*/Object.freeze({ diff --git a/build/widgets/partials/debug.widget.js.map b/build/widgets/partials/debug.widget.js.map index dabf9609..9a29eaa6 100644 --- a/build/widgets/partials/debug.widget.js.map +++ b/build/widgets/partials/debug.widget.js.map @@ -1 +1 @@ -{"version":3,"file":"debug.widget.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"} \ No newline at end of file +{"version":3,"file":"debug.widget.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"} \ No newline at end of file diff --git a/build/widgets/partials/guidance.widget.js b/build/widgets/partials/guidance.widget.js index 7e8112e4..25dc91e1 100644 --- a/build/widgets/partials/guidance.widget.js +++ b/build/widgets/partials/guidance.widget.js @@ -5,26 +5,26 @@ import 'https://cdnjs.cloudflare.com/ajax/libs/graphlib/2.1.8/graphlib.min.js'; import { Doc } from 'yjs'; import { WebsocketProvider } from 'y-websocket'; -/****************************************************************************** -Copyright (c) Microsoft Corporation. - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. -***************************************************************************** */ - -function __decorate(decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; +/****************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */ + +function __decorate(decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; } /** @@ -24570,7 +24570,7 @@ class ActivityStatus extends ConcurrentRegion { } } -const guidanceStrategyUiHtml = "
\r\n\t

Available Guidance

\r\n\t
\r\n\t\t
    \r\n\t\t
\r\n\t
\r\n
\r\n
\r\n\t

Activity History

\r\n\t
\r\n\t\t
    \r\n\t\t
\r\n\t
\r\n
"; // replaced by importmap.plugin.js +const guidanceStrategyUiHtml = "
\n\t

Available Guidance

\n\t
\n\t\t
    \n\t\t
\n\t
\n
\n
\n\t

Activity History

\n\t
\n\t\t
    \n\t\t
\n\t
\n
"; // replaced by importmap.plugin.js class CollaborationStrategy extends GuidanceStrategy { diff --git a/build/widgets/partials/heatmap.widget.js b/build/widgets/partials/heatmap.widget.js index 567fe2a2..df6f3360 100644 --- a/build/widgets/partials/heatmap.widget.js +++ b/build/widgets/partials/heatmap.widget.js @@ -4,26 +4,26 @@ import { Doc } from 'yjs'; import { WebsocketProvider } from 'y-websocket'; import 'https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.13.2/jquery-ui.min.js'; -/****************************************************************************** -Copyright (c) Microsoft Corporation. - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. -***************************************************************************** */ - -function __decorate(decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; +/****************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */ + +function __decorate(decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; } /** @@ -6291,7 +6291,7 @@ class IWCW { } } -const heatspotHtml = "
\r\n\t
\r\n\t
\r\n
"; // replaced by importmap.plugin.js +const heatspotHtml = "
\n\t
\n\t
\n
"; // replaced by importmap.plugin.js class Heatspot { constructor(id, x, y, width, height, scaleFactor, color) { diff --git a/build/widgets/partials/imsld.export.widget.js b/build/widgets/partials/imsld.export.widget.js index 10299cc1..73df808d 100644 --- a/build/widgets/partials/imsld.export.widget.js +++ b/build/widgets/partials/imsld.export.widget.js @@ -3,26 +3,26 @@ import 'https://unpkg.com/jquery@3.6.0/dist/jquery.js'; import { Doc } from 'yjs'; import { WebsocketProvider } from 'y-websocket'; -/****************************************************************************** -Copyright (c) Microsoft Corporation. - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. -***************************************************************************** */ - -function __decorate(decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; +/****************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */ + +function __decorate(decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; } /** diff --git a/build/widgets/partials/json.export.widget.js b/build/widgets/partials/json.export.widget.js index f642565e..ca6a4dd0 100644 --- a/build/widgets/partials/json.export.widget.js +++ b/build/widgets/partials/json.export.widget.js @@ -4,26 +4,26 @@ import { Doc } from 'yjs'; import { WebsocketProvider } from 'y-websocket'; import 'https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.13.2/jquery-ui.min.js'; -/****************************************************************************** -Copyright (c) Microsoft Corporation. - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. -***************************************************************************** */ - -function __decorate(decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; +/****************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */ + +function __decorate(decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; } /** diff --git a/build/widgets/partials/main.widget.js b/build/widgets/partials/main.widget.js index bebc5de1..430ac105 100644 --- a/build/widgets/partials/main.widget.js +++ b/build/widgets/partials/main.widget.js @@ -61,7 +61,7 @@ function styleInject(css, ref) { var css_248z$1 = "/* \n Default styles for jsPlumb Toolkit\n\n Copyright 2020 https://jsplumbtoolkit.com\n*/\n\n/* --------------------------------------------------------------------------------------------- */\n/* --- SURFACE WIDGET -------------------------------------------------------------------------- */\n/* --------------------------------------------------------------------------------------------- */\n\n/*\n Assigned to SVG elements for edges. This style allows overlays to paint outside the bounds, and\n for arbitrary stroke widths for connectors.\n */\n.jtk-connector {\n overflow:visible;\n}\n\n/*\n Assigned to every Node managed by an instance of the Toolkit. They are required to be positioned absolute, to\n enable dragging to work properly.\n*/\n.jtk-node {\n position: absolute;\n}\n\n/*\n Assigned to every Group managed by an instance of the Toolkit. They are required to be positioned absolute, to\n enable dragging to work properly. We set overflow:visible on Group elements too, as a drag outside of the bounds\n is automatically reverted anyway, and without overflow:visible you cannot drag a node to some other element. You can\n also drag a node out of the element's viewport and if you drop it you can never get it back.\n*/\n.jtk-group {\n position: absolute;\n overflow: visible;\n}\n\n/*\n Default behaviour for children of a collapsed group - hide them.\n */\n[data-jtk-group].jtk-group-collapsed [data-jtk-managed] {\n display:none;\n}\n\n/*\n\n This is the attribute used to mark which part of a Group DOM element should contain the child Nodes. We mark it\n as having `position:relative` so that the absolute positioned Nodes are drawn correctly.\n*/\n[data-jtk-group-content] {\n position:relative;\n}\n\n/*\n This style was created in response to this Chrome bug:\n http://stackoverflow.com/questions/13758215/artifacts-when-css-scaled-in-chrome\n\n Basically it's about how sometimes there can be artefacts left on screen when the user drags an element. It seems\n the issue has been fixed in more recent versions of Chrome, but the style is left here in case you come across\n the problem.\n*/\n.jtk-node.jtk-drag {\n /*-webkit-backface-visibility: hidden;*/\n}\n\n/*\n Suppresses the pointer events on an element that was created by Katavorio in response to a drag in which the element\n should first be cloned. Having this clone ignore pointer events means there is less chance that any other\n mouse activity (such as click) on the original element will not be consumed by katavorio.\n */\n.katavorio-clone-drag {\n pointer-events:none;\n}\n\n/*\n Assigned to an element that is the `Container` in a `render` call.\n Elements that are acting as Surface widgets should have overflow:hidden set to prevent libs from\n scrolling them during drag (we don't want scrollbars; we have an infinite canvas). Position is set to\n `relative` as this is the parent for nodes, which are positioned absolute (and for absolute positioning\n to work, you need to ensure the parent node has `position:relative`). This style also sets some default\n values for the cursor - using a `grab` cursor where supported.\n*/\n.jtk-surface {\n overflow: hidden !important;\n position: relative;\n cursor: move;\n cursor: -moz-grab;\n cursor: -webkit-grab;\n\n /*\n For IE10+. As discussed on this page:\n\n https://msdn.microsoft.com/en-us/library/ie/jj583807(v=vs.85).aspx\n\n Microsoft have very helpfully implemented default behaviours for a bunch of touch events and\n then consumed the events so you don't have to be bothered by them. They've \"done a lot of research\"\n about this stuff and put together a really great default experience for everyone in the entire world.\n */\n touch-action:none;\n\n /*\n Another Chrome issue that appears to have been fixed in later versions\n http://stackoverflow.com/questions/15464055/css-transition-effect-makes-image-blurry-moves-image-1px-in-chrome\n */\n /*\n -webkit-backface-visibility: hidden;\n -webkit-transform: translateZ(0) scale(1.0, 1.0);\n */\n}\n\n/**\n* Assigned to a Surface element when direct rendering is switched on - no pan or zoom, the underlying canvas scaled to fit its contents at zoom:1.\n */\n.jtk-surface-direct-render {\n overflow:hidden !important;\n}\n\n/*\n Assigned to the surface when it is being panned. The default is to change the cursor (in browsers that support\n a `grabbing` cursor), and to disable text selection.\n*/\n.jtk-surface-panning {\n cursor: -moz-grabbing;\n cursor: -webkit-grabbing;\n -webkit-touch-callout: none;\n -webkit-user-select: none;\n -khtml-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n\n/*\n The work area in a surface renderer.\n*/\n.jtk-surface-canvas {\n overflow: visible !important;\n}\n\n/*\n For IE10+. Discussed above in the .jtk-surface styles. This one is specific to elements that are configured\n to be droppable on a Surface via its `registerDroppableNodes` method.\n*/\n.jtk-surface-droppable-node {\n touch-action:none;\n}\n\n/*\n Assigned to a Surface widget when panning is disabled (and therefore the app is relying on scrollbars when the content overflows).\n*/\n.jtk-surface-nopan {\n overflow: scroll !important;\n cursor:default;\n}\n\n/*\nAssigned to tile images in a tiled background\n*/\n.jtk-surface-tile {\n border:none;\n outline:none;\n margin:0;\n -webkit-transition: opacity .3s ease .15s;\n -moz-transition: opacity .3s ease .15s;\n -o-transition: opacity .3s ease .15s;\n -ms-transition: opacity .3s ease .15s;\n transition: opacity .3s ease .15s;\n}\n\n/*\n Assigned to the element used for node select with the mouse (\"lasso\").\n*/\n.jtk-lasso {\n border: 2px solid rgb(49, 119, 184);\n background-color: WhiteSmoke;\n opacity: 0.5;\n display: none;\n z-index: 20000;\n position: absolute;\n}\n\n/*\n This class is added to the document body on lasso drag start and removed at the end of lasso dragging. Its purpose\n is to switch off text selection on all elements while the user is dragging the lasso.\n*/\n.jtk-lasso-select-defeat * {\n -webkit-touch-callout: none;\n -webkit-user-select: none;\n -khtml-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n\n/**\n Added to the lasso mask when it is operating in 'inverted' mode, ie. the excluded parts of the UI are covered, rather\n than the normal mode in which the selected parts of the UI are covered.\n*/\n.jtk-lasso-mask {\n position:fixed;\n z-index:20000;\n display:none;\n opacity:0.5;\n background-color: #07234E;\n top:0;\n bottom:0;\n left:0;\n right:0;\n}\n\n/*\n Assigned to some element that has been selected (either via lasso or programmatically).\n*/\n.jtk-surface-selected-element {\n border: 2px dotted #c7726c !important;\n}\n\n/*\n Assigned to all pan buttons in a surface widget.\n*/\n.jtk-surface-pan {\n background-color: Azure;\n opacity: 0.4;\n text-align: center;\n cursor: pointer;\n z-index: 2;\n -webkit-transition: background-color 0.15s ease-in;\n -moz-transition: background-color 0.15s ease-in;\n -o-transition: background-color 0.15s ease-in;\n transition: background-color 0.15s ease-in;\n}\n\n/*\n Specific styles for the top and bottom pan buttons.\n Top/bottom are 100% width and 20px high by default\n*/\n.jtk-surface-pan-top, .jtk-surface-pan-bottom {\n width: 100%;\n height: 20px;\n display: flex;\n justify-content: center;\n}\n\n/*\n Hover styles for all pan buttons.\n On hover, change color, background color, font weight and opacity.\n*/\n.jtk-surface-pan-top:hover, .jtk-surface-pan-bottom:hover, .jtk-surface-pan-left:hover, .jtk-surface-pan-right:hover {\n opacity: 0.6;\n background-color: rgb(49, 119, 184);\n color: white;\n font-weight: bold;\n}\n\n/*\n Specific styles for the left and right pan buttons.\n Left/right pan buttons are 100% height and 20px wide\n*/\n.jtk-surface-pan-left, .jtk-surface-pan-right {\n width: 20px;\n height: 100%;\n display: flex;\n align-items: center;\n}\n\n\n/*\n Assigned to a pan button when the user is pressing it.\n*/\n.jtk-surface-pan-active, .jtk-surface-pan-active:hover {\n background-color: #f76258;\n}\n\n/* --------------------------------------------------------------------------------------------- */\n/* --- MINIVIEW WIDGET ------------------------------------------------------------------------- */\n/* --------------------------------------------------------------------------------------------- */\n\n/*\n Assigned to an element that is acting as a Miniview.\n As with Surface, Miniview elements should have overflow:hidden set to prevent\n libs from scrolling them during drag. This style also provides a default width/height for a miniview,\n which you may wish to override.\n*/\n.jtk-miniview {\n overflow: hidden !important;\n width: 125px;\n height: 125px;\n position: relative;\n background-color: transparent;\n border: 2px solid #d4d8dc;\n border-radius: 4px;\n opacity: 0.8;\n}\n\n/*\n Assigned to the element that shows the size of the related viewport in a Miniview widget, and which can be dragged to\n move the surface.\n*/\n.jtk-miniview-panner {\n border: 5px dotted WhiteSmoke;\n opacity: 0.4;\n background-color: rgb(79, 111, 126);\n cursor: move;\n cursor: -moz-grab;\n cursor: -webkit-grab;\n}\n\n/*\n Assigned to the miniview's panner when it is being dragged.\n*/\n.jtk-miniview-panning {\n cursor: -moz-grabbing;\n cursor: -webkit-grabbing;\n}\n\n/*\n Added to all elements displayed in a miniview.\n*/\n.jtk-miniview-element {\n background-color: rgb(96, 122, 134);\n position: absolute;\n}\n\n/*\n Added to Group elements displayed in a miniview\n*/\n.jtk-miniview-group-element {\n background: transparent;\n border: 3px solid black;\n}\n\n/*\n Assigned to the collapse/expand miniview button\n*/\n.jtk-miniview-collapse {\n color: whiteSmoke;\n position: absolute;\n font-size: 18px;\n top: -1px;\n right: 3px;\n cursor: pointer;\n font-weight: bold;\n}\n\n/*\n The '-' symbol when the miniview is expanded\n*/\n.jtk-miniview-collapse:before {\n content: \"\\2012\";\n}\n\n/*\n Assigned to the miniview element when it is collapsed.\n*/\n.jtk-miniview-collapsed {\n background-color: #449ea6;\n border-radius: 4px;\n height: 22px;\n margin-right: 0;\n padding: 4px;\n width: 21px;\n}\n\n/*\n Hide all children of the miniview (except the expand button) when it is collapsed so you don't see anything\n poking through under the + icon.\n*/\n.jtk-miniview-collapsed .jtk-miniview-element, .jtk-miniview-collapsed .jtk-miniview-panner {\n visibility: hidden;\n}\n\n/*\n The '+' symbol when the miniview is collapsed.\n*/\n.jtk-miniview-collapsed .jtk-miniview-collapse:before {\n content: \"+\";\n}\n\n/*\n Hover state for the collapse/expand icon.\n*/\n.jtk-miniview-collapse:hover {\n color: #E4F013;\n}\n\n/* -------------------------------------------------------------------------------------------- */\n/* --- DRAWING TOOLS -------------------------------------------------------------------------- */\n/* -------------------------------------------------------------------------------------------- */\n\n/*\n Assigned to the element that is drawn around some other element when a drawing operation is taking place.\n*/\n.jtk-draw-skeleton {\n position: absolute;\n left: 0;\n right: 0;\n top: 0;\n bottom: 0;\n outline: 2px solid #84acb3;\n opacity: 0.8;\n}\n\n/*\n Assigned to every handle (top left, top right, bottom left, bottom right, center) in a draw skeleton.\n*/\n.jtk-draw-handle {\n position: absolute;\n width: 7px;\n height: 7px;\n background-color: #84acb3;\n}\n\n/*\n Assigned to the top left handle in a draw skeleton\n*/\n.jtk-draw-handle-tl {\n left: 0;\n top: 0;\n cursor: nw-resize;\n}\n\n/*\n Assigned to the top right handle in a draw skeleton\n*/\n.jtk-draw-handle-tr {\n right: 0;\n top: 0;\n cursor: ne-resize;\n}\n\n/*\n Assigned to the bottom left handle in a draw skeleton\n*/\n.jtk-draw-handle-bl {\n left: 0;\n bottom: 0;\n cursor: sw-resize;\n}\n\n/*\n Assigned to the bottom right handle in a draw skeleton\n*/\n.jtk-draw-handle-br {\n bottom: 0;\n right: 0;\n cursor: se-resize;\n}\n\n/*\n Assigned to the center handle in a draw skeleton (the handle by which the element may be dragged). This is\n not visible by defaut; enable if you need it.\n*/\n.jtk-draw-drag {\n display:none;\n position: absolute;\n left: 50%;\n top: 50%;\n margin-left: -10px;\n margin-top: -10px;\n width: 20px;\n height: 20px;\n background-color: #84acb3;\n cursor: move;\n}\n\n/*\n This class is added to the document body on drag resize start and removed at the end of resizing. Its purpose\n is to switch off text selection on all elements while the user is resizing an element.\n*/\n.jtk-drag-select-defeat * {\n -webkit-touch-callout: none;\n -webkit-user-select: none;\n -khtml-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n"; styleInject(css_248z$1); -var css_248z = ".ui-resizable {\r\n /*jquery-ui adds this class to resizable objects. \r\n However, the jsplumb library requires the position to be absolute, otherwise \r\n offsets will be wrong. So we need to override this here.\r\n see https://github.com/rwth-acis/syncmeta/issues/86\r\n */\r\n position: absolute !important;\r\n}\r\n\r\n.button_bar {\r\n width: 50%;\r\n float: left;\r\n display: flex;\r\n flex-wrap: wrap;\r\n}\r\n\r\n.main-container {\r\n position: relative;\r\n}\r\n\r\n.button_bar.left {\r\n text-align: left;\r\n}\r\n\r\n.button_bar.right {\r\n text-align: right;\r\n}\r\n\r\n.node {\r\n z-index: 1;\r\n position: absolute;\r\n overflow: visible;\r\n border: 2px solid transparent;\r\n}\r\n\r\n.trace_awareness {\r\n z-index: 0;\r\n position: absolute;\r\n overflow: visible;\r\n opacity: 0;\r\n pointer-events: none;\r\n}\r\n\r\ndiv.class_node {\r\n height: inherit;\r\n width: inherit;\r\n border: 1px solid #aaa;\r\n border-radius: 1px;\r\n box-shadow: 2px 2px 2px #cccccc;\r\n color: #666 !important;\r\n font-size: 12px;\r\n}\r\n\r\ndiv.default_node {\r\n height: inherit;\r\n width: inherit;\r\n}\r\n\r\ndiv.custom_node {\r\n height: 100%;\r\n width: 100%;\r\n position: relative;\r\n}\r\n\r\ndiv.custom_node .fill_parent {\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n bottom: 0;\r\n right: 0;\r\n width: inherit;\r\n height: inherit;\r\n}\r\n\r\n/*adjust label of custom nodes*/\r\ndiv.custom_node .fill_parent>div {\r\n left: 50%;\r\n top: -8px !important;\r\n -webkit-transform: translateY(-50%) translateX(-50%);\r\n -moz-transform: translateY(-50%) translateX(-50%);\r\n transform: translateY(-50%) translateX(-50%);\r\n pointer-events: none;\r\n overflow-x: auto;\r\n}\r\n\r\ndiv.simple_node {\r\n height: inherit;\r\n width: inherit;\r\n display: table;\r\n}\r\n\r\n.center .single_value_attribute .name {\r\n display: none;\r\n}\r\n\r\n.center .single_value_attribute .value .val {\r\n text-align: center;\r\n}\r\n\r\ndiv.simple_node div.label {\r\n display: table-cell;\r\n text-align: center;\r\n vertical-align: middle;\r\n}\r\n\r\n.box-overlay {\r\n position: absolute;\r\n background-color: #bbbbbb;\r\n opacity: 0;\r\n border-radius: 10px;\r\n cursor: move;\r\n}\r\n\r\n.selected {\r\n border: 3px solid #2bff6e;\r\n}\r\n\r\n#canvas-frame {\r\n overflow: hidden;\r\n width: 100%;\r\n height: 100%;\r\n position: relative;\r\n background-color: #afafaf;\r\n}\r\n\r\n#canvas {\r\n width: 100%;\r\n height: 100%;\r\n max-width: none !important;\r\n max-height: none !important;\r\n border-radius: 6px;\r\n position: relative !important;\r\n /*important because jsplumb will position according to this*/\r\n background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAzsAAASRCAYAAAAQD4IpAAAAAXNSR0IArs4c6QAAAp90RVh0bXhmaWxlACUzQ214ZmlsZSUyMGhvc3QlM0QlMjJ3d3cuZHJhdy5pbyUyMiUyMG1vZGlmaWVkJTNEJTIyMjAyMy0wMy0yMlQxNSUzQTI2JTNBMTUuOTM5WiUyMiUyMGFnZW50JTNEJTIyNS4wJTIwKE1hY2ludG9zaCUzQiUyMEludGVsJTIwTWFjJTIwT1MlMjBYJTIwMTBfMTVfNyklMjBBcHBsZVdlYktpdCUyRjUzNy4zNiUyMChLSFRNTCUyQyUyMGxpa2UlMjBHZWNrbyklMjBDaHJvbWUlMkYxMDQuMC41MTEyLjEwMiUyMFNhZmFyaSUyRjUzNy4zNiUyMiUyMGV0YWclM0QlMjJzeFdZTGwyVUdZTThRQnRLMks2USUyMiUyMHZlcnNpb24lM0QlMjIyMS4wLjEwJTIyJTNFJTNDZGlhZ3JhbSUyMG5hbWUlM0QlMjJQYWdlLTElMjIlMjBpZCUzRCUyMkhWSkRESVpkc0VfN29vQWx0cl9lJTIyJTNFZGRITkVvSWdFQURncCUyQkZ1VUZwbnM3cDA4dENaa1UyWVFkZEJHcTJuVDJjMVk2d0xzM3k3c1B3d2tWYjkyY2xHWDFHQlpUeFNQUk5IeG5rU2kyRWM0VW13alhZRXBUT0thTE5BYmw0d1lUVHB3eWhvZzBLUGFMMXBRaXl3cnFId2dVbm5zQXZMN21qRHJvMHNZUVY1SWUxYWIwWjVUYnJueWVJWE1LV2VPMiUyRmlBMlVxT1JkUE4ybTFWTmg5a2NpWVNCMmlwNmpxVTdEajI4M3ZRdXRPZjdLZmd6bW8lMkZZOEZRN0RzUFV5Q0R4TFpHdyUzRCUzRCUzQyUyRmRpYWdyYW0lM0UlM0MlMkZteGZpbGUlM0WOPzA6AAAgAElEQVR4Xry9y5JlRa4tusKAxoEmpEH+/2/t080ES6qZ7EaBxTW56zEkf2jMqjw3rayIWDGXT3e9Xy69/c///Z/3n/7PT6/X28v/vb/k1/n/4z+v99f7620+oh/F4/E3+Un+9/Y2/6or+A/x+/vr/c1eCS+2L8F7/vrr62vsT9az74yFYn/vb+/6K7x37Nu+M/f4ep8f5v3FacffxhH0y296Zj/N3Jif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);\r\n background-repeat: round;\r\n opacity: 1 !important;\r\n border-radius: 20px;\r\n border: 10px solid #000000;\r\n}\r\n\r\n#canvas.tool-move {\r\n cursor: move !important;\r\n}\r\n\r\n#canvas.tool-move ._jsPlumb_connector {\r\n cursor: pointer !important;\r\n}\r\n\r\n#canvas.tool-node {\r\n cursor: pointer !important;\r\n}\r\n\r\n#canvas.tool-edge {\r\n cursor: default !important;\r\n}\r\n\r\n#canvas.tool-edge.dragging {\r\n cursor: move !important;\r\n}\r\n\r\n#canvas.tool-edge .node,\r\n#canvas.tool-node .node {\r\n opacity: 1;\r\n}\r\n\r\n#canvas.tool-edge .node {\r\n cursor: pointer !important;\r\n}\r\n\r\n#canvas.tool-edge.dragging .node {\r\n cursor: move !important;\r\n}\r\n\r\n#feedback {\r\n margin: 10px;\r\n color: #777777;\r\n}\r\n\r\nbutton[disabled=\"disabled\"],\r\nbutton:disabled {\r\n opacity: 0.5;\r\n}\r\n\r\n._jsPlumb_overlay {\r\n font-size: 12px;\r\n}\r\n\r\n.class_node,\r\n.edge_shape_node,\r\n.node_shape_node,\r\n.enum_node,\r\n.abstract_class_node,\r\n.object_node,\r\n.relation_node {\r\n overflow: hidden;\r\n}\r\n\r\n.class_node .label,\r\n.edge_shape_node .label,\r\n.node_shape_node .label,\r\n.enum_node .label,\r\n.abstract_class_node .label,\r\n.object_node .label,\r\n.relation_node .label {\r\n border-bottom: 1px solid #999999;\r\n}\r\n\r\n.edge_label .single_value_attribute .name,\r\n.label .single_value_attribute .name,\r\n.title .single_value_attribute .name,\r\n.name .single_value_attribute .name {\r\n display: none;\r\n}\r\n\r\n.class_node .label,\r\n.edge_shape_node .label,\r\n.node_shape_node .label,\r\n.enum_node .label,\r\n.abstract_class_node .label,\r\n.object_node .label,\r\n.relation_node .label {\r\n text-align: center;\r\n font-weight: bold;\r\n display: block;\r\n}\r\n\r\n.value input {\r\n border: 0;\r\n background: none;\r\n outline: none;\r\n}\r\n\r\n.edge_label {\r\n width: 200px;\r\n cursor: pointer;\r\n}\r\n\r\n.edge_label.fixed {\r\n background-color: #f5f5f5;\r\n width: auto;\r\n font-size: 14px;\r\n}\r\n\r\n.edge_label .single_value_attribute .value input,\r\n.label .single_value_attribute .value input,\r\n.title .single_value_attribute .value input,\r\n.name .single_value_attribute .value input {\r\n border: 0;\r\n background: none;\r\n width: 100%;\r\n text-align: center;\r\n font-weight: bold;\r\n outline: none;\r\n margin: 2px auto;\r\n display: block;\r\n}\r\n\r\n.edge_label .single_value_attribute .value div.val {\r\n text-align: center;\r\n}\r\n\r\n.attributes .list_attribute .name {\r\n display: none;\r\n}\r\n\r\n.attributes .list_attribute ul.list {\r\n padding: 2px;\r\n margin: 0;\r\n list-style: none;\r\n}\r\n\r\n.attributes .list_attribute ul.list li.key_value_attribute,\r\n.attributes .list_attribute ul.list li.condition_predicate,\r\n.attributes .list_attribute ul.list li.renaming_attr {\r\n overflow: hidden;\r\n}\r\n\r\n.attributes .list_attribute ul.list li.key_value_attribute div.key {\r\n float: left;\r\n width: 50%;\r\n}\r\n\r\n.attributes .list_attribute ul.list li.key_value_attribute div.value {\r\n float: left;\r\n width: 50%;\r\n}\r\n\r\n.attributes .list_attribute ul.list li.condition_predicate div.property,\r\n.attributes .list_attribute ul.list li.condition_predicate div.operator,\r\n.attributes .list_attribute ul.list li.condition_predicate div.val,\r\n.attributes .list_attribute ul.list li.condition_predicate div.operator2 {\r\n float: left;\r\n margin-left: 3px;\r\n}\r\n\r\n.attributes .list_attribute ul.list li.renaming_attr div.val,\r\n.attributes .list_attribute ul.list li.renaming_attr div.ref {\r\n float: left;\r\n margin-left: 3px;\r\n width: 50%;\r\n}\r\n\r\n.attributes .list_attribute ul.list li.renaming_attr div.vis {\r\n float: right;\r\n margin-left: 3px;\r\n}\r\n\r\n.attributes .list_attribute ul.list li.key_value_attribute div.key input,\r\n.attributes .list_attribute ul.list li.key_value_attribute div.value input,\r\n.attributes .list_attribute ul.list li.condition_predicate div.val input,\r\n.attributes .list_attribute ul.list li.renaming_attr div.val input,\r\n.attributes .list_attribute ul.list li.renaming_attr div.ref input {\r\n width: 100%;\r\n border: 0;\r\n outline: none;\r\n background: none;\r\n}\r\n\r\n.attributes .single_value_attribute {\r\n overflow: hidden;\r\n margin-left: 1px;\r\n}\r\n\r\n.attributes .single_value_attribute .name {\r\n width: 50%;\r\n float: left;\r\n margin: 3px 0;\r\n}\r\n\r\n.attributes .single_value_attribute .value {\r\n width: 50%;\r\n float: left;\r\n}\r\n\r\n.attributes .single_value_attribute .value input {\r\n border: 0;\r\n color: #666 !important;\r\n margin: 0;\r\n background: none;\r\n}\r\n\r\n.attributes .value div.val {\r\n text-align: right;\r\n margin: 3px;\r\n}\r\n\r\n.attributes .value input.val {\r\n text-align: right;\r\n float: right;\r\n}\r\n\r\n.size-preview {\r\n z-index: 99;\r\n background-color: #ffffff;\r\n color: #666666;\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n border: 1px dashed black;\r\n}\r\n\r\n#canvas.tool-edge .node.lowlighted,\r\n#canvas.tool-edge .node.target {\r\n opacity: 0.5;\r\n}\r\n\r\n#canvas.tool-edge .node.source {\r\n opacity: 1;\r\n}\r\n\r\n#canvas.tool-edge.dragging .node.source {\r\n opacity: 0.5;\r\n}\r\n\r\n#canvas.tool-edge.dragging .node.source.current,\r\n#canvas.tool-edge.dragging .node.target {\r\n opacity: 1;\r\n}\r\n\r\n#canvas.tool-edge ._jsPlumb_connector {\r\n opacity: 0.5;\r\n}\r\n\r\n#canvas.tool-edge ._jsPlumb_connector._jsPlumb_dragging {\r\n opacity: 1;\r\n}\r\n\r\n/*noinspection CssUnknownProperty*/\r\n.type {\r\n position: absolute;\r\n bottom: 105%;\r\n left: 50%;\r\n transform: translateX(-50%);\r\n -o-transform: translateX(-50%);\r\n -ms-transform: translateX(-50%);\r\n -moz-transform: translateX(-50%);\r\n -webkit-transform: translateX(-50%);\r\n text-align: center;\r\n overflow: visible;\r\n white-space: nowrap;\r\n color: #aaaaaa;\r\n font-size: 0.9em;\r\n}\r\n\r\n#canvas.hide_type .type {\r\n display: none;\r\n}\r\n\r\n#viewsHide {\r\n display: none;\r\n}\r\n\r\n#lblCurrentView {\r\n display: none;\r\n}\r\n\r\n.user_highlight {\r\n position: absolute;\r\n top: 100%;\r\n left: 0;\r\n font-size: 12px;\r\n font-weight: bold;\r\n white-space: nowrap;\r\n text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;\r\n}\r\n\r\n.jtk-endpoint {\r\n z-index: 300000;\r\n}\r\n\r\n.ghost-edge {\r\n opacity: 0.3;\r\n z-index: 30000;\r\n}\r\n\r\n.ghost-edge-overlay {\r\n z-index: 31000;\r\n}\r\n\r\n/* VML colors */\r\n.object {\r\n background-color: rgb(213, 235, 253);\r\n}\r\n\r\n.nodeshape {\r\n background-color: rgba(213, 235, 253, 0.5);\r\n}\r\n\r\n.enum {\r\n background-color: #f9ffc6;\r\n}\r\n\r\n.relationship {\r\n background-color: #ffcece;\r\n}\r\n\r\n.edgeshape {\r\n background-color: rgba(255, 206, 206, 0.5);\r\n}\r\n\r\n.relation {\r\n background-color: #d5f5d5;\r\n}\r\n\r\n.abstractclass {\r\n background-color: #ffffff;\r\n}\r\n\r\n.main-container {\r\n position: relative;\r\n}"; +var css_248z = ".ui-resizable {\n /*jquery-ui adds this class to resizable objects. \n However, the jsplumb library requires the position to be absolute, otherwise \n offsets will be wrong. So we need to override this here.\n see https://github.com/rwth-acis/syncmeta/issues/86\n */\n position: absolute !important;\n}\n\n.button_bar {\n width: 50%;\n float: left;\n display: flex;\n flex-wrap: wrap;\n}\n\n.main-container {\n position: relative;\n}\n\n.button_bar.left {\n text-align: left;\n}\n\n.button_bar.right {\n text-align: right;\n}\n\n.node {\n z-index: 1;\n position: absolute;\n overflow: visible;\n border: 2px solid transparent;\n}\n\n.trace_awareness {\n z-index: 0;\n position: absolute;\n overflow: visible;\n opacity: 0;\n pointer-events: none;\n}\n\ndiv.class_node {\n height: inherit;\n width: inherit;\n border: 1px solid #aaa;\n border-radius: 1px;\n box-shadow: 2px 2px 2px #cccccc;\n color: #666 !important;\n font-size: 12px;\n}\n\ndiv.default_node {\n height: inherit;\n width: inherit;\n}\n\ndiv.custom_node {\n height: 100%;\n width: 100%;\n position: relative;\n}\n\ndiv.custom_node .fill_parent {\n position: absolute;\n top: 0;\n left: 0;\n bottom: 0;\n right: 0;\n width: inherit;\n height: inherit;\n}\n\n/*adjust label of custom nodes*/\ndiv.custom_node .fill_parent>div {\n left: 50%;\n top: -8px !important;\n -webkit-transform: translateY(-50%) translateX(-50%);\n -moz-transform: translateY(-50%) translateX(-50%);\n transform: translateY(-50%) translateX(-50%);\n pointer-events: none;\n overflow-x: auto;\n}\n\ndiv.simple_node {\n height: inherit;\n width: inherit;\n display: table;\n}\n\n.center .single_value_attribute .name {\n display: none;\n}\n\n.center .single_value_attribute .value .val {\n text-align: center;\n}\n\ndiv.simple_node div.label {\n display: table-cell;\n text-align: center;\n vertical-align: middle;\n}\n\n.box-overlay {\n position: absolute;\n background-color: #bbbbbb;\n opacity: 0;\n border-radius: 10px;\n cursor: move;\n}\n\n.selected {\n border: 3px solid #2bff6e;\n}\n\n#canvas-frame {\n overflow: hidden;\n width: 100%;\n height: 100%;\n position: relative;\n background-color: #afafaf;\n}\n\n#canvas {\n width: 100%;\n height: 100%;\n max-width: none !important;\n max-height: none !important;\n border-radius: 6px;\n position: relative !important;\n /*important because jsplumb will position according to this*/\n background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAzsAAASRCAYAAAAQD4IpAAAAAXNSR0IArs4c6QAAAp90RVh0bXhmaWxlACUzQ214ZmlsZSUyMGhvc3QlM0QlMjJ3d3cuZHJhdy5pbyUyMiUyMG1vZGlmaWVkJTNEJTIyMjAyMy0wMy0yMlQxNSUzQTI2JTNBMTUuOTM5WiUyMiUyMGFnZW50JTNEJTIyNS4wJTIwKE1hY2ludG9zaCUzQiUyMEludGVsJTIwTWFjJTIwT1MlMjBYJTIwMTBfMTVfNyklMjBBcHBsZVdlYktpdCUyRjUzNy4zNiUyMChLSFRNTCUyQyUyMGxpa2UlMjBHZWNrbyklMjBDaHJvbWUlMkYxMDQuMC41MTEyLjEwMiUyMFNhZmFyaSUyRjUzNy4zNiUyMiUyMGV0YWclM0QlMjJzeFdZTGwyVUdZTThRQnRLMks2USUyMiUyMHZlcnNpb24lM0QlMjIyMS4wLjEwJTIyJTNFJTNDZGlhZ3JhbSUyMG5hbWUlM0QlMjJQYWdlLTElMjIlMjBpZCUzRCUyMkhWSkRESVpkc0VfN29vQWx0cl9lJTIyJTNFZGRITkVvSWdFQURncCUyQkZ1VUZwbnM3cDA4dENaa1UyWVFkZEJHcTJuVDJjMVk2d0xzM3k3c1B3d2tWYjkyY2xHWDFHQlpUeFNQUk5IeG5rU2kyRWM0VW13alhZRXBUT0thTE5BYmw0d1lUVHB3eWhvZzBLUGFMMXBRaXl3cnFId2dVbm5zQXZMN21qRHJvMHNZUVY1SWUxYWIwWjVUYnJueWVJWE1LV2VPMiUyRmlBMlVxT1JkUE4ybTFWTmg5a2NpWVNCMmlwNmpxVTdEajI4M3ZRdXRPZjdLZmd6bW8lMkZZOEZRN0RzUFV5Q0R4TFpHdyUzRCUzRCUzQyUyRmRpYWdyYW0lM0UlM0MlMkZteGZpbGUlM0WOPzA6AAAgAElEQVR4Xry9y5JlRa4tusKAxoEmpEH+/2/t080ES6qZ7EaBxTW56zEkf2jMqjw3rayIWDGXT3e9Xy69/c///Z/3n/7PT6/X28v/vb/k1/n/4z+v99f7620+oh/F4/E3+Un+9/Y2/6or+A/x+/vr/c1eCS+2L8F7/vrr62vsT9az74yFYn/vb+/6K7x37Nu+M/f4ep8f5v3FacffxhH0y296Zj/N3Jif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);\n background-repeat: round;\n opacity: 1 !important;\n border-radius: 20px;\n border: 10px solid #000000;\n}\n\n#canvas.tool-move {\n cursor: move !important;\n}\n\n#canvas.tool-move ._jsPlumb_connector {\n cursor: pointer !important;\n}\n\n#canvas.tool-node {\n cursor: pointer !important;\n}\n\n#canvas.tool-edge {\n cursor: default !important;\n}\n\n#canvas.tool-edge.dragging {\n cursor: move !important;\n}\n\n#canvas.tool-edge .node,\n#canvas.tool-node .node {\n opacity: 1;\n}\n\n#canvas.tool-edge .node {\n cursor: pointer !important;\n}\n\n#canvas.tool-edge.dragging .node {\n cursor: move !important;\n}\n\n#feedback {\n margin: 10px;\n color: #777777;\n}\n\nbutton[disabled=\"disabled\"],\nbutton:disabled {\n opacity: 0.5;\n}\n\n._jsPlumb_overlay {\n font-size: 12px;\n}\n\n.class_node,\n.edge_shape_node,\n.node_shape_node,\n.enum_node,\n.abstract_class_node,\n.object_node,\n.relation_node {\n overflow: hidden;\n}\n\n.class_node .label,\n.edge_shape_node .label,\n.node_shape_node .label,\n.enum_node .label,\n.abstract_class_node .label,\n.object_node .label,\n.relation_node .label {\n border-bottom: 1px solid #999999;\n}\n\n.edge_label .single_value_attribute .name,\n.label .single_value_attribute .name,\n.title .single_value_attribute .name,\n.name .single_value_attribute .name {\n display: none;\n}\n\n.class_node .label,\n.edge_shape_node .label,\n.node_shape_node .label,\n.enum_node .label,\n.abstract_class_node .label,\n.object_node .label,\n.relation_node .label {\n text-align: center;\n font-weight: bold;\n display: block;\n}\n\n.value input {\n border: 0;\n background: none;\n outline: none;\n}\n\n.edge_label {\n width: 200px;\n cursor: pointer;\n}\n\n.edge_label.fixed {\n background-color: #f5f5f5;\n width: auto;\n font-size: 14px;\n}\n\n.edge_label .single_value_attribute .value input,\n.label .single_value_attribute .value input,\n.title .single_value_attribute .value input,\n.name .single_value_attribute .value input {\n border: 0;\n background: none;\n width: 100%;\n text-align: center;\n font-weight: bold;\n outline: none;\n margin: 2px auto;\n display: block;\n}\n\n.edge_label .single_value_attribute .value div.val {\n text-align: center;\n}\n\n.attributes .list_attribute .name {\n display: none;\n}\n\n.attributes .list_attribute ul.list {\n padding: 2px;\n margin: 0;\n list-style: none;\n}\n\n.attributes .list_attribute ul.list li.key_value_attribute,\n.attributes .list_attribute ul.list li.condition_predicate,\n.attributes .list_attribute ul.list li.renaming_attr {\n overflow: hidden;\n}\n\n.attributes .list_attribute ul.list li.key_value_attribute div.key {\n float: left;\n width: 50%;\n}\n\n.attributes .list_attribute ul.list li.key_value_attribute div.value {\n float: left;\n width: 50%;\n}\n\n.attributes .list_attribute ul.list li.condition_predicate div.property,\n.attributes .list_attribute ul.list li.condition_predicate div.operator,\n.attributes .list_attribute ul.list li.condition_predicate div.val,\n.attributes .list_attribute ul.list li.condition_predicate div.operator2 {\n float: left;\n margin-left: 3px;\n}\n\n.attributes .list_attribute ul.list li.renaming_attr div.val,\n.attributes .list_attribute ul.list li.renaming_attr div.ref {\n float: left;\n margin-left: 3px;\n width: 50%;\n}\n\n.attributes .list_attribute ul.list li.renaming_attr div.vis {\n float: right;\n margin-left: 3px;\n}\n\n.attributes .list_attribute ul.list li.key_value_attribute div.key input,\n.attributes .list_attribute ul.list li.key_value_attribute div.value input,\n.attributes .list_attribute ul.list li.condition_predicate div.val input,\n.attributes .list_attribute ul.list li.renaming_attr div.val input,\n.attributes .list_attribute ul.list li.renaming_attr div.ref input {\n width: 100%;\n border: 0;\n outline: none;\n background: none;\n}\n\n.attributes .single_value_attribute {\n overflow: hidden;\n margin-left: 1px;\n}\n\n.attributes .single_value_attribute .name {\n width: 50%;\n float: left;\n margin: 3px 0;\n}\n\n.attributes .single_value_attribute .value {\n width: 50%;\n float: left;\n}\n\n.attributes .single_value_attribute .value input {\n border: 0;\n color: #666 !important;\n margin: 0;\n background: none;\n}\n\n.attributes .value div.val {\n text-align: right;\n margin: 3px;\n}\n\n.attributes .value input.val {\n text-align: right;\n float: right;\n}\n\n.size-preview {\n z-index: 99;\n background-color: #ffffff;\n color: #666666;\n position: absolute;\n top: 0;\n left: 0;\n border: 1px dashed black;\n}\n\n#canvas.tool-edge .node.lowlighted,\n#canvas.tool-edge .node.target {\n opacity: 0.5;\n}\n\n#canvas.tool-edge .node.source {\n opacity: 1;\n}\n\n#canvas.tool-edge.dragging .node.source {\n opacity: 0.5;\n}\n\n#canvas.tool-edge.dragging .node.source.current,\n#canvas.tool-edge.dragging .node.target {\n opacity: 1;\n}\n\n#canvas.tool-edge ._jsPlumb_connector {\n opacity: 0.5;\n}\n\n#canvas.tool-edge ._jsPlumb_connector._jsPlumb_dragging {\n opacity: 1;\n}\n\n/*noinspection CssUnknownProperty*/\n.type {\n position: absolute;\n bottom: 105%;\n left: 50%;\n transform: translateX(-50%);\n -o-transform: translateX(-50%);\n -ms-transform: translateX(-50%);\n -moz-transform: translateX(-50%);\n -webkit-transform: translateX(-50%);\n text-align: center;\n overflow: visible;\n white-space: nowrap;\n color: #aaaaaa;\n font-size: 0.9em;\n}\n\n#canvas.hide_type .type {\n display: none;\n}\n\n#viewsHide {\n display: none;\n}\n\n#lblCurrentView {\n display: none;\n}\n\n.user_highlight {\n position: absolute;\n top: 100%;\n left: 0;\n font-size: 12px;\n font-weight: bold;\n white-space: nowrap;\n text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;\n}\n\n.jtk-endpoint {\n z-index: 300000;\n}\n\n.ghost-edge {\n opacity: 0.3;\n z-index: 30000;\n}\n\n.ghost-edge-overlay {\n z-index: 31000;\n}\n\n/* VML colors */\n.object {\n background-color: rgb(213, 235, 253);\n}\n\n.nodeshape {\n background-color: rgba(213, 235, 253, 0.5);\n}\n\n.enum {\n background-color: #f9ffc6;\n}\n\n.relationship {\n background-color: #ffcece;\n}\n\n.edgeshape {\n background-color: rgba(255, 206, 206, 0.5);\n}\n\n.relation {\n background-color: #d5f5d5;\n}\n\n.abstractclass {\n background-color: #ffffff;\n}\n\n.main-container {\n position: relative;\n}"; styleInject(css_248z); /** @@ -33504,25138 +33504,25161 @@ if (symIterator) { lodash.prototype[symIterator] = seq.toIterator; } -/** - * Function to check if the event was triggered by the current user - * @param {YEvent} yEvent YEvent - * @returns {boolean} true if the event was triggered by the current user - */ -function eventWasTriggeredByMe(yEvent) { - const array = Array.from(yEvent.changes.keys.keys()); - if (!array) return false; - const modifiedByKey = array.find((key) => key === "modifiedBy"); - if ( - modifiedByKey && - yEvent.currentTarget.get(modifiedByKey) === window.y.clientID - ) - // modified by us - return true; - return false; -} - -const CONFIG = { - TEST: { - USER: "Luigi Test", - EMAIL: "luigi.test05@gmail.com", - CANVAS: false, - ATTRIBUTE: false, - PALETTE: false, - ACTIVITY: false, - }, - LAYER: { - META: "META", - MODEL: "MODEL", - }, - WIDGET: { - NAME: { - MAIN: "Canvas", - PALETTE: "Palette", - ATTRIBUTE: "Property Browser", - ACTIVITY: "User Activity", - GUIDANCE: "Guidance", - HEATMAP: "Heatmap", - METADATA: "METADATA", - OPENAPI: "Metadata Widget", - DEBUG: "Debug", - IMSLD_EXPORT: "IMSLD Export", - JSON_EXPORT: "JSON Export", - VIEWCONTROL: "View Control", - }, - }, - ENTITY: { - NODE: "node", - EDGE: "edge", - ATTR: "attr", - VAL: "val", - }, - IWC: { - FLAG: { - PUBLISH_GLOBAL: "PUBLISH_GLOBAL", - PUBLISH_LOCAL: "PUBLISH_LOCAL", - }, - ACTION: { - SYNC: "ACTION_SYNC", - DATA: "ACTION_DATA", - DATA_ARRAY: "ACTION_DATA_ARRAY", - }, - POSITION: { - NODE: { - ADD: 0, - DEL: 0, - POS: 1, - Z: 2, - DIM: 3, - }, - EDGE: { - ADD: 0, - DEL: 0, - MOV: 1, - }, - ATTR: { - ADD: 0, - DEL: 0, - }, - }, - }, - OPERATION: { - TYPE: { - INSERT: "insert", - UPDATE: "update", - DELETE: "delete", - }, - }, - ACTIVITY: { - TYPE: { - NODEADD: 0, - EDGEADD: 1, - NODEDEL: 2, - EDGEDEL: 3, - NODEATTRCHANGE: 4, - }, - }, - DATA: { - RELATION: { - GLOBAL: { - MAIN: { - MAIN: { - OPERATION: "MAIN2MAIN4OPERATION", - }, - }, - }, - LOCAL: { - PALETTE: { - MAIN: { - TOOLSELECTION: "PALETTE2MAIN4TOOLSELECTION", - }, - }, - MAIN: { - ATTRIBUTE: { - NODESELECTION: "MAIN2ATTRIBUTE4NODESELECTION", - NODEADDITION: "MAIN2ATTRIBUTE4NODEADDITION", - ATTRIBUTECHANGE: "MAIN2ATTRIBUTE4ATTRIBUTECHANGE", - }, - ACTIVITY: { - NEWACTIVITY: "MAIN2ACTIVITY4NEWACTIVITY", - }, - PALETTE: { - TOOLSELECTION: "MAIN2PALETTE4TOOLSELECTION", - }, - }, - ATTRIBUTE: { - MAIN: { - ATTRIBUTECHANGE: "ATTRIBUTE2MAIN4ATTRIBUTECHANGE", - }, - }, - }, - }, - }, - NS: { - PERSON: { - TITLE: "http://purl.org/dc/terms/title", - JABBERID: "http://xmlns.com/foaf/0.1/jabberID", - MBOX: "http://xmlns.com/foaf/0.1/mbox", - }, - MY: { - MODEL: "my:ns:model", - METAMODEL: "my:ns:metamodel", - INSTANCE: "my:ns:instance", - VIEWPOINT: "my:ns:viewpoint", - VIEW: "my:ns:view", - COPY: "my:ns:copy", - GUIDANCEMODEL: "my:ns:guidancemodel", - METAMODELPREVIEW: "my:ns:metamodelpreview", - GUIDANCEMETAMODEL: "my:ns:guidancemetamodel", - LOGICALGUIDANCEREPRESENTATION: "my:ns:logicalguidancerepresentation", - }, - }, -}; - - /** - * Gets the html tag name of a widget. - * Use this function to get the tag name of a or your own widget. - * @example getWidgetTagName("My Widget") // returns "my-widget-widget" - * @param {*} name name of the widget - * @returns {string} tag name of the widget - */ -function getWidgetTagName(name) { - if (!name) return; - if ( - !Object.values(CONFIG.WIDGET.NAME).some( - (n) => n.toLocaleLowerCase() === name.toLocaleLowerCase() - ) - ) { - console.warn( - `Widget name ${name} is not defined in config.js. Add it to the CONFIG.WIDGET.NAME object.` - ); - } - let widgetName = name; - widgetName = widgetName.replace(/\s+/g, "-"); - return `${widgetName}-widget`.toLowerCase(); -} - -function getQuerySelectorFromNode(node) { - if (node instanceof jQuery) { - node = node.get(0); - } - if (node.id) { - return `[id="${node.id}"]`; - // return `#${node.id}`; // This is not working since the implementation of querySelectorAll disallows getting elements by id with a hash if the id starts with a number - } - if (node.className) { - return `.${node.className}`; - } - return null; -} - -/** - * Namespace for operations - * @namespace operations - */ - -/** - * Operation - * @class operations.Operation - * @memberof operations - * @constructor - */ -class Operation { - constructor() {} -} - -/** - * Namespace for ot operations - * @namespace operations.ot - */ - - /** - * OTOperation - * @class operations.ot.OTOperation - * @memberof operations.ot - * @constructor - * @param {string} name Name of operation - * @param {string} value Value of operation - * @param {string} type Type of operation - * @param {number} position Position of operation - */ - class OTOperation extends Operation { - constructor(name, value, type, position) { - super(); - /** - * JabberId of the user who issued this activity - * @type {string} - * @private - */ - var _sender = null; - - - /** - * Operation details - * @type {{name: string, value: string, type: string, position: number}} - * @private - */ - var _operation = { - name: name, - value: value, - type: type, - position: position - }; - - /** - * Set JabberId of the user who issued this activity - * @param sender - */ - this.setSender = function (sender) { - _sender = sender; - }; - - /** - * Get JabberId of the user who issued this activity - */ - this.getSender = function () { - return _sender; - }; - - /** - * Get name of operation - * @returns {string} - */ - this.getName = function () { - return _operation.name; - }; - - /** - * Get value of operation - * @returns {string} - */ - this.getValue = function () { - return _operation.value; - }; - - /** - * Get type of operation - * @returns {string} - */ - this.getType = function () { - return _operation.type; - }; - - /** - * Get position of operation - * @returns {number} - */ - this.getPosition = function () { - return _operation.position; - }; - - /** - * Get JSON Representation of operation - * @returns {{type: string, data: string}} - */ - this.getOperationObject = function () { - return _operation; - }; - } -} - -/** - * Namespace for non ot operations - * @namespace operations.non_ot - */ - - NonOTOperation.prototype = new Operation(); - NonOTOperation.prototype.constructor = NonOTOperation; - /** - * NonOTOperation - * @class operations.non_ot.NonOTOperation - * @memberof operations.non_ot - * @constructor - * @param {string} type Type of Operation - * @param {string} data Additional data for operation - */ - function NonOTOperation(type,data){ - /** - * JabberId of the user who issued this activity - * @type {string} - * @private - */ - var _sender = null; - - /** - * Operation details - * @type {{type: string, data: string}} - * @private - */ - var _operation = { - type: type, - data: data - }; - - /** - * Set JabberId of the user who issued this activity - * @param sender - */ - this.setSender = function(sender){ - _sender = sender; - }; - - /** - * Get JabberId of the user who issued this activity - * @returns {string} - */ - this.getSender = function(){ - return _sender; - }; - - /** - * Get type of Operation - * @returns {string} - */ - this.getType = function(){ - //noinspection JSAccessibilityCheck - return _operation.type; - }; - - /** - * Get additional data for operation - * @returns {string} - */ - this.getData = function(){ - return _operation.data; - }; - - /** - * Get JSON Representation of operation - * @returns {{type: string, data: string}} - */ - this.getOperationObject = function(){ - return _operation; - }; - } - -/** - * EntityOperation - * @class operations.ot.EntityOperation - * @memberof operations.ot - * @param {string} operationType Type of operation - * @param {string} entityId Entity id of the entity this activity works on - * @param {string} entityType Type of the entity this activity works on - * @constructor - */ -class EntityOperation { - static TYPES = { - AttributeAddOperation: "AttributeAddOperation", - AttributeDeleteOperation: "AttributeDeleteOperation", - EdgeAddOperation: "EdgeAddOperation", - EdgeDeleteOperation: "EdgeDeleteOperation", - NodeAddOperation: "NodeAddOperation", - NodeDeleteOperation: "NodeDeleteOperation", - NodeMoveOperation: "NodeMoveOperation", - NodeMoveZOperation: "NodeMoveZOperation", - NodeResizeOperation: "NodeResizeOperation", - ValueChangeOperation: "ValueChangeOperation", - }; - getOperationType; - setOTOperation; - _getOTOperation; - getEntityId; - getEntityType; - adjust; - inverse; - toJSON; - - triggeredBy; - constructor(operationType, entityId, entityType) { - this.triggeredBy = window.y.clientID; - - /** - * Type of operation - * @type {string} - * @private - */ - var _operationType = operationType; - - /** - * Corresponding OtOperation - * @type {operations.ot.OTOperation} - * @private - */ - var _otOperation = null; - - /** - * Entity id of the entity this activity works on - * @type {string} - * @private - */ - var _entityId = entityId; - - /** - * Type of the entity this activity works on - * @type {string} - * @private - */ - var _entityType = entityType; - - /** - * Get type of operation - * @returns {string} - */ - this.getOperationType = function () { - return _operationType; - }; - - /** - * Set corresponding ot operation - * @param {operations.ot.OTOperation} otOperation - */ - this.setOTOperation = function (otOperation) { - _otOperation = otOperation; - }; - - /** - * Get corresponding ot operation - * @returns {operations.ot.OTOperation} - * @private - */ - this._getOTOperation = function () { - return _otOperation; - }; - - /** - * Get entity id of the entity this activity works onf - * @returns {string} - */ - this.getEntityId = function () { - return _entityId; - }; - - //noinspection JSUnusedGlobalSymbols - /** - * Get type of the entity this activity works on - * @returns {string} - */ - this.getEntityType = function () { - return _entityType; - }; - - /** - * Adjust the passed operation in the history of operation - * when this operation is applied remotely after the passed operation - * on an graph instance stored in the passed EntityManager - * @param {canvas_widget.EntityManager} EntityManager - * @param {EntityOperation} operation Remote operation - * @returns {EntityOperation} - */ - this.adjust = function (EntityManager, operation) { - return operation; - }; - - /** - * Compute the inverse of the operation - * @returns {operations.ot.EntityOperation} - */ - this.inverse = function () { - return this; - }; - } - //noinspection JSAccessibilityCheck - /** - * Get corresponding ot operation - * @returns {operations.ot.OTOperation} - */ - getOTOperation() { - return this._getOTOperation(); - } -} - -/** - * NodeDeleteOperation - * @class operations.ot.NodeDeleteOperation - * @memberof operations.ot - * @extends operations.ot.EntityOperation - * @param {String} entityId Entity id of the entity this activity works on - * @param {String} type Type of node to delete - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {number} zIndex Position of node on z-axis - * @param {boolean} containment containment - * @param {object} json JSON representation of node - * @constructor - */ -class NodeDeleteOperation extends EntityOperation { - static TYPE = "NodeDeleteOperation"; - getType; - getLeft; - getTop; - getWidth; - getHeight; - getZIndex; - getContainment; - getJSON; - constructor( - entityId, - type, - left, - top, - width, - height, - zIndex, - containment, - json - ) { - super( - EntityOperation.TYPES.NodeDeleteOperation, - entityId, - CONFIG.ENTITY.NODE - ); - var that = this; - - /** - * Type of node to add - * @type {String} - * @private - */ - var _type = type; - - /** - * x-coordinate of node position - * @type {number} - * @private - */ - var _left = left; - - /** - * y-coordinate of node position - * @type {number} - * @private - */ - var _top = top; - - /** - * Width of node - * @type {number} - * @private - */ - var _width = width; - - /** - * Height of node - * @type {number} - * @private - */ - var _height = height; - - /** - * Position of node on z-axis - * @type {number} - * @private - */ - var _zIndex = zIndex; - - /** - * is containment type - * @type {boolean} - * @private - */ - var _containment = containment; - - /** - * JSON representation of node - * @type {Object} - * @private - */ - var _json = json; - - /** - * Create OTOperation for operation - * @returns {operations.ot.OTOperation} - */ - var createOTOperation = function () { - return new OTOperation( - CONFIG.ENTITY.NODE + ":" + that.getEntityId(), - JSON.stringify({ - type: _type, - left: _left, - top: _top, - width: _width, - height: _height, - zIndex: _zIndex, - containment: _containment, - json: _json, - }), - CONFIG.OPERATION.TYPE.UPDATE, - CONFIG.IWC.POSITION.NODE.DEL - ); - }; - - /** - * Get type of node to add - * @returns {String} - */ - this.getType = function () { - return _type; - }; - - /** - * Get x-coordinate of node position - * @returns {number} - */ - this.getLeft = function () { - return _left; - }; - - /** - * Get y-coordinate of node position - * @returns {number} - */ - this.getTop = function () { - return _top; - }; - - /** - * Get width of node - * @returns {number} - */ - this.getWidth = function () { - return _width; - }; - - /** - * Get height of node - * @returns {number} - */ - this.getHeight = function () { - return _height; - }; - - /** - * Get position of node on z-axis - * @returns {number} - */ - this.getZIndex = function () { - return _zIndex; - }; - - /** - * is containment type - * @returns {boolean} - */ - this.getContainment = function () { - return _containment; - }; - - /** - * Get JSON representation of node - * @return {Object} - */ - this.getJSON = function () { - return _json; - }; - - /** - * Get corresponding ot operation - * @returns {operations.ot.OTOperation} - * @private - */ - this.getOTOperation = function () { - var otOperation = EntityOperation.prototype.getOTOperation.call(this); - if (otOperation === null) { - otOperation = createOTOperation(); - this.setOTOperation(otOperation); - } - return otOperation; - }; - - /** - * Adjust the passed operation in the history of operation - * when this operation is applied remotely after the passed operation - * on an graph instance stored in the passed EntityManager - * @param {canvas_widget.EntityManager} EntityManager - * @param {EntityOperation} operation Remote operation - * @returns {EntityOperation} - */ - this.adjust = function (EntityManager, operation) { - var edge; - switch (operation.getOperationType()) { - case EntityOperation.TYPES.AttributeAddOperation: - case EntityOperation.TYPES.AttributeDeleteOperation: - edge = EntityManager.findEdge(operation.getRootSubjectEntityId()); - if ( - edge && - (edge.getSource().getEntityId() === this.getEntityId() || - edge.getTarget().getEntityId() === this.getEntityId()) - ) { - return null; - } - if (this.getEntityId() === operation.getRootSubjectEntityId()) { - return null; - } - break; - case EntityOperation.TYPES.EdgeAddOperation: - case EntityOperation.TYPES.EdgeDeleteOperation: - edge = EntityManager.findEdge(operation.getEntityId()); - if ( - edge && - (edge.getSource().getEntityId() === this.getEntityId() || - edge.getTarget().getEntityId() === this.getEntityId()) - ) { - return null; - } - break; - case EntityOperation.TYPES.NodeAddOperation: - case EntityOperation.TYPES.NodeDeleteOperation: - case EntityOperation.TYPES.NodeMoveOperation: - case EntityOperation.TYPES.NodeResizeOperation: - if (this.getEntityId() === operation.getEntityId()) { - return null; - } - break; - case EntityOperation.TYPES.ValueChangeOperation: - edge = EntityManager.findEdge(operation.getRootSubjectEntityId()); - if ( - edge && - (edge.getSource().getEntityId() === this.getEntityId() || - edge.getTarget().getEntityId() === this.getEntityId()) - ) { - return null; - } - if (operation.getRootSubjectEntityId() === this.getEntityId()) { - return null; - } - break; - } - - return operation; - }; - - /** - * Compute the inverse of the operation - * @returns {operations.ot.NodeAddOperation} - */ - this.inverse = function () { - return new NodeAddOperation( - this.getEntityId(), - this.getType(), - this.getLeft(), - this.getTop(), - this.getWidth(), - this.getHeight(), - this.getZIndex(), - this.getContainment(), - this.getContainment(), - json - ); - }; - } - static getOperationDescription(nodeType, nodeLabel, viewId) { - if (!nodeLabel && !viewId) { - return "..deleted " + nodeType; - } else if (!viewId) { - return "..deleted " + nodeType + " " + nodeLabel; - } else - return "..deleted " + nodeType + " " + nodeLabel + " in View " + viewId; - } - toJSON = function () { - return { - id: this.getEntityId(), - type: this.getType(), - left: this.getLeft(), - top: this.getTop(), - width: this.getWidth(), - height: this.getHeight(), - zIndex: this.getZIndex(), - containment: this.getContainment(), - json: this.getJSON(), - }; - }; -} - -class NodeAddOperation extends EntityOperation { - static TYPE = "NodeAddOperation"; - getType; - getOriginType; - getLeft; - getTop; - getWidth; - getHeight; - getZIndex; - getContainment; - getJSON; - getViewId; - getJabberId; - getDefaultLabel; - getDefaultAttributeValues; - toJSON; - - constructor( - entityId, - type, - left, - top, - width, - height, - zIndex, - containment, - json = null, - viewId = null, - oType = null, - jabberId = null, - defaultLabel = null, - defaultAttributeValues = null - ) { - super(EntityOperation.TYPES.NodeAddOperation, entityId, CONFIG.ENTITY.NODE); - var that = this; - - /** - * the identifier of the view - * @type {string} - * @private - */ - var _viewId = viewId; - - /** - * the jabberId of the user - * @type {string} - * @private - */ - var _jabberId = jabberId; - - var _oType = oType; - - /** - * Type of node to add - * @type {String} - * @private - */ - var _type = type; - - /** - * x-coordinate of node position - * @type {number} - * @private - */ - var _left = left; - - /** - * y-coordinate of node position - * @type {number} - * @private - */ - var _top = top; - - /** - * Width of node - * @type {number} - * @private - */ - var _width = width; - - /** - * Height of node - * @type {number} - * @private - */ - var _height = height; - - /** - * Position of node on z-axis - * @type {number} - * @private - */ - var _zIndex = zIndex; - - /** - * is containment type - * @type {boolean} - * @private - */ - var _containment = containment; - - /** - * JSON representation of node - * @type {Object} - * @private - */ - var _json = json; - - /** - * Default label of node - * @type {String} - * @private - */ - var _defaultLabel = defaultLabel; - - /** - * May be used to set default values for node attributes. - */ - var _defaultAttributeValues = defaultAttributeValues; - - /** - * Create OTOperation for operation - * @returns {operations.ot.OTOperation} - */ - var createOTOperation = function () { - return new OTOperation( - CONFIG.ENTITY.NODE + ":" + that.getEntityId(), - JSON.stringify({ - type: _type, - left: _left, - top: _top, - width: _width, - height: _height, - zIndex: _zIndex, - containment: _containment, - json: _json, - viewId: _viewId, - oType: _oType, - jabberId: _jabberId, - }), - CONFIG.OPERATION.TYPE.INSERT, - CONFIG.IWC.POSITION.NODE.ADD - ); - }; - - /** - * Get type of node to add - * @returns {String} - */ - this.getType = function () { - return _type; - }; - - this.getOriginType = function () { - return _oType; - }; - - /** - * Get x-coordinate of node position - * @returns {number} - */ - this.getLeft = function () { - return _left; - }; - - /** - * Get y-coordinate of node position - * @returns {number} - */ - this.getTop = function () { - return _top; - }; - - /** - * Get width of node - * @returns {number} - */ - this.getWidth = function () { - return _width; - }; - - /** - * Get height of node - * @returns {number} - */ - this.getHeight = function () { - return _height; - }; - - /** - * Get position of node on z-axis - * @returns {number} - */ - this.getZIndex = function () { - return _zIndex; - }; - - /** - * Get containment - * @returns {boolean} - */ - this.getContainment = function () { - return _containment; - }; - - /** - * Get JSON representation of node - * @return {Object} - */ - this.getJSON = function () { - return _json; - }; - - /** - * the identifier of the view - * @returns {string} - */ - this.getViewId = function () { - return _viewId; - }; - - /** - * Get the jabberid - * @returns {string} - */ - this.getJabberId = function () { - return _jabberId; - }; - - /** - * Get default label of node - * @returns {string} - */ - this.getDefaultLabel = function () { - return _defaultLabel; - }; - - /** - * Get default values for node attributes. - * @returns {*} - */ - this.getDefaultAttributeValues = function () { - return _defaultAttributeValues; - }; - - /** - * Get corresponding ot operation - * @returns {operations.ot.OTOperation} - * @private - */ - this.getOTOperation = function () { - var otOperation = EntityOperation.prototype.getOTOperation.call(this); - if (otOperation === null) { - otOperation = createOTOperation(); - this.setOTOperation(otOperation); - } - return otOperation; - }; - - /** - * Adjust the passed operation in the history of operation - * when this operation is applied remotely after the passed operation - * on an graph instance stored in the passed EntityManager - * @param {canvas_widget.EntityManager} EntityManager - * @param {EntityOperation} operation Remote operation - * @returns {EntityOperation} - */ - this.adjust = function (EntityManager, operation) { - return operation; - }; - - /** - * Compute the inverse of the operation - * @returns {NodeDeleteOperation} - */ - this.inverse = function () { - return new NodeDeleteOperation( - this.getEntityId(), - this.getType(), - this.getLeft(), - this.getTop(), - this.getWidth(), - this.getHeight(), - this.getZIndex(), - this.getContainment(), - json - ); - }; - - this.toJSON = function () { - return { - id: this.getEntityId(), - type: this.getType(), - left: this.getLeft(), - top: this.getTop(), - width: this.getWidth(), - height: this.getHeight(), - zIndex: this.getZIndex(), - containment: this.getContainment(), - json: this.getJSON(), - viewId: this.getViewId(), - oType: this.getOriginType(), - jabberId: this.getJabberId(), - defaultLabel: this.getDefaultLabel(), - defaultAttributeValues: this.getDefaultAttributeValues(), - triggeredBy: this.triggeredBy, - }; - }; - } - static getOperationDescription(nodeType, nodeLabel, viewId) { - if (!nodeLabel && !viewId) { - return "..created a new " + nodeType; - } else if (!viewId) { - return "..created " + nodeType + " " + nodeLabel; - } else - return ".. created " + nodeType + " " + nodeLabel + " in View " + viewId; - } -} - -/** - * EdgeDeleteOperation - * @class operations.ot.EdgeDeleteOperation - * @memberof operations.ot - * @extends operations.ot.EntityOperation - * @param entityId Entity id of the entity this activity works on - * @param {String} type Type of edge to delete - * @param {String} source Entity id of source node - * @param {String} target Entity id of target node - * @param {object} json JSON representation of edge - * @constructor - */ -class EdgeDeleteOperation extends EntityOperation { - static TYPE = "EdgeDeleteOperation"; - getType; - getSource; - getTarget; - getJSON; - constructor(entityId, type, source, target, json = null) { - super( - EntityOperation.TYPES.EdgeDeleteOperation, - entityId, - CONFIG.ENTITY.EDGE - ); - var that = this; - - /** - * Type of edge to delte - * @type {String} - * @private - */ - var _type = type; - - /** - * Entity id of source node - * @type {String} - * @private - */ - var _source = source; - - /** - * Entity id of target node - * @type {String} - * @private - */ - var _target = target; - - /** - * JSON representation of node - * @type {Object} - * @private - */ - var _json = json; - - /** - * Create OTOperation for operation - * @returns {operations.ot.OTOperation} - */ - var createOTOperation = function () { - return new OTOperation( - CONFIG.ENTITY.EDGE + ":" + that.getEntityId(), - JSON.stringify({ - type: _type, - source: _source, - target: _target, - json: _json, - }), - CONFIG.OPERATION.TYPE.UPDATE, - CONFIG.IWC.POSITION.EDGE.DEL - ); - }; - - /** - * Get type of edge to delete - * @returns {String} - */ - this.getType = function () { - return _type; - }; - - /** - * Get entity id of source node - * @returns {String} - */ - this.getSource = function () { - return _source; - }; - - /** - * Get entity id of target node - * @returns {String} - */ - this.getTarget = function () { - return _target; - }; - - /** - * Get JSON representation of edge - * @return {Object} - */ - this.getJSON = function () { - return _json; - }; - - /** - * Get corresponding ot operation - * @returns {operations.ot.OTOperation} - * @private - */ - this.getOTOperation = function () { - var otOperation = EntityOperation.prototype.getOTOperation.call(this); - if (otOperation === null) { - otOperation = createOTOperation(); - this.setOTOperation(otOperation); - } - return otOperation; - }; - - /** - * Adjust the passed operation in the history of operation - * when this operation is applied remotely after the passed operation - * on an graph instance stored in the passed EntityManager - * @param {canvas_widget.EntityManager} EntityManager - * @param {EntityOperation} operation Remote operation - * @returns {EntityOperation} - */ - this.adjust = function (EntityManager, operation) { - switch (operation.getOperationType()) { - case EntityOperation.TYPES.AttributeAddOperation: - case EntityOperation.TYPES.AttributeDeleteOperation: - if (this.getEntityId() === operation.getRootSubjectEntityId()) { - return null; - } - break; - case EntityOperation.TYPES.EdgeAddOperation: - case EntityOperation.TYPES.EdgeDeleteOperation: - if (this.getEntityId() === operation.getEntityId()) { - return null; - } - break; - case EntityOperation.TYPES.ValueChangeOperation: - if (this.getEntityId() === operation.getRootSubjectEntityId()) { - return null; - } - break; - } - - return operation; - }; - - /** - * Compute the inverse of the operation - * @returns {EdgeAddOperation} - */ - this.inverse = function () { - return new EdgeAddOperation( - this.getEntityId(), - this.getType(), - this.getSource(), - this.getTarget() - ); - }; - } - static getOperationDescription(edgeType, edgeLabel, viewId) { - if (!edgeLabel && !viewId) { - return "..deleted " + edgeType; - } else if (!viewId) { - return "..deleted " + edgeType + " " + edgeLabel; - } else { - return "..deleted " + edgeType + " " + edgeLabel + "in View " + viewId; - } - } - toJSON = function () { - return { - id: this.getEntityId(), - type: this.getType(), - source: this.getSource(), - target: this.getTarget(), - json: this.getJSON(), - }; - }; -} - -/** - * EdgeAddOperation - * @class operations.ot.EdgeAddOperation - * @memberof operations.ot - * @extends operations.ot.EntityOperation - * @param {String} entityId Entity id of the entity this activity works on - * @param {String} type Type of edge to add - * @param {String} source Entity id of source node - * @param {String} target Entity id of target node - * @param {object} json JSON representation of edge - * @param {string} viewId the identifier of the view - * @param {string} oType oType the original Type, only set in views - * @param {string} jabberId the jabberId of the user - * @constructor - */ -class EdgeAddOperation extends EntityOperation { - static TYPE = "EdgeAddOperation"; - getOriginType; - getType; - getSource; - getTarget; - getViewId; - getJabberId; - getJSON; - constructor( - entityId, - type, - source, - target, - json = null, - viewId = null, - oType = null, - jabberId = null - ) { - super(EntityOperation.TYPES.EdgeAddOperation, entityId, CONFIG.ENTITY.EDGE); - var that = this; - - var _oType = oType; - - var _jabberId = jabberId; - - this.getOriginType = function () { - return _oType; - }; - - /** - * the identifier of the view - * @type {string} - * @private - */ - var _viewId = viewId; - - /** - * Type of edge to add - * @type {String} - * @private - */ - var _type = type; - - /** - * Entity id of source node - * @type {String} - * @private - */ - var _source = source; - - /** - * Entity id of target node - * @type {String} - * @private - */ - var _target = target; - - /** - * JSON representation of edge - * @type {Object} - * @private - */ - var _json = json; - - /** - * Create OTOperation for operation - * @returns {operations.ot.OTOperation} - */ - var createOTOperation = function () { - return new OTOperation( - CONFIG.ENTITY.EDGE + ":" + that.getEntityId(), - JSON.stringify({ - type: _type, - source: _source, - target: _target, - json: _json, - viewId: _viewId, - oType: _oType, - jabberId: _jabberId, - }), - CONFIG.OPERATION.TYPE.INSERT, - CONFIG.IWC.POSITION.EDGE.ADD - ); - }; - - /** - * Get type of edge to add - * @returns {String} - */ - this.getType = function () { - return _type; - }; - - /** - * Get entity id of source node - * @returns {String} - */ - this.getSource = function () { - return _source; - }; - - /** - * Get entity id of target node - * @returns {String} - */ - this.getTarget = function () { - return _target; - }; - - /** - * get the identifier of the view - * @returns {string} - */ - this.getViewId = function () { - return _viewId; - }; - - /** - * Get the jabber id - * @returns {string} - */ - this.getJabberId = function () { - return _jabberId; - }; - - /** - * Get JSON representation of edge - * @return {Object} - */ - this.getJSON = function () { - return _json; - }; - - /** - * Get corresponding ot operation - * @returns {operations.ot.OTOperation} - * @private - */ - this.getOTOperation = function () { - var otOperation = EntityOperation.prototype.getOTOperation.call(this); - if (otOperation === null) { - otOperation = createOTOperation(); - this.setOTOperation(otOperation); - } - return otOperation; - }; - - /** - * Adjust the passed operation in the history of operation - * when this operation is applied remotely after the passed operation - * on an graph instance stored in the passed EntityManager - * @param {canvas_widget.EntityManager} EntityManager - * @param {EntityOperation} operation Remote operation - * @returns {EntityOperation} - */ - this.adjust = function (EntityManager, operation) { - return operation; - }; - - /** - * Compute the inverse of the operation - * @returns {EdgeDeleteOperation} - */ - this.inverse = function () { - return new EdgeDeleteOperation( - this.getEntityId(), - this.getType(), - this.getSource(), - this.getTarget() - ); - }; - } - static getOperationDescription( - edgeType, - edgeLabel, - sourceNodeType, - sourceNodeLabel, - targetNodeType, - targetNodeLabel, - viewId - ) { - if (!edgeLabel && !viewId) { - return ( - "..created a new " + - edgeType + - " between " + - sourceNodeType + - " " + - sourceNodeLabel + - " and " + - targetNodeType + - " " + - targetNodeLabel - ); - } else if (!viewId) { - return ( - "..created " + - edgeType + - " " + - edgeLabel + - " between " + - sourceNodeType + - " " + - sourceNodeLabel + - " and " + - targetNodeType + - " " + - targetNodeLabel - ); - } else { - return ( - "..created " + - edgeType + - " " + - edgeLabel + - " between " + - sourceNodeType + - " " + - sourceNodeLabel + - " and " + - targetNodeType + - " " + - targetNodeLabel + - " in View " + - viewId - ); - } - } - toJSON = function () { - return { - id: this.getEntityId(), - type: this.getType(), - source: this.getSource(), - target: this.getTarget(), - json: this.getJSON(), - viewId: this.getViewId(), - oType: this.getOriginType(), - jabberId: this.getJabberId(), - }; - }; -} - -/** - * AttributeAddOperation - * @class operations.ot.AttributeAddOperation - * @memberof operations.ot - * @extends operations.ot.EntityOperation - * @param {String} entityId Entity id of the entity this activity works on - * @param {String} subjectEntityId Id of the entity the attribute is assigned to - * @param {String} rootSubjectEntityId Id of topmost entity in the chain of entities the attribute is assigned to - * @param {String} type Type of attribute to add - * @constructor - */ -class AttributeAddOperation extends EntityOperation { - static TYPE = "AttributeAddOperation"; - getSubjectEntityId; - getRootSubjectEntityId; - getType; - getData; - toJSON; - constructor( - entityId, - subjectEntityId, - rootSubjectEntityId, - type, - data = null - ) { - super( - EntityOperation.TYPES.AttributeAddOperation, - entityId, - CONFIG.ENTITY.ATTR - ); - var that = this; - - /** - * Id of the entity the attribute is assigned to - * @type {String} - * @private - */ - var _subjectEntityId = subjectEntityId; - - /** - * Id of topmost entity in the chain of entities the attribute is assigned to - * @type {String} - * @private - */ - var _rootSubjectEntityId = rootSubjectEntityId; - - /** - * Type of attribute to add - * @type {String} - * @private - */ - var _type = type; - - var _data = data; - - /** - * Create OTOperation for operation - * @returns {operations.ot.OTOperation} - */ - var createOTOperation = function () { - return new OTOperation( - CONFIG.ENTITY.ATTR + ":" + that.getEntityId(), - JSON.stringify({ - type: _type, - subjectEntityId: _subjectEntityId, - rootSubjectEntityId: _rootSubjectEntityId, - data: _data, - }), - CONFIG.OPERATION.TYPE.INSERT, - CONFIG.IWC.POSITION.ATTR.ADD - ); - }; - - /** - * Get id of the entity the attribute is assigned to - * @returns {*} - */ - this.getSubjectEntityId = function () { - return _subjectEntityId; - }; - - /** - * Get id of topmost entity in the chain of entities the attribute is assigned to - * @returns {*} - */ - this.getRootSubjectEntityId = function () { - return _rootSubjectEntityId; - }; - - /** - * Get type of attribute to add - * @returns {*} - */ - this.getType = function () { - return _type; - }; - - /** - * Get corresponding ot operation - * @returns {operations.ot.OTOperation} - * @private - */ - this.getOTOperation = function () { - var otOperation = EntityOperation.prototype.getOTOperation.call(this); - if (otOperation === null) { - otOperation = createOTOperation(); - that.setOTOperation(otOperation); - } - return otOperation; - }; - - this.getData = function () { - return _data; - }; - - /** - * Adjust the passed operation in the history of operation - * when this operation is applied remotely after the passed operation - * on an graph instance stored in the passed EntityManager - * @param {canvas_widget.EntityManager} EntityManager - * @param {EntityOperation} operation Remote operation - * @returns {EntityOperation} - */ - this.adjust = function (EntityManager, operation) { - return operation; - }; - - /** - * Compute the inverse of the operation - * @returns {AttributeDeleteOperation} - */ - this.inverse = function () { - return new AttributeDeleteOperation( - that.getEntityId(), - that.getSubjectEntityId(), - that.getRootSubjectEntityId(), - that.getType() - ); - }; - - this.toJSON = function () { - return { - entityId: this.getEntityId(), - type: this.getType(), - subjectEntityId: this.getSubjectEntityId(), - rootSubjectEntityId: this.getRootSubjectEntityId(), - data: this.getData(), - }; - }; - } -} - -/** - * AttributeDeleteOperation - * @class operations.ot.AttributeDeleteOperation - * @memberof operations.ot - * @extends operations.ot.EntityOperation - * @param {String} entityId Entity id of the entity this activity works on - * @param {String} subjectEntityId Id of the entity the attribute is assigned to - * @param {String} rootSubjectEntityId Id of topmost entity in the chain of entities the attribute is assigned to - * @param {String} type Type of attribute to delete - * @constructor - */ -class AttributeDeleteOperation extends EntityOperation { - static TYPE = "AttributeDeleteOperation"; - getSubjectEntityId; - getRootSubjectEntityId; - getType; - toJSON; - constructor(entityId, subjectEntityId, rootSubjectEntityId, type) { - super( - EntityOperation.TYPES.AttributeDeleteOperation, - entityId, - CONFIG.ENTITY.ATTR - ); - var that = this; - - /** - * Id of the entity the attribute is assigned to - * @type {String} - * @private - */ - var _subjectEntityId = subjectEntityId; - - /** - * Id of topmost entity in the chain of entities the attribute is assigned to - * @type {String} - * @private - */ - var _rootSubjectEntityId = rootSubjectEntityId; - - /** - * Type of attribute to add - * @type {String} - * @private - */ - var _type = type; - - /** - * Create OTOperation for operation - * @returns {operations.ot.OTOperation} - */ - var createOTOperation = function () { - return new OTOperation( - CONFIG.ENTITY.ATTR + ":" + that.getEntityId(), - JSON.stringify({ - type: _type, - subjectEntityId: _subjectEntityId, - rootSubjectEntityId: _rootSubjectEntityId, - }), - CONFIG.OPERATION.TYPE.UPDATE, - CONFIG.IWC.POSITION.ATTR.DEL - ); - }; - - /** - * Get id of the entity the attribute is assigned to - * @returns {*} - */ - this.getSubjectEntityId = function () { - return _subjectEntityId; - }; - - /** - * Get id of topmost entity in the chain of entities the attribute is assigned to - * @returns {*} - */ - this.getRootSubjectEntityId = function () { - return _rootSubjectEntityId; - }; - - /** - * Get type of attribute to add - * @returns {*} - */ - this.getType = function () { - return _type; - }; - - /** - * Get corresponding ot operation - * @returns {operations.ot.OTOperation} - * @private - */ - this.getOTOperation = function () { - var otOperation = EntityOperation.prototype.getOTOperation.call(this); - if (otOperation === null) { - otOperation = createOTOperation(); - that.setOTOperation(otOperation); - } - return otOperation; - }; - - /** - * Adjust the passed operation in the history of operation - * when this operation is applied remotely after the passed operation - * on an graph instance stored in the passed EntityManager - * @param {canvas_widget.EntityManager} EntityManager - * @param {operations.ot.EntityOperation} operation Remote operation - * @returns {operations.ot.EntityOperation} - */ - this.adjust = function (EntityManager, operation) { - switch (operation.getOperationType()) { - case EntityOperation.TYPES.AttributeAddOperation: - case EntityOperation.TYPES.AttributeDeleteOperation: - if ( - that.getRootSubjectEntityId() === operation.getRootSubjectEntityId() - ) { - return null; - } - break; - case EntityOperation.TYPES.ValueChangeOperation: - if (operation.getEntityIdChain().indexOf(this.getEntityId()) !== -1) { - return null; - } - break; - } - - return operation; - }; - - /** - * Compute the inverse of the operation - * @returns {operations.ot.AttributeAddOperation} - */ - this.inverse = function () { - return new AttributeAddOperation( - this.getEntityId(), - this.getSubjectEntityId(), - this.getRootSubjectEntityId(), - this.getType() - ); - }; - this.toJSON = function () { - return { - entityId: this.getEntityId(), - type: this.getType(), - subjectEntityId: this.getSubjectEntityId(), - rootSubjectEntityId: this.getRootSubjectEntityId(), - }; - }; - } -} - -/** - * NodeMoveOperation - * @class operations.ot.NodeMoveOperation - * @memberof operations.ot - * @extends operations.ot.EntityOperation - * @param {String} entityId Entity id of the entity this activity works on - * @param {number} offsetX Offset in x-direction - * @param {number} offsetY Offset in y-direction - * @param {string} optional: jabberId the jabberId of the user (is automatically set by propagateNodeMoveOperation) - * @constructor - */ -class NodeMoveOperation extends EntityOperation { - static TYPE = "NodeMoveOperation"; - getOffsetX; - getOffsetY; - getJabberId; - setJabberId; - constructor(entityId, offsetX, offsetY, jabberId) { - super( - EntityOperation.TYPES.NodeMoveOperation, - entityId, - CONFIG.ENTITY.NODE - ); - var that = this; - - /** - * Offset in x-direction - * @type {number} - * @private - */ - var _offsetX = offsetX; - - /** - * Offset in y-direction - * @type {number} - * @private - */ - var _offsetY = offsetY; - - /** - * jabber id of the user - * @type {string} - * @private - */ - var _jabberId = jabberId; - - /** - * Create OTOperation for operation - * @returns {operations.ot.OTOperation} - */ - var createOTOperation = function () { - return new OTOperation( - CONFIG.ENTITY.NODE + ":" + that.getEntityId(), - JSON.stringify({ - offsetX: _offsetX, - offsetY: _offsetY, - jabberId: _jabberId, - }), - CONFIG.OPERATION.TYPE.UPDATE, - CONFIG.IWC.POSITION.NODE.POS - ); - }; - - /** - * Get offset in x-direction - * @returns {number} - */ - this.getOffsetX = function () { - return _offsetX; - }; - - /** - * Get offset in y-direction - * @returns {number} - */ - this.getOffsetY = function () { - return _offsetY; - }; - - /** - * Get the JabberId - * @returns {string} - */ - this.getJabberId = function () { - return _jabberId; - }; - /** - * Set the JabberId - * @param {string} jabberId - */ - this.setJabberId = function (jabberId) { - _jabberId = jabberId; - }; - - /** - * Get corresponding ot operation - * @returns {operations.ot.OTOperation} - * @private - */ - this.getOTOperation = function () { - var otOperation = EntityOperation.prototype.getOTOperation.call(this); - if (otOperation === null) { - otOperation = createOTOperation(); - this.setOTOperation(otOperation); - } - return otOperation; - }; - - /** - * Adjust the passed operation in the history of operation - * when this operation is applied remotely after the passed operation - * on an graph instance stored in the passed EntityManager - * @param {canvas_widget.EntityManager} EntityManager - * @param {EntityOperation} operation Remote operation - * @returns {EntityOperation} - */ - this.adjust = function (EntityManager, operation) { - return operation; - }; - - /** - * Compute the inverse of the operation - * @returns {NodeMoveOperation} - */ - this.inverse = function () { - return new NodeMoveOperation( - this.getEntityId(), - -this.getOffsetX(), - -this.getOffsetY(), - this.getJabberId() - ); - }; - } - static getOperationDescription(nodeType, nodeLabel, viewId) { - if (!nodeLabel && !viewId) { - return "..moved " + nodeType; - } else if (!viewId) { - return "..moved " + nodeType + " " + nodeLabel; - } else { - return "..moved " + nodeType + " " + nodeLabel + " in View " + viewId; - } - } - toJSON = function () { - return { - id: this.getEntityId(), - offsetX: this.getOffsetX(), - offsetY: this.getOffsetY(), - jabberId: this.getJabberId(), - }; - }; -} - -/** - * NodeMoveZOperation - * @class operations.ot.NodeMoveZOperation - * @memberof operations.ot - * @extends operations.ot.EntityOperation - * @param {String} entityId Entity id of the entity this activity works on - * @param {number} offsetZ Offset in z-direction - * @param {string} optional: jabberId the jabberId of the user (is automatically set by propagateNodeMoveOperation) - * @constructor - */ -class NodeMoveZOperation extends EntityOperation { - static TYPE = "NodeMoveZOperation"; - getOffsetZ; - getJabberId; - setJabberId; - constructor(entityId, offsetZ, jabberId) { - super( - EntityOperation.TYPES.NodeMoveZOperation, - entityId, - CONFIG.ENTITY.NODE - ); - var that = this; - - /** - * Offset in y-direction - * @type {number} - * @private - */ - var _offsetZ = offsetZ; - - /** - * the jabberId - * @type {string} - * @private - */ - var _jabberId = jabberId; - - /** - * Create OTOperation for operation - * @returns {operations.ot.OTOperation} - */ - var createOTOperation = function () { - return new OTOperation( - CONFIG.ENTITY.NODE + ":" + that.getEntityId(), - JSON.stringify({ - offsetZ: _offsetZ, - jabberId: _jabberId, - }), - CONFIG.OPERATION.TYPE.UPDATE, - CONFIG.IWC.POSITION.NODE.Z - ); - }; - - /** - * Get offset in z-direction - * @returns {number} - */ - this.getOffsetZ = function () { - return _offsetZ; - }; - - this.getJabberId = function () { - return _jabberId; - }; - - this.setJabberId = function (jabberId) { - _jabberId = jabberId; - }; - - /** - * Get corresponding ot operation - * @returns {operations.ot.OTOperation} - * @private - */ - this.getOTOperation = function () { - var otOperation = EntityOperation.prototype.getOTOperation.call(this); - if (otOperation === null) { - otOperation = createOTOperation(); - this.setOTOperation(otOperation); - } - return otOperation; - }; - - /** - * Adjust the passed operation in the history of operation - * when this operation is applied remotely after the passed operation - * on an graph instance stored in the passed EntityManager - * @param {canvas_widget.EntityManager} EntityManager - * @param {EntityOperation} operation Remote operation - * @returns {EntityOperation} - */ - this.adjust = function (EntityManager, operation) { - return operation; - }; - - /** - * Compute the inverse of the operation - * @returns {NodeMoveZOperation} - */ - this.inverse = function () { - return new NodeMoveZOperation( - this.getEntityId(), - -this.getOffsetZ(), - this.getJabberId() - ); - }; - } - static getOperationDescription(nodeType, nodeLabel, viewId) { - if (!nodeLabel && !viewId) { - return "..moved " + nodeType + " on on Z-Axis"; - } else if (!viewId) { - return "..moved " + nodeType + " " + nodeLabel + " on Z-Axis"; - } else { - return ( - "..moved " + - nodeType + - " " + - nodeLabel + - " in View " + - viewId + - " on Z-Axis" - ); - } - } - toJSON = function () { - return { - id: this.getEntityId(), - offsetZ: this.getOffsetZ(), - jabberId: this.getJabberId(), - }; - }; -} - -/** - * NodeResizeOperation - * @class operations.ot.NodeResizeOperation - * @memberof operations.ot - * @extends operations.ot.EntityOperation - * @param {String} entityId Entity id of the entity this activity works on - * @param {number} offsetX Offset in x-direction - * @param {number} offsetY Offset in y-direction - * @param {string} optional: jabberId the jabberId of the user (is automatically set by propagateNodeMoveOperation) - * @constructor - */ -class NodeResizeOperation extends EntityOperation { - static TYPE = "NodeResizeOperation"; - getOffsetX - getOffsetY - getJabberId - setJabberId - constructor(entityId, offsetX, offsetY, jabberId) { - super( - EntityOperation.TYPES.NodeResizeOperation, - entityId, - CONFIG.ENTITY.NODE - ); - var that = this; - - var _jabberId = jabberId; - - /** - * Offset in x-direction - * @type {number} - * @private - */ - var _offsetX = offsetX; - - /** - * Offset in y-direction - * @type {number} - * @private - */ - var _offsetY = offsetY; - - /** - * Create OTOperation for operation - * @returns {operations.ot.OTOperation} - */ - var createOTOperation = function () { - return new OTOperation( - CONFIG.ENTITY.NODE + ":" + that.getEntityId(), - JSON.stringify({ - offsetX: _offsetX, - offsetY: _offsetY, - jabberId: _jabberId, - }), - CONFIG.OPERATION.TYPE.UPDATE, - CONFIG.IWC.POSITION.NODE.DIM - ); - }; - - /** - * Get offset in x-direction - * @returns {number} - */ - this.getOffsetX = function () { - return _offsetX; - }; - - /** - * Get offset in y-direction - * @returns {number} - */ - this.getOffsetY = function () { - return _offsetY; - }; - - this.getJabberId = function () { - return _jabberId; - }; - - this.setJabberId = function (jabberId) { - _jabberId = jabberId; - }; - - /** - * Get corresponding ot operation - * @returns {operations.ot.OTOperation} - * @private - */ - this.getOTOperation = function () { - var otOperation = EntityOperation.prototype.getOTOperation.call(this); - if (otOperation === null) { - otOperation = createOTOperation(); - this.setOTOperation(otOperation); - } - return otOperation; - }; - - /** - * Adjust the passed operation in the history of operation - * when this operation is applied remotely after the passed operation - * on an graph instance stored in the passed EntityManager - * @param {canvas_widget.EntityManager} EntityManager - * @param {EntityOperation} operation Remote operation - * @returns {EntityOperation} - */ - this.adjust = function (EntityManager, operation) { - return operation; - }; - - /** - * Compute the inverse of the operation - * @returns {NodeResizeOperation} - */ - this.inverse = function () { - return new NodeResizeOperation( - this.getEntityId(), - -this.getOffsetX(), - -this.getOffsetY(), - this.getJabberId() - ); - }; - } - static getOperationDescription(nodeType, nodeLabel, viewId) { - if (!nodeLabel && !viewId) { - return "..resized " + nodeType; - } else if (!viewId) { - return "..resized " + nodeType + " " + nodeLabel; - } else { - return "..resized " + nodeType + " " + nodeLabel + " in View " + viewId; - } - } - toJSON=function() { - return { - id: this.getEntityId(), - offsetX: this.getOffsetX(), - offsetY: this.getOffsetY(), - jabberId: this.getJabberId(), - }; - } -} - -/** - * ValueChangeOperation - * @class operations.ot.ValueChangeOperation - * @memberof operations.ot - * @extends operations.ot.EntityOperation - * @param entityId Entity id of the entity this activity works on - * @param {string} value Char that has been added resp. deleted - * @param {string} type Type of operation (insertion resp. deletion) - * @param {number} position Position where the char has been added resp. deleted - * @constructor - */ -class ValueChangeOperation extends EntityOperation { - static TYPE = "ValueChangeOperation"; - getJabberId; - setJabberId; - getFromView; - setFromView; - getValue; - getType; - setPosition; - getPosition; - setRemote; - getRemote; - setEntityIdChain; - getEntityIdChain; - getRootSubjectEntityId; - constructor( - entityId, - value, - type, - position, - jabberId = null, - fromView = null - ) { - if (!entityId) throw new Error("Entity id is required"); - super( - EntityOperation.TYPES.ValueChangeOperation, - entityId, - CONFIG.ENTITY.VAL - ); - var that = this; - - var _fromView = fromView; - - var _jabberId = jabberId; - - /** - * Char that has been added resp. deleted - * @type {string} - * @private - */ - var _value = value; - - /** - * Type of operation (insertion resp. deletion) - * @type {string} - * @private - */ - var _type = type; - - /** - * Position where the char has been added resp. deleted - * @type {number} - * @private - */ - var _position = position; - - /** - * Is the change issued by a remote user - * @type {boolean} - * @private - */ - var _remote = true; - - /** - * Chain of entities the value is assigned to - * @type {string[]} - * @private - */ - var _entityIdChain = []; - - /** - * Create OTOperation for operation - * @returns {operations.ot.OTOperation} - */ - var createOTOperation = function () { - return new OTOperation( - CONFIG.ENTITY.VAL + ":" + that.getEntityId(), - _value, - _type, - _position, - _jabberId, - _fromView - ); - }; - - this.getJabberId = function () { - return _jabberId; - }; - this.setJabberId = function (jabberId) { - _jabberId = jabberId; - }; - - this.getFromView = function () { - return _fromView; - }; - - this.setFromView = function (fromView) { - _fromView = fromView; - }; - /** - * Get char that has been added resp. deleted - * @returns {string} - */ - this.getValue = function () { - return _value; - }; - - /** - * Get type of operation (insertion resp. deletion) - * @returns {string} - */ - this.getType = function () { - return _type; - }; - - /** - * Set type of operation (insertion resp. deletion) - * @param position - */ - this.setPosition = function (position) { - _position = position; - }; - - /** - * Get position where the char has been added resp. deleted - * @returns {number} - */ - this.getPosition = function () { - return _position; - }; - - /** - * Set if the change is issued by a remote user - * @param remote - */ - this.setRemote = function (remote) { - _remote = remote; - }; - - /** - * Get if the change is issued by a remote user - * @returns {boolean} - */ - this.getRemote = function () { - return _remote; - }; - - /** - * Set chain of entities the value is assigned to - * @param {string[]} entityIdChain - */ - this.setEntityIdChain = function (entityIdChain) { - _entityIdChain = entityIdChain; - }; - - /** - * Get chain of entities the value is assigned to - * @returns {string[]} - */ - this.getEntityIdChain = function () { - return _entityIdChain; - }; - - /** - * Get topmost entity in the chain of entity the value is assigned to - * @returns {string} - */ - this.getRootSubjectEntityId = function () { - return _entityIdChain[0]; - }; - - /** - * Get corresponding ot operation - * @returns {operations.ot.OTOperation} - * @private - */ - this.getOTOperation = function () { - var otOperation = EntityOperation.prototype.getOTOperation.call(this); - if (otOperation === null) { - otOperation = createOTOperation(); - this.setOTOperation(otOperation); - } - return otOperation; - }; - - /** - * Adjust the passed operation in the history of operation - * when this operation is applied remotely after the passed operation - * on an graph instance stored in the passed EntityManager - * @param {canvas_widget.EntityManager} EntityManager - * @param {operations.ot.EntityOperation} operation Remote operation - * @returns {operations.ot.EntityOperation} - */ - this.adjust = function (EntityManager, operation) { - switch (operation.getOperationType()) { - case EntityOperation.TYPES.ValueChangeOperation: - if (this.getEntityId() === operation.getEntityId()) { - if ( - (this.getPosition() === operation.getPosition && - this.getValue() === operation.getValue && - this.getType() === CONFIG.OPERATION.TYPE.INSERT && - operation.getType() === CONFIG.OPERATION.TYPE.DELETE) || - (this.getType() === CONFIG.OPERATION.TYPE.DELETE && - operation.getType() === CONFIG.OPERATION.TYPE.INSERT) - ) { - return null; - } - if (this.getPosition() <= operation.getPosition()) { - switch (this.getType()) { - case CONFIG.OPERATION.TYPE.INSERT: - operation.setPosition(operation.getPosition() + 1); - break; - case CONFIG.OPERATION.TYPE.DELETE: - operation.setPosition(operation.getPosition() - 1); - break; - } - } - } - break; - } - - return operation; - }; - - /** - * Compute the inverse of the operation - * @returns {ValueChangeOperation} - */ - this.inverse = function () { - var newType, - ValueChangeOperation = ValueChangeOperation; - - switch (this.getType()) { - case CONFIG.OPERATION.TYPE.INSERT: - newType = CONFIG.OPERATION.TYPE.DELETE; - break; - case CONFIG.OPERATION.TYPE.DELETE: - newType = CONFIG.OPERATION.TYPE.INSERT; - break; - case CONFIG.OPERATION.TYPE.UPDATE: - newType = CONFIG.OPERATION.TYPE.UPDATE; - break; - } - return new ValueChangeOperation( - this.getEntityId(), - this.getValue(), - newType, - this.getPosition() - ); - }; - this.toJSON = function () { - return { - entityId: this.getEntityId(), - value: this.getValue(), - position: this.getPosition(), - type: this.getType(), - jabberId: this.getJabberId(), - }; - }; - } - - static getOperationDescription(valueKey, entityType, entityName, viewId) { - if (!viewId) - return ( - ".. changed " + - valueKey + - " of " + - entityType + - (entityName ? " " : "") + - entityName - ); - else - return ( - ".. changed " + - valueKey + - " of " + - entityType + - (entityName ? " " : "") + - entityName + - " in View " + - viewId - ); - } -} - -EntitySelectOperation.TYPE = "EntitySelectOperation"; - -/** - * Entity Select Operation - * @class operations.non_ot.EntitySelectOperation - * @memberof operations.non_ot - * @constructor - * @param {string} selectedEntityId Entity id of the selected entity - * @param {string} selectedEntityType - * @param {string} jabberId - */ - -function EntitySelectOperation(selectedEntityId, selectedEntityType, jabberId) { - /** - * Entity id of the selected entity - * @type {string} - * @private - */ - var _selectedEntityId = selectedEntityId; - - var _jabberId = jabberId; - - var _selectedEntityType = selectedEntityType; - - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var _nonOTOperation = null; - - /** - * Get entity id of the selected entity - * @returns {string} - */ - this.getSelectedEntityId = function () { - return _selectedEntityId; - }; - - this.getSelectedEntityType = function () { - return _selectedEntityType; - }; - - this.getJabberId = function () { - return _jabberId; - }; - - /** - * Set corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - */ - this.setNonOTOperation = function (nonOTOperation) { - _nonOTOperation = nonOTOperation; - }; - - /** - * Get corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - */ - this.getNonOTOperation = function () { - return _nonOTOperation; - }; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (_nonOTOperation === null) { - _nonOTOperation = new NonOTOperation( - EntitySelectOperation.TYPE, - JSON.stringify({ - selectedEntityId: _selectedEntityId, - selectedEntityType: _selectedEntityType, - }) - ); - } - return _nonOTOperation; - }; -} - -EntitySelectOperation.prototype.toJSON = function () { - return { - selectedEntityId: this.getSelectedEntityId(), - selectedEntityType: this.getSelectedEntityType(), - jabberId: this.getJabberId(), - }; +/** + * Function to check if the event was triggered by the current user + * @param {YEvent} yEvent YEvent + * @returns {boolean} true if the event was triggered by the current user + */ +function eventWasTriggeredByMe(yEvent) { + const array = Array.from(yEvent.changes.keys.keys()); + if (!array) return false; + const modifiedByKey = array.find((key) => key === "modifiedBy"); + if ( + modifiedByKey && + yEvent.currentTarget.get(modifiedByKey) === window.y.clientID + ) + // modified by us + return true; + return false; +} + +const CONFIG = { + TEST: { + USER: "Luigi Test", + EMAIL: "luigi.test05@gmail.com", + CANVAS: false, + ATTRIBUTE: false, + PALETTE: false, + ACTIVITY: false, + }, + LAYER: { + META: "META", + MODEL: "MODEL", + }, + WIDGET: { + NAME: { + MAIN: "Canvas", + PALETTE: "Palette", + ATTRIBUTE: "Property Browser", + ACTIVITY: "User Activity", + GUIDANCE: "Guidance", + HEATMAP: "Heatmap", + METADATA: "METADATA", + OPENAPI: "Metadata Widget", + DEBUG: "Debug", + IMSLD_EXPORT: "IMSLD Export", + JSON_EXPORT: "JSON Export", + VIEWCONTROL: "View Control", + }, + }, + ENTITY: { + NODE: "node", + EDGE: "edge", + ATTR: "attr", + VAL: "val", + }, + IWC: { + FLAG: { + PUBLISH_GLOBAL: "PUBLISH_GLOBAL", + PUBLISH_LOCAL: "PUBLISH_LOCAL", + }, + ACTION: { + SYNC: "ACTION_SYNC", + DATA: "ACTION_DATA", + DATA_ARRAY: "ACTION_DATA_ARRAY", + }, + POSITION: { + NODE: { + ADD: 0, + DEL: 0, + POS: 1, + Z: 2, + DIM: 3, + }, + EDGE: { + ADD: 0, + DEL: 0, + MOV: 1, + }, + ATTR: { + ADD: 0, + DEL: 0, + }, + }, + }, + OPERATION: { + TYPE: { + INSERT: "insert", + UPDATE: "update", + DELETE: "delete", + }, + }, + ACTIVITY: { + TYPE: { + NODEADD: 0, + EDGEADD: 1, + NODEDEL: 2, + EDGEDEL: 3, + NODEATTRCHANGE: 4, + }, + }, + DATA: { + RELATION: { + GLOBAL: { + MAIN: { + MAIN: { + OPERATION: "MAIN2MAIN4OPERATION", + }, + }, + }, + LOCAL: { + PALETTE: { + MAIN: { + TOOLSELECTION: "PALETTE2MAIN4TOOLSELECTION", + }, + }, + MAIN: { + ATTRIBUTE: { + NODESELECTION: "MAIN2ATTRIBUTE4NODESELECTION", + NODEADDITION: "MAIN2ATTRIBUTE4NODEADDITION", + ATTRIBUTECHANGE: "MAIN2ATTRIBUTE4ATTRIBUTECHANGE", + }, + ACTIVITY: { + NEWACTIVITY: "MAIN2ACTIVITY4NEWACTIVITY", + }, + PALETTE: { + TOOLSELECTION: "MAIN2PALETTE4TOOLSELECTION", + }, + }, + ATTRIBUTE: { + MAIN: { + ATTRIBUTECHANGE: "ATTRIBUTE2MAIN4ATTRIBUTECHANGE", + }, + }, + }, + }, + }, + NS: { + PERSON: { + TITLE: "http://purl.org/dc/terms/title", + JABBERID: "http://xmlns.com/foaf/0.1/jabberID", + MBOX: "http://xmlns.com/foaf/0.1/mbox", + }, + MY: { + MODEL: "my:ns:model", + METAMODEL: "my:ns:metamodel", + INSTANCE: "my:ns:instance", + VIEWPOINT: "my:ns:viewpoint", + VIEW: "my:ns:view", + COPY: "my:ns:copy", + GUIDANCEMODEL: "my:ns:guidancemodel", + METAMODELPREVIEW: "my:ns:metamodelpreview", + GUIDANCEMETAMODEL: "my:ns:guidancemetamodel", + LOGICALGUIDANCEREPRESENTATION: "my:ns:logicalguidancerepresentation", + }, + }, }; -/** - * ToolSelectOperation - * @class operations.non_ot.ToolSelectOperation.non_ot.ToolSelectOperation - * @memberof operations.non_ot - * @constructor - * @param {string} toolName Name of selected tool - * @param label - * @param {map} defaultAttributeValues Map containing default values for the attributes of a node. - */ -class ToolSelectOperation { - static TYPE = "ToolSelectOperation"; - /** - * Name of selected tool - * @type {string} - */ - selectedToolName; - - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - nonOTOperation; - - /** - * Default label of selected tool - * @type {string} - */ - defaultLabel; - - /** - * May be used to set default values for node attributes. - * @type {map} - */ - defaultAttributeValues; - - /** - * Get name of selected tool - * @returns {string} - */ - getSelectedToolName; - - /** - * Get default label of selected tool - * @returns {string} - */ - getDefaultLabel; - - /** - * Get default values for node attributes. - * @returns {map} - */ - getDefaultAttributeValues; - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - toNonOTOperation; - constructor(toolName, label, defaultAttributeValues = {}) { - /** - * Name of selected tool - * @type {string} - */ - var selectedToolName = toolName; - - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var nonOTOperation = null; - - /** - * Default label of selected tool - * @type {string} - */ - var defaultLabel = label; - - /** - * May be used to set default values for node attributes. - * @type {map} - */ - var defaultAttributeValues = defaultAttributeValues; - - /** - * Get name of selected tool - * @returns {string} - */ - this.getSelectedToolName = function () { - return selectedToolName; - }; - - /** - * Get default label of selected tool - * @returns {string} - */ - this.getDefaultLabel = function () { - return defaultLabel; - }; - - /** - * Get default values for node attributes. - * @returns {map} - */ - this.getDefaultAttributeValues = function () { - return defaultAttributeValues; - }; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (nonOTOperation === null) { - nonOTOperation = new NonOTOperation( - ToolSelectOperation.TYPE, - JSON.stringify({ selectedToolName: selectedToolName }) - ); - } - return nonOTOperation; - }; - } -} - -/** - * ActivityOperation - * @class operations.non_ot.ActivityOperation - * @memberof operations.non_ot - * @constructor - * @param {string} type Type of activity - * @param {string} entityId Entity id of the entity this activity works on - * @param {string} sender JabberId of the user who issued this activity - * @param {string} text Text of this activity which is displayed in the activity widget - * @param {object} data Additional data for the activity - */ -class ActivityOperation { - static TYPE = "ActivityOperation"; - constructor(type, entityId, sender, text, data) { - /** - * Type of activity - * @type {string} - * @private - */ - var _type = type; - - /** - * Entity id of the entity this activity works on - * @type {string} - * @private - */ - var _entityId = entityId; - - /** - * JabberId of the user who issued this activity - * @type {string} - * @private - */ - var _sender = sender; - - /** - * Text of this activity which is displayed in the activity widget - * @type {string} - * @private - */ - var _text = text; - - /** - * Additional data for the activity - * @type {Object} - * @private - */ - var _data = data; - - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var _nonOTOperation = null; - - /** - * Get type of activity - * @returns {string} - */ - this.getType = function () { - return _type; - }; - - /** - * Get entity id of the entity this activity works on - * @returns {string} - */ - this.getEntityId = function () { - return _entityId; - }; - - /** - * Get JabberId of the user who issued this activity - * @returns {string} - */ - this.getSender = function () { - return _sender; - }; - - /** - * Get text of this activity which is displayed in the activity widget - * @returns {string} - */ - this.getText = function () { - return _text; - }; - - /** - * Get additional data for the activity - * @returns {Object} - */ - this.getData = function () { - return _data; - }; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (_nonOTOperation === null) { - _nonOTOperation = new NonOTOperation( - ActivityOperation.TYPE, - JSON.stringify({ - type: _type, - entityId: _entityId, - sender: _sender, - text: _text, - data: _data, - }) - ); - } - return _nonOTOperation; - }; - } - toJSON() { - return { - type: this.getType(), - entityId: this.getEntityId(), - sender: this.getSender(), - text: this.getText(), - data: this.getData(), - }; - } -} - -ExportMetaModelOperation.TYPE = "ExportMetaModelOperation"; - -/** - * Export Image Operation - * @class operations.non_ot.ExportMetaModelOperation - * @memberof operations.non_ot - * @constructor - * @param {string} requestingComponent Name of requesting Component - * @param {string} data Meta model - */ -function ExportMetaModelOperation(requestingComponent, data) { - /** - * Name of requesting Component - * @type {string} - * @private - */ - var _requestingComponent = requestingComponent; - /** - * Meta model - * @type {object} - * @private - */ - var _data = data; - - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var _nonOTOperation = null; - - /** - * Get name of requesting Component - * @returns {string} - */ - this.getRequestingComponent = function () { - return _requestingComponent; - }; - - /** - * Get data URL of image - * @returns {object} - */ - this.getData = function () { - return _data; - }; - - /** - * Get exported JSON representation of the graph - * @param {object} data - */ - this.setData = function (data) { - _data = data; - }; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (_nonOTOperation === null) { - _nonOTOperation = new NonOTOperation( - ExportMetaModelOperation.TYPE, - JSON.stringify({ - requestingComponent: _requestingComponent, - data: _data, - }) - ); - } - return _nonOTOperation; - }; -} - -ExportLogicalGuidanceRepresentationOperation.TYPE = - "ExportLogicalGuidanceRepresentationOperation"; - -/** - * Export Image Operation - * @class operations.non_ot.ExportLogicalGuidanceRepresentationOperation - * @memberof operations.non_ot - * @constructor - * @param {string} requestingComponent Name of requesting Component - * @param {string} data Meta model - */ -function ExportLogicalGuidanceRepresentationOperation( - requestingComponent, - data -) { - /** - * Name of requesting Component - * @type {string} - * @private - */ - var _requestingComponent = requestingComponent; - /** - * Guidance rules - * @type {object} - * @private - */ - var _data = data; - - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var _nonOTOperation = null; - - /** - * Get name of requesting Component - * @returns {string} - */ - this.getRequestingComponent = function () { - return _requestingComponent; - }; - - /** - * Get data URL of image - * @returns {object} - */ - this.getData = function () { - return _data; - }; - - /** - * Get exported JSON representation of the graph - * @param {object} data - */ - this.setData = function (data) { - _data = data; - }; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (_nonOTOperation === null) { - _nonOTOperation = new NonOTOperation( - ExportLogicalGuidanceRepresentationOperation.TYPE, - JSON.stringify({ - requestingComponent: _requestingComponent, - data: _data, - }) - ); - } - return _nonOTOperation; - }; -} - -ExportImageOperation.TYPE = "ExportImageOperation"; - -/** - * Export Image Operation - * @class operations.non_ot.ExportImageOperation - * @memberof operations.non_ot - * @constructor - * @param {string} requestingComponent Name of requesting Component - * @param {string} data Data URL of image - */ -function ExportImageOperation(requestingComponent, data) { - /** - * Name of requesting Component - * @type {string} - * @private - */ - var _requestingComponent = requestingComponent; - /** - * Data URL of image - * @type {object} - * @private - */ - var _data = data; - - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var _nonOTOperation = null; - - /** - * Get name of requesting Component - * @returns {string} - */ - this.getRequestingComponent = function () { - return _requestingComponent; - }; - - /** - * Get data URL of image - * @returns {object} - */ - this.getData = function () { - return _data; - }; - - /** - * Get exported JSON representation of the graph - * @param {object} data - */ - this.setData = function (data) { - _data = data; - }; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (_nonOTOperation === null) { - _nonOTOperation = new NonOTOperation( - ExportImageOperation.TYPE, - JSON.stringify({ - requestingComponent: _requestingComponent, - data: _data, - }) - ); - } - return _nonOTOperation; - }; -} - -/** - * SetViewTypesOperation - * @class operations.non_ot.WidgetEnterOperation - * @memberof operations.non_ot - * @constructor - * @param {boolean} flag enable (true)/disable(false) the view types of the vml in the palette widget - */ -class SetViewTypesOperation { - static TYPE = "SetViewTypesOperation"; - _flag; - nonOTOperation; - /** - * Get name of selected tool - * @returns {string} - */ - getFlag = function () { - return this._flag; - }; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - toNonOTOperation = function () { - if (this.nonOTOperation === null) { - this.nonOTOperation = new NonOTOperation( - SetViewTypesOperation.TYPE, - JSON.stringify({ flag: this._flag }) - ); - } - return this.nonOTOperation; - }; - - constructor(flag) { - /** - * Enable or disable the view types of the vml - * @type {boolean} - * @private - */ - this._flag = flag; - - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - this.nonOTOperation = null; - } -} - -/** - * InitModelTypesOperation - * @class operations.non_ot.InitModelTypesOperation - * @memberof operations.non_ot - * @constructor - * @param {string} vls the visual language specification - * @param {bool} startViewGeneration - */ -class InitModelTypesOperation { - static TYPE = "InitModelTypesOperation"; - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - nonOTOperation = null; - _vls; - _startViewGeneration; - getVLS = function () { - return this._vls; - }; - - /** - * Get name of selected tool - * @returns {string} - */ - getViewGenerationFlag = function () { - return this._startViewGeneration; - }; - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - toNonOTOperation = function () { - if (this.nonOTOperation === null) { - this.nonOTOperation = new NonOTOperation( - InitModelTypesOperation.TYPE, - JSON.stringify({ - vls: this._vls, - startViewGeneration: this._startViewGeneration, - }) - ); - } - return this.nonOTOperation; - }; - constructor(vls, startViewGeneration) { - /** - * Name of selected tool - * @type {string} - */ - this._vls = vls; - - this._startViewGeneration = startViewGeneration; - } + /** + * Gets the html tag name of a widget. + * Use this function to get the tag name of a or your own widget. + * @example getWidgetTagName("My Widget") // returns "my-widget-widget" + * @param {*} name name of the widget + * @returns {string} tag name of the widget + */ +function getWidgetTagName(name) { + if (!name) return; + if ( + !Object.values(CONFIG.WIDGET.NAME).some( + (n) => n.toLocaleLowerCase() === name.toLocaleLowerCase() + ) + ) { + console.warn( + `Widget name ${name} is not defined in config.js. Add it to the CONFIG.WIDGET.NAME object.` + ); + } + let widgetName = name; + widgetName = widgetName.replace(/\s+/g, "-"); + return `${widgetName}-widget`.toLowerCase(); +} + +function getQuerySelectorFromNode(node) { + if (node instanceof jQuery) { + node = node.get(0); + } + if (node.id) { + return `[id="${node.id}"]`; + // return `#${node.id}`; // This is not working since the implementation of querySelectorAll disallows getting elements by id with a hash if the id starts with a number + } + if (node.className) { + return `.${node.className}`; + } + return null; } -ViewInitOperation.TYPE = "ViewInitOperation"; - -/** - * ViewInitOperation - * @class operations.non_ot.ViewInitOperation - * @memberof operations.non_ot - * @constructor - * @param {object} data the view as json - * @param {object} viewpoint the viewpoint vls as json - */ -function ViewInitOperation(data, viewpoint) { - /** - * Name of selected tool - * @type {string} - */ - var _data = data; - - var _viewpoint = viewpoint; - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var nonOTOperation = null; - - /** - * Get name of selected tool - * @returns {string} - */ - this.getData = function () { - return _data; - }; - - this.getViewpoint = function () { - return _viewpoint; - }; - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (nonOTOperation === null) { - nonOTOperation = new NonOTOperation( - ViewInitOperation.TYPE, - JSON.stringify({ data: _data, viewpoint: _viewpoint }) - ); - } - return nonOTOperation; - }; -} - -/** - * DeleteViewOperation - * @class operations.non_ot.DeleteViewOperation - * @memberof operations.non_ot - * @constructor - * @param {string} viewId identifier of the view - */ -class DeleteViewOperation { - static TYPE = "DeleteViewOperation"; - constructor(viewId) { - /** - * Name of selected tool - * @type {string} - */ - var _viewId = viewId; - - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var nonOTOperation = null; - - /** - * Get the list with node ids to delete - * @returns {string} - */ - this.getViewId = function () { - return _viewId; - }; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (nonOTOperation === null) { - nonOTOperation = new NonOTOperation( - DeleteViewOperation.TYPE, - JSON.stringify({ viewId: _viewId }) - ); - } - return nonOTOperation; - }; - } -} - -SetModelAttributeNodeOperation.TYPE = "SetModelAttributeNodeOperation"; - -/** - * SetModelAttributeNodeOperation - * @class operations.non_ot.SetModelAttributeNodeOperation - * @memberof operations.non_ot - * @constructor - */ -function SetModelAttributeNodeOperation() { - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var nonOTOperation = null; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (nonOTOperation === null) { - nonOTOperation = new NonOTOperation( - SetModelAttributeNodeOperation.TYPE, - JSON.stringify({ empty: "empty" }) - ); - } - return nonOTOperation; - }; -} - -UpdateViewListOperation.TYPE = "UpdateViewListOperation"; - -/** - * UpdateViewListOperation - * @class operations.non_ot.UpdateViewListOperation - * @memberof operations.non_ot - * @constructor - */ -function UpdateViewListOperation() { - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var nonOTOperation = null; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (nonOTOperation === null) { - nonOTOperation = new NonOTOperation( - UpdateViewListOperation.TYPE, - JSON.stringify({}) - ); - } - return nonOTOperation; - }; -} - -ShowGuidanceBoxOperation.TYPE = "ShowGuidanceBoxOperation"; - -/** - * ToolGuidanceOperation - * @class operations.non_ot.ToolGuidanceOperation - * @memberof operations.non_ot - * @constructor - * @param {string} toolName Name of selected tool - */ -function ShowGuidanceBoxOperation(label, guidance, entityId) { - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var nonOTOperation = null; - var _label = label; - var _guidance = guidance; - var _entityId = entityId; - - this.getLabel = function () { - return _label; - }; - - this.getGuidance = function () { - return _guidance; - }; - - this.getEntityId = function () { - return _entityId; - }; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (nonOTOperation === null) { - nonOTOperation = new NonOTOperation( - ShowGuidanceBoxOperation.TYPE, - JSON.stringify({ - label: _label, - guidance: _guidance, - entityId: _entityId, - }) - ); - } - return nonOTOperation; - }; -} - -CanvasViewChangeOperation.TYPE = "CanvasViewChangeOperation"; - -/** - * Entity Select Operation - * @class operations.non_ot.EntitySelectOperation - * @memberof operations.non_ot - * @constructor - * @param {string} selectedEntityId Entity id of the selected entity - */ -function CanvasViewChangeOperation(left, top, width, height, zoom) { - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var _nonOTOperation = null; - - this.getLeft = function () { - return left; - }; - - this.getTop = function () { - return top; - }; - - this.getWidth = function () { - return width; - }; - - this.getHeight = function () { - return height; - }; - - this.getZoom = function () { - return zoom; - }; - - /** - * Set corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - */ - this.setNonOTOperation = function (nonOTOperation) { - _nonOTOperation = nonOTOperation; - }; - - /** - * Get corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - */ - this.getNonOTOperation = function () { - return _nonOTOperation; - }; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (_nonOTOperation === null) { - _nonOTOperation = new NonOTOperation( - CanvasViewChangeOperation.TYPE, - JSON.stringify({ - left: left, - top: top, - width: width, - height: height, - zoom: zoom, - }) - ); - } - return _nonOTOperation; - }; -} - -RevokeSharedActivityOperation.TYPE = "RevokeSharedActivityOperation"; - -/** - * Entity Select Operation - * @class operations.non_ot.EntitySelectOperation - * @memberof operations.non_ot - * @constructor - * @param {string} selectedEntityId Entity id of the selected entity - */ -function RevokeSharedActivityOperation(id) { - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var _nonOTOperation = null; - - this.getId = function () { - return id; - }; - - /** - * Set corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - */ - this.setNonOTOperation = function (nonOTOperation) { - _nonOTOperation = nonOTOperation; - }; - - /** - * Get corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - */ - this.getNonOTOperation = function () { - return _nonOTOperation; - }; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (_nonOTOperation === null) { - _nonOTOperation = new NonOTOperation( - RevokeSharedActivityOperation.TYPE, - JSON.stringify({ - id: id, - }) - ); - } - return _nonOTOperation; - }; -} - -RevokeSharedActivityOperation.prototype.toJSON = function () { - return { id: this.getId() }; -}; +/** + * Namespace for operations + * @namespace operations + */ -CollaborateInActivityOperation.TYPE = "CollaborateInActivityOperation"; - -/** - * Entity Select Operation - * @class operations.non_ot.EntitySelectOperation - * @memberof operations.non_ot - * @constructor - * @param {string} selectedEntityId Entity id of the selected entity - */ -function CollaborateInActivityOperation(id) { - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var _nonOTOperation = null; - - this.getId = function () { - return id; - }; - - /** - * Set corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - */ - this.setNonOTOperation = function (nonOTOperation) { - _nonOTOperation = nonOTOperation; - }; - - /** - * Get corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - */ - this.getNonOTOperation = function () { - return _nonOTOperation; - }; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (_nonOTOperation === null) { - _nonOTOperation = new NonOTOperation( - CollaborateInActivityOperation.TYPE, - JSON.stringify({ - id: id, - }) - ); - } - return _nonOTOperation; - }; -} - -MoveCanvasOperation.TYPE = "MoveCanvasOperation"; - -/** - * Entity Select Operation - * @class operations.non_ot.EntitySelectOperation - * @memberof operations.non_ot - * @constructor - * @param {string} selectedEntityId Entity id of the selected entity - */ -function MoveCanvasOperation(objectId, transition) { - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var _nonOTOperation = null; - - this.getObjectId = function () { - return objectId; - }; - - this.getTransition = function () { - return transition; - }; - - /** - * Set corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - */ - this.setNonOTOperation = function (nonOTOperation) { - _nonOTOperation = nonOTOperation; - }; - - /** - * Get corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - */ - this.getNonOTOperation = function () { - return _nonOTOperation; - }; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (_nonOTOperation === null) { - _nonOTOperation = new NonOTOperation( - MoveCanvasOperation.TYPE, - JSON.stringify({ - objectId: objectId, - transition: transition, - }) - ); - } - return _nonOTOperation; - }; -} - -/** - * Entity Select Operation - * @class operations.non_ot.EntitySelectOperation - * @memberof operations.non_ot - * @constructor - * @param {string} data - */ -class GuidanceStrategyOperation { - static TYPE = "GuidanceStrategyOperation"; - constructor(data) { - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var _nonOTOperation = null; - - this.getData = function () { - return data; - }; - - /** - * Set corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - */ - this.setNonOTOperation = function (nonOTOperation) { - _nonOTOperation = nonOTOperation; - }; - - /** - * Get corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - */ - this.getNonOTOperation = function () { - return _nonOTOperation; - }; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (_nonOTOperation === null) { - _nonOTOperation = new NonOTOperation( - GuidanceStrategyOperation.TYPE, - JSON.stringify({ - data: data, - }) - ); - } - return _nonOTOperation; - }; - } - toJSON() { - return { data: this.getData() }; - } -} - -UpdateMetamodelOperation.TYPE = "UpdateMetamodelOperation"; - -/** - * UpdateMetamodelOperation - * @class operations.non_ot.UpdateMetamodelOperation - * @memberof operations.non_ot - * @constructor - */ -function UpdateMetamodelOperation(metaModelingRoomName, modelingRoomName) { - /** - * Room name of metamodel is created - * @type {string} - */ - var _metaModelingRoomName = metaModelingRoomName; - - /** - * Room name to upload created metamodel - * @type {string} - */ - var _modelingRoomName = modelingRoomName; - - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var _nonOTOperation = null; - - /** - * Get metamodeling room name - * @returns {string} - */ - this.getMetaModelingRoomName = function () { - return _metaModelingRoomName; - }; - - /** - * Get modeling room name - * @returns {string} - */ - this.getModelingRoomName = function () { - return _modelingRoomName; - }; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (_nonOTOperation === null) { - _nonOTOperation = new NonOTOperation( - UpdateMetamodelOperation.TYPE, - JSON.stringify({ empty: "empty" }) - ); - } - return _nonOTOperation; - }; -} -UpdateMetamodelOperation.prototype.toJSON = function () { - return {}; -}; +/** + * Operation + * @class operations.Operation + * @memberof operations + * @constructor + */ +class Operation { + constructor() {} +} -/** - * OperationFactory - * @class operations.OperationFactory - * @memberof operations.ot - * @constructor - */ -function OperationFactory() { - return { - /** - * Creates an Operation from a received NonOTOperation - * @memberof operations.OperationFactory# - * @param operation - * @returns {operations.non_ot.ToolSelectOperation|EntitySelectOperation|ToolSelectOperation} - */ - createOperationFromNonOTOperation: function (operation) { - var type = operation.getType(), - data, - resOperation; - - try { - data = JSON.parse(operation.getData()); - } catch (e) { - console.error( - "Not able to parse data to JSON. Check the corresponding operation" - ); - return null; - } - - switch (type) { - case EntitySelectOperation.TYPE: - resOperation = new EntitySelectOperation( - data.selectedEntityId, - data.selectedEntityType, - data.jabberId - ); - resOperation.setNonOTOperation(operation); - break; - case ToolSelectOperation.TYPE: - resOperation = new ToolSelectOperation( - data.selectedToolName, - data.name, - data.defaultAttributeValues - ); - break; - case ActivityOperation.TYPE: - resOperation = new ActivityOperation( - data.type, - data.entityId, - data.sender, - data.text, - data.data - ); - break; - case ExportMetaModelOperation.TYPE: - resOperation = new ExportMetaModelOperation( - data.requestingComponent, - data.data - ); - break; - case ExportLogicalGuidanceRepresentationOperation.TYPE: - resOperation = new ExportLogicalGuidanceRepresentationOperation( - data.requestingComponent, - data.data - ); - break; - case ExportImageOperation.TYPE: - resOperation = new ExportImageOperation( - data.requestingComponent, - data.data - ); - break; - case SetViewTypesOperation.TYPE: - resOperation = new SetViewTypesOperation(data.flag); - break; - case InitModelTypesOperation.TYPE: - resOperation = new InitModelTypesOperation( - data.vls, - data.startViewGeneration - ); - break; - case ViewInitOperation.TYPE: - resOperation = new ViewInitOperation(data.data, data.viewpoint); - break; - case DeleteViewOperation.TYPE: - resOperation = new DeleteViewOperation(data.viewId); - break; - case ShowGuidanceBoxOperation.TYPE: - resOperation = new ShowGuidanceBoxOperation( - data.label, - data.guidance, - data.entityId - ); - break; - case SetModelAttributeNodeOperation.TYPE: - resOperation = new SetModelAttributeNodeOperation(); - break; - case UpdateViewListOperation.TYPE: - resOperation = new UpdateViewListOperation(); - break; - case CanvasViewChangeOperation.TYPE: - resOperation = new CanvasViewChangeOperation( - data.left, - data.top, - data.width, - data.height, - data.zoom - ); - resOperation.setNonOTOperation(operation); - break; - case RevokeSharedActivityOperation.TYPE: - resOperation = new RevokeSharedActivityOperation(data.id); - break; - case CollaborateInActivityOperation.TYPE: - resOperation = new CollaborateInActivityOperation(data.id); - break; - case MoveCanvasOperation.TYPE: - resOperation = new MoveCanvasOperation( - data.objectId, - data.transition - ); - break; - case GuidanceStrategyOperation.TYPE: - resOperation = new GuidanceStrategyOperation(data.data); - resOperation.setNonOTOperation(operation); - break; - case UpdateMetamodelOperation.TYPE: - resOperation = new UpdateMetamodelOperation( - data.metamodelingRoomName, - data.modelingRoomName - ); - break; - default: - resOperation = new NonOTOperation(type, data); - break; - } - return resOperation; - }, - /** - * Creates an entity operation from a received OTOperation - * @memberof operations.OperationFactory# - * @param operation - * @returns {EntityOperation} - */ - createOperationFromOTOperation: function (operation) { - var value; - var entityType; - var entityId; - var components = operation.getName().split(":"); - - var resOperation; - - if (components.length === 2) { - entityType = components[0]; - entityId = components[1]; - - switch (entityType) { - case CONFIG.ENTITY.NODE: - try { - value = JSON.parse(operation.getValue()); - } catch (e) { - return null; - } - switch (operation.getPosition()) { - case CONFIG.IWC.POSITION.NODE.ADD: - switch (operation.getType()) { - case CONFIG.OPERATION.TYPE.INSERT: - resOperation = new NodeAddOperation( - entityId, - value.type, - value.left, - value.top, - value.width, - value.height, - value.zIndex, - value.containment, - value.json, - value.viewId, - value.oType, - value.jabberId - ); - break; - case CONFIG.OPERATION.TYPE.UPDATE: - resOperation = new NodeDeleteOperation( - entityId, - value.type, - value.left, - value.top, - value.width, - value.height, - value.zIndex, - value.containment, - value.json - ); - break; - } - break; - case CONFIG.IWC.POSITION.NODE.POS: - resOperation = new NodeMoveOperation( - entityId, - value.offsetX, - value.offsetY, - value.jabberId - ); - break; - case CONFIG.IWC.POSITION.NODE.Z: - resOperation = new NodeMoveZOperation( - entityId, - value.offsetZ, - value.jabberId - ); - break; - case CONFIG.IWC.POSITION.NODE.DIM: - resOperation = new NodeResizeOperation( - entityId, - value.offsetX, - value.offsetY, - value.jabberId - ); - break; - } - break; - case CONFIG.ENTITY.EDGE: - try { - value = JSON.parse(operation.getValue()); - } catch (e) { - return null; - } - switch (operation.getType()) { - case CONFIG.OPERATION.TYPE.INSERT: - resOperation = new EdgeAddOperation( - entityId, - value.type, - value.source, - value.target, - value.json, - value.viewId, - value.oType, - value.jabberId - ); - break; - case CONFIG.OPERATION.TYPE.UPDATE: - resOperation = new EdgeDeleteOperation( - entityId, - value.type, - value.source, - value.target, - value.json - ); - break; - } - break; - case CONFIG.ENTITY.ATTR: - try { - value = JSON.parse(operation.getValue()); - } catch (e) { - return null; - } - switch (operation.getType()) { - case CONFIG.OPERATION.TYPE.INSERT: - resOperation = new AttributeAddOperation( - entityId, - value.subjectEntityId, - value.rootSubjectEntityId, - value.type, - value.data - ); - break; - case CONFIG.OPERATION.TYPE.UPDATE: - resOperation = new AttributeDeleteOperation( - entityId, - value.subjectEntityId, - value.rootSubjectEntityId, - value.type - ); - break; - } - break; - case CONFIG.ENTITY.VAL: - resOperation = new ValueChangeOperation( - entityId, - operation.getValue(), - operation.getType(), - operation.getPosition(), - null - ); - break; - } - } - if (resOperation !== null) { - resOperation.setOTOperation(operation); - } - return resOperation; - }, - }; -} - -var OperationFactory$1 = OperationFactory(); +/** + * Namespace for ot operations + * @namespace operations.ot + */ -class OpenAppProvider { - openapp; - gadgets; - constructor() { - var openapp = {}; - this.openapp = openapp; - openapp["event"] = {}; - var gadgets = "undefined" !== typeof this.gadgets ? this.gadgets : {}; - this.gadgets = gadgets; - gadgets.openapp = gadgets.openapp || {}; - var usePostMessage = - "undefined" !== typeof window && - "undefined" !== typeof window.parent && - "undefined" !== typeof window.postMessage && - "undefined" !== typeof JSON && - "undefined" !== typeof JSON.parse && - "undefined" !== typeof JSON.stringify, - usePubSub = - !usePostMessage && - "undefined" !== typeof gadgets && - "undefined" !== typeof gadgets.pubsub && - "undefined" !== typeof gadgets.pubsub.subscribe && - "undefined" !== typeof gadgets.pubsub.unsubscribe && - "undefined" !== typeof gadgets.pubsub.publish, - init = { postParentOnly: true }, - ownData, - doCallback, - onMessage; - usePostMessage - ? ((onMessage = function (a) { - if ( - "string" === typeof a.data && - '{"OpenApplicationEvent":{' === a.data.slice(0, 25) - ) { - var b = JSON.parse(a.data).OpenApplicationEvent; - if ( - "openapp" === b.event && - !0 === b.welcome && - a.source === window.parent - ) { - for (var d in b.message) { - b.message.hasOwnProperty(d) && (init[d] = b.message[d]); - } - } else { - (b.source = a.source), - (b.origin = a.origin), - (b.toJSON = function () { - var a = {}, - b; - for (b in this) { - this.hasOwnProperty(b) && - "function" !== typeof this[b] && - "source" !== b && - "origin" !== b && - (a[b] = this[b]); - } - return a; - }), - "function" === typeof doCallback && - // @ts-ignore - !0 === doCallback(b, b.message) && - window.parent.postMessage( - JSON.stringify({ - OpenApplicationEvent: { event: "openapp", receipt: !0 }, - }), - "*" - ); - } - } - }), - // @ts-ignore - "undefined" !== typeof window.attachEvent - ? // @ts-ignore - window.attachEvent("onmessage", onMessage) - : window.addEventListener("message", onMessage, !1), - "undefined" !== typeof window.parent && - window.parent.postMessage( - JSON.stringify({ - OpenApplicationEvent: { event: "openapp", hello: !0 }, - }), - "*" - )) - : usePubSub && - (onMessage = function (a, b) { - b.source = void 0; - b.origin = void 0; - b.sender = a; - "function" === typeof doCallback && - // @ts-ignore - !0 === doCallback(b, b.message) && - gadgets.pubsub.publish("openapp-recieve", !0); - }); - gadgets.openapp.RDF = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; - gadgets.openapp.connect = function (a) { - doCallback = a; - usePubSub && gadgets.pubsub.subscribe("openapp", onMessage); - }; - gadgets.openapp.disconnect = function () { - usePubSub && gadgets.pubsub.unsubscribe("openapp"); - doCallback = null; - }; - gadgets.openapp.publish = function (a, b) { - a.event = a.event || "select"; - a.type = a.type || "namespaced-properties"; - a.sharing = a.sharing || "public"; - a.date = a.date || new Date(); - a.message = b || a.message; - if (usePostMessage) { - if (!1 === init.postParentOnly && null === ownData) { - // @ts-ignore - ownData = { sender: "unknown", viewer: "unknown" }; - if ( - "undefined" !== typeof window.location && - "string" === typeof window.location.search && - "function" === typeof window.unescape - ) { - var d = window.location.search.substring(1).split("&"), - c, - e = {}; - if (!(1 == d.length && "" === d[0])) { - for (var f = 0; f < d.length; f++) { - (c = d[f].split("=")), - 2 == c.length && (e[c[0]] = window.unescape(c[1])); - } - } - // @ts-ignore - "string" === typeof e.url && (ownData.sender = e.url); - } - if ( - // @ts-ignore - "undefined" !== typeof opensocial && - // @ts-ignore - "function" === typeof opensocial.newDataRequest - ) { - // @ts-ignore - d = opensocial.newDataRequest(); - // @ts-ignore - d.add( - // @ts-ignore - d.newFetchPersonRequest(opensocial.IdSpec.PersonId.VIEWER), - "viewer" - ); - var g = this; - // @ts-ignore - d.send(function (c) { - c = c.get("viewer").getData(); - "object" === typeof c && - null !== c && - "function" === typeof c.getId && - ((c = c.getId()), - // @ts-ignore - "string" === typeof c && (ownData.viewer = c)); - g.publish(a, b); - }); - return; - } - } - null !== ownData && - // @ts-ignore - ("string" === typeof ownData.sender && (a.sender = ownData.sender), - // @ts-ignore - "string" === typeof ownData.viewer && (a.viewer = ownData.viewer)); - // @ts-ignore - d = JSON.stringify({ OpenApplicationEvent: a }); - // @ts-ignore - if ("undefined" !== window.parent) { - if ((window.parent.postMessage(d, "*"), !init.postParentOnly)) { - c = window.parent.frames; - // @ts-ignore - for (e = 0; e < c.length; e++) { - // @ts-ignore - c[e].postMessage(d, "*"); - } - } - } else { - window.postMessage(d, "*"); - } - } else { - usePubSub && gadgets.pubsub.publish("openapp", a); - } - }; - openapp["io"] = {}; - openapp["io"].createXMLHttpRequest = function () { - if ("undefined" !== typeof XMLHttpRequest) { - return new XMLHttpRequest(); - } - // @ts-ignore - if ("undefined" !== typeof ActiveXObject) { - // @ts-ignore - return new ActiveXObject("Microsoft.XMLHTTP"); - } - throw { - name: "XMLHttpRequestError", - message: "XMLHttpRequest not supported", - }; - }; - openapp["io"].makeRequest = function (a, b, d) { - gadgets.io.makeRequest( - a, - function (c) { - var e, f, g, h, j, k, l, p; - if (null === document.getElementById("oauthPersonalize")) { - e = document.createElement("div"); - f = document.createElement("input"); - g = document.createElement("input"); - h = document.createElement("div"); - j = document.createElement("input"); - k = document.createElement("div"); - l = document.createElement("span"); - p = document.createElement("input"); - e.id = "oauthPersonalize"; - f.id = "oauthPersonalizeButton"; - g.id = "oauthPersonalizeDenyButton"; - h.id = "oauthPersonalizeDone"; - j.id = "oauthPersonalizeDoneButton"; - k.id = "oauthPersonalizeComplete"; - l.id = "oauthPersonalizeMessage"; - p.id = "oauthPersonalizeHideButton"; - f.id = "oauthPersonalizeButton"; - e.style.display = "none"; - h.style.display = "none"; - k.style.display = "none"; - f.type = "button"; - g.type = "button"; - j.type = "button"; - p.type = "button"; - f.value = "Continue"; - g.value = "Ignore"; - j.value = "Done"; - p.value = "Hide"; - e.appendChild( - document.createTextNode( - "In order to provide the full functionality of this tool, access to your personal data is being requested." - ) - ); - h.appendChild( - document.createTextNode( - "If you have provided authorization and are still reading this, click the Done button." - ) - ); - var m = document.getElementById("openappDialog"); - null == m && - ((m = document.createElement("div")), - null != document.body.firstChild - ? document.body.insertBefore(m, document.body.firstChild) - : document.body.appendChild(m)); - m.appendChild(e); - m.appendChild(h); - m.appendChild(k); - e.appendChild(f); - e.appendChild(g); - h.appendChild(j); - k.appendChild(l); - k.appendChild(p); - g.onclick = function () { - e.style.display = "none"; - }; - p.onclick = function () { - k.style.display = "none"; - }; - } - if (c.oauthApprovalUrl) { - var r = function () { - q && (window.clearInterval(q), (q = null)); - // @ts-ignore - n && (n.close(), (n = null)); - // @ts-ignore - document.getElementById("oauthPersonalizeDone").style.display = - "none"; - // @ts-ignore - document.getElementById( - "oauthPersonalizeComplete" - ).style.display = "block"; - openapp["io"].makeRequest(a, b, d); - return !1; - }, - s = function () { - // @ts-ignore - if (!n || n.closed) { - (n = null), r(); - } - }, - t = c.oauthApprovalUrl, - n = null, - q = null; - c = { - createOpenerOnClick: function () { - return function () { - // @ts-ignore - if ((n = window.open(t, "_blank", "width=450,height=500"))) { - // @ts-ignore - (q = window.setInterval(s, 100)), - // @ts-ignore - (document.getElementById( - "oauthPersonalize" - ).style.display = "none"), - // @ts-ignore - (document.getElementById( - "oauthPersonalizeDone" - ).style.display = "block"); - } - return !1; - }; - }, - createApprovedOnClick: function () { - return r; - }, - }; - // @ts-ignore - document.getElementById("oauthPersonalizeButton").onclick = - c.createOpenerOnClick(); - // @ts-ignore - document.getElementById("oauthPersonalizeDoneButton").onclick = - c.createApprovedOnClick(); - f = "Please wait."; - document.all - ? // @ts-ignore - (document.getElementById("oauthPersonalizeMessage").innerText = - f) - : // @ts-ignore - (document.getElementById( - "oauthPersonalizeMessage" - ).textContent = f); - // @ts-ignore - document.getElementById("oauthPersonalize").style.display = "block"; - } else { - c.oauthError - ? ((f = - "The authorization was not completed successfully. (" + - c.oauthError + - ")"), - document.all - ? // @ts-ignore - (document.getElementById( - "oauthPersonalizeMessage" - ).innerText = f) - : // @ts-ignore - (document.getElementById( - "oauthPersonalizeMessage" - ).textContent = f), - // @ts-ignore - (document.getElementById( - "oauthPersonalizeComplete" - ).style.display = "block")) - : ((f = - "You have now granted authorization. To revoke authorization, go to your Privacy settings."), - document.all - ? // @ts-ignore - (document.getElementById( - "oauthPersonalizeMessage" - ).innerText = f) - : // @ts-ignore - (document.getElementById( - "oauthPersonalizeMessage" - ).textContent = f), - b(c)); - } - }, - d - ); - }; - openapp["ns"] = {}; - openapp["ns"].rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; - openapp["ns"].rdfs = "http://www.w3.org/2000/01/rdf-schema#"; - openapp["ns"].dcterms = "http://purl.org/dc/terms/"; - openapp["ns"].foaf = "http://xmlns.com/foaf/0.1/"; - openapp["ns"].rest = "http://purl.org/openapp/"; - openapp["ns"].conserve = "http://purl.org/openapp/"; - openapp["ns"].openapp = "http://purl.org/openapp/"; - openapp["ns"].role = "http://purl.org/role/terms/"; - openapp["ns"].widget = "http://purl.org/role/widget/"; - openapp["resource"] = {}; - var linkexp = - /<[^>]*>\s*(\s*;\s*[^\(\)<>@,;:"\/\[\]\?={} \t]+=(([^\(\)<>@,;:"\/\[\]\?={} \t]+)|("[^"]*")))*(,|\$)/g, - paramexp = - /[^\(\)<>@,;:"\/\[\]\?={} \t]+=(([^\(\)<>@,;:"\/\[\]\?={} \t]+)|("[^"]*"))/g; - function unquote(a) { - return '"' === a.charAt(0) && '"' === a.charAt(a.length - 1) - ? a.substring(1, a.length - 1) - : a; - } - function parseLinkHeader(a) { - var b = (a + ",").match(linkexp); - a = {}; - var d = {}, - c = {}, - e, - f, - g, - h, - j, - k; - for (e = 0; e < b.length; e++) { - f = b[e].split(">"); - g = f[0].substring(1); - h = f[1]; - f = {}; - f.href = g; - g = h.match(paramexp); - for (h = 0; h < g.length; h++) { - (j = g[h]), (j = j.split("=")), (k = j[0]), (f[k] = unquote(j[1])); - } - void 0 !== f.rel && "undefined" === typeof f.anchor && (a[f.rel] = f); - void 0 !== f.title && - "undefined" === typeof f.anchor && - (d[f.title] = f); - g = c[f.anchor || ""] || {}; - h = g[f.rel || "http://purl.org/dc/terms/relation"] || []; - h.push({ type: "uri", value: f.href }); - g[f.rel || "http://purl.org/dc/terms/relation"] = h; - c[f.anchor || ""] = g; - } - // @ts-ignore - b = {}; - // @ts-ignore - b.rels = a; - // @ts-ignore - b.titles = d; - // @ts-ignore - b.rdf = c; - return b; - } - var isStringValue = function (a) { - return "" !== a && "string" === typeof a; - }; - openapp["resource"].makeRequest = function (a, b, d, c, e, f) { - var g = openapp["io"].createXMLHttpRequest(), - h, - j = 0; - if ("undefined" !== typeof c) { - for (h in c) { - c.hasOwnProperty(h) && j++; - } - if (0 < j) { - // @ts-ignore - j = ""; - -1 !== b?.indexOf("?") && - ((j = b?.substring(b.indexOf("?"))), - // @ts-ignore - (b = b?.substring(0, b.length - j.length))); - switch (b?.substring(b.length - 1)) { - case "/": - b += ":"; - break; - case ":": - break; - default: - b += "/:"; - } - for (h in c) { - c.hasOwnProperty(h) && - (b = - h === openapp["ns"].rdf + "predicate" - ? b + (";predicate=" + encodeURIComponent(c[h])) - : b + - (";" + - encodeURIComponent(h) + - "=" + - encodeURIComponent(c[h]))); - } - b += j; - } - } - g.open(a, b, !0); - g.setRequestHeader("Accept", "application/json"); - e = e || ""; - if (0 < e.length || "POST" === a || "PUT" === a) { - g.setRequestHeader( - "Content-Type", - "undefined" !== typeof f ? f : "application/json" - ); - } - d = d || function () {}; - g.onreadystatechange = function () { - if (4 === g.readyState) { - var a = { - data: g.responseText, - link: isStringValue(g.getResponseHeader("link")) - ? parseLinkHeader(g.getResponseHeader("link")) - : {}, - }; - isStringValue(g.getResponseHeader("location")) - ? (a["uri"] = g.getResponseHeader("location")) - : isStringValue(g.getResponseHeader("content-base")) - ? (a["uri"] = g.getResponseHeader("content-base")) - : a["link"].hasOwnProperty("http://purl.org/dc/terms/subject") && - (a["uri"] = a["link"]["http://purl.org/dc/terms/subject"].href); - isStringValue(g.getResponseHeader("content-location")) && - (a["contentUri"] = g.getResponseHeader("content-location")); - isStringValue(g.getResponseHeader("content-type")) && - "application/json" === - g.getResponseHeader("content-type").split(";")[0] && - (a.data = JSON.parse(a.data)); - a["subject"] = - "undefined" !== typeof g.responseText - ? a.data.hasOwnProperty("") - ? a.data[""] - : a.data[a["uri"]] || {} - : {}; - d(a); - } - }; - g.send(e); - }; - // @ts-ignore - "undefined" === typeof openapp_forceXhr && - "undefined" !== typeof gadgets && - "undefined" !== typeof gadgets.io && - "undefined" !== typeof gadgets.io.makeRequest && - (openapp["resource"].makeRequest = function (a, b, d, c, e, f) { - var g = {}, - h, - j = 0; - if ("undefined" !== typeof c) { - for (h in c) { - c.hasOwnProperty(h) && j++; - } - if (0 < j) { - // @ts-ignore - j = ""; - -1 !== b.indexOf("?") && - ((j = b.substring(b.indexOf("?"))), - // @ts-ignore - (b = b.substring(0, b.length - j.length))); - switch (b.substring(b.length - 1)) { - case "/": - b += ":"; - break; - case ":": - break; - default: - b += "/:"; - } - for (h in c) { - c.hasOwnProperty(h) && - (b = - h === openapp["ns"].rdf + "predicate" - ? b + (";predicate=" + encodeURIComponent(c[h])) - : b + - (";" + - encodeURIComponent(h) + - "=" + - encodeURIComponent(c[h]))); - } - b += j; - } - } - g[gadgets.io.RequestParameters.GET_FULL_HEADERS] = !0; - g[gadgets.io.RequestParameters.CONTENT_TYPE] = - gadgets.io.ContentType.TEXT; - g[gadgets.io.RequestParameters.AUTHORIZATION] = - gadgets.io.AuthorizationType.OAUTH; - g[gadgets.io.RequestParameters.OAUTH_SERVICE_NAME] = "openapp"; - g[gadgets.io.RequestParameters.OAUTH_USE_TOKEN] = "always"; - g[gadgets.io.RequestParameters.METHOD] = a; - g[gadgets.io.RequestParameters.HEADERS] = - g[gadgets.io.RequestParameters.HEADERS] || {}; - "undefined" !== typeof e && - null !== e && - ((g[gadgets.io.RequestParameters.HEADERS]["Content-Type"] = - "undefined" !== typeof f ? f : "application/json"), - (g[gadgets.io.RequestParameters.POST_DATA] = e)); - g[gadgets.io.RequestParameters.HEADERS].Accept = "application/json"; - d = d || function () {}; - openapp["io"].makeRequest( - b, - function (a) { - var b = { - data: a.data, - link: - "undefined" !== typeof a.headers.link - ? parseLinkHeader(a.headers.link[0]) - : {}, - }; - a.headers.hasOwnProperty("location") - ? (b["uri"] = a.headers.location[0]) - : a.headers.hasOwnProperty("content-base") - ? (b["uri"] = a.headers["content-base"][0]) - : // @ts-ignore - b["link"].hasOwnProperty("http://purl.org/dc/terms/subject") && - // @ts-ignore - (b["uri"] = b["link"]["http://purl.org/dc/terms/subject"].href); - a.headers.hasOwnProperty("content-location") && - (b["contentUri"] = a.headers["content-location"][0]); - a.headers.hasOwnProperty("content-type") && - "application/json" === - a.headers["content-type"][0].split(";")[0] && - (b.data = gadgets.json.parse(b.data)); - b["subject"] = - "undefined" !== typeof a.data - ? b.data.hasOwnProperty("") - ? b.data[""] - : b.data[b["uri"]] || {} - : {}; - d(b); - }, - g - ); - }); - openapp["resource"].get = function (a, b, d) { - return openapp["resource"].makeRequest( - "GET", - a, - b, - d || { - "http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate": - openapp["ns"].conserve + "info", - } - ); - }; - openapp["resource"].post = function (a, b, d, c, e) { - return openapp["resource"].makeRequest("POST", a, b, d, c, e); - }; - openapp["resource"].put = function (a, b, d, c, e) { - return openapp["resource"].makeRequest("PUT", a, b, d, c, e); - }; - openapp["resource"].del = function (a, b, d) { - return openapp["resource"].makeRequest("DELETE", a, b, d); - }; - openapp["resource"].context = function (a) { - return { - sub: function (b) { - var d = {}; - return { - control: function (a, b) { - d[a] = b; - return this; - }, - type: function (a) { - return this.control(openapp["ns"].rdf + "type", a); - }, - seeAlso: function (a) { - return this.control(openapp["ns"].rdfs + "seeAlso", a); - }, - list: function () { - var c = [], - e = a["subject"][b], - f, - g, - h, - j, - k, - l; - if ("undefined" === typeof e) { - return c; - } - h = 0; - a: for (; h < e.length; h++) { - f = e[h]; - g = a.data[f.value]; - for (j in d) { - if (d.hasOwnProperty(j)) { - if (!g.hasOwnProperty(j)) { - continue a; - } - l = !1; - for (k = 0; k < g[j].length; k++) { - if (g[j][k].value === d[j]) { - l = !0; - break; - } - } - if (!l) { - continue a; - } - } - } - // @ts-ignore - c.push({ data: a.data, link: {}, uri: f.value, subject: g }); - } - return c; - }, - create: function (c) { - if (!a["link"].rdf.hasOwnProperty(b)) { - throw ( - "The context does not support the requested relation: " + b - ); - } - var e = a["uri"]; - d[openapp["ns"].rdf + "predicate"] = b; - openapp["resource"].post( - e, - function (a) { - c(a); - }, - d - ); - }, - }; - }, - metadata: function () { - return openapp["resource"] - .context(a) - .content(openapp["ns"].rest + "metadata"); - }, - representation: function () { - return openapp["resource"] - .context(a) - .content(openapp["ns"].rest + "representation"); - }, - content: function (b) { - return { - get: function (d) { - openapp["resource"].get( - a["uri"], - function (a) { - d(a); - }, - { "http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate": b } - ); - }, - mediaType: function (d) { - var c = null; - return { - string: function (a) { - c = a; - return this; - }, - json: function (a) { - c = JSON.stringify(a); - return this; - }, - put: function (e) { - openapp["resource"].put( - a["uri"], - function (a) { - "function" === typeof e && e(a); - }, - { - "http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate": b, - }, - c, - d - ); - }, - }; - }, - string: function (a) { - return this.mediaType("text/plain").string(a); - }, - json: function (a) { - return this.mediaType("application/json").json(a); - }, - graph: function () { - var d = {}, - c = ""; - return { - subject: function (a) { - c = a; - return this; - }, - resource: function (a, b) { - d[c] = d[c] || {}; - d[c][a] = d[c][a] || []; - d[c][a].push({ value: b, type: "uri" }); - return this; - }, - literal: function (a, b, g, h) { - d[c] = d[c] || {}; - d[c][a] = d[c][a] || []; - d[c][a].push({ - value: b, - type: "literal", - lang: g, - datatype: h, - }); - return this; - }, - put: function (c) { - openapp["resource"].put( - a["uri"], - function (a) { - "function" === typeof c && c(a); - }, - { - "http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate": b, - }, - JSON.stringify(d) - ); - }, - }; - }, - }; - }, - properties: function () { - var b = {}, - d; - for (d in a["subject"]) { - a["subject"].hasOwnProperty(d) && (b[d] = a["subject"][d][0].value); - } - return b; - }, - string: function () { - return "string" === typeof a.data - ? a.data - : gadgets.json.stringify(a.data); - }, - json: function () { - return "string" === typeof a.data ? null : a.data; - }, - followSeeAlso: function () { - var b = a["subject"][openapp["ns"].rdfs + "seeAlso"], - d = 0, - c, - e; - if ("undefined" !== typeof b) { - b = b[0].value; - for ( - e = 0; - e < b.length && - e < a["uri"].length && - b.charAt(e) === a["uri"].charAt(e); - e++ - ) { - "/" === b.charAt(e) && d++; - } - for (c = d; e < b.length; e++) { - "/" === b.charAt(e) && c++; - } - return 3 > d || 4 < c - ? this - : openapp["resource"].context({ - data: a.data, - link: {}, - uri: b, - subject: a.data[b], - }); - } - return this; - }, - }; - }; - openapp["resource"].content = function (a) { - return { - properties: function () { - return openapp["resource"].context(a).properties(); - }, - string: function () { - return openapp["resource"].context(a).string(); - }, - json: function () { - return openapp["resource"].context(a).json(); - }, - }; - }; - openapp["oo"] = {}; - openapp["oo"].Resource = function (a, b, d) { - this.uri = a; - this.context = b; - this.info = d; - }; - var OARP = openapp["oo"].Resource.prototype; - OARP.getURI = function () { - return this.uri; - }; - OARP._call = function (a) { - var b = this; - null == this.context - ? null == this._deferred - ? ((this._deferred = [a]), - openapp["resource"].get(this.uri, function (a) { - b.context = a; - a = b._deferred; - delete b._deferred; - for (var c = 0; c < a.length; c++) { - a[c].call(b); - } - })) - : this._deferred.push(a) - : a.call(b); - }; - OARP.refresh = function (a) { - delete this.context; - delete this.info; - a && - this._call(function () { - a(); - }); - }; - OARP.getSubResources = function (a) { - this._call(function () { - for ( - var b = - null != a.type - ? openapp["resource"] - .context(this.context) - .sub(a.relation) - .type(a.type) - .list() - : openapp["resource"] - .context(this.context) - .sub(a.relation) - .list(), - d = [], - c = 0; - c < b.length; - c++ - ) { - var e = b[c].uri; - if (a.followReference) { - var f = - this.context.data[e]["http://www.w3.org/2002/07/owl#sameAs"]; - null != f && 0 < f.length && (e = f[0].value); - } - f = new openapp["oo"].Resource(e, null, b[c]); - null == a.followReference && - ((f._referenceLoaded = !0), - (e = this.context.data[e]["http://www.w3.org/2002/07/owl#sameAs"]), - null != e && 0 < e.length && (f._reference = e[0].value)); - if (a.onEach) { - a.onEach(f); - } - a.onAll && d.push(f); - } - if (a.onAll) { - a.onAll(d); - } - }); - }; - OARP.followReference = function (a) { - this._referenceLoaded - ? a( - null != this._reference - ? new openapp["oo"].Resource(this._reference) - : this - ) - : this._call(function () { - var b = - this.context.data[this.uri][ - "http://www.w3.org/2002/07/owl#sameAs" - ]; - null != b && 0 < b.length - ? a(new openapp["oo"].Resource(b[0].value)) - : a(this); - }); - }; - OARP.getReference = function (a) { - this._referenceLoaded - ? a(this._reference) - : this._call(function () { - var b = this.context.subject[openapp["ns"].rdfs + "seeAlso"]; - null != b && 0 < b.length - ? a(this.context.subject[openapp["ns"].rdfs + "seeAlso"][0].value) - : a(); - }); - }; - OARP.getMetadata = function (a, b) { - this._call(function () { - openapp["resource"] - .context(this.context) - .metadata() - .get(function (d) { - switch (a || "properties") { - case "properties": - b(openapp["resource"].context(d).properties()); - break; - case "graph": - b(openapp["resource"].content(d).graph()); - break; - case "rdfjson": - b(openapp["resource"].content(d).json()); - } - }); - }); - }; - OARP.getInfo = function (a) { - if (a) { - this.context || this.info - ? a( - openapp["resource"] - .context(this.context || this.info) - .properties() - ) - : this._call(function () { - a( - openapp["resource"] - .context(this.context || this.info) - .properties() - ); - }); - } else { - if (this.context || this.info) { - return openapp["resource"] - .context(this.context || this.info) - .properties(); - } - } - }; - OARP.getRepresentation = function (a, b) { - this._call(function () { - openapp["resource"] - .context(this.context) - .representation() - .get(function (d) { - switch (a || "text/html") { - case "properties": - b(openapp["resource"].context(d).properties()); - break; - case "graph": - b(openapp["resource"].content(d).graph()); - break; - case "rdfjson": - b(openapp["resource"].content(d).json()); - break; - case "text/html": - b(openapp["resource"].content(d).string()); - } - }); - }); - }; - OARP.setMetadata = function (a, b, d) { - var c = {}; - switch (b || "properties") { - case "properties": - b = {}; - for (var e in a) { - b[e] = [{ type: "literal", value: a[e] }]; - } - c[this.context.uri] = b; - break; - case "rdfjson": - c = a; - break; - case "graph": - // @ts-ignore - graph.put(d); - return; - } - openapp["resource"].put( - this.context.uri, - d, - { - "http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate": - openapp["ns"].rest + "metadata", - }, - JSON.stringify(c) - ); - }; - OARP.setRepresentation = function (a, b, d) { - this._call(function () { - var c = openapp["resource"] - .context(this.context) - .representation() - .mediaType(b); - "string" === typeof a ? c.string(a).put(d) : c.json(a).put(d); - }); - }; - OARP.create = function (a) { - this._call(function () { - var b = openapp["resource"] - .context(this.context) - .sub(a.relation || openapp["ns"].role + "data"); - null != a.referenceTo && (b = b.seeAlso(a.referenceTo)); - null != a.type && (b = b.type(a.type)); - b.create(function (b) { - var c = new openapp["oo"].Resource(b["uri"], b); - a.metadata - ? c.setMetadata(a.metadata, a.format, function () { - a.representation - ? c.setRepresentation( - a.representation, - a.medieType || "application/json", - function () { - a.callback(c); - } - ) - : a.callback(c); - }) - : a.representation - ? c.setRepresentation( - a.representation, - a.medieType || "application/json", - function () { - a.callback(c); - } - ) - : a.callback(c); - }); - }); - }; - OARP.del = function (a) { - openapp["resource"].del(this.uri, a); - }; - openapp["param"] = {}; - var parseQueryParams = function (a) { - var b, - d, - c = {}; - if (0 > a.indexOf("?")) { - return {}; - } - a = a.substr(a.indexOf("?") + 1).split("&"); - if (!(1 == a.length && "" === a[0])) { - for (d = 0; d < a.length; d++) { - (b = a[d].split("=")), - 2 == b.length && (c[b[0]] = window.unescape(b[1])); - } - } - return c; - }, - parseOpenAppParams = function (a) { - var b = {}, - d = {}, - c, - e; - for (c in a) { - a.hasOwnProperty(c) && - "openapp['ns']." === c.substring(0, 11) && - (b[c.substr(11)] = a[c]); - } - for (c in a) { - a.hasOwnProperty(c) && - ((e = c.split(".")), - 3 === e.length && - "openapp" === e[0] && - b.hasOwnProperty(e[1]) && - (d[b[e[1]] + e[2]] = a[c])); - } - return d; - }, - _openAppParams = parseOpenAppParams( - parseQueryParams(parseQueryParams(window.location.href)["url"] || "") - ); - openapp["param"].get = function (a) { - return _openAppParams[a]; - }; - openapp["param"].space = function () { - return openapp["param"].get("http://purl.org/role/terms/space"); - }; - openapp["param"].user = function () { - return openapp["param"].get("http://purl.org/role/terms/user"); - }; - } -} - -const openapp$2 = new OpenAppProvider().openapp; -/** - * Util - * @class Util - * @name Util - * @constructor - */ -var Util = { - /** - * Generate random hex string - * @param {number} [length] Length of string (Default=24) - * @returns {string} - */ - generateRandomId: function (length) { - var chars = "1234567890abcdef"; - var numOfChars = chars.length; - var i, rand; - var res = ""; - - if (typeof length === "undefined") length = 24; - - for (i = 0; i < length; i++) { - rand = Math.floor(Math.random() * numOfChars); - res += chars[rand]; - } - return res; - }, - - generateAnonymousUser: function () { - const user = {}; - var id = this.generateRandomId(); - user[CONFIG.NS.PERSON.TITLE] = "Anonymous"; - user[CONFIG.NS.PERSON.JABBERID] = id; - user[CONFIG.NS.PERSON.MBOX] = id + "@anonym.com"; - user.globalId = -1; - user.self = true; - return user; - }, - - /** - * Wait for delay milliseconds then return - * @param delay - * @returns {promise} - */ - delay: function (delay) { - var deferred = jQuery.Deferred(); - setTimeout(function () { - deferred.resolve(); - }, delay); - return deferred.promise(); - }, - - /** - * Union the two passed objects into a new object (on a duplicate key, the first object has priority) - * @param {object} obj1 - * @param {object} obj2 - * @returns {object} - */ - union: function (obj1, obj2) { - var res = {}, - i; - for (i in obj1) { - if (obj1.hasOwnProperty(i)) { - res[i] = obj1[i]; - } - } - for (i in obj2) { - if (obj2.hasOwnProperty(i) && !obj1.hasOwnProperty(i)) { - res[i] = obj2[i]; - } - } - return res; - }, - - /** - * Merge the elements of the second object into the first (on a duplicate key, the first object has priority) - * @param {object} obj1 - * @param {object} obj2 - * @returns {object} - */ - merge: function (obj1, obj2) { - var i; - for (i in obj2) { - if (obj2.hasOwnProperty(i) && !obj1.hasOwnProperty(i)) { - obj1[i] = obj2[i]; - } - } - return obj1; - }, - - /** - * Converts an async function that expects a callback as last parameter into a promise - * @param func - * @returns {promise} - */ - toPromise: function (func) { - return function () { - //noinspection JSAccessibilityCheck - var args = Array.prototype.slice.call(arguments); - var deferred = jQuery.Deferred(); - args.push(function () { - deferred.resolve.apply(this, arguments); - }); - func.apply(this, args); - return deferred.promise(); - }; - }, - - COLORS: [ - "#8AFFC8", //türkis - "#8A9FFF", //light blue - "#FF8A8A", //Rot - "#FFC08A", //Orange - "#FF8AD2", //Pink - "#8AEBFF", //Blue - "#C68AFF", //Lila - "#8EFF8A", //green - ], - - /** - * Map an integer to one of ten colors - * @param id - * @returns {string} - */ - getColor: function (id) { - return this.COLORS[id % this.COLORS.length]; - }, - - /*function hashCode(s){ - return s.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0); - };*/ - /** - * Returns the id of the given user (will be its index in the user list) - * @param {*} user - * @param {*} y the shared yjs document - * @returns - */ - getGlobalId: function (user, y) { - var mbox = user.user[CONFIG.NS.PERSON.MBOX]; // mailbox of the user - const userMap = y.getMap("users"); - var users = Array.from(userMap.values()); // get all users - var id = users.indexOf(mbox); - if (id === -1) { - id = users.length; - userMap.set(y.clientID, mbox); - } - return id; - }, - - /** - * Get the current state of the primary document store - * @returns {*} - * @constructor - */ - GetCurrentBaseModel: function () { - var resourceSpace = new openapp$2.oo.Resource(openapp$2.param.space()); - var deferred = jQuery.Deferred(); - resourceSpace.getSubResources({ - relation: openapp$2.ns.role + "data", - type: CONFIG.NS.MY.MODEL, - onAll: function (data) { - if (data === null || data.length === 0) { - deferred.resolve([]); - } else { - data[0].getRepresentation("rdfjson", function (representation) { - if (!representation) { - deferred.resolve([]); - } else { - deferred.resolve(representation); - } - }); - } - }, - }); - return deferred.promise(); - }, - - getSpaceTitle: function (url) { - return url - .substring(url.lastIndexOf("spaces/")) - .replace(/spaces|#\S*|\?\S*|\//g, ""); - }, -}; + /** + * OTOperation + * @class operations.ot.OTOperation + * @memberof operations.ot + * @constructor + * @param {string} name Name of operation + * @param {string} value Value of operation + * @param {string} type Type of operation + * @param {number} position Position of operation + */ + class OTOperation extends Operation { + constructor(name, value, type, position) { + super(); + /** + * JabberId of the user who issued this activity + * @type {string} + * @private + */ + var _sender = null; + + + /** + * Operation details + * @type {{name: string, value: string, type: string, position: number}} + * @private + */ + var _operation = { + name: name, + value: value, + type: type, + position: position + }; -/** - * Provides messaging functionality. - * @param {Array} categories - (currently not implemented) categories of widgets that shall process the intent (e.g. ["editor","proxy" ]) - * @param {String} origin - The origin (i.e. the url where your application script lives) is needed for messaging - * @param {} y - A reference to yjs' Y object for global messaging - */ -class Client { - //console.log(y); - _y; - _componentName = "unknown"; - - //private variables - _connected = false; - _categories; - _callback; - - // Needed for HTML5 messaging - _origin; - - constructor(componentName, categories, origin, y) { - //console.log(y); - this._y = y; - - this._componentName = componentName; - this._categories = categories; - // Needed for HTML5 messaging - this._origin = origin; - } - - /** - * Connect widget to messaging. This sets up the callback function and creates - * an event listener for HTML5 messaging and a yjs observer for global messaging. - * If yjs is not available only local messaging is set up. - * @param {function} callback - The callback function used for receiving messages. - */ - connect(callback) { - this._callback = callback; - var handler = this.receiveMessage.bind(this); - //Todo - const widgetTageName = getWidgetTagName(this._componentName); - try { - const _node = document.querySelector(widgetTageName); - - if (!_node) { - throw new Error( - "html tag not found in document. Please make sure that you added the " + - widgetTageName + - " to the document. Hint: do not use the shadow dom." - ); - } - _node.addEventListener("syncmeta-message", handler); - } catch (error) { - console.error(error); - } - - - if (this._y) { - // If yjs is available also connect a global listener - const intents = this._y.getMap("intents"); - if (intents) intents.observe(handler); - } - } - - /** - * Disconnect the widget from messaging. This removes the event listener - * and the callback for both local and global messaging. If yjs is not available, - * only local messaging will be available. - */ - disconnect() { - //THISELEMENT.removeEventListener("syncmeta-message", this.receiveMessage, false); - this._callback = null; - - if (!(this._y === null || this._y === undefined)) { - this._y.getMap("intents").unobserve(this.receiveMessage); - } - } - - /** - * Publishes an intent, - * @param {intent} - The intent about to be published, this object contains all information. - */ - publish(intent) { - if (util.validateIntent(intent)) { - if (intent.flags[0] === util.FLAGS.PUBLISH_GLOBAL) { - this.publishGlobal(intent, this._y); - } else if (intent.flags[0] === util.FLAGS.PUBLISH_LOCAL) { - this.publishLocal(intent, this._origin); - } - } - } - - publishLocal(intent, origin) { - //Find iframe and post message - const widgets = []; - for (const el of document.querySelectorAll("*")) { - if (el.tagName.match(/-widget$/i)) { - widgets.push(el); - } - } - - widgets.forEach(function (widget) { - const receiverTagName = getWidgetTagName(intent.receiver.toLowerCase()); - if (widget.tagName.toLowerCase() === receiverTagName.toLowerCase()) { - const event = new CustomEvent("syncmeta-message", { - detail: { - intent, - origin, - }, - }); - widget.dispatchEvent(event); - } - }); - } - - publishGlobal(intent, y) { - //y.share.intents.push(intent); - y.getMap("intents").set(intent.receiver, intent); - } - - /** - * Unpack events and pre process them. This unwraps HTML5 messages and manages the yjs map - * used for global messaging. - * @param {Event} event - The event that activated the callback - */ - receiveMessage(event) { - // Local messaging events - if (event.type === "syncmeta-message") { - //Unpack message events - if (event instanceof CustomEvent) { - this._callback(event.detail.intent); - } - } else if (event.type === "add" || event.type == "update") { - //Unpack yjs event and remove from map - var intent = event.object.get(event.name); - event.object.delete(event.name); - console.log(intent); - this._callback(intent); - } - } -} - -//======================= IWC.util ============================== - -class util { - /** - * Used to determine whether global or local messaging should be used. - * Local messaging uses HTML5 messaging, global messaging uses yjs. - */ - static FLAGS = { - PUBLISH_LOCAL: "PUBLISH_LOCAL", - PUBLISH_GLOBAL: "PUBLISH_GLOBAL", - }; - - /** - * Check intent for correctness. - */ - static validateIntent(intent) { - if (typeof intent.sender != "string") { - throw new Error( - "Intent object must possess property 'component' of type 'String'" - ); - } - if (typeof intent.data != "string") { - throw new Error( - "Intent object must possess property 'data' of type 'String'" - ); - } - if (typeof intent.dataType != "string") { - throw new Error( - "Intent object must possess property 'dataType' of type 'String'" - ); - } - return true; - } -} - -var PAYLOAD_DATA_TYPE = { - OT_OPERATION: "OTOperation", - NON_OT_OPERATION: "NonOTOperation", -}; - -class IWCWrapper { - /** - * Inter-widget communication wrapper - * @class IWCWrapper - * @constructor - * @param componentName Name of component (widget) using the wrapper - */ - - /** - * Set if local messages should be buffered - * @type {boolean} - */ - BUFFER_ENABLED = false; - - /** - * Interval for sending buffered local messages - * @type {number} - */ - INTERVAL_SEND = 25; - - Space = null; - - //noinspection JSMismatchedCollectionQueryUpdate - /** - * Buffer for local messages - * @type {Array} - * @private - */ - _messageBuffer = []; - - //noinspection JSMismatchedCollectionQueryUpdate - /** - * Set of registered Callbacks for local data receive events - * @type {Array} - * @private - */ - _onDataReceivedCallbacks = []; - - _onDataReceivedCallers = []; - - /** - * Stores (for each user) the times an inocming messages has been received to drop duplicate (same time) messages - * @type {object} - * @private - */ - _times = {}; - - /** - * Inter widget communication client - * @type {iwc.Client} - * @private - */ - _iwc; - /** - * Disconnect the iwc client - * @memberof IWCWrapper# - */ - disconnect; - /** - * Connect the iwc client - * @memberof IWCWrapper# - */ - connect; - sendLocalMessage; - sendLocalOTOperation; - sendLocalNonOTOperation; - getUserColor; - registerOnDataReceivedCallback; - unregisterOnDataReceivedCallback; - getUser; - getMembers; - getSpaceTitle; - setSpace; - componentName; - - /** - * Encapsulates the passed message information into the Android Intent-like format required by the iwc client - * @param {string} receiver Component name of the receiving component (widget), empty string for remote messages - * @param {string|string[]} flags Single flag or array of flags to indicate if the messages should be propagate locally or remotely - * @param {string} action Type of data (DATA, DATA_ARRAY, SYNC) - * @param {object} payload Message Payload - * @returns {Object} - */ - encapsulateMessage(receiver, flags, action, payload) { - var i, numOfFlags, flag; - // @ts-ignore - var validatedFlags = []; - - if (flags instanceof Array) { - for (i = 0, numOfFlags = flags.length; i < numOfFlags; i++) { - flag = flags[i]; - if ( - flag === CONFIG.IWC.FLAG.PUBLISH_LOCAL || - flag === CONFIG.IWC.FLAG.PUBLISH_GLOBAL - ) { - // @ts-ignore - validatedFlags.push(flag); - } - } - } else if (typeof flags === "string") { - if ( - flags === CONFIG.IWC.FLAG.PUBLISH_LOCAL || - flags === CONFIG.IWC.FLAG.PUBLISH_GLOBAL - ) { - // @ts-ignore - validatedFlags.push(flags); - } - } else { - throw "Parameter flags has wrong type. Array or String expected."; - } - - if (typeof action !== "string") { - throw "Parameter action has wrong type. String expected."; - } - - receiver = receiver || ""; - - return { - receiver: receiver, - sender: this.componentName, - data: "", - dataType: "", - action: action, - flags: validatedFlags, - extras: { - payload: payload, - time: new Date().getTime(), - }, - }; - } - - /** - * Send all buffered local messages encapsulated in one message - */ - sendBufferedMessages() { - var intent; - var data = null; - - for (var receiver in this._messageBuffer) { - if (this._messageBuffer.hasOwnProperty(receiver)) { - data = this._messageBuffer[receiver].splice( - 0, - this._messageBuffer[receiver].length - ); - //sendBufferTimer.pause(); - if (data.length == 1) { - intent = this.encapsulateMessage( - receiver, - CONFIG.IWC.FLAG.PUBLISH_LOCAL, - CONFIG.IWC.ACTION.DATA, - data[0] - ); - if (util.validateIntent(intent)) { - //console.log("=== " + intent.flags.toString().replace(/PUBLISH_/g, "") + " INTENT TRANSMITTED AT COMPONENT " + componentName + " ==="); - //console.log(intent); - - this._iwc.publish(intent); - } - } else if (data.length > 1) { - intent = this.encapsulateMessage( - receiver, - CONFIG.IWC.FLAG.PUBLISH_LOCAL, - CONFIG.IWC.ACTION.DATA_ARRAY, - data - ); - if (util.validateIntent(intent)) { - //console.log("=== " + intent.flags.toString().replace(/PUBLISH_/g, "") + " INTENT TRANSMITTED AT COMPONENT " + componentName + " ==="); - //console.log(intent); - - this._iwc.publish(intent); - } - } - } - } - //sendBufferTimer.resume(); - } - - /** - * Callback for received local messages - * @param {object} intent Message content in Android Intent-like format required by the iwc client - */ - onIntentReceivedCallback(_self, intent) { - //some CAE widgets still use the old iwc.js library - //then it happens that intent are not parsed and processes correctly by the new iwc and then - //the complete message as string is returned - //this workaround should help for now to make it work with syncmeta - if (typeof intent === "string") { - try { - intent = JSON.parse(intent); - if (intent.hasOwnProperty("OpenApplicationEvent")) { - intent = intent["OpenApplicationEvent"]; - if (intent.hasOwnProperty("message")) intent = intent.message; - } - } catch (e) { - return; - } - } - - if ( - !intent.hasOwnProperty("extras") || - !intent.extras.hasOwnProperty("payload") - ) { - return; - } - - var payload = intent.extras.payload, - senderTime = intent.extras.time, - senderTimes = _self._times[intent.sender]; - - var i, numOfSenderTimes, numOfMessages; - - function handleMessage(payload) { - var type, data, sender, operation, resOperation, i, numOfCallbacks; - - if ( - !payload || - !payload.hasOwnProperty("type") || - !payload.hasOwnProperty("data") - ) { - return; - } - type = payload.type; - data = payload.data; - sender = payload.sender; - switch (type) { - case PAYLOAD_DATA_TYPE.OT_OPERATION: - operation = new OTOperation( - data.name, - data.value, - data.type, - data.position - ); - operation.setSender(sender); - resOperation = - OperationFactory$1.createOperationFromOTOperation(operation); - //adjustHistory(remoteOp); - for ( - i = 0, numOfCallbacks = _self._onDataReceivedCallbacks.length; - i < numOfCallbacks; - i++ - ) { - if (typeof _self._onDataReceivedCallbacks[i] === "function") { - var caller = _self._onDataReceivedCallers[i] || _self; - _self._onDataReceivedCallbacks[i].call(caller, resOperation); - } - } - break; - case PAYLOAD_DATA_TYPE.NON_OT_OPERATION: - operation = new NonOTOperation(data.type, data.data); - operation.setSender(sender); - resOperation = - OperationFactory$1.createOperationFromNonOTOperation(operation); - //adjustHistory(remoteOp); - for ( - i = 0, numOfCallbacks = _self._onDataReceivedCallbacks.length; - i < numOfCallbacks; - i++ - ) { - if (typeof _self._onDataReceivedCallbacks[i] === "function") { - var caller = _self._onDataReceivedCallers[i] || _self; - _self._onDataReceivedCallbacks[i].call(caller, resOperation); - } - } - break; - } - } - - if (intent.flags.indexOf(CONFIG.IWC.FLAG.PUBLISH_GLOBAL) !== -1) return; - - if (typeof senderTimes === "undefined") { - senderTimes = _self._times[intent.sender] = []; - } else { - for ( - i = 0, numOfSenderTimes = senderTimes.length; - i < numOfSenderTimes; - i++ - ) { - if (senderTime === senderTimes[i]) { - return; - } - } - } - - senderTimes.push(senderTime); - - //console.log("=== " + intent.flags.toString().replace(/PUBLISH_/g,"") + " INTENT RECEIVED AT COMPONENT " + componentName + " ==="); - //console.log(intent); - - switch (intent.action) { - case CONFIG.IWC.ACTION.DATA: - handleMessage(payload); - break; - case CONFIG.IWC.ACTION.DATA_ARRAY: - for (i = 0, numOfMessages = payload.length; i < numOfMessages; i++) { - handleMessage(payload[i]); - } - break; - } - } - - constructor(componentName, y) { - this.componentName = componentName; - this._iwc = new Client(componentName, "*", null, y); - window._iwc_instance_ = this._iwc; - - //var sendBufferTimer; - //if(BUFFER_ENABLED) sendBufferTimer = new IWCWrapper.PausableInterval(sendBufferedMessages, INTERVAL_SEND); - if (this.BUFFER_ENABLED) - setInterval(this.sendBufferedMessages, this.INTERVAL_SEND); - - this.connect = () => - this._iwc.connect((intent) => - this.onIntentReceivedCallback(this, intent) - ); - this.disconnect = () => this._iwc.disconnect; - - /** - * Send data locally to an other component - * @memberof IWCWrapper# - * @param {string} receiver Component name of receiving component, empty string for broadcast - * @param {object} data Data to send - */ - this.sendLocalMessage = function (receiver, data) { - var intent; - - if (!receiver || receiver === "") return; - - if (this.BUFFER_ENABLED) { - //sendBufferTimer.pause(); - if (this._messageBuffer.hasOwnProperty(receiver)) { - this._messageBuffer[receiver].push(data); - } else { - this._messageBuffer[receiver] = [data]; - } - //sendBufferTimer.resume(); - } else { - intent = this.encapsulateMessage( - receiver, - CONFIG.IWC.FLAG.PUBLISH_LOCAL, - CONFIG.IWC.ACTION.DATA, - data - ); - if (util.validateIntent(intent)) { - //console.log("=== " + intent.flags.toString().replace(/PUBLISH_/g,"") + " INTENT TRANSMITTED AT COMPONENT " + componentName + " ==="); - //console.log(intent); - - this._iwc.publish(intent); - } - } - }; - /** - * Send OTOperation locally to an other component - * @memberof IWCWrapper# - * @param {string} receiver Component name of receiving component, empty string for broadcast - * @param {operations.ot.OTOperation} operation Operation to send - */ - this.sendLocalOTOperation = function (receiver, operation) { - this.sendLocalMessage(receiver, { - type: PAYLOAD_DATA_TYPE.OT_OPERATION, - data: operation.getOperationObject(), - sender: operation.getSender(), - }); - }; - /** - * Send NonOTOperation locally to an other component - * @memberof IWCWrapper# - * @param {string} receiver Component name of receiving component, empty string for broadcast - * @param {operations.non_ot.NonOTOperation} operation Operation to send - */ - this.sendLocalNonOTOperation = function (receiver, operation) { - this.sendLocalMessage(receiver, { - type: PAYLOAD_DATA_TYPE.NON_OT_OPERATION, - data: operation.getOperationObject(), - sender: operation.getSender(), - }); - }; - this.getUserColor = function (jabberId) { - return Util.getColor(this.Space.members[jabberId].globalId); - }; - /** - * Register callback for local data receive events - * @memberof IWCWrapper# - * @param {function} callback - */ - this.registerOnDataReceivedCallback = function (callback, caller) { - if (typeof callback === "function") { - this.unregisterOnDataReceivedCallback(callback); - this._onDataReceivedCallbacks.push(callback); - this._onDataReceivedCallers.push(caller); - } - }; - /** - * Unregister callback for local data receive events - * @memberof IWCWrapper# - * @param {function} callback - */ - this.unregisterOnDataReceivedCallback = function (callback) { - var i, numOfCallbacks; - - if (typeof callback === "function") { - for ( - i = 0, numOfCallbacks = this._onDataReceivedCallbacks.length; - i < numOfCallbacks; - i++ - ) { - if (callback === this._onDataReceivedCallbacks[i]) { - this._onDataReceivedCallbacks.splice(i, 1); - this._onDataReceivedCallers.splice(i, 1); - } - } - } - }; - this.getUser = function () { - if (!this.Space) { - console.error("Space is null"); - this.Space = { user: {} }; - } else if (!this.Space.user) { - console.error("User in space is null, generating new anonymous user"); - this.Space.user = Util.generateAnonymousUser(); - } - return this.Space.user; - }; - this.getMembers = function () { - return this.Space.members; - }; - this.getSpaceTitle = function () { - return this.Space.title; - }; - this.setSpace = function (s) { - this.Space = s; - }; - - return this; - } -} - -/** - * Inter widget communication and OT client module - * @exports IWCW - */ -class IWCW { - static instances = {}; //static variable to store instances of IWCWrapper. One for each widget - constructor() {} - /** - * Instance of IWCWrapper - * @type {IWCWrapper} - */ - - static hasInstance(componentName) { - return componentName in IWCW.instances; - } - - /** - * Get instance of IWCOTWrapper - * @param {string} componentName Name of component (widget) using the wrapper - * @returns {IWCWrapper} - */ - static getInstance(componentName, y) { - if (!this.hasInstance(componentName)) { - y = y || window.y; - if (!y) { - console.error( - "y is null, y is the shared y document that should be passed along when calling getInstance, proceed with caution" - ); - } - IWCW.instances[componentName] = new IWCWrapper(componentName, y); - IWCW.instances[componentName].connect(); - } - return IWCW.instances[componentName]; - } -} - -$.fn.autoGrowInput = function (o) { - o = $.extend( - { - maxWidth: 1000, - minWidth: 0, - comfortZone: 70, - }, - o - ); - - this.filter("input:text").each(function () { - var minWidth = o.minWidth || $(this).width(), - val = "", - input = $(this), - testSubject = $("").css({ - position: "absolute", - top: -9999, - left: -9999, - width: "auto", - fontSize: input.css("fontSize"), - fontFamily: input.css("fontFamily"), - fontWeight: input.css("fontWeight"), - letterSpacing: input.css("letterSpacing"), - whiteSpace: "nowrap", - }), - check = function () { - val = input.val(); - - // Enter new content into testSubject - var escaped = val - .replace(/&/g, "&") - .replace(/\s/g, " ") - .replace(//g, ">"); - testSubject.html(escaped); - - // Calculate new width + whether to change - var testerWidth = testSubject.width(), - newWidth = - testerWidth + o.comfortZone >= minWidth - ? testerWidth + o.comfortZone - : minWidth, - currentWidth = input.width(), - isValidWidthChange = - (newWidth < currentWidth && newWidth >= minWidth) || - (newWidth > minWidth && newWidth < o.maxWidth); - - // Animate width - if (isValidWidthChange) { - input.width(newWidth); - } - }; - - $("body").append(testSubject); - - $(this).bind("keyup keydown blur update", check); - }); - - return this; -}; + /** + * Set JabberId of the user who issued this activity + * @param sender + */ + this.setSender = function (sender) { + _sender = sender; + }; -/** - * AbstractEntity - * @class canvas_widget.AbstractEntity - * @memberof canvas_widget - * @constructor - * @param {string} id Identifier of this entity - */ - class AbstractEntity { - static MAX_Z_INDEX = 32000; - static MIN_Z_INDEX = 1; - static CONTEXT_MENU_Z_INDEX = 32000 + 1; - - static maxZIndex = 16000; - static minZIndex = 16000; - constructor(id) { - /** - * Entity identifier - * @type {string} - * @private - */ - var _id = id; - - /** - * Get the entity identifier - * @returns {string} entity id - */ - this.getEntityId = function () { - return _id; - }; - } - } + /** + * Get JabberId of the user who issued this activity + */ + this.getSender = function () { + return _sender; + }; -const abstractAttributeHtml = "
"; // replaced by importmap.plugin.js - -/** - * AbstractAttribute - * @class canvas_widget.AbstractAttribute - * @extends canvas_widget.AbstractEntity - * @memberof canvas_widget - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to - */ -class AbstractAttribute extends AbstractEntity { - constructor(id, name, subjectEntity) { - super(id); - - /** - * Entity id - * @type {string} - * @private - */ - var _id = id; - - /** - * Name of Attribute - * @type {string} - * @private - */ - var _name = name; - - /** - * jQuery object of DOM node representing the attribute - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(abstractAttributeHtml)()); - - /** - * Entity the attribute is assigned to - * @type {canvas_widget.AbstractEntity} - * @private - */ - var _subjectEntity = subjectEntity; - - /** - * Set name of the attribute - * @param {string} name - */ - this.setName = function (name) { - _name = name; - }; - - /** - * Get name of the attribute - * @returns {String} - */ - this.getName = function () { - return _name; - }; - - /** - * Get entity the attribute is assigned to - * @returns {canvas_widget.AbstractEntity} - */ - this.getSubjectEntity = function () { - return _subjectEntity; - }; - - /** - * Get topmost entity in the chain of entities the attribute is assigned to - * @returns {canvas_widget.AbstractEdge|canvas_widget.AbstractNode} - */ - this.getRootSubjectEntity = function () { - var rootSubjectEntity = this.getSubjectEntity(); - while (rootSubjectEntity instanceof AbstractAttribute) { - rootSubjectEntity = rootSubjectEntity.getSubjectEntity(); - } - return rootSubjectEntity; - }; - - /** - * Get id of the entity the attribute is assigned to - * @returns {String} - */ - this.getSubjectEntityId = function () { - return _subjectEntity.getEntityId(); - }; - - /** - * Get jQuery object of the DOM node representing the attribute - * @returns {jQuery} - * @private - */ - this._get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the attribute - * @returns {Object} - * @private - */ - this._toJSON = function () { - return { - id: _id, - name: _name, - }; - }; - } - /** - * Get jQuery object of the DOM node representing the attribute - * @returns {jQuery} - */ - get$node() { - return this._get$node(); - } - /** - * Get JSON representation of the attribute - * @returns {Object} - */ - toJSON() { - return this._toJSON(); - } - registerYTypeForValue(map, value) { - var deferred = $.Deferred(); - map.get(value.getEntityId()).then(function (type) { - value.registerYType(type); - deferred.resolve(); - }); - return deferred.promise(); - } -} - -/** - * AbstractValue - * @class canvas_widget.AbstractValue - * @member of canvas_widget - * @constructor - * @param {string} id Entity identifier - * @param {string} name Name of attribute - * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {canvas_widget.AbstractNode|canvas_widget.AbstractEdge} rootSubjectEntity Topmost entity in the chain of entity the attribute is assigned to - */ - class AbstractValue { - constructor(id, name, subjectEntity, rootSubjectEntity) { - var that = this; - - /** - * The entity identifier - * @returns {string} entity id - */ - var _id = id; - - /** - * Name of Attribute - * @type {string} - * @private - */ - var _name = name; - - /** - * Entity the attribute is assigned to - * @type {canvas_widget.AbstractEntity} - * @private - */ - var _subjectEntity = subjectEntity; - - /** - * Topmost entity in the chain of entity the attribute is assigned to - * @type {canvas_widget.AbstractEdge|canvas_widget.AbstractNode} - * @private - */ - var _rootSubjectEntity = rootSubjectEntity; - - /** - * Get the entity identifier - * @returns {string} entity id - */ - this.getEntityId = function () { - return _id; - }; - - /** - * Get name of value - * @returns {string} - */ - this.getName = function () { - return _name; - }; - - /** - * Get entity the attribute is assigned to - * @returns {canvas_widget.AbstractEntity} - */ - this.getSubjectEntity = function () { - return _subjectEntity; - }; - - /** - * Get topmost entity in the chain of entity the attribute is assigned to - * @returns {canvas_widget.AbstractEdge|canvas_widget.AbstractNode} - */ - this.getRootSubjectEntity = function () { - return _rootSubjectEntity; - }; - - /** - * Get JSON representation of the edge - * @returns {Object} - */ - this._toJSON = function () { - return { - id: that.getEntityId(), - name: _name, - }; - }; - } - //noinspection JSAccessibilityCheck - toJSON() { - return this._toJSON(); - } - } - -function Arrows(color){ - return { - //"bidirassociation": {}, //No overlays for bi-dir-association - unidirassociation: { - type: "Arrow", - options: { - width: 20, - length: 30, - location: 1, - foldback: 0.1, - paintStyle: { - fill: "#ffffff", - outlineWidth: 2, - outlineStroke: color, - }, - }, - }, - generalisation: { - type: "Arrow", - options: { - width: 20, - length: 30, - location: 1, - foldback: 1, - paintStyle: { - fill: "#ffffff", - outlineWidth: 2, - outlineStroke: color, - }, - }, - }, - diamond: { - type: "Arrow", - options: { - width: 20, - length: 20, - location: 1, - foldback: 2, - paintStyle: { - fill: "#ffffff", - outlineWidth: 2, - outlineStroke: color, - }, - }, - }, - }; - } - -let booleanValueHtml = "
<%= value %>
"; // replaced by importmap.plugin.js -const attributeBooleanValueHtml = "\"\r\n <% if (value) { %> checked=\"checked\" <% } %> />\r\n"; // replaced by importmap.plugin.js - -/** - * BooleanValue - * @class canvas_widget.BooleanValue - * @extends canvas_widget.AbstractValue - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier - * @param {string} name Name of attribute - * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {canvas_widget.AbstractNode|canvas_widget.AbstractEdge} rootSubjectEntity Topmost entity in the chain of entity the attribute is assigned to - */ -class BooleanValue extends AbstractValue { - constructor(id, name, subjectEntity, rootSubjectEntity, useAttributeHtml) { - if (useAttributeHtml) booleanValueHtml = attributeBooleanValueHtml; - - super(id, name, subjectEntity, rootSubjectEntity); - var that = this; - /** - * Value - * @type {boolean} - * @private - */ - var _value = false; - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(booleanValueHtml)({ value: _value })); - - /** - * Inter widget communication wrapper - * @type {Object} - * @private - */ - y = y || window.y; - var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); - - /** - * Apply a Value Change Operation - * @param {operations.ot.ValueChangeOperation} operation - */ - var processValueChangeOperation = function (operation) { - that.setValue(operation.getValue()); - }; - - var init = function () { - _$node.off(); - }; - - /** - * Set value - * @param {boolean} value - */ - this.setValue = function (value) { - _value = value; - if (useAttributeHtml) _$node.prop("checked", value); - else _$node.text(value); - }; - - /** - * Get value - * @returns {boolean} - */ - this.getValue = function () { - return _value; - }; - - /** - * Get jQuery object of DOM node representing the value - * @returns {jQuery} - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the edge - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractValue.prototype.toJSON.call(this); - json.value = _value; - return json; - }; - - /** - * Set value by its JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - this.setValue(json.value); - }; - - this.registerYType = function () { - that - .getRootSubjectEntity() - .getYMap() - .observe(function (event) { - const array = Array.from(event.changes.keys.entries()); - array.forEach(function ([key, change]) { - if (change.action !== "update" || key !== that.getEntityId()) { - return; - } - const map = event.currentTarget.get(key); - const json = map; - - var operation = new ValueChangeOperation( - json.entityId, - json.value, - json.type, - json.position, - json.jabberId - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.getOTOperation() - ); - processValueChangeOperation(operation); - - //Only the local user Propagates the activity - if ( - _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID] === - operation.getJabberId() - ) { - const activityMap = y.getMap("activity"); - activityMap.set( - ActivityOperation.TYPE, - new ActivityOperation( - "ValueChangeActivity", - that.getEntityId(), - _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], - ValueChangeOperation.getOperationDescription( - that.getSubjectEntity().getName(), - that.getRootSubjectEntity().getType(), - that.getRootSubjectEntity().getLabel().getValue().getValue() - ), - { - value: operation.getValue(), - subjectEntityName: that.getSubjectEntity().getName(), - rootSubjectEntityType: that - .getRootSubjectEntity() - .getType(), - rootSubjectEntityId: that - .getRootSubjectEntity() - .getEntityId(), - } - ).toJSON() - ); - } else { - //the remote users propagtes the change to their local attribute widget - //TODO(PENDING): can be replace with yjs as well - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.ATTRIBUTE, - operation.getOTOperation() - ); - } - }); - }); - - //Debounce the save function - that - .getRootSubjectEntity() - .getYMap() - .observe( - lodash.debounce(function (event) { - event.keysChanged.forEach(function (key) { - if ( - key == "jabberId" && - key === _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID] - ) - EntityManager.storeDataYjs(); - }); - }, 500) - ); - }; - - init(); - } -} + /** + * Get name of operation + * @returns {string} + */ + this.getName = function () { + return _operation.name; + }; -const booleanAttributeHtml = "
\r\n
\r\n
\r\n
"; // replaced by importmap.plugin.js - -/** - * BooleanAttribute - * @class canvas_widget.BooleanAttribute - * @extends canvas_widget.AbstractAttribute - * @memberof canvas_widget - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to - */ -class BooleanAttribute extends AbstractAttribute { - constructor(id, name, subjectEntity, useAttributeHtml) { - useAttributeHtml = - typeof useAttributeHtml !== "undefined" ? useAttributeHtml : false; - super(id, name, subjectEntity); - - /*** - * Value object of value - * @type {canvas_widget.BooleanValue} - * @private - */ - var _value = new BooleanValue( - id, - name, - this, - this.getRootSubjectEntity(), - useAttributeHtml - ); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(booleanAttributeHtml)()); - - /** - * Set Value object of value - * @param {canvas_widget.BooleanValue} value - */ - this.setValue = function (value) { - _value = value; - _$node.val(value); - }; - - /** - * Get Value object of value - * @return {canvas_widget.BooleanValue} value - */ - this.getValue = function () { - return _value; - }; - - /** - * jQuery object of DOM node representing the attribute - * @type {jQuery} - * @private - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the attribute - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.value = _value.toJSON(); - return json; - }; - - /** - * Set attribute value by its JSON representation - * @param {Object} json - */ - this.setValueFromJSON = function (json) { - _value.setValueFromJSON(json.value); - }; - - _$node.find(".name").text(this.getName()); - _$node.find(".value").append(_value.get$node()); - } + /** + * Get value of operation + * @returns {string} + */ + this.getValue = function () { + return _operation.value; + }; + + /** + * Get type of operation + * @returns {string} + */ + this.getType = function () { + return _operation.type; + }; + + /** + * Get position of operation + * @returns {number} + */ + this.getPosition = function () { + return _operation.position; + }; + + /** + * Get JSON Representation of operation + * @returns {{type: string, data: string}} + */ + this.getOperationObject = function () { + return _operation; + }; + } } -const openapp$1 = new OpenAppProvider().openapp; - -let fileValueHtml = "
<%= value %>
"; // replaced by importmap.plugin.js -const attributeFileValueHtml = "
\r\n
\r\n \r\n \r\n
\r\n
\r\n \r\n \r\n \r\n \r\n
\r\n
\r\n"; // replaced by importmap.plugin.js - -FileValue.prototype = new AbstractValue(); -FileValue.prototype.constructor = FileValue; -/** - * FileValue - * @class canvas_widget.FileValue - * @extends canvas_widget.AbstractValue - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier - * @param {string} name Name of attribute - * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {canvas_widget.AbstractNode|canvas_widget.AbstractEdge} rootSubjectEntity Topmost entity in the chain of entity the attribute is assigned to - */ -function FileValue( - id, - name, - subjectEntity, - rootSubjectEntity, - useAttributeHtml -) { - var that = this; - - if (useAttributeHtml) fileValueHtml = attributeFileValueHtml; - - AbstractValue.call(this, id, name, subjectEntity, rootSubjectEntity); - - /** - * Value - * @type {string} - * @private - */ - var _value = ""; - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node; - - if (useAttributeHtml) _$node = $(lodash.template(fileValueHtml)({ name: name })); - else _$node = $(lodash.template(fileValueHtml)({ value: _value })); - - var _$selectFile = _$node.find(".select_file"); - - var _$manageFile = _$node.find(".manage_file"); - - /** - * Inter widget communication wrapper - * @type {Object} - * @private - */ - y = y || window.y; - var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); - - /** - * Get chain of entities the attribute is assigned to - * @returns {string[]} - */ - var getEntityIdChain = function () { - var chain = [that.getEntityId()], - entity = that; - while (entity instanceof AbstractAttribute) { - chain.unshift(entity.getSubjectEntity().getEntityId()); - entity = entity.getSubjectEntity(); - } - return chain; - }; - - var uploadFile = function (name, type, data) { - var resourceSpace = new openapp$1.oo.Resource(openapp$1.param.space()); - - resourceSpace.create({ - relation: openapp$1.ns.role + "data", - type: "my:ns:file", - representation: { - name: name, - type: type, - data: data, - }, - callback: function (d) { - if (d.uri) { - propagateValueChange(CONFIG.OPERATION.TYPE.UPDATE, d.uri, 0); - } - }, - }); - }; - - /** - * Apply a Value Change Operation - * @param {operations.ot.ValueChangeOperation} operation - */ - var processValueChangeOperation = function (operation) { - that.setValue(operation.getValue()); - }; - - var propagateValueChange = function (type, value, position) { - var operation = new ValueChangeOperation( - that.getEntityId(), - value, - type, - position - ); - propagateValueChangeOperation(operation); - }; - - /** - * Propagate a Value Change Operation to the remote users and the local widgets - * @param {operations.ot.ValueChangeOperation} operation - */ - var propagateValueChangeOperation = function (operation) { - operation.setEntityIdChain(getEntityIdChain()); - processValueChangeOperation(operation); - if (_iwcw.sendRemoteOTOperation(operation)) { - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.ATTRIBUTE, - operation.getOTOperation() - ); - const activityMap = y.getMap("activity"); - - activityMap.set( - ActivityOperation.TYPE, - new ActivityOperation( - "ValueChangeActivity", - that.getEntityId(), - _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], - ValueChangeOperation.getOperationDescription( - that.getSubjectEntity().getName(), - that.getRootSubjectEntity().getType(), - that.getRootSubjectEntity().getLabel().getValue().getValue() - ), - { - value: operation.getValue(), - subjectEntityName: that.getSubjectEntity().getName(), - rootSubjectEntityType: that.getRootSubjectEntity().getType(), - rootSubjectEntityId: that.getRootSubjectEntity().getEntityId(), - } - ).toJSON() - ); - } - }; - - /** - * Callback for a local Value Change Operation - * @param {operations.ot.ValueChangeOperation} operation - */ - var localValueChangeCallback = function (operation) { - if ( - operation instanceof ValueChangeOperation && - operation.getEntityId() === that.getEntityId() - ) { - propagateValueChangeOperation(operation); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.getOTOperation() - ); - } - }; - - var init = function () { - if (!useAttributeHtml) return; - - _$selectFile.find("#file_object").change(function () { - var files = $(this)[0].files, - file; - - if (!files || files.length === 0) return; - file = files[0]; - if (file.size > 1048576) { - alert("Chosen file is too large. Maximum size: 1MB"); - } - }); - - _$selectFile.find("#file_submit").click(function () { - var fileReader, - files = _$selectFile.find("#file_object")[0].files, - file; - - if (!files || files.length === 0) return; - file = files[0]; - - fileReader = new FileReader(); - fileReader.onload = function (e) { - uploadFile(file.name, file.type, e.target.result); - }; - fileReader.readAsDataURL(file); - }); - - _$manageFile.find("#file_delete").click(function () { - //openapp.resource.del(_value); - propagateValueChange(CONFIG.OPERATION.TYPE.UPDATE, "", 0); - }); - - _$selectFile.show(); - _$manageFile.hide(); - }; - - /** - * Set value - * @param {string} value - */ - this.setValue = function (value) { - _value = value; - if (_value === "") { - _$node.text(""); - } else { - $.get(_value + "/:representation").done(function (data) { - _$node.text(data.name); - }); - } - }; - - /** - * Get value - * @returns {string} - */ - this.getValue = function () { - return _value; - }; - - /** - * Get jQuery object of DOM node representing the value - * @returns {jQuery} - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the edge - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractValue.prototype.toJSON.call(this); - json.value = _value; - return json; - }; - - /** - * Set value by its JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - this.setValue(json.value); - }; - - /** - * Register inter widget communication callbacks - */ - this.registerCallbacks = function () { - //_iwcw.registerOnRemoteDataReceivedCallback(remoteValueChangeCallback); - _iwcw.registerOnDataReceivedCallback(localValueChangeCallback); - //_iwcw.registerOnHistoryChangedCallback(historyValueChangeCallback); - }; - - /** - * Unregister inter widget communication callbacks - */ - this.unregisterCallbacks = function () { - //_iwcw.unregisterOnRemoteDataReceivedCallback(remoteValueChangeCallback); - _iwcw.unregisterOnDataReceivedCallback(localValueChangeCallback); - //_iwcw.unregisterOnHistoryChangedCallback(historyValueChangeCallback); - }; - - if (_iwcw) { - that.registerCallbacks(); - } - - init(); -} +/** + * Namespace for non ot operations + * @namespace operations.non_ot + */ -const fileAttributeHtml = "
\r\n
\r\n
\r\n
"; // replaced by importmap.plugin.js - -/** - * FileAttribute - * @class canvas_widget.FileAttribute - * @extends canvas_widget.AbstractAttribute - * @memberof canvas_widget - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to - */ -class FileAttribute extends AbstractAttribute { - constructor(id, name, subjectEntity, useAttributeHtml) { - useAttributeHtml = - typeof useAttributeHtml !== "undefined" ? useAttributeHtml : false; - super(id, name, subjectEntity); - - /*** - * Value object of value - * @type {canvas_widget.FileValue} - * @private - */ - var _value = new FileValue( - id, - name, - this, - this.getRootSubjectEntity(), - useAttributeHtml - ); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(fileAttributeHtml)()); - - /** - * Set Value object of value - * @param {canvas_widget.FileValue} value - */ - this.setValue = function (value) { - _value = value; - _$node.val(value); - }; - - /** - * Get Value object of value - * @return {canvas_widget.FileValue} value - */ - this.getValue = function () { - return _value; - }; - - /** - * jQuery object of DOM node representing the attribute - * @type {jQuery} - * @private - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the attribute - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.value = _value.toJSON(); - return json; - }; - - /** - * Set attribute value by its JSON representation - * @param {Object} json - */ - this.setValueFromJSON = function (json) { - _value.setValueFromJSON(json.value); - }; - - _$node.find(".name").text(this.getName()); - _$node.find(".value").append(_value.get$node()); - } + NonOTOperation.prototype = new Operation(); + NonOTOperation.prototype.constructor = NonOTOperation; + /** + * NonOTOperation + * @class operations.non_ot.NonOTOperation + * @memberof operations.non_ot + * @constructor + * @param {string} type Type of Operation + * @param {string} data Additional data for operation + */ + function NonOTOperation(type,data){ + /** + * JabberId of the user who issued this activity + * @type {string} + * @private + */ + var _sender = null; + + /** + * Operation details + * @type {{type: string, data: string}} + * @private + */ + var _operation = { + type: type, + data: data + }; + + /** + * Set JabberId of the user who issued this activity + * @param sender + */ + this.setSender = function(sender){ + _sender = sender; + }; + + /** + * Get JabberId of the user who issued this activity + * @returns {string} + */ + this.getSender = function(){ + return _sender; + }; + + /** + * Get type of Operation + * @returns {string} + */ + this.getType = function(){ + //noinspection JSAccessibilityCheck + return _operation.type; + }; + + /** + * Get additional data for operation + * @returns {string} + */ + this.getData = function(){ + return _operation.data; + }; + + /** + * Get JSON Representation of operation + * @returns {{type: string, data: string}} + */ + this.getOperationObject = function(){ + return _operation; + }; + } + +/** + * EntityOperation + * @class operations.ot.EntityOperation + * @memberof operations.ot + * @param {string} operationType Type of operation + * @param {string} entityId Entity id of the entity this activity works on + * @param {string} entityType Type of the entity this activity works on + * @constructor + */ +class EntityOperation { + static TYPES = { + AttributeAddOperation: "AttributeAddOperation", + AttributeDeleteOperation: "AttributeDeleteOperation", + EdgeAddOperation: "EdgeAddOperation", + EdgeDeleteOperation: "EdgeDeleteOperation", + NodeAddOperation: "NodeAddOperation", + NodeDeleteOperation: "NodeDeleteOperation", + NodeMoveOperation: "NodeMoveOperation", + NodeMoveZOperation: "NodeMoveZOperation", + NodeResizeOperation: "NodeResizeOperation", + ValueChangeOperation: "ValueChangeOperation", + }; + getOperationType; + setOTOperation; + _getOTOperation; + getEntityId; + getEntityType; + adjust; + inverse; + toJSON; + + triggeredBy; + constructor(operationType, entityId, entityType) { + this.triggeredBy = window.y.clientID; + + /** + * Type of operation + * @type {string} + * @private + */ + var _operationType = operationType; + + /** + * Corresponding OtOperation + * @type {operations.ot.OTOperation} + * @private + */ + var _otOperation = null; + + /** + * Entity id of the entity this activity works on + * @type {string} + * @private + */ + var _entityId = entityId; + + /** + * Type of the entity this activity works on + * @type {string} + * @private + */ + var _entityType = entityType; + + /** + * Get type of operation + * @returns {string} + */ + this.getOperationType = function () { + return _operationType; + }; + + /** + * Set corresponding ot operation + * @param {operations.ot.OTOperation} otOperation + */ + this.setOTOperation = function (otOperation) { + _otOperation = otOperation; + }; + + /** + * Get corresponding ot operation + * @returns {operations.ot.OTOperation} + * @private + */ + this._getOTOperation = function () { + return _otOperation; + }; + + /** + * Get entity id of the entity this activity works onf + * @returns {string} + */ + this.getEntityId = function () { + return _entityId; + }; + + //noinspection JSUnusedGlobalSymbols + /** + * Get type of the entity this activity works on + * @returns {string} + */ + this.getEntityType = function () { + return _entityType; + }; + + /** + * Adjust the passed operation in the history of operation + * when this operation is applied remotely after the passed operation + * on an graph instance stored in the passed EntityManager + * @param {canvas_widget.EntityManager} EntityManager + * @param {EntityOperation} operation Remote operation + * @returns {EntityOperation} + */ + this.adjust = function (EntityManager, operation) { + return operation; + }; + + /** + * Compute the inverse of the operation + * @returns {operations.ot.EntityOperation} + */ + this.inverse = function () { + return this; + }; + } + //noinspection JSAccessibilityCheck + /** + * Get corresponding ot operation + * @returns {operations.ot.OTOperation} + */ + getOTOperation() { + return this._getOTOperation(); + } } -const multiLineValueHtml = "
<%= value %>
"; // replaced by importmap.plugin.js - -/** - * MultiLineValue - * @class canvas_widget.MultiLineValue - * @extends canvas_widget.AbstractValue - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier - * @param {string} name Name of attribute - * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {canvas_widget.AbstractNode|canvas_widget.AbstractEdge} rootSubjectEntity Topmost entity in the chain of entity the attribute is assigned to - */ -class MultiLineValue extends AbstractValue { - constructor(id, name, subjectEntity, rootSubjectEntity, y) { - super(id, name, subjectEntity, rootSubjectEntity); - var that = this; - - var _ytext = null; - y = y || window.y; - if (y) { - const yMap = rootSubjectEntity.getYMap(); - if (!yMap) { - rootSubjectEntity.registerYMap(); - } - - if (rootSubjectEntity.getYMap()?.has(id)) - _ytext = rootSubjectEntity.getYMap().get(id); - else { - _ytext = new Text(); - rootSubjectEntity.getYMap().set(id, _ytext); - } - } - - /** - * MultiLineValue - * @type {string} - * @private - */ - var _value = ""; - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(multiLineValueHtml)({ value: _value })); - - /** - * Inter widget communication wrapper - * @type {Object} - * @private - */ - y = y || window.y; - var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); - - /** - * Get chain of entities the attribute is assigned to - * @returns {string[]} - */ - var getEntityIdChain = function () { - var chain = [that.getEntityId()], - entity = that; - while (entity instanceof AbstractAttribute) { - chain.unshift(entity.getSubjectEntity().getEntityId()); - entity = entity.getSubjectEntity(); - } - return chain; - }; - - /** - * Propagate a Value Change Operation to the remote users and the local widgets - * @param {operations.ot.ValueChangeOperation} operation - */ - var propagateValueChangeOperation = function (operation) { - operation.setEntityIdChain(getEntityIdChain()); - operation.setRemote(false); - that.setValue(operation.getValue()); - operation.setRemote(true); - const activityMap = y.getMap("activity"); - - activityMap.set( - ActivityOperation.TYPE, - new ActivityOperation( - "ValueChangeActivity", - that.getEntityId(), - _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], - ValueChangeOperation.getOperationDescription( - that.getSubjectEntity().getName(), - that.getRootSubjectEntity().getType(), - that.getRootSubjectEntity().getLabel().getValue().getValue() - ), - { - value: _value, - subjectEntityName: that.getSubjectEntity().getName(), - rootSubjectEntityType: that.getRootSubjectEntity().getType(), - rootSubjectEntityId: that.getRootSubjectEntity().getEntityId(), - } - ) - .toNonOTOperation() - .toJSON() - ); - - /*if(that.getRootSubjectEntity().getYMap()){ - that.getRootSubjectEntity().getYMap().set(that.getEntityId(),operation.toJSON()); - }*/ - }; - - /** - * Callback for a local Value Change Operation - * @param {operations.ot.ValueChangeOperation} operation - */ - var localValueChangeCallback = function (operation) { - if ( - operation instanceof ValueChangeOperation && - operation.getEntityId() === that.getEntityId() - ) { - propagateValueChangeOperation(operation); - } - }; - - /** - * Set value - * @param {string} value - */ - this.setValue = function (value) { - _value = value; - _$node.text(value); - }; - - /** - * Get value - * @returns {string} - */ - this.getValue = function () { - return _value; - }; - - /** - * Get jQuery object of DOM node representing the value - * @returns {jQuery} - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the edge - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractValue.prototype.toJSON.call(this); - json.value = _value; - return json; - }; - - /** - * Set value by its JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - this.setValue(json.value); - }; - - /** - * Register inter widget communication callbacks - */ - this.registerCallbacks = function () { - _iwcw.registerOnDataReceivedCallback(localValueChangeCallback); - //_iwcw.registerOnHistoryChangedCallback(historyValueChangeCallback); - }; - - /** - * Unregister inter widget communication callbacks - */ - this.unregisterCallbacks = function () { - _iwcw.unregisterOnDataReceivedCallback(localValueChangeCallback); - //_iwcw.unregisterOnHistoryChangedCallback(historyValueChangeCallback); - }; - - this.registerYType = function () { - if (!_ytext) throw new Error("_ytext is undefined"); - // _ytext.bind(_$node[0]); - - if (that.getValue() !== _ytext.toString()) { - if (_ytext.toString().length > 0) - _ytext.delete(0, _ytext.toString().length - 1); - _ytext.insert(0, that.getValue()); - } - - _ytext.observe(function (event) { - _value = _ytext.toString(); - - //TODO i can not find out who triggered the delete :-(. Therefore do this only for non delete event types - if (event.type !== "delete") { - y.getMap("users"); - var jabberId = "User"; - const activityMap = y.getMap("activity"); - - activityMap.set( - ActivityOperation.TYPE, - new ActivityOperation( - "ValueChangeActivity", - that.getEntityId(), - jabberId, - ValueChangeOperation.getOperationDescription( - that.getSubjectEntity().getName(), - that.getRootSubjectEntity().getType(), - that.getRootSubjectEntity().getLabel().getValue().getValue() - ), - { - value: "", - subjectEntityName: that.getSubjectEntity().getName(), - rootSubjectEntityType: that.getRootSubjectEntity().getType(), - rootSubjectEntityId: that.getRootSubjectEntity().getEntityId(), - } - ).toJSON() - ); - } - }); - }; - - if (_iwcw) { - that.registerCallbacks(); - } - } +/** + * NodeDeleteOperation + * @class operations.ot.NodeDeleteOperation + * @memberof operations.ot + * @extends operations.ot.EntityOperation + * @param {String} entityId Entity id of the entity this activity works on + * @param {String} type Type of node to delete + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {number} zIndex Position of node on z-axis + * @param {boolean} containment containment + * @param {object} json JSON representation of node + * @constructor + */ +class NodeDeleteOperation extends EntityOperation { + static TYPE = "NodeDeleteOperation"; + getType; + getLeft; + getTop; + getWidth; + getHeight; + getZIndex; + getContainment; + getJSON; + constructor( + entityId, + type, + left, + top, + width, + height, + zIndex, + containment, + json + ) { + super( + EntityOperation.TYPES.NodeDeleteOperation, + entityId, + CONFIG.ENTITY.NODE + ); + var that = this; + + /** + * Type of node to add + * @type {String} + * @private + */ + var _type = type; + + /** + * x-coordinate of node position + * @type {number} + * @private + */ + var _left = left; + + /** + * y-coordinate of node position + * @type {number} + * @private + */ + var _top = top; + + /** + * Width of node + * @type {number} + * @private + */ + var _width = width; + + /** + * Height of node + * @type {number} + * @private + */ + var _height = height; + + /** + * Position of node on z-axis + * @type {number} + * @private + */ + var _zIndex = zIndex; + + /** + * is containment type + * @type {boolean} + * @private + */ + var _containment = containment; + + /** + * JSON representation of node + * @type {Object} + * @private + */ + var _json = json; + + /** + * Create OTOperation for operation + * @returns {operations.ot.OTOperation} + */ + var createOTOperation = function () { + return new OTOperation( + CONFIG.ENTITY.NODE + ":" + that.getEntityId(), + JSON.stringify({ + type: _type, + left: _left, + top: _top, + width: _width, + height: _height, + zIndex: _zIndex, + containment: _containment, + json: _json, + }), + CONFIG.OPERATION.TYPE.UPDATE, + CONFIG.IWC.POSITION.NODE.DEL + ); + }; + + /** + * Get type of node to add + * @returns {String} + */ + this.getType = function () { + return _type; + }; + + /** + * Get x-coordinate of node position + * @returns {number} + */ + this.getLeft = function () { + return _left; + }; + + /** + * Get y-coordinate of node position + * @returns {number} + */ + this.getTop = function () { + return _top; + }; + + /** + * Get width of node + * @returns {number} + */ + this.getWidth = function () { + return _width; + }; + + /** + * Get height of node + * @returns {number} + */ + this.getHeight = function () { + return _height; + }; + + /** + * Get position of node on z-axis + * @returns {number} + */ + this.getZIndex = function () { + return _zIndex; + }; + + /** + * is containment type + * @returns {boolean} + */ + this.getContainment = function () { + return _containment; + }; + + /** + * Get JSON representation of node + * @return {Object} + */ + this.getJSON = function () { + return _json; + }; + + /** + * Get corresponding ot operation + * @returns {operations.ot.OTOperation} + * @private + */ + this.getOTOperation = function () { + var otOperation = EntityOperation.prototype.getOTOperation.call(this); + if (otOperation === null) { + otOperation = createOTOperation(); + this.setOTOperation(otOperation); + } + return otOperation; + }; + + /** + * Adjust the passed operation in the history of operation + * when this operation is applied remotely after the passed operation + * on an graph instance stored in the passed EntityManager + * @param {canvas_widget.EntityManager} EntityManager + * @param {EntityOperation} operation Remote operation + * @returns {EntityOperation} + */ + this.adjust = function (EntityManager, operation) { + var edge; + switch (operation.getOperationType()) { + case EntityOperation.TYPES.AttributeAddOperation: + case EntityOperation.TYPES.AttributeDeleteOperation: + edge = EntityManager.findEdge(operation.getRootSubjectEntityId()); + if ( + edge && + (edge.getSource().getEntityId() === this.getEntityId() || + edge.getTarget().getEntityId() === this.getEntityId()) + ) { + return null; + } + if (this.getEntityId() === operation.getRootSubjectEntityId()) { + return null; + } + break; + case EntityOperation.TYPES.EdgeAddOperation: + case EntityOperation.TYPES.EdgeDeleteOperation: + edge = EntityManager.findEdge(operation.getEntityId()); + if ( + edge && + (edge.getSource().getEntityId() === this.getEntityId() || + edge.getTarget().getEntityId() === this.getEntityId()) + ) { + return null; + } + break; + case EntityOperation.TYPES.NodeAddOperation: + case EntityOperation.TYPES.NodeDeleteOperation: + case EntityOperation.TYPES.NodeMoveOperation: + case EntityOperation.TYPES.NodeResizeOperation: + if (this.getEntityId() === operation.getEntityId()) { + return null; + } + break; + case EntityOperation.TYPES.ValueChangeOperation: + edge = EntityManager.findEdge(operation.getRootSubjectEntityId()); + if ( + edge && + (edge.getSource().getEntityId() === this.getEntityId() || + edge.getTarget().getEntityId() === this.getEntityId()) + ) { + return null; + } + if (operation.getRootSubjectEntityId() === this.getEntityId()) { + return null; + } + break; + } + + return operation; + }; + + /** + * Compute the inverse of the operation + * @returns {operations.ot.NodeAddOperation} + */ + this.inverse = function () { + return new NodeAddOperation( + this.getEntityId(), + this.getType(), + this.getLeft(), + this.getTop(), + this.getWidth(), + this.getHeight(), + this.getZIndex(), + this.getContainment(), + this.getContainment(), + json + ); + }; + } + static getOperationDescription(nodeType, nodeLabel, viewId) { + if (!nodeLabel && !viewId) { + return "..deleted " + nodeType; + } else if (!viewId) { + return "..deleted " + nodeType + " " + nodeLabel; + } else + return "..deleted " + nodeType + " " + nodeLabel + " in View " + viewId; + } + toJSON = function () { + return { + id: this.getEntityId(), + type: this.getType(), + left: this.getLeft(), + top: this.getTop(), + width: this.getWidth(), + height: this.getHeight(), + zIndex: this.getZIndex(), + containment: this.getContainment(), + json: this.getJSON(), + }; + }; } -const singleMultiLineValueAttributeHtml = "
\r\n
\r\n
\r\n
"; // replaced by importmap.plugin.js - -/** - * SingleMultiLineValueAttribute - * @class canvas_widget.SingleMultiLineValueAttribute - * @extends canvas_widget.AbstractAttribute - * @memberof canvas_widget - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to - */ -class SingleMultiLineValueAttribute extends AbstractAttribute { - constructor(id, name, subjectEntity, y) { - super(id, name, subjectEntity); - - /*** - * Value object of value - * @type {canvas_widget.MultiLineValue} - * @private - */ - var _value = new MultiLineValue( - id, - name, - this, - this.getRootSubjectEntity(), - y - ); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(singleMultiLineValueAttributeHtml)()); - - /** - * Set Value object of value - * @param {canvas_widget.MultiLineValue} value - */ - this.setValue = function (value) { - _value = value; - }; - - /** - * Get Value object of value - * @returns {canvas_widget.MultiLineValue} - */ - this.getValue = function () { - return _value; - }; - - /** - * jQuery object of DOM node representing the attribute - * @type {jQuery} - * @private - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the attribute - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.value = _value.toJSON(); - return json; - }; - - /** - * Set attribute value by its JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - _value.setValueFromJSON(json.value); - }; - - _$node.find(".name").text(this.getName()); - _$node.find(".value").append(_value.get$node()); - } -} - -function makeViewEdge( - type, - arrowType, - shapeType, - color, - dashstyle, - overlay, - overlayPosition, - overlayRotate, - attributes, - edgeType, - conditions, - conj -) { - function ViewEdge(id, source, target) { - var viewEdge = new edgeType(id, source, target); - viewEdge.restyle( - arrowType, - color, - shapeType, - dashstyle, - overlay, - overlayPosition, - overlayRotate, - attributes - ); - viewEdge.setCurrentViewType(type); - return viewEdge; - } - - ViewEdge.getConditions = function () { - return conditions; - }; - - ViewEdge.getConditionConj = function () { - return conj; - }; - - ViewEdge.getArrowType = function () { - return arrowType; - }; - ViewEdge.getShapeType = function () { - return shapeType; - }; - ViewEdge.getColor = function () { - return color; - }; - ViewEdge.getOverlay = function () { - return overlay; - }; - ViewEdge.getOverlayPosition = function () { - return overlayPosition; - }; - ViewEdge.getOverlayRotate = function () { - return overlayRotate; - }; - ViewEdge.getAttributes = function () { - return attributes; - }; - ViewEdge.getTargetEdgeType = function () { - return edgeType; - }; - ViewEdge.getType = function () { - return type; - }; - ViewEdge.getArrowOverlays = function () { - var overlays = []; - if (Arrows().hasOwnProperty(arrowType)) { - overlays.push(Arrows(color)[arrowType]); - } - return overlays; - }; - ViewEdge.getShape = function () { - return this.getTargetEdgeType().getShape(); - }; - - return ViewEdge; +class NodeAddOperation extends EntityOperation { + static TYPE = "NodeAddOperation"; + getType; + getOriginType; + getLeft; + getTop; + getWidth; + getHeight; + getZIndex; + getContainment; + getJSON; + getViewId; + getJabberId; + getDefaultLabel; + getDefaultAttributeValues; + toJSON; + + constructor( + entityId, + type, + left, + top, + width, + height, + zIndex, + containment, + json = null, + viewId = null, + oType = null, + jabberId = null, + defaultLabel = null, + defaultAttributeValues = null + ) { + super(EntityOperation.TYPES.NodeAddOperation, entityId, CONFIG.ENTITY.NODE); + var that = this; + + /** + * the identifier of the view + * @type {string} + * @private + */ + var _viewId = viewId; + + /** + * the jabberId of the user + * @type {string} + * @private + */ + var _jabberId = jabberId; + + var _oType = oType; + + /** + * Type of node to add + * @type {String} + * @private + */ + var _type = type; + + /** + * x-coordinate of node position + * @type {number} + * @private + */ + var _left = left; + + /** + * y-coordinate of node position + * @type {number} + * @private + */ + var _top = top; + + /** + * Width of node + * @type {number} + * @private + */ + var _width = width; + + /** + * Height of node + * @type {number} + * @private + */ + var _height = height; + + /** + * Position of node on z-axis + * @type {number} + * @private + */ + var _zIndex = zIndex; + + /** + * is containment type + * @type {boolean} + * @private + */ + var _containment = containment; + + /** + * JSON representation of node + * @type {Object} + * @private + */ + var _json = json; + + /** + * Default label of node + * @type {String} + * @private + */ + var _defaultLabel = defaultLabel; + + /** + * May be used to set default values for node attributes. + */ + var _defaultAttributeValues = defaultAttributeValues; + + /** + * Create OTOperation for operation + * @returns {operations.ot.OTOperation} + */ + var createOTOperation = function () { + return new OTOperation( + CONFIG.ENTITY.NODE + ":" + that.getEntityId(), + JSON.stringify({ + type: _type, + left: _left, + top: _top, + width: _width, + height: _height, + zIndex: _zIndex, + containment: _containment, + json: _json, + viewId: _viewId, + oType: _oType, + jabberId: _jabberId, + }), + CONFIG.OPERATION.TYPE.INSERT, + CONFIG.IWC.POSITION.NODE.ADD + ); + }; + + /** + * Get type of node to add + * @returns {String} + */ + this.getType = function () { + return _type; + }; + + this.getOriginType = function () { + return _oType; + }; + + /** + * Get x-coordinate of node position + * @returns {number} + */ + this.getLeft = function () { + return _left; + }; + + /** + * Get y-coordinate of node position + * @returns {number} + */ + this.getTop = function () { + return _top; + }; + + /** + * Get width of node + * @returns {number} + */ + this.getWidth = function () { + return _width; + }; + + /** + * Get height of node + * @returns {number} + */ + this.getHeight = function () { + return _height; + }; + + /** + * Get position of node on z-axis + * @returns {number} + */ + this.getZIndex = function () { + return _zIndex; + }; + + /** + * Get containment + * @returns {boolean} + */ + this.getContainment = function () { + return _containment; + }; + + /** + * Get JSON representation of node + * @return {Object} + */ + this.getJSON = function () { + return _json; + }; + + /** + * the identifier of the view + * @returns {string} + */ + this.getViewId = function () { + return _viewId; + }; + + /** + * Get the jabberid + * @returns {string} + */ + this.getJabberId = function () { + return _jabberId; + }; + + /** + * Get default label of node + * @returns {string} + */ + this.getDefaultLabel = function () { + return _defaultLabel; + }; + + /** + * Get default values for node attributes. + * @returns {*} + */ + this.getDefaultAttributeValues = function () { + return _defaultAttributeValues; + }; + + /** + * Get corresponding ot operation + * @returns {operations.ot.OTOperation} + * @private + */ + this.getOTOperation = function () { + var otOperation = EntityOperation.prototype.getOTOperation.call(this); + if (otOperation === null) { + otOperation = createOTOperation(); + this.setOTOperation(otOperation); + } + return otOperation; + }; + + /** + * Adjust the passed operation in the history of operation + * when this operation is applied remotely after the passed operation + * on an graph instance stored in the passed EntityManager + * @param {canvas_widget.EntityManager} EntityManager + * @param {EntityOperation} operation Remote operation + * @returns {EntityOperation} + */ + this.adjust = function (EntityManager, operation) { + return operation; + }; + + /** + * Compute the inverse of the operation + * @returns {NodeDeleteOperation} + */ + this.inverse = function () { + return new NodeDeleteOperation( + this.getEntityId(), + this.getType(), + this.getLeft(), + this.getTop(), + this.getWidth(), + this.getHeight(), + this.getZIndex(), + this.getContainment(), + json + ); + }; + + this.toJSON = function () { + return { + id: this.getEntityId(), + type: this.getType(), + left: this.getLeft(), + top: this.getTop(), + width: this.getWidth(), + height: this.getHeight(), + zIndex: this.getZIndex(), + containment: this.getContainment(), + json: this.getJSON(), + viewId: this.getViewId(), + oType: this.getOriginType(), + jabberId: this.getJabberId(), + defaultLabel: this.getDefaultLabel(), + defaultAttributeValues: this.getDefaultAttributeValues(), + triggeredBy: this.triggeredBy, + }; + }; + } + static getOperationDescription(nodeType, nodeLabel, viewId) { + if (!nodeLabel && !viewId) { + return "..created a new " + nodeType; + } else if (!viewId) { + return "..created " + nodeType + " " + nodeLabel; + } else + return ".. created " + nodeType + " " + nodeLabel + " in View " + viewId; + } } -function makeViewNode(type, $shape, anchors, attributes, nodeType, conditions, conj) { - - ViewNode.prototype.constructor = ViewNode; - function ViewNode(id, left, top, width, height, zIndex) { - var viewNode = new nodeType(id, left, top, width, height, zIndex); - - viewNode.set$shape($shape); - viewNode.setAnchorOptions(anchors); - viewNode.setCurrentViewType(type); - - return viewNode; - - } - - ViewNode.getConditions = function(){ - return conditions; - }; - - ViewNode.getConditionConj = function(){ - return conj; - }; - - ViewNode.get$shape = function(){ - return $shape; - }; - - ViewNode.getAnchors = function(){ - return anchors; - }; - - ViewNode.getTargetNodeType = function(){ - return nodeType; - }; - return ViewNode; +/** + * EdgeDeleteOperation + * @class operations.ot.EdgeDeleteOperation + * @memberof operations.ot + * @extends operations.ot.EntityOperation + * @param entityId Entity id of the entity this activity works on + * @param {String} type Type of edge to delete + * @param {String} source Entity id of source node + * @param {String} target Entity id of target node + * @param {object} json JSON representation of edge + * @constructor + */ +class EdgeDeleteOperation extends EntityOperation { + static TYPE = "EdgeDeleteOperation"; + getType; + getSource; + getTarget; + getJSON; + constructor(entityId, type, source, target, json = null) { + super( + EntityOperation.TYPES.EdgeDeleteOperation, + entityId, + CONFIG.ENTITY.EDGE + ); + var that = this; + + /** + * Type of edge to delte + * @type {String} + * @private + */ + var _type = type; + + /** + * Entity id of source node + * @type {String} + * @private + */ + var _source = source; + + /** + * Entity id of target node + * @type {String} + * @private + */ + var _target = target; + + /** + * JSON representation of node + * @type {Object} + * @private + */ + var _json = json; + + /** + * Create OTOperation for operation + * @returns {operations.ot.OTOperation} + */ + var createOTOperation = function () { + return new OTOperation( + CONFIG.ENTITY.EDGE + ":" + that.getEntityId(), + JSON.stringify({ + type: _type, + source: _source, + target: _target, + json: _json, + }), + CONFIG.OPERATION.TYPE.UPDATE, + CONFIG.IWC.POSITION.EDGE.DEL + ); + }; + + /** + * Get type of edge to delete + * @returns {String} + */ + this.getType = function () { + return _type; + }; + + /** + * Get entity id of source node + * @returns {String} + */ + this.getSource = function () { + return _source; + }; + + /** + * Get entity id of target node + * @returns {String} + */ + this.getTarget = function () { + return _target; + }; + + /** + * Get JSON representation of edge + * @return {Object} + */ + this.getJSON = function () { + return _json; + }; + + /** + * Get corresponding ot operation + * @returns {operations.ot.OTOperation} + * @private + */ + this.getOTOperation = function () { + var otOperation = EntityOperation.prototype.getOTOperation.call(this); + if (otOperation === null) { + otOperation = createOTOperation(); + this.setOTOperation(otOperation); + } + return otOperation; + }; + + /** + * Adjust the passed operation in the history of operation + * when this operation is applied remotely after the passed operation + * on an graph instance stored in the passed EntityManager + * @param {canvas_widget.EntityManager} EntityManager + * @param {EntityOperation} operation Remote operation + * @returns {EntityOperation} + */ + this.adjust = function (EntityManager, operation) { + switch (operation.getOperationType()) { + case EntityOperation.TYPES.AttributeAddOperation: + case EntityOperation.TYPES.AttributeDeleteOperation: + if (this.getEntityId() === operation.getRootSubjectEntityId()) { + return null; + } + break; + case EntityOperation.TYPES.EdgeAddOperation: + case EntityOperation.TYPES.EdgeDeleteOperation: + if (this.getEntityId() === operation.getEntityId()) { + return null; + } + break; + case EntityOperation.TYPES.ValueChangeOperation: + if (this.getEntityId() === operation.getRootSubjectEntityId()) { + return null; + } + break; + } + + return operation; + }; + + /** + * Compute the inverse of the operation + * @returns {EdgeAddOperation} + */ + this.inverse = function () { + return new EdgeAddOperation( + this.getEntityId(), + this.getType(), + this.getSource(), + this.getTarget() + ); + }; + } + static getOperationDescription(edgeType, edgeLabel, viewId) { + if (!edgeLabel && !viewId) { + return "..deleted " + edgeType; + } else if (!viewId) { + return "..deleted " + edgeType + " " + edgeLabel; + } else { + return "..deleted " + edgeType + " " + edgeLabel + "in View " + viewId; } + } + toJSON = function () { + return { + id: this.getEntityId(), + type: this.getType(), + source: this.getSource(), + target: this.getTarget(), + json: this.getJSON(), + }; + }; +} -var LogicalConjunctions = { - "AND" : "&&", - "OR" : "||" - }; +/** + * EdgeAddOperation + * @class operations.ot.EdgeAddOperation + * @memberof operations.ot + * @extends operations.ot.EntityOperation + * @param {String} entityId Entity id of the entity this activity works on + * @param {String} type Type of edge to add + * @param {String} source Entity id of source node + * @param {String} target Entity id of target node + * @param {object} json JSON representation of edge + * @param {string} viewId the identifier of the view + * @param {string} oType oType the original Type, only set in views + * @param {string} jabberId the jabberId of the user + * @constructor + */ +class EdgeAddOperation extends EntityOperation { + static TYPE = "EdgeAddOperation"; + getOriginType; + getType; + getSource; + getTarget; + getViewId; + getJabberId; + getJSON; + constructor( + entityId, + type, + source, + target, + json = null, + viewId = null, + oType = null, + jabberId = null + ) { + super(EntityOperation.TYPES.EdgeAddOperation, entityId, CONFIG.ENTITY.EDGE); + var that = this; + + var _oType = oType; + + var _jabberId = jabberId; + + this.getOriginType = function () { + return _oType; + }; -var LogicalOperator = { - "greater" : ">", - "smaller" : "<", - "equal" : "==", - "greater_eq" : ">=", - "smaller_eq" : "<=", - "nequal" : "!=" - }; + /** + * the identifier of the view + * @type {string} + * @private + */ + var _viewId = viewId; -function ViewTypesUtil() {} - -ViewTypesUtil.GetAllNodesOfBaseModelAsSelectionList = function (nodes) { - var selectionList = {}; - for (var key in nodes) { - if (nodes.hasOwnProperty(key)) { - selectionList[key] = nodes[key].getLabel().getValue().getValue(); - } - } - return selectionList; -}; -ViewTypesUtil.GetAllNodesOfBaseModelAsSelectionList2 = function (nodes, types) { - var selectionList = {}; - selectionList["empty"] = ""; - for (var key in nodes) { - if (nodes.hasOwnProperty(key)) { - if (lodash.indexOf(types, nodes[key].type) != -1) - selectionList[key] = nodes[key].label.value.value; - } - } - return selectionList; -}; - -ViewTypesUtil.createReferenceToOrigin = function (viewtype) { - const dataMap = y.getMap("data"); - var vls = dataMap.get("metamodelpreview"); - var originEntity; - if (vls) { - var targetAttr = viewtype.getAttribute(viewtype.getEntityId() + "[target]"); - var originId = targetAttr.getValue().getValue(); - if (viewtype.getType() === "ViewObject") { - if (vls.nodes.hasOwnProperty(originId)) { - originEntity = vls.nodes[originId]; - //By default the label for the ViewObject is the same as for the Origin - viewtype.getLabel().getValue().setValue(originEntity.label); - } - } else { - if (vls.edges.hasOwnProperty(originId)) { - originEntity = vls.edges[originId]; - //By default the label for the ViewObject is the same as for the Origin - viewtype.getLabel().getValue().setValue(originEntity.label); - } - } - //Initialize the Renaming list Attribute - var originAttrs = originEntity.attributes; - var renamingList = viewtype.getAttribute("[attributes]"); - var optionMap = {}; - for (var attrKey in originAttrs) { - if (originAttrs.hasOwnProperty(attrKey)) { - var attr = originAttrs[attrKey]; - var id = Util.generateRandomId(); - var operation = new AttributeAddOperation( - id, - renamingList.getEntityId(), - viewtype.getEntityId, - "RenamingAttribute" - ); - var renamingAttr = - renamingList.propagateAttributeAddOperation(operation); - renamingAttr.getKey().setValue(attr.key); - renamingAttr.getRef().setValue(attr.key); - optionMap[id] = attr.key; - } - } - //Initialize the Condition list attribute - viewtype.getYMap().set("updateConditionOption", optionMap); - - //targetAttr.get$node().hide(); - renamingList.get$node().show(); - viewtype - .getAttribute(viewtype.getEntityId() + "[conjunction]") - .get$node() - .show(); - viewtype.getAttribute("[condition]").get$node().show(); - } -}; + /** + * Type of edge to add + * @type {String} + * @private + */ + var _type = type; -const keySelectionValueSelectionValueListAttributeHtml = "
\r\n
\r\n
    \r\n
    "; // replaced by importmap.plugin.js - -const singleQuizAttributeHtml = "
    \r\n
    \r\n
    \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
    Assessment Name :
    NrQuestionCorrect IntentOptional Hint
    \r\n \r\n +\r\n \r\n \r\n -\r\n \r\n \r\n Submit\r\n \r\n \r\n Display\r\n \r\n
    \r\n"; // replaced by importmap.plugin.js - -const singleValueListAttributeHtml = "
    \r\n
    \r\n
      \r\n
      "; // replaced by importmap.plugin.js - -const canvasSingleValueAttributeHtml = "
      \r\n
      \r\n
      \r\n
      "; // replaced by importmap.plugin.js - -const listHtml = "
      \r\n
      \r\n
        \r\n
        "; // replaced by importmap.plugin.js - -const renamingAttrHTML = "
      • \r\n
        \r\n
        \r\n
        \r\n
      • "; // replaced by importmap.plugin.js - -const singleSelectionAttributeHtml = "
        \r\n
        \r\n
        \r\n
        "; // replaced by importmap.plugin.js - -const singleColorValueAttributeHtml = "
        \r\n
        \r\n
        \r\n
        "; // replaced by importmap.plugin.js - -const keySelectionValueSelectionValueAttributeHtml = "
      • \">\r\n
        \r\n
        \r\n
      • "; // replaced by importmap.plugin.js - -const keySelectionValueListAttributeHtml = "
        \r\n
        \r\n
          \r\n
          "; // replaced by importmap.plugin.js - -const keySelectionValueAttributeHtml = "
        • \">\r\n
          \r\n
          \r\n
        • "; // replaced by importmap.plugin.js -const integerAttributeHtml = "
          \r\n
          \r\n
          \r\n
          "; // replaced by importmap.plugin.js - -let integerValueHtml = "
          <%= value %>
          "; // replaced by importmap.plugin.js -const attributeIntegerValueHtml = "\"\r\n value=\"0\"\r\n/>\r\n"; // replaced by importmap.plugin.js - -const valueHtml = "\"\r\n disabled=\"disabled\"\r\n/>\r\n"; // replaced by importmap.plugin.js - -let selectionValueHtml = "
          <%= options[_.keys(options)[0]] %>
          "; // replaced by importmap.plugin.js -const attributeSelectionValueHtml = "\r\n"; // replaced by importmap.plugin.js - -const viewrelationshipNodeHtml$1 = "
          \r\n
          <%= type %>
          \r\n
          <<ViewRelationship>>
          \r\n
          \r\n
          "; // replaced by importmap.plugin.js - -const viewobjectNodeHtml = "
          \r\n
          <%= type %>
          \r\n
          <<ViewObject>>
          \r\n
          \r\n
          "; // replaced by importmap.plugin.js - -const nodeShapeNodeHtml = "
          \r\n
          <%= type %>
          \r\n
          <<NodeShape>>
          \r\n
          \r\n
          "; // replaced by importmap.plugin.js - -const modelAttributesNodeHtml = "
          \r\n
          \r\n
          \r\n
          "; // replaced by importmap.plugin.js - -const relationshipGroupNodeHtml = "
          \r\n
          <%= type %>
          \r\n
          <<Relation>>
          \r\n
          \r\n
          "; // replaced by importmap.plugin.js - -const enumNodeHtml = "
          \r\n
          <%= type %>
          \r\n
          <<Enumeration>>
          \r\n
          \r\n
          "; // replaced by importmap.plugin.js - -const abstractEdgeHtml = "
          \r\n
          <%= type %>
          \r\n
          \r\n
          "; // replaced by importmap.plugin.js - -const edgeShapeNodeHtml = "
          \r\n
          <%= type %>
          \r\n
          <<EdgeShape>>
          \r\n
          \r\n
          "; // replaced by importmap.plugin.js - -const abstractNodeHtml$1 = "
          \" class=\"node\">\r\n
          "; // replaced by importmap.plugin.js -const awarenessTraceHtml = "
          \" class=\"trace_awareness\">\r\n\r\n \r\n\r\n
          "; // replaced by importmap.plugin.js - -const abstractClassNodeHtml = "
          \r\n
          <%= type %>
          \r\n
          <<abstract>>
          \r\n
          \r\n
          \r\n"; // replaced by importmap.plugin.js - -const relationshipNodeHtml = "
          \r\n
          <%= type %>
          \r\n
          <<Relationship>>
          \r\n
          \r\n
          "; // replaced by importmap.plugin.js -const actionNodeHtml = "
          \r\n
          <%= \"<\\%= type %\\>\" %>
          \r\n \r\n \r\n \r\n
          \r\n \t\r\n\t\t \r\n\t\t \r\n\t\t \t\t\r\n\t\t \r\n\t\t
          fa-2x\"><%= label %>
          \r\n
          \r\n
          "; // replaced by importmap.plugin.js -const circleNodeHtml = "
          \r\n
          <%= type %>
          \r\n \r\n \"\r\n stroke=\"lightgray\"\r\n stroke-width=\"2\"\r\n />\r\n \r\n
          \r\n
          \r\n
          \r\n\r\n"; // replaced by importmap.plugin.js -const diamondNodeHtml = "
          \r\n
          <%= type %>
          \r\n \r\n \"\r\n stroke=\"lightgray\"\r\n stroke-width=\"2\"\r\n transform=\"rotate(-45 50 50)\"\r\n />\r\n \r\n
          \r\n
          \r\n
          \r\n\r\n"; // replaced by importmap.plugin.js -const objectNodeHtml = "
          \r\n
          <%= type %>
          \r\n
          <<Object>>
          \r\n
          \r\n
          "; // replaced by importmap.plugin.js -const rectangleNodeHtml = "
          \r\n
          <%= type %>
          \r\n \r\n \"\r\n stroke=\"lightgray\"\r\n stroke-width=\"2\"\r\n />\r\n \r\n
          \r\n
          \r\n
          \r\n\r\n"; // replaced by importmap.plugin.js -const roundedRectangleNodeHtml = "
          \r\n
          <%= type %>
          \r\n \r\n \"\r\n stroke=\"lightgray\"\r\n stroke-width=\"2\"\r\n />\r\n \r\n
          \r\n
          \r\n
          \r\n\r\n"; // replaced by importmap.plugin.js -const startActivityNodeHtml = "
          \r\n
          <%= type %>
          \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
          \r\n \t\r\n\t\t \r\n\t\t \r\n\t\t \t\t\r\n\t\t \r\n\t\t
          \r\n
          \r\n
          "; // replaced by importmap.plugin.js -const triangleNodeHtml = "
          \r\n
          <%= type %>
          \r\n \r\n \"\r\n stroke=\"lightgray\"\r\n stroke-width=\"2\"\r\n />\r\n \r\n
          \r\n
          \r\n
          \r\n\r\n"; // replaced by importmap.plugin.js -const activityFinalNodeHtml = "
          \r\n
          <%= type %>
          \r\n \r\n \r\n \r\n \r\n
          \r\n
          \r\n
          "; // replaced by importmap.plugin.js -const callActivityNodeHtml = "
          \r\n
          <%= type %>
          \r\n \r\n \r\n \r\n
          \r\n \r\n \r\n \r\n \r\n \r\n
          \r\n
          \r\n
          "; // replaced by importmap.plugin.js -const entityNodeHtml = "
          \r\n
          <%= \"<\\%= type %\\>\" %>
          \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
          \r\n \t\r\n\t\t \r\n\t\t \r\n\t\t \t\t\r\n\t\t \r\n\t\t
          fa-2x\"><%= label %>
          \r\n
          \r\n
          "; // replaced by importmap.plugin.js -const setPropertyNodeHtml = "
          \r\n
          <%= \"<\\%= type %\\>\" %>
          \r\n \r\n \r\n \r\n
          \r\n \t\r\n\t\t \r\n\t\t \r\n\t\t \t\t\r\n\t\t \r\n\t\t
          \r\n
          \r\n
          "; // replaced by importmap.plugin.js - -var shapes = { - straight: { - type: StraightConnector.type, - options: { gap: 0 }, - }, - curved: { - type: BezierConnector.type, - options: { gap: 0 }, - }, - segmented: { - type: FlowchartConnector.type, - options: { gap: 0 }, - }, -}; - -function HistoryManager() { - var bufferSize = 20; - - var _canvas = null; - - var latestOp = null; - var undo = []; - var redo = []; - - var $undo = $("#undo"); - - var $redo = $("#redo"); - - var propagateHistoryOperationFromJson = function (json) { - var EntityManager = EntityManager; - var operation = null, - data = null, - entity; - switch (json.TYPE) { - case NodeDeleteOperation.TYPE: { - entity = EntityManager.findNode(json.id); - if (entity) { - entity.triggerDeletion(true); - operation = new NodeDeleteOperation( - json.id, - json.type, - json.left, - json.top, - json.width, - json.height, - json.zIndex, - json.containment, - json.json - ); - } - break; - } - case NodeAddOperation.TYPE: { - _canvas.createNode( - json.type, - json.left, - json.top, - json.width, - json.height, - json.zIndex, - json.containment, - json.json, - json.id, - true - ); - operation = new NodeAddOperation( - json.id, - json.type, - json.left, - json.top, - json.width, - json.height, - json.zIndex, - json.containment, - json.json - ); - break; - } - case EdgeAddOperation.TYPE: { - _canvas.createEdge( - json.type, - json.source, - json.target, - json.json, - json.id, - true - ); - operation = new EdgeAddOperation( - json.id, - json.type, - json.source, - json.target, - json.json - ); - break; - } - case EdgeDeleteOperation.TYPE: { - entity = EntityManager.findEdge(json.id); - if (entity) { - entity.triggerDeletion(true); - operation = new EdgeDeleteOperation( - json.id, - json.type, - json.source, - json.target, - json.json - ); - } - break; - } - case NodeMoveOperation.TYPE: { - entity = EntityManager.findNode(json.id); - if (entity) { - const nodesMap = y.getMap("nodes"); - operation = new NodeMoveOperation( - json.id, - json.offsetX, - json.offsetY - ); - var ymap = nodesMap.get(json.id); - data = operation.toJSON(); - data.historyFlag = true; - ymap.set(NodeMoveOperation.TYPE, data); - } - break; - } - case NodeMoveZOperation.TYPE: { - entity = EntityManager.findNode(json.id); - if (entity) { - operation = new NodeMoveZOperation(json.id, json.offsetZ); - const nodesMap = y.getMap("nodes"); - var ymap = nodesMap.get(json.id); - data = operation.toJSON(); - data.historyFlag = true; - ymap.set(NodeMoveZOperation.TYPE, data); - } - break; - } - case NodeResizeOperation.TYPE: { - entity = EntityManager.findNode(json.id); - if (entity) { - operation = new NodeResizeOperation( - json.id, - json.offsetX, - json.offsetY - ); - const nodesMap = y.getMap("nodes"); - var ymap = nodesMap.get(json.id); - data = operation.toJSON(); - data.historyFlag = true; - ymap.set(NodeResizeOperation.TYPE, data); - } - break; - } - } - return operation; - }; - - return { - init: function (canvas) { - if (!canvas) throw new Error("Canvas is null"); - _canvas = canvas; - }, - add: function (operation) { - if (operation.hasOwnProperty("inverse")) { - var inverseOp = operation.inverse(); - var json = inverseOp.toJSON(); - json.TYPE = inverseOp.constructor.name; - undo.push(json); - redo = []; - $undo.prop("disabled", false); - $redo.prop("disabled", true); - } - if (undo.length > bufferSize) { - undo.shift(); - } - }, - undo: function () { - if (undo.length > 0) { - var jsonOp = undo.pop(); - if (undo.length === 0) { - $undo.prop("disabled", true); - } - var operation = propagateHistoryOperationFromJson(jsonOp); - if (!operation) { - this.undo(); - return; - } else latestOp = operation; - - var inverseOp = operation.inverse(); - var json = inverseOp.toJSON(); - json.TYPE = inverseOp.constructor.name; - - if (redo.length === 0) $redo.prop("disabled", false); - redo.push(json); - } else { - $undo.prop("disabled", true); - } - }, - redo: function () { - if (redo.length > 0) { - var jsonOp = redo.pop(); - if (redo.length === 0) { - $redo.prop("disabled", true); - } - var operation = propagateHistoryOperationFromJson(jsonOp); - if (!operation) { - this.redo(); - return; - } else latestOp = operation; - var inverseOp = operation.inverse(); - var json = inverseOp.toJSON(); - json.TYPE = inverseOp.constructor.name; - - if (undo.length === 0) $undo.prop("disabled", false); - undo.push(json); - } else { - $redo.prop("disabled", true); - } - }, - clean: function (entityId) { - var entityIdFilter = function (value, idx) { - if (value.id === entityId) return false; - else return true; - }; - undo = undo.filter(entityIdFilter); - redo = redo.filter(entityIdFilter); - if (undo.length === 0) { - $undo.prop("disabled", true); - } - if (redo.length === 0) { - $redo.prop("disabled", true); - } - }, - getLatestOperation: function () { - return latestOp; - }, - getUndoList: function () { - return undo; - }, - getRedoList: function () { - return redo; - }, - }; -} - -const HistoryManagerInstance = new HistoryManager(); - -const openapp = new OpenAppProvider().openapp; - -/** - * Predefined node shapes, first is default - * @type {{circle: *, diamond: *, rectangle: *, triangle: *}} - */ -var nodeShapeTypes = { - circle: circleNodeHtml, - diamond: diamondNodeHtml, - rectangle: rectangleNodeHtml, - rounded_rectangle: roundedRectangleNodeHtml, - triangle: triangleNodeHtml, -}; - -/** - * jQuery object to test for valid color - * @type {$} - */ -var $colorTestElement = $("
          "); - -/** Determines the current layer of syncmeta. - * can be CONFIG.LAYER.MODEL or CONFIG.LAYER.META*/ -var _layer = null; - -/** - * Different node types - * @type {object} - */ -var nodeTypes = {}; - -var _initNodeTypes = function (vls) { - var _nodeTypes = {}; - - var nodes = vls.nodes, - node, - shape, - anchors; - - // Start creating nodes based on metamodel - for (var nodeId in nodes) { - if (nodes.hasOwnProperty(nodeId)) { - node = nodes[nodeId]; - if (node.shape.customShape) { - shape = node.shape.customShape; - } else { - shape = nodeShapeTypes.hasOwnProperty(node.shape.shape) - ? nodeShapeTypes[node.shape.shape] - : lodash.keys(nodeShapeTypes)[0]; - } - if (node.shape.customAnchors) { - try { - if (node.shape.customAnchors) { - anchors = JSON.parse(node.shape.customAnchors); - } - if (!node.shape.customAnchors instanceof Array) { - anchors = { - type: "Perimeter", - options: { - shape: "Rectangle", - anchorCount: 10, - }, - }; - } - } catch (e) { - anchors = { - type: "Perimeter", - options: { - shape: "Rectangle", - anchorCount: 10, - }, - }; - } - } else { - switch (node.shape.shape) { - case "circle": - anchors = { - type: "Perimeter", - options: { - shape: "Circle", - anchorCount: 10, - }, - }; - break; - case "diamond": - anchors = { - type: "Perimeter", - options: { - shape: "Diamond", - anchorCount: 10, - }, - }; - break; - case "rounded_rectangle": - anchors = { - type: "Perimeter", - options: { - shape: "Rectangle", - anchorCount: 10, - }, - }; - break; - case "triangle": - anchors = { - type: "Perimeter", - options: { - shape: "Triangle", - anchorCount: 10, - }, - }; - break; - default: - case "rectangle": - anchors = { - type: "Perimeter", - options: { - shape: "Rectangle", - anchorCount: 10, - }, - }; - break; - } - } - var color = node.shape.color - ? $colorTestElement - .css("color", "#FFFFFF") - .css("color", node.shape.color) - .css("color") - : "#FFFFFF"; - var $shape = $(lodash.template(shape)({ color: color, type: node.label })); - - if ( - node.hasOwnProperty("targetName") && - !$.isEmptyObject(nodeTypes) && - nodeTypes.hasOwnProperty(node.targetName) - ) { - _nodeTypes[node.label] = makeViewNode( - node.label, - $shape, - anchors, - node.attributes, - nodeTypes[node.targetName], - node.conditions, - node.conjunction - ); - nodeTypes[node.targetName].VIEWTYPE = node.label; - } else { - _nodeTypes[node.label] = makeNode( - node.label, - $shape, - anchors, - node.attributes - ); - } - _nodeTypes[node.label].TYPE = node.label; - _nodeTypes[node.label].DEFAULT_WIDTH = node.shape.defaultWidth; - _nodeTypes[node.label].DEFAULT_HEIGHT = node.shape.defaultHeight; - _nodeTypes[node.label].CONTAINMENT = node.shape.containment; - _nodeTypes[node.label].SHAPE = $shape; - /* - nodeTypes[node.label] = Node(node.label, $shape, anchors, node.attributes, node.jsplumb); - nodeTypes[node.label].TYPE = node.label; - nodeTypes[node.label].SHAPE = $shape; - nodeTypes[node.label].DEFAULT_WIDTH = node.shape.defaultWidth; - nodeTypes[node.label].DEFAULT_HEIGHT = node.shape.defaultHeight;*/ - } - } - return _nodeTypes; -}; - -var _initEdgeTypes = function (vls) { - var _edgeTypes = {}; - var _relations = {}; - var edges = vls.edges, - edge; - for (var edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - - if ( - edge.hasOwnProperty("targetName") && - !$.isEmptyObject(edgeTypes) && - edgeTypes.hasOwnProperty(edge.targetName) - ) { - _edgeTypes[edge.label] = makeViewEdge( - edge.label, - edge.shape.arrow, - edge.shape.shape, - edge.shape.color, - edge.shape.dashstyle, - edge.shape.overlay, - edge.shape.overlayPosition, - edge.shape.overlayRotate, - edge.attributes, - edgeTypes[edge.targetName], - edge.conditions, - edge.conjunction - ); - edgeTypes[edge.targetName].VIEWTYPE = edge.label; - } else { - _edgeTypes[edge.label] = makeEdge( - edge.label, - edge.shape.arrow, - edge.shape.shape, - edge.shape.color, - edge.shape.dashstyle, - edge.shape.overlay, - edge.shape.overlayPosition, - edge.shape.overlayRotate, - edge.attributes - ); - } - - _edgeTypes[edge.label].TYPE = edge.label; - _relations[edge.label] = edge.relations; - } - } - return { - edgeTypes: _edgeTypes, - relations: _relations, - }; -}; - -/** - * contains all view node types of the current view - * @type {{}} - */ -var viewNodeTypes = {}; - -/** - * contains all view edge types of the current view - * @type {{}} - */ -var viewEdgeTypes = {}; - -/** - * Different edge types - * @type {object} - */ -var edgeTypes = {}; -var relations = {}; -/* - if (metamodel && metamodel.hasOwnProperty("edges")) { - var res = _initEdgeTypes(metamodel); - edgeTypes = res.edgeTypes; - relations = res.relations; - } else { - edgeTypes[GeneralisationEdge.TYPE] = GeneralisationEdge; - edgeTypes[BiDirAssociationEdge.TYPE] = BiDirAssociationEdge; - edgeTypes[UniDirAssociationEdge.TYPE] = UniDirAssociationEdge; - - relations[BiDirAssociationEdge.TYPE] = BiDirAssociationEdge.RELATIONS; - relations[UniDirAssociationEdge.TYPE] = UniDirAssociationEdge.RELATIONS; - relations[GeneralisationEdge.TYPE] = GeneralisationEdge.RELATIONS; - }*/ - -/** - * AbstractEdge - * @class canvas_widget.AbstractEdge - * @extends canvas_widget.AbstractEntity - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of edge - * @param {string} type Type of edge - * @param {canvas_widget.AbstractNode} source Source node - * @param {canvas_widget.AbstractNode} target Target node - * @param {boolean} [overlayRotate] Flag if edge overlay should be flipped automatically to avoid being upside down - */ -class AbstractEdge extends AbstractEntity { - constructor(id, type, source, target, overlayRotate, y) { - super(id); - y = y || window.y; - var that = this; - - /** - * Inter widget communication wrapper - * @type {Object} - */ - var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); // y comes from the window object but should in the future be passed through the constructor since we should avoid binding to window - - var _ymap = null; - if (!y) { - throw new Error("y is not defined"); - } - - const edgeMap = y.getMap("edges"); - if (edgeMap.has(id)) { - _ymap = edgeMap.get(id); - } else if (id && type && source && target) { - _ymap = new Map$2(); - edgeMap.set(id, new Map$2()); - y.transact(() => { - _ymap.set("id", id); - _ymap.set("type", type); - _ymap.set("source", source.getEntityId()); - _ymap.set("target", target.getEntityId()); - _ymap.set("jabberId", _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]); - }); - } - - this.getYMap = function () { - return _ymap; - }; - - /** - * Type of edge - * @type {string} - * @private - */ - var _type = type; - - /** - * Label of edge - * @type {canvas_widget.SingleValueAttribute} - * @private - */ - var _label = new SingleValueAttribute(id + "[label]", "Label", this, y); - - /** - * Appearance information of edge - * @type {{source: (canvas_widget.AbstractNode), target: (canvas_widget.AbstractNode)}} - * @private - */ - var _appearance = { - source: source, - target: target, - }; - - /** - * Flag if edge overlay should be flipped automatically to avoid being upside down - * @type {boolean} - * @private - */ - var _overlayRotate = overlayRotate !== false; - - /** - * jQuery object of DOM node representing the edge's overlay - * @type {jQuery} - * @private - */ - var _$overlay = $(lodash.template(abstractEdgeHtml)({ type: type })) - .find(".edge_label") - .append(_label.get$node()) - .parent(); - - /** - * Canvas the edge is drawn on - * @type {canvas_widget.AbstractCanvas} - * @private - */ - var _canvas = null; - - /** - * jsPlumb object representing the edge - * @type {Object} - * @private - */ - var _jsPlumbConnection = null; - - /** - * Attributes of edge - * @type {Object} - * @private - */ - var _attributes = {}; - - /** - * Stores current highlighting color - * @type {string} - * @private - */ - var _highlightColor = null; - - /** - * Callback to generate list of context menu items - * @type {function} - */ - var _contextMenuItemCallback = function () { - return {}; - }; - - //noinspection JSUnusedLocalSymbols - /** - * Apply an Edge Delete Operation - * @param {operations.ot.EdgeDeleteOperation} operation - */ - var processEdgeDeleteOperation = function (operation) { - that.remove(); - }; - - /** - * Propagate an Edge Delete Operation to the remote users and the local widgets - * @param {operations.ot.EdgeDeleteOperation} operation - */ - var propagateEdgeDeleteOperation = function (operation) { - processEdgeDeleteOperation(); - - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.ATTRIBUTE, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.getOTOperation() - ); - const activityMap = y.getMap("activity"); - activityMap.set( - ActivityOperation.TYPE, - new ActivityOperation( - "EdgeDeleteActivity", - operation.getEntityId(), - _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], - EdgeDeleteOperation.getOperationDescription( - that.getType(), - that.getLabel().getValue().getValue() - ), - {} - ).toJSON() - ); - }; - - /** - * Callback for a remote Edge Delete Operation - * @param {operations.ot.EdgeDeleteOperation} operation - */ - this.remoteEdgeDeleteCallback = function (operation) { - if ( - operation instanceof EdgeDeleteOperation && - operation.getEntityId() == that.getEntityId() - ) { - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.ATTRIBUTE, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.getOTOperation() - ); - processEdgeDeleteOperation(); - } - }; - - /** - * Get jQuery object of all DOM nodes belonging to the edge - */ - var getAllAssociatedDOMNodes = function () { - var overlays, - i, - numOfOverlays, - $e = $("." + id); - - if (_jsPlumbConnection) { - overlays = _jsPlumbConnection.getOverlays(); - for (i = 0, numOfOverlays = overlays.length; i < numOfOverlays; i++) { - if (overlays[i] instanceof jsPlumb.Overlays.Custom) { - $e = $e.add(overlays[i].getElement()); - } - } - } else throw new Error("jsPlumbConnection is null"); - return $e; - }; - - /** - * Default paint style of edge - */ - var _defaultPaintStyle; - - /** - * Set the default paint style - * @param paintStyle - */ - this.setDefaultPaintStyle = function (paintStyle) { - _defaultPaintStyle = paintStyle; - }; - - /** - * Get the default paint style - * @returns {*} - */ - this.getDefaultPaintStyle = function () { - return _defaultPaintStyle; - }; - - /** - * Send NodeDeleteOperation for node - */ - this.triggerDeletion = function (historyFlag) { - _canvas.select(null); - var operation = new EdgeDeleteOperation( - id, - that.getType(), - that.getSource().getEntityId(), - that.getTarget().getEntityId() - ); - - if (_ymap) { - propagateEdgeDeleteOperation(operation); - const edgeMap = y.getMap("edges"); - edgeMap.delete(that.getEntityId()); - } else { - propagateEdgeDeleteOperation(operation); - } - if (!historyFlag) HistoryManagerInstance.add(operation); - }; - - //noinspection JSUnusedGlobalSymbols - /** - * Get callback to generate list of context menu items - * @returns {object} - */ - this.getContextMenuItemCallback = function () { - return _contextMenuItemCallback; - }; - - /** - * Set callback to generate list of context menu items - * @param {function} contextMenuItemCallback - */ - this.setContextMenuItemCallback = function (contextMenuItemCallback) { - _contextMenuItemCallback = contextMenuItemCallback; - }; - - /** - * Adds edge to canvas - * @param {canvas_widget.AbstractCanvas} canvas - */ - this.addToCanvas = function (canvas) { - if (!canvas) throw new Error("Canvas is null"); - _canvas = canvas; - }; - - /** - * Get associated canvas - * @returns {canvas_widget.AbstractCanvas} - */ - this.getCanvas = function () { - return _canvas; - }; - - /** - * Removes edge from canvas - */ - this.removeFromCanvas = function () { - _canvas = null; - $.contextMenu("destroy", "." + that.getEntityId()); - window.jsPlumbInstance.deleteConnection(_jsPlumbConnection, { - fireEvent: false, - }); - _jsPlumbConnection = null; - }; - - /** - * Add attribute to edge - * @param {canvas_widget.AbstractAttribute} attribute - */ - this.addAttribute = function (attribute) { - var id = attribute.getEntityId(); - if (!_attributes.hasOwnProperty(id)) { - _attributes[id] = attribute; - } - }; - - /** - * Set edge's attributes - * @param {Object} attributes - */ - this.setAttributes = function (attributes) { - _attributes = attributes; - }; - - /** - * Get edge's attributes - * @returns {Object} - */ - this.getAttributes = function () { - return _attributes; - }; - - /** - * Get attribute by id - * @param {String} id Attribute's entity id - * @returns {canvas_widget.AbstractAttribute} - */ - this.getAttribute = function (id) { - if (_attributes.hasOwnProperty(id)) { - return _attributes[id]; - } - return null; - }; - - /** - * Delete attribute by id - * @param {String} id Attribute's entity id - */ - this.deleteAttribute = function (id) { - if (!_attributes.hasOwnProperty(id)) { - delete _attributes[id]; - } - }; - - /** - * Set edge label - * @param {canvas_widget.SingleValueAttribute} label - */ - this.setLabel = function (label) { - _label = label; - }; - - /** - * Get edge label - * @returns {canvas_widget.SingleValueAttribute} - */ - this.getLabel = function () { - return _label; - }; - - /** - * Get edge type - * @returns {string} - */ - this.getType = function () { - return _type; - }; - - /** - * Get source node - * @returns {canvas_widget.AbstractNode} - */ - this.getSource = function () { - return _appearance.source; - }; - - /** - * Get target node - * @returns {canvas_widget.AbstractNode} - */ - this.getTarget = function () { - //noinspection JSAccessibilityCheck - return _appearance.target; - }; - - /** - * Get jQuery object of DOM node representing the edge's overlay - * @returns {jQuery} - */ - this.get$overlay = function () { - return _$overlay; - }; - - //noinspection JSUnusedGlobalSymbols - /** - * Set flag if edge overlay should be flipped automatically to avoid being upside down - * @param {boolean} rotateOverlay - */ - this.setRotateOverlay = function (rotateOverlay) { - _overlayRotate = rotateOverlay; - }; - - //noinspection JSUnusedGlobalSymbols - /** - * Get flag if edge overlay should be flipped automatically to avoid being upside down - * @return {boolean} rotateOverlay - */ - this.isRotateOverlay = function () { - return _overlayRotate; - }; - - /** - * Set jsPlumb object representing the edge - * @param {Object} jsPlumbConnection - */ - this.setJsPlumbConnection = function (jsPlumbConnection) { - _jsPlumbConnection = jsPlumbConnection; - _defaultPaintStyle = jsPlumbConnection.getPaintStyle(); - }; - - //noinspection JSUnusedGlobalSymbols - /** - * Get jsPlumb object representing the edge - * @return {Object} jsPlumbConnection - */ - this.getJsPlumbConnection = function () { - return _jsPlumbConnection; - }; - - /** - * Repaint edge overlays (adjust angle of fixed overlays) - */ - this.repaintOverlays = function () { - function makeRotateOverlayCallback(angle) { - return function rotateOverlay() { - var $this = $(this), - oldTransform = $this.css("transform", "").css("transform"); - - if (oldTransform === "none") oldTransform = ""; - - $this.css({ - transform: oldTransform + " rotate(" + angle + "rad)", - "-o-transform": oldTransform + " rotate(" + angle + "rad)", - "-ms-transform": oldTransform + " rotate(" + angle + "rad)", - "-moz-transform": oldTransform + " rotate(" + angle + "rad)", - "-webkit-transform": oldTransform + " rotate(" + angle + "rad)", - }); - }; - } - - var i, numOfOverlays, overlays, sourceEndpoint, targetEndpoint, angle; - - if (_jsPlumbConnection) { - sourceEndpoint = _jsPlumbConnection.endpoints[0].endpoint; - targetEndpoint = _jsPlumbConnection.endpoints[1].endpoint; - angle = Math.atan2( - sourceEndpoint.y - targetEndpoint.y, - sourceEndpoint.x - targetEndpoint.x - ); - if (!_overlayRotate || Math.abs(angle) > Math.PI / 2) { - angle += Math.PI; - } - overlays = _jsPlumbConnection.getOverlays(); - for (i = 0, numOfOverlays = overlays.length; i < numOfOverlays; i++) { - if (overlays[i] instanceof jsPlumb.Overlays.Custom) { - $(overlays[i].getElement()) - .find(".fixed") - .not(".segmented") - .each(makeRotateOverlayCallback(angle)); - //Always flip type overlay - $(overlays[i].getElement()) - .find(".fixed.type") - .not(".segmented") - .each( - makeRotateOverlayCallback( - Math.abs(angle - Math.PI) > Math.PI / 2 - ? angle - : angle + Math.PI - ) - ); - } - } - } else throw new Error("jsPlumbConnection is null"); - }; - - /** - * Sets position of edge on z-axis as max of the z-indices of source and target - */ - this.setZIndex = function () { - var $e = getAllAssociatedDOMNodes(), - zIndex = Math.max(source.getZIndex(), target.getZIndex()); - $e.css("zIndex", zIndex); - }; - - /** - * Connect source and target node and draw the edge on canvas - */ - this.connect = function () { - source.addOutgoingEdge(this); - target.addIngoingEdge(this); - //noinspection JSAccessibilityCheck - _jsPlumbConnection = window.jsPlumbInstance.connect({ - source: _appearance.source.get$node().get(0), - target: _appearance.target.get$node().get(0), - paintStyle: { stroke: "black", outlineWidth: 4 }, - endpoint: "Dot", - connector: { type: FlowchartConnector.type }, - anchors: [source.getAnchorOptions(), target.getAnchorOptions()], - overlays: [ - { - type: "Custom", - options: { - create: function () { - return _$overlay.get(0); - }, - location: 0.5, - id: "label", - }, - }, - ], - cssClass: id, - }); - this.repaintOverlays(); - lodash.each(EntityManagerInstance.getEdges(), function (e) { - e.setZIndex(); - }); - }; - - /** - * Lowlight the edge - */ - this.lowlight = function () { - $("." + id).addClass("lowlighted"); - }; - - /** - * Unlowlight the edge - */ - this.unlowlight = function () { - $("." + id).removeClass("lowlighted"); - }; - - /** - * Select the edge - */ - this.select = function () { - var paintStyle = lodash.clone(_defaultPaintStyle), - overlays, - i, - numOfOverlays; - - function makeBold() { - $(this).css("fontWeight", "bold"); - } - this.unhighlight(); - if (_jsPlumbConnection) { - paintStyle.lineWidth = 4; - _jsPlumbConnection.setPaintStyle(paintStyle); - overlays = _jsPlumbConnection.getOverlays(); - for (i = 0, numOfOverlays = overlays.length; i < numOfOverlays; i++) { - if (overlays[i] instanceof jsPlumb.Overlays.Custom) { - $(overlays[i].getElement()).find(".fixed").each(makeBold); - } - } - } else throw new Error("jsPlumbConnection is null"); - }; - - /** - * Unselect the edge - */ - this.unselect = function () { - var overlays, i, numOfOverlays; - - function unmakeBold() { - $(this).css("fontWeight", ""); - } - this.highlight(_highlightColor); - if (_jsPlumbConnection) { - _jsPlumbConnection.setPaintStyle(_defaultPaintStyle); - overlays = _jsPlumbConnection.getOverlays(); - for (i = 0, numOfOverlays = overlays.length; i < numOfOverlays; i++) { - if (overlays[i] instanceof jsPlumb.Overlays.Custom) { - $(overlays[i].getElement()).find(".fixed").each(unmakeBold); - } - } - } - }; - - /** - * Highlight the edge - * @param {String} color - */ - this.highlight = function (color) { - var paintStyle = lodash.clone(_defaultPaintStyle); - - if (color) { - paintStyle.strokeStyle = color; - paintStyle.lineWidth = 4; - if (_jsPlumbConnection) _jsPlumbConnection.setPaintStyle(paintStyle); - else throw new Error("jsPlumbConnection is null"); - } - }; - - /** - * Unhighlight the edge - */ - this.unhighlight = function () { - if (_jsPlumbConnection) { - _jsPlumbConnection.setPaintStyle(_defaultPaintStyle); - } else throw new Error("jsPlumbConnection is null"); - }; - - /** - * Remove the edge - */ - this.remove = function () { - source.deleteOutgoingEdge(this); - target.deleteIngoingEdge(this); - this.removeFromCanvas(); - //this.unregisterCallbacks(); - EntityManagerInstance.deleteEdge(this.getEntityId()); - if (_ymap) { - _ymap = null; - } - }; - - /** - * Get JSON representation of the edge - * @returns {Object} - * @private - */ - this._toJSON = function () { - var attr = {}; - lodash.forEach(this.getAttributes(), function (val, key) { - attr[key] = val.toJSON(); - }); - return { - label: _label.toJSON(), - source: source.getEntityId(), - target: target.getEntityId(), - attributes: attr, - type: _type, - }; - }; - - /** - * Bind events for move tool - */ - this.bindMoveToolEvents = function () { - if (_jsPlumbConnection) { - //Enable Edge Select - $("." + id).on("click", function (e) { - _canvas.select(that); - }); - - $(_jsPlumbConnection.getOverlay("label").canvas) - .find("input") - .prop("disabled", false) - .css("pointerEvents", ""); - - /*$(_jsPlumbConnection.getOverlay("label").canvas).find("input[type=text]").autoGrowInput({ - comfortZone: 10, - minWidth: 40, - maxWidth: 100 - }).trigger("blur");*/ - } else throw new Error("jsPlumbConnection is null"); - - if (id) { - // view_only is used by the CAE and allows to show a model in the Canvas which is not editable - // therefore, the context menu of every edge must be disabled - const widgetConfigMap = y.getMap("widgetConfig"); - var viewOnly = widgetConfigMap.get("view_only"); - if (viewOnly) return; - } - - //Define Edge Rightclick Menu - $.contextMenu({ - selector: "." + id, - zIndex: AbstractEntity.CONTEXT_MENU_Z_INDEX, - build: function () { - var menuItems = lodash.extend(_contextMenuItemCallback(), { - delete: { - name: "Delete", - callback: function (/*key, opt*/) { - that.triggerDeletion(); - }, - }, - }); - - return { - items: menuItems, - events: { - show: function (/*opt*/) { - _canvas.select(that); - }, - }, - }; - }, - }); - - //$("."+id).contextMenu(true); - }; - - /** - * Unbind events for move tool - */ - this.unbindMoveToolEvents = function () { - if (_jsPlumbConnection) { - //Disable Edge Select - _jsPlumbConnection.unbind("click"); - - $(_jsPlumbConnection.getOverlay("label").canvas) - .find("input") - .prop("disabled", true) - .css("pointerEvents", "none"); - } else throw new Error("jsPlumbConnection is null"); - - //$("."+id).contextMenu(false); - }; - - this._registerYMap = function () { - that.getLabel().getValue().registerYType(); - }; - } - /** - * Get JSON representation of the edge - * @returns {{label: Object, source: string, target: string, attributes: Object, type: string}} - */ - toJSON() { - return this._toJSON(); - } - /** - * Hide a jsPlumb connection - */ - hide() { - var connector = this.getJsPlumbConnection(); - connector.setVisible(false); - } - /** - * Show a jsPlumb connection - */ - show() { - var connector = this.getJsPlumbConnection(); - connector.setVisible(true); - } - registerYMap() { - this._registerYMap(); - } -} - -/** - * AbstractNode - * @class canvas_widget.AbstractNode - * @extends canvas_widget.AbstractEntity - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of node - * @param {string} type Type of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {boolean} containment containment - * @param {number} zIndex Position of node on z-axis - */ -class AbstractNode extends AbstractEntity { - nodeSelector; - _$node; - constructor( - id, - type, - left, - top, - width, - height, - zIndex, - containment, - json, - y - ) { - super(id); - var that = this; - y = y || window.y; - if (!y) { - throw new Error("y is undefined"); - } - - /** - * Inter widget communication wrapper - * @type {Object} - * @private - */ - var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); - /**y-map instances which belongs to the node - * @type {YMap} - * @private - * */ - var _ymap = null; - y = y || window.y; - if (!y) { - throw new Error("y is undefined"); - } - const nodesMap = y.getMap("nodes"); - - if (nodesMap.has(id)) { - _ymap = nodesMap.get(id); - } else { - window.y.transact(() => { - _ymap = new Map$2(); - nodesMap.set(id, _ymap); - _ymap.set("modifiedBy", window.y.clientID); - _ymap.set("left", left); - _ymap.set("top", top); - _ymap.set("width", width); - _ymap.set("height", height); - _ymap.set("zIndex", zIndex); - _ymap.set("containment", containment); - _ymap.set("type", type); - _ymap.set("id", id); - if (json) _ymap.set("json", json); - if (_iwcw.getUser().globalId !== -1) - _ymap.set("jabberId", _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]); - }); - } - - this.getYMap = function () { - return _ymap; - }; - - /** - * Type of node - * @type {string} - * @private - */ - var _type = type; - - /** - * Label of edge - * @type {canvas_widget.SingleValueAttribute} - * @private - */ - var _label = new SingleValueAttribute(id + "[label]", "Label", this, y); - - /** - * Appearance information of edge - * @type {{left: number, top: number, width: number, height: number}} - * @private - */ - var _appearance = { - left: left, - top: top, - width: width, - height: height, - containment: containment, - }; - - /** - * Position of node on z-axis - * @type {number} - * @private - */ - var _zIndex = zIndex; - - /** - * Type of node - * @containment {boolean} - * @private - */ - var _containment = containment; - - /** - * Canvas the node is drawn on - * @type {canvas_widget.AbstractCanvas} - * @private - */ - var _canvas = null; - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(abstractNodeHtml$1)({ id: id })); - this._$node = _$node; - const resizeHandle = $( - `
          ` - ); - resizeHandle.css({ - position: "absolute", - bottom: "0", - right: "0", - cursor: "nwse-resize", - zIndex: 100000, - }); - - // append to node - _$node.append(resizeHandle); - resizeHandle.on("mouseover", () => { - this.disableDraggable(); - }); - resizeHandle.on("mouseout", () => { - this.enableDraggable(); - }); - - this.nodeSelector = getQuerySelectorFromNode(this._$node[0]); - - // this is the node's awareness trace. - // If I understand correctly, it is showing the activity of other users on the node. - var _$awarenessTrace = $( - lodash.template(awarenessTraceHtml)({ id: id + "_awareness" }) - ); - - var _awarenessTimer = setInterval(function () { - var opacity = _$awarenessTrace.css("opacity"); - opacity -= 0.1; - if (opacity < 0) opacity = 0; - _$awarenessTrace.css({ - opacity: opacity, - }); - }, 3000); - - this._$node.on("mousedown", function (e) { - _canvas.select(that); - _canvas.unbindMoveToolEvents(); - }); - - this._$node.on("mouseup", function (e) { - _canvas.bindMoveToolEvents(); - }); - - /** - * Attributes of node - * @type {Object} - * @private - */ - var _attributes = {}; - - /** - * Callback to generate list of context menu items - * @type {function} - */ - var _contextMenuItemCallback = function () { - return {}; - }; - - /** - * Set of ingoing edges - * @type {Object} - * @private - */ - var _ingoingEdges = {}; - - /** - * Set of outgoing edges - * @type {Object} - * @private - */ - var _outgoingEdges = {}; - - /** - * Set of nodes with an edge to the node - * @type {Object} - * @private - */ - var _ingoingNeighbors = {}; - - /** - * Set of nodes with an edge from the node - * @type {Object} - * @private - */ - var _outgoingNeighbors = {}; - - var _relatedGhostEdges = []; - - /** - * Apply a Node Move Operation - * @param {operations.ot.NodeMoveOperation} operation - */ - var processNodeMoveOperation = function (operation) { - _canvas.hideGuidanceBox(); - that.move(operation.getOffsetX(), operation.getOffsetY(), 0); - _canvas.showGuidanceBox(); - }; - - /** - * Apply a Node Move Z Operation - * @param {operations.ot.NodeMoveZOperation} operation - */ - var processNodeMoveZOperation = function (operation) { - that.move(0, 0, operation.getOffsetZ()); - }; - - /** - * Propagate a Node Move Operation to the remote users and the local widgets - * @param {operations.ot.NodeMoveOperation} operation - */ - this.propagateNodeMoveOperation = function (operation) { - operation.setJabberId(_iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]); - processNodeMoveOperation(operation); - HistoryManagerInstance.add(operation); - EntityManagerInstance.storeDataYjs(); - - hideTraceAwareness(); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.ATTRIBUTE, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.HEATMAP, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.getOTOperation() - ); - const activityMap = y.getMap("activity"); - activityMap.set( - ActivityOperation.TYPE, - new ActivityOperation( - "NodeMoveActivity", - operation.getEntityId(), - operation.getJabberId(), - NodeMoveOperation.getOperationDescription( - that.getType(), - that.getLabel().getValue().getValue() - ), - { nodeType: that.getType() } - ).toJSON() - ); - - if (_ymap) { - _ymap.set(NodeMoveOperation.TYPE, operation.toJSON()); - } - }; - - /** - * Propagate a Node Move Z Operation to the remote users and the local widgets - * @param {operations.ot.NodeMoveZOperation} operation - */ - this.propagateNodeMoveZOperation = function (operation) { - var jabberId = _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]; - operation.setJabberId(jabberId); - processNodeMoveZOperation(operation); - HistoryManagerInstance.add(operation); - hideTraceAwareness(); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.ATTRIBUTE, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.getOTOperation() - ); - const activityMap = y.getMap("activity"); - activityMap.set( - ActivityOperation.TYPE, - new ActivityOperation( - "NodeMoveActivity", - operation.getEntityId(), - jabberId, - NodeMoveOperation.getOperationDescription( - that.getType(), - that.getLabel().getValue().getValue() - ), - { nodeType: that.getType() } - ).toJSON() - ); - - if (_ymap) _ymap.set(NodeMoveZOperation.TYPE, operation.toJSON()); - }; - - /** - * Apply a Node Resize Operation - * @param {operations.ot.NodeResizeOperation} operation - */ - var processNodeResizeOperation = function (operation) { - _canvas.hideGuidanceBox(); - that.resize(operation.getOffsetX(), operation.getOffsetY()); - _canvas.showGuidanceBox(); - }; - - /** - * Propagate a Node Resize Operation to the remote users and the local widgets - * @param {operations.ot.NodeResizeOperation} operation - */ - this.propagateNodeResizeOperation = function (operation) { - operation.setJabberId(_iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]); - processNodeResizeOperation(operation); - HistoryManagerInstance.add(operation); - EntityManagerInstance.storeDataYjs(); - hideTraceAwareness(); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.ATTRIBUTE, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.HEATMAP, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.getOTOperation() - ); - const activityMap = y.getMap("activity"); - activityMap.set( - ActivityOperation.TYPE, - new ActivityOperation( - "NodeResizeActivity", - operation.getEntityId(), - operation.getJabberId(), - NodeResizeOperation.getOperationDescription( - that.getType(), - that.getLabel().getValue().getValue() - ), - { nodeType: that.getType() } - ).toJSON() - ); - - if (_ymap) _ymap.set("NodeResizeOperation", operation.toJSON()); - }; - - /** - * Apply a Node Delete Operation - * @param {operations.ot.NodeDeleteOperation} operation - */ - var processNodeDeleteOperation = function (operation) { - var edges = that.getEdges(), - edgeId, - edge; - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - edge.remove(); - } - } - - for (var i = 0; i < _relatedGhostEdges.length; i++) { - if (typeof _relatedGhostEdges[i].remove == "function") - _relatedGhostEdges[i].remove(); - } - if (_ymap) { - _ymap = null; - } - that.remove(); - }; - - /** - * Propagate a Node Delete Operation to the remote users and the local widgets - * @param {operations.ot.NodeDeleteOperation} operation - */ - var propagateNodeDeleteOperation = function (operation) { - processNodeDeleteOperation(); - EntityManagerInstance.storeDataYjs(); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.ATTRIBUTE, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.HEATMAP, - operation.getOTOperation() - ); - const activityMap = y.getMap("activity"); - activityMap.set( - ActivityOperation.TYPE, - new ActivityOperation( - "NodeDeleteActivity", - operation.getEntityId(), - _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], - NodeDeleteOperation.getOperationDescription( - that.getType(), - that.getLabel().getValue().getValue() - ), - {} - ).toJSON() - ); - }; - - var refreshTraceAwareness = function (color) { - _$awarenessTrace.css({ - opacity: 1, - fill: color, - }); - }; - - var hideTraceAwareness = function () { - _$awarenessTrace.css({ - opacity: 0, - }); - }; - - /** - * Callback for a remote Node Move Operation - * @param {operations.ot.NodeMoveOperation} operation - */ - var remoteNodeMoveCallback = function (operation) { - if ( - operation instanceof NodeMoveOperation && - operation.getEntityId() === that.getEntityId() - ) { - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.ATTRIBUTE, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.HEATMAP, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.getOTOperation() - ); - const userMap = y.getMap("users"); - if (userMap.get(y.clientID) !== operation.getJabberId()) { - const userList = y.getMap("userList"); - var color = Util.getColor( - userList.get(operation.getJabberId()).globalId - ); - refreshTraceAwareness(color); - } - - processNodeMoveOperation(operation); - } - }; - - /** - * Callback for a remote Node Move Z Operation - * @param {operations.ot.NodeMoveZOperation} operation - */ - var remoteNodeMoveZCallback = function (operation) { - if ( - operation instanceof NodeMoveZOperation && - operation.getEntityId() === that.getEntityId() - ) { - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.ATTRIBUTE, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.getOTOperation() - ); - const userMap = y.getMap("users"); - if (userMap.get(y.clientID) !== operation.getJabberId()) { - const userList = y.getMap("userList"); - var color = Util.getColor( - userList.get(operation.getJabberId()).globalId - ); - refreshTraceAwareness(color); - } - processNodeMoveZOperation(operation); - } - }; - - /** - * Callback for a remote Node Resize Operation - * @param {operations.ot.NodeResizeOperation} operation - */ - var remoteNodeResizeCallback = function (operation) { - if ( - operation instanceof NodeResizeOperation && - operation.getEntityId() === that.getEntityId() - ) { - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.ATTRIBUTE, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.HEATMAP, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.getOTOperation() - ); - const userMap = y.getMap("users"); - if (userMap.get(y.clientID) !== operation.getJabberId()) { - const userList = y.getMap("userList"); - var color = Util.getColor( - userList.get(operation.getJabberId()).globalId - ); - refreshTraceAwareness(color); - } - processNodeResizeOperation(operation); - } - }; - - /** - * Callback for a remote Node Delete Operation - * @param {operations.ot.NodeDeleteOperation} operation - */ - this.remoteNodeDeleteCallback = function (operation) { - if ( - operation instanceof NodeDeleteOperation && - operation.getEntityId() === that.getEntityId() - ) { - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.ATTRIBUTE, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.HEATMAP, - operation.getOTOperation() - ); - processNodeDeleteOperation(); - HistoryManagerInstance.clean(operation.getEntityId()); - } - }; - - this.init = function () { - //Define Node Rightclick Menu - $.contextMenu({ - selector: "#" + id, - zIndex: AbstractEntity.CONTEXT_MENU_Z_INDEX, - build: function ($trigger, e) { - var menuItems; - var EntityManager = EntityManagerInstance; - - $(e.target).offset(); - that.getCanvas().get$node().offset(); - - if ( - _canvas.getSelectedEntity() === null || - _canvas.getSelectedEntity() === that - ) { - menuItems = lodash.extend(_contextMenuItemCallback(), { - connectTo: EntityManager.generateConnectToMenu(that), - sepMove: "---------", - moveToForeground: { - name: "Move to Foreground", - callback: function (/*key, opt*/) { - that.propagateNodeMoveZOperation( - new NodeMoveZOperation( - that.getEntityId(), - ++AbstractEntity.maxZIndex - _zIndex - ) - ); - }, - }, - moveToBackground: { - name: "Move to Background", - callback: function (/*key, opt*/) { - that.propagateNodeMoveZOperation( - new NodeMoveZOperation( - that.getEntityId(), - --AbstractEntity.minZIndex - _zIndex - ) - ); - }, - }, - sepDelete: "---------", - delete: { - name: "Delete", - callback: function (/*key, opt*/) { - that.triggerDeletion(); - }, - }, - quit: { - name: " ", - disabled: true, - }, - }); - - return { - items: menuItems, - events: { - show: function (/*opt*/) { - _canvas.select(that); - }, - }, - }; - } else { - _canvas.select(null); - return false; - } - }, - }); - }; - - /** - * Triggers jsPlumb's repaint function and adjusts the angle of the edge labels - */ - - /** - * Anchor options for new connections - * @type {object} - */ - var _anchorOptions = AnchorLocations.AutoDefault; - - /** - * Get options for new connections - * @returns {Object} - */ - this.getAnchorOptions = function () { - return _anchorOptions; - }; - - /** - * Send NodeDeleteOperation for node - */ - this.triggerDeletion = function (historyFlag) { - var edgeId, - edges = this.getEdges(), - edge; - _canvas.select(null); - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - edge.triggerDeletion(); - } - } - var operation = new NodeDeleteOperation( - id, - that.getType(), - _appearance.left, - _appearance.top, - _appearance.width, - _appearance.height, - _zIndex, - _appearance.containment, - that.toJSON() - ); - if (_ymap) { - propagateNodeDeleteOperation(operation); - const nodesMap = y.getMap("nodes"); - nodesMap.delete(that.getEntityId()); - } else { - propagateNodeDeleteOperation(operation); - } - if (!historyFlag) HistoryManagerInstance.add(operation); - }; - - //noinspection JSUnusedGlobalSymbols - /** - * Get callback to generate list of context menu items - * @returns {object} - */ - this.getContextMenuItemCallback = function () { - return _contextMenuItemCallback; - }; - - /** - * Set callback to generate list of context menu items - * @param {function} contextMenuItemCallback - */ - this.setContextMenuItemCallback = function (contextMenuItemCallback) { - if (typeof contextMenuItemCallback === "function") { - _contextMenuItemCallback = contextMenuItemCallback; - } - }; - - /** - * Get node appearance - * @returns {{left: number, top: number, width: number, height: number}} - */ - this.getAppearance = function () { - return _appearance; - }; - - /** - * Get position of node on z-axis - * @return {number} - */ - this.getZIndex = function () { - return _zIndex; - }; - - this.refreshTraceAwareness = function (color) { - refreshTraceAwareness(color); - }; - - /** - * Adds node to canvas - * @param {canvas_widget.AbstractCanvas} canvas - */ - this.addToCanvas = function (canvas) { - if (!canvas) throw new Error("Canvas is null"); - _canvas = canvas; - canvas.get$canvas().append(_$awarenessTrace); - canvas.get$canvas().append(this._$node); - }; - - /** - * Get associated canvas - * @returns {canvas_widget.AbstractCanvas} - */ - this.getCanvas = function () { - return _canvas; - }; - - /** - * Removes node from canvas - */ - this.removeFromCanvas = function () { - this._$node.remove(); - //destroy the context menu - $.contextMenu("destroy", "#" + that.getEntityId()); - _canvas = null; - _$awarenessTrace.remove(); - if (this.hasOwnProperty("unregisterCallbacks")) - this.unregisterCallbacks(); - }; - - /** - * Add attribute to node - * @param {canvas_widget.AbstractAttribute} attribute - */ - this.addAttribute = function (attribute) { - var id = attribute.getEntityId(); - if (!_attributes.hasOwnProperty(id)) { - _attributes[id] = attribute; - } - }; - - /** - * Get attribute by id - * @param {String} id Attribute's entity id - * @returns {canvas_widget.AbstractAttribute} - */ - this.getAttribute = function (id) { - if (_attributes.hasOwnProperty(id)) { - return _attributes[id]; - } - return null; - }; - - /** - * Delete attribute by id - * @param {String} id Attribute's entity id - */ - this.deleteAttribute = function (id) { - if (_attributes.hasOwnProperty(id)) { - delete _attributes[id]; - } - }; - - /** - * Set node's attributes - * @param {Object} attributes - */ - this.setAttributes = function (attributes) { - _attributes = attributes; - }; - - /** - * Get node's attributes - * @returns {Object} - */ - this.getAttributes = function () { - return _attributes; - }; - - /** - * Set edge label - * @param {canvas_widget.SingleValueAttribute} label - */ - this.setLabel = function (label) { - _label = label; - }; - - /** - * Get edge label - * @returns {canvas_widget.SingleValueAttribute} - */ - this.getLabel = function () { - return _label; - }; - - /** - * Get edge type - * @returns {string} - */ - this.getType = function () { - return _type; - }; - - /** - * Get edge type - * @returns {boolean} - */ - this.getContainment = function () { - return _containment; - }; - - /** - * Get jQuery object of DOM node representing the node - * @returns {jQuery} - * @private - */ - this._get$node = function () { - return this._$node; - }; - - /** - * Apply position and dimension attributes to the node - * @private - */ - this._draw = function () { - //noinspection JSAccessibilityCheck - _$awarenessTrace.css({ - left: _appearance.left + _appearance.width / 2, - top: _appearance.top + _appearance.height / 2, - width: _appearance.width * 1.2, - height: _appearance.height * 1.2, - zIndex: _zIndex - 1, - }); - this._$node.css({ - left: _appearance.left, - top: _appearance.top, - width: _appearance.width, - height: _appearance.height, - zIndex: _zIndex, - }); - }; - - /** - * Move the node - * @param {number} offsetX Offset in x-direction - * @param {number} offsetY Offset in y-direction - * @param {number} offsetZ Offset in z-direction - */ - this.move = function (offsetX, offsetY, offsetZ) { - const x = _appearance.left + offsetX; - const y = _appearance.top + offsetY; - if ( - x < 0 || - y < 0 || - x > _canvas.width - _appearance.width || - y > _canvas.height - _appearance.height - ) { - // reset the position - _$node.css({ - left: _appearance.left, - top: _appearance.top, - }); - console.error("Node cannot be moved outside of canvas"); - if (_ymap) { - window.y.transact(() => { - _ymap.set("left", _appearance.left); - _ymap.set("top", _appearance.top); - _ymap.set("zIndex", _zIndex); - }); - } - } else { - if (_ymap) { - window.y.transact(() => { - _ymap.set("left", (_appearance.left += offsetX)); - _ymap.set("top", (_appearance.top += offsetY)); - _ymap.set("zIndex", _zIndex); - }); - } - } - this._draw(); - this.repaint(); - }; - - this.moveAbs = function (left, top, zIndex) { - if (left < 0 || top < 0) { - console.error("Node cannot be moved outside of canvas"); - } - if ( - left > _canvas.width - _appearance.width || - top > _canvas.height - _appearance.height - ) { - console.error("Node cannot be moved outside of canvas"); - } - _appearance.left = left; - _appearance.top = top; - - if (zIndex) _zIndex = zIndex; - - if (_ymap) { - y.transact(() => { - _ymap.set("left", _appearance.left); - _ymap.set("top", _appearance.top); - if (zIndex) _ymap.set("zIndex", _zIndex); - }); - } - this._draw(); - this.repaint(); - }; - - /** - * Resize the node - * @param {number} offsetX Offset in x-direction - * @param {number} offsetY Offset in y-direction - */ - this.resize = function (offsetX, offsetY) { - _appearance.width += offsetX; - _appearance.height += offsetY; - if (_ymap) { - y.transact(() => { - _ymap.set("width", _appearance.width); - _ymap.set("height", _appearance.height); - }); - } - this._draw(); - this.repaint(); - }; - - /** - * Add ingoing edge - * @param {canvas_widget.AbstractEdge} edge - */ - this.addIngoingEdge = function (edge) { - var id = edge.getEntityId(); - var source = edge.getSource(); - var sourceEntityId = source.getEntityId(); - if (!_ingoingEdges.hasOwnProperty(id)) { - _ingoingEdges[id] = edge; - if (!_ingoingNeighbors.hasOwnProperty(sourceEntityId)) { - _ingoingNeighbors[sourceEntityId] = source; - } - } - }; - - /** - * Add outgoing edge - * @param {canvas_widget.AbstractEdge} edge - */ - this.addOutgoingEdge = function (edge) { - var id = edge.getEntityId(); - var target = edge.getTarget(); - var targetEntityId = target?.getEntityId(); - if (!_outgoingEdges.hasOwnProperty(id)) { - _outgoingEdges[id] = edge; - if (!_outgoingNeighbors.hasOwnProperty(targetEntityId)) { - _outgoingNeighbors[targetEntityId] = target; - } - } - }; - - /** - * Delete ingoing edge - * @param {canvas_widget.AbstractEdge} edge - */ - this.deleteIngoingEdge = function (edge) { - var id = edge.getEntityId(); - var source = edge.getSource(); - var sourceEntityId = source.getEntityId(); - var isMultiEdge = false; - if (_ingoingEdges.hasOwnProperty(id)) { - delete _ingoingEdges[id]; - for (var edgeId in _ingoingEdges) { - if ( - _ingoingEdges.hasOwnProperty(edgeId) && - _ingoingEdges[edgeId].getSource().getEntityId() === sourceEntityId - ) { - isMultiEdge = true; - } - } - if (!isMultiEdge) { - delete _ingoingNeighbors[sourceEntityId]; - } - } - }; - - /** - * Delete outgoing edge - * @param {canvas_widget.AbstractEdge} edge - */ - this.deleteOutgoingEdge = function (edge) { - var id = edge.getEntityId(); - var target = edge.getTarget(); - var targetEntityId = target?.getEntityId(); - var isMultiEdge = false; - if (_outgoingEdges.hasOwnProperty(id)) { - delete _outgoingEdges[id]; - for (var edgeId in _outgoingEdges) { - if ( - _outgoingEdges.hasOwnProperty(edgeId) && - _outgoingEdges[edgeId].getTarget().getEntityId() === targetEntityId - ) { - isMultiEdge = true; - } - } - if (!isMultiEdge) { - delete _outgoingNeighbors[targetEntityId]; - } - } - }; - - //noinspection JSUnusedGlobalSymbols - /** - * Get ingoing edges - * @returns {Object} - */ - this.getIngoingEdges = function () { - return _ingoingEdges; - }; - - /** - * Get outgoing edges - * @returns {Object} - */ - this.getOutgoingEdges = function () { - return _outgoingEdges; - }; - - /** - * Get all ingoing and outgoing edges - * @returns {Array} - */ - this.getEdges = function () { - return Util.union(_ingoingEdges, _outgoingEdges); - }; - - //noinspection JSUnusedGlobalSymbols - /** - * Get neighbors with an edge to the node - * @returns {Object} - */ - this.getIngoingNeighbors = function () { - return _ingoingNeighbors; - }; - - //noinspection JSUnusedGlobalSymbols - /** - * Get neighbors with an edge from the node - * @returns {Object} - */ - this.getOutgoingNeighbors = function () { - return _outgoingNeighbors; - }; - - //noinspection JSUnusedGlobalSymbols - /** - * Get neighbors with an edge to or from the node - * @returns {Object} - */ - this.getNeighbors = function () { - return Util.union(_ingoingNeighbors, _outgoingNeighbors); - }; - - /** - * Lowlight the node - */ - this.lowlight = function () { - this._$node.addClass("lowlighted"); - }; - - /** - * Unlowlight the node - */ - this.unlowlight = function () { - this._$node.removeClass("lowlighted"); - }; - - /** - * Select the node - */ - this.select = function () { - this.unhighlight(); - this._$node.addClass("selected"); - Util.delay(100).then(function () { - lodash.each(EntityManagerInstance.getEdges(), function (e) { - e.setZIndex(); - }); - }); - }; - - /** - * Unselect the node - */ - this.unselect = function () { - //this.highlight(_highlightColor,_highlightUsername); - this._$node.removeClass("selected"); - //trigger save when unselecting an entity - EntityManagerInstance.storeDataYjs(); - - Util.delay(100).then(function () { - lodash.each(EntityManagerInstance.getEdges(), function (e) { - e.setZIndex(); - }); - }); - }; - - /** - * Highlight the node by assigning it the passed color and label it with the passed username - * @param {String} color - * @param {String} username - */ - this.highlight = function (color, username) { - if (color && username) { - this._$node.css({ border: "2px solid " + color }); - this._$node.append( - $("
          ") - .addClass("user_highlight") - .css("color", color) - .text(username) - ); - Util.delay(100).then(function () { - lodash.each(EntityManagerInstance.getEdges(), function (e) { - e.setZIndex(); - }); - }); - } - }; - - /** - * Unhighlight the node - */ - this.unhighlight = function () { - this._$node.css({ border: "" }); - this._$node.find(".user_highlight").remove(); - Util.delay(100).then(function () { - lodash.each(EntityManagerInstance.getEdges(), function (e) { - e.setZIndex(); - }); - }); - }; - - /** - * Remove the node - */ - this.remove = function () { - clearInterval(_awarenessTimer); - this.removeFromCanvas(); - jsPlumbInstance.removeAllEndpoints(_$node.get(0)); - jsPlumbInstance.unmanage(_$node.get(0)); - EntityManagerInstance.deleteNode(this.getEntityId()); - }; - - /** - * Get JSON representation of the node - * @returns {Object} - * @private - */ - this._toJSON = function () { - var attr = {}; - lodash.forEach(this.getAttributes(), function (val, key) { - attr[key] = val.toJSON(); - }); - //noinspection JSAccessibilityCheck - return { - label: _label.toJSON(), - left: _appearance.left, - top: _appearance.top, - width: _appearance.width, - height: _appearance.height, - zIndex: _zIndex, - type: _type, - attributes: attr, - }; - }; - - this.addGhostEdge = function (ghostEdge) { - _relatedGhostEdges.push(ghostEdge); - }; - - /** - * Bind events for move tool - */ - this.bindMoveToolEvents = () => { - this.enableDraggable(); - var originalPos = { - left: 0, - top: 0, - }; - - var $sizePreview = $('
          ').hide(); - - this.makeResizable(that, _canvas, $sizePreview, id); - - this._$node - //Enable Node Rightclick menu - .contextMenu(true) - .find("input") - .prop("disabled", false) - .css("pointerEvents", ""); - - this.jsPlumbManagedElement = jsPlumbInstance.manage(this._$node.get(0)); - - jsPlumbInstance.bind(EVENT_DRAG_START, (params) => { - if (params.el.id !== this._$node.attr("id")) return true; - - originalPos.top = params.el.offsetTop; - originalPos.left = params.el.offsetLeft; - - _canvas.hideGuidanceBox(); - _$node.css({ opacity: 0.5 }); - - return true; - }); - - jsPlumbInstance.bind(EVENT_DRAG_STOP, (params) => { - if (params.el.id !== this._$node.attr("id")) return true; - - _$node.css({ opacity: "" }); - _canvas.bindMoveToolEvents(); - var offsetX = Math.round(params.el.offsetLeft - originalPos.left); - var offsetY = Math.round(params.el.offsetTop - originalPos.top); - // if offset is 0, no need to send the operation - if (offsetX === 0 && offsetY === 0) return; - // if offset bigger than canvas size, no need to send the operation - if ( - params.el.offsetLeft < 0 || - params.el.offsetTop < 0 || - params.el.offsetLeft > _canvas.width || - params.el.offsetTop > _canvas.height - ) { - console.error(" offset bigger than canvas size"); - return; - } - - var operation = new NodeMoveOperation( - that.getEntityId(), - offsetX, - offsetY - ); - that.propagateNodeMoveOperation(operation); - - //Avoid node selection on drag stop - _canvas.showGuidanceBox(); - }); - - // view_only is used by the CAE and allows to show a model in the Canvas which is not editable - // therefore, the nodes should not be draggable and their context menu should be disabled - const widgetConfigMap = y.getMap("widgetConfig"); - var viewOnly = widgetConfigMap.get("view_only"); - if (viewOnly) { - this.disableDraggable(); - _$node.on("click").contextMenu(false); - } - }; - - /** - * Unbind events for move tool - */ - this.unbindMoveToolEvents = () => { - //Disable Node Selection - // called for e.g. if we want to draw an edge - this._$node - .off("click") - .contextMenu(false) - .find("input") - .prop("disabled", true) - .css("pointerEvents", "none"); - - //Disable Node Dragging - this.disableDraggable(); - }; - - /** - * Bind source node events for edge tool - */ - this.makeSource = () => { - _$node.addClass("source"); - this.endPoint = window.jsPlumbInstance.addEndpoint(this._$node.get(0), { - connectorPaintStyle: { fill: "black", strokeWidth: 4 }, - source: true, - endpoint: { - type: "Rectangle", - options: { - width: _$node.width() + 50, - height: _$node.height() + 50, - }, - }, - paintStyle: { fill: "transparent" }, - anchor: AnchorLocations.Center, - deleteOnEmpty: true, - //maxConnections:1, - uniqueEndpoint: false, - deleteEndpointsOnDetach: true, - onMaxConnections: function (info /*, originalEvent*/) { - console.log( - "element is ", - info.element, - "maxConnections is", - info.maxConnections - ); - }, - }); - }; - - /** - * Bind target node events for edge tool - */ - this.makeTarget = () => { - _$node.addClass("target"); - this.endPoint = window.jsPlumbInstance.addEndpoint(this._$node.get(0), { - target: true, - endpoint: { - type: "Rectangle", - options: { - width: _$node.width() + 50, - height: _$node.height() + 50, - }, - }, - paintStyle: { fill: "transparent" }, - anchor: AnchorLocations.Center, - uniqueEndpoint: false, - //maxConnections:1, - deleteOnEmpty: true, - onMaxConnections: function (info /*, originalEvent*/) { - console.log( - "user tried to drop connection", - info.connection, - "on element", - info.element, - "with max connections", - info.maxConnections - ); - }, - }); - }; - - /** - * Unbind events for edge tool - */ - this.unbindEdgeToolEvents = function () { - try { - _$node.removeClass("source target"); - jsPlumbInstance.getEndpoints(_$node.get(0)).forEach((endpoint) => { - // We need to remove the endpoint that was created to enable node connection by dragging - // since we are not using the edge tool anymore - if (endpoint.connections.length === 0) { - jsPlumbInstance.deleteEndpoint(endpoint); - } - }); - } catch (error) { - console.error(error); - } - }; - - that.init(); - - this._registerYMap = function () { - _ymap.observe(function (event) { - const array = Array.from(event.changes.keys.entries()); - array.forEach(([key, change]) => { - if (event.value && event.value.historyFlag) { - var operation; - var data = event.value; - const userMap = y.getMap("users"); - var jabberId = userMap.get(yUserId); - switch (key) { - case NodeMoveOperation.TYPE: { - operation = new NodeMoveOperation( - data.id, - data.offsetX, - data.offsetY, - jabberId - ); - remoteNodeMoveCallback(operation); - break; - } - case NodeMoveZOperation.TYPE: { - operation = new NodeMoveZOperation( - data.id, - data.offsetZ, - jabberId - ); - remoteNodeMoveZCallback(operation); - break; - } - case NodeResizeOperation.TYPE: { - operation = new NodeResizeOperation( - data.id, - data.offsetX, - data.offsetY, - jabberId - ); - remoteNodeResizeCallback(operation); - break; - } - } - } - }); - }); - }; - - jsPlumbInstance.manage(this._$node.get(0)); - EntityManagerInstance.storeDataYjs(); - } - nodeSelector; - jsPlumbManagedElement; - endPoint; - - repaint() { - window.jsPlumbInstance.repaint(this._$node.get(0)); - - lodash.each(EntityManagerInstance.getEdges(), function (e) { - e.setZIndex(); - }); - } - - enableDraggable() { - jsPlumbInstance.setDraggable(this._$node.get(0), true); - } - - disableDraggable() { - jsPlumbInstance.setDraggable(this._$node.get(0), false); - } - - makeResizable(that, _canvas, $sizePreview, id) { - const initialSize = { - width: that._$node.width(), - height: that._$node.height(), - }; - interact(that.nodeSelector) - .resizable({ - // resize from all edges and corners - edges: { right: ".bi", bottom: ".bi" }, - square: true, - listeners: { - move(event) { - that.disableDraggable(); - let { x, y } = event.target.dataset; - - x = (parseFloat(x) || 0) + event.deltaRect.left; - y = (parseFloat(y) || 0) + event.deltaRect.top; - - Object.assign(event.target.style, { - width: `${event.rect.width}px`, - height: `${event.rect.height}px`, - transform: `translate(${x}px, ${y}px)`, - }); - - Object.assign(event.target.dataset, { x, y }); - - event.rect.width = Math.max(50, event.rect.width); - event.rect.height = Math.max(50, event.rect.height); - - $sizePreview.text( - Math.round(event.rect.width) + - "\u00D7" + - Math.round(event.rect.height) - ); - // that.repaint(); - }, - }, - modifiers: [ - // keep the edges inside the parent - interact.modifiers.restrictEdges({ - outer: "parent", - }), - // minimum size - interact.modifiers.restrictSize({ - min: { width: 40, height: 40 }, - }), - ], - inertia: { enabled: false }, - }) - .on(["resizestart"], (event) => { - // add resizing class - that._$node.addClass("resizing"); - that.disableDraggable(); - _canvas.hideGuidanceBox(); - $sizePreview.show(); - that._$node.css({ opacity: 0.5 }); - that._$node.append($sizePreview); - initialSize.width = that._$node.width(); - initialSize.height = that._$node.height(); - _canvas.unbindMoveToolEvents(); - }) - .on(["resizeend"], (event) => { - // remove resizing class - that._$node.removeClass("resizing"); - that.enableDraggable(); - const offsetX = event.rect.width - initialSize.width; - const offsetY = event.rect.height - initialSize.height; - $sizePreview.hide(); - that._$node.css({ opacity: "" }); - that.repaint(); - var operation = new NodeResizeOperation(id, offsetX, offsetY); - that.propagateNodeResizeOperation(operation); - _canvas.bindMoveToolEvents(); - }) - .draggable(); - } - - disableResizable() { - interact(this.nodeSelector).unset(); - } - - /** - * Apply position and dimension attributes to the node - */ - draw() { - return this._draw(); - } - /** - * Get jQuery object of DOM node representing the node - * @returns {jQuery} - */ - get$node() { - return this._get$node(); - } - /** - * Get JSON representation of the node - * @returns {{label: Object, left: number, top: number, width: number, height: number, type: string, attributes: Object}} - */ - toJSON() { - return this._toJSON(); - } - /** - * hide the node and all associated edges - */ - hide() { - this.get$node().hide(); - window.jsPlumbInstance.hide(this.get$node()); - } - /** - * show the node and all associated edges - */ - show() { - this.get$node().show(); - window.jsPlumbInstance.show(this.get$node()[0]); - window.jsPlumbInstance.repaint(this.get$node()[0]); - } - registerYMap() { - this._registerYMap(); - } -} - -/** - * Abstract Class Node - * @class canvas_widget.EnumNode - * @extends canvas_widget.AbstractNode - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {number} zIndex Position of node on z-axis - */ -class EnumNode extends AbstractNode { - static TYPE = "Enumeration"; - static DEFAULT_WIDTH = 150; - static DEFAULT_HEIGHT = 100; - constructor(id, left, top, width, height, zIndex, json) { - super(id, EnumNode.TYPE, left, top, width, height, zIndex, json); - var that = this; - - /** - * jQuery object of node template - * @type {jQuery} - * @private - */ - var _$template = $(lodash.template(enumNodeHtml)({ type: that.getType() })); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = AbstractNode.prototype.get$node - .call(this) - .append(_$template) - .addClass("class"); - - /** - * jQuery object of DOM node representing the attributes - * @type {jQuery} - * @private - */ - var _$attributeNode = _$node.find(".attributes"); - - /** - * Attributes of node - * @type {Object} - * @private - */ - var _attributes = this.getAttributes(); - - /** - * Get JSON representation of the node - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractNode.prototype.toJSON.call(this); - json.type = EnumNode.TYPE; - return json; - }; - var attr = new SingleValueListAttribute("[attributes]", "Attributes", this); - this.addAttribute(attr); - - this.registerYMap = function () { - AbstractNode.prototype.registerYMap.call(this); - that.getLabel().getValue().registerYType(); - attr.registerYMap(); - }; - this.unregisterCallbacks = function () { - that.getAttribute("[attributes]").unregisterCallbacks(); - }; - this.registerYTextAttributes = function (map) { - map.get(that.getLabel().getValue().getEntityId()).then(function (ytext) { - that.getLabel().getValue().registerYType(ytext); - }); - }; - - _$node.find(".label").append(this.getLabel().get$node()); - - for (var attributeKey in _attributes) { - if (_attributes.hasOwnProperty(attributeKey)) { - _$attributeNode.append(_attributes[attributeKey].get$node()); - } - } - } -} - -/** - * Abstract Class Node - * @class canvas_widget.NodeShapeNode - * @extends canvas_widget.AbstractNode - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {number} zIndex Position of node on z-axis - * @param {boolean} containment containment - */ -class NodeShapeNode extends AbstractNode { - static TYPE = "Node Shape"; - static DEFAULT_WIDTH = 150; - static DEFAULT_HEIGHT = 150; - constructor(id, left, top, width, height, zIndex, containment, json) { - super( - id, - "Node Shape", - left, - top, - width, - height, - zIndex, - containment, - json - ); - var that = this; - - /** - * jQuery object of node template - * @type {jQuery} - * @private - */ - var _$template = $(lodash.template(nodeShapeNodeHtml)({ type: that.getType() })); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = AbstractNode.prototype.get$node - .call(this) - .append(_$template) - .addClass("class"); - - /** - * jQuery object of DOM node representing the attributes - * @type {jQuery} - * @private - */ - var _$attributeNode = _$node.find(".attributes"); - - /** - * Attributes of node - * @type {Object} - * @private - */ - var _attributes = this.getAttributes(); - - /** - * Get JSON representation of the node - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractNode.prototype.toJSON.call(this); - json.type = NodeShapeNode.TYPE; - return json; - }; - - var attrShapeSelect = new SingleSelectionAttribute( - this.getEntityId() + "[shape]", - "Shape", - this, - { - circle: "Circle", - diamond: "Diamond", - rectangle: "Rectangle", - rounded_rectangle: "Rounded Rectangle", - triangle: "Triangle", - } - ); - var attrWidth = new IntegerAttribute( - this.getEntityId() + "[defaultWidth]", - "Default Width", - this - ); - var attrHeight = new IntegerAttribute( - this.getEntityId() + "[defaultHeight]", - "Default Height", - this - ); - var attrColor = new SingleColorValueAttribute( - this.getEntityId() + "[color]", - "Color", - this - ); - var attrContaintment = new BooleanAttribute( - this.getEntityId() + "[containment]", - "Containment", - this - ); - var attrCustomShape = new SingleMultiLineValueAttribute( - this.getEntityId() + "[customShape]", - "Custom Shape", - this - ); - var attrAnchors = new SingleValueAttribute( - this.getEntityId() + "[customAnchors]", - "Custom Anchors", - this - ); - - this.addAttribute(attrShapeSelect); - this.addAttribute(attrColor); - this.addAttribute(attrWidth); - this.addAttribute(attrHeight); - this.addAttribute(attrContaintment); - this.addAttribute(attrCustomShape); - this.addAttribute(attrAnchors); - - _$node.find(".label").append(this.getLabel().get$node()); - - for (var attributeKey in _attributes) { - if (_attributes.hasOwnProperty(attributeKey)) { - _$attributeNode.append(_attributes[attributeKey].get$node()); - } - } - - this.registerYMap = function () { - AbstractNode.prototype.registerYMap.call(this); - attrShapeSelect.getValue().registerYType(); - attrWidth.getValue().registerYType(); - attrHeight.getValue().registerYType(); - attrContaintment.getValue().registerYType(); - that.getLabel().getValue().registerYType(); - attrColor.getValue().registerYType(); - attrAnchors.getValue().registerYType(); - attrCustomShape.getValue().registerYType(); - }; - } -} - -/** - * EntityManager - * @class canvas_widget.EntityManager - * @memberof canvas_widget - * @constructor - */ -let EntityManager$1 = class EntityManager { - y = null; - setSharedDocument(y) { - this.y = y; - } - _nodes; - _edges; - - constructor() { - /** - * the view id indicates if the EntityManager should use View types for modeling or node types - * @type {string} - * @private - */ - var _viewId = undefined; - - /** - * Model attributes node - * @type {canvas_widget.ModelAttributesNode} - * @private - */ - var _modelAttributesNode = null; - /** - * Nodes of the graph - * @type {{}} - * @private - */ - var _nodes = {}; - this._nodes = _nodes; - /** - * Edges of the graph - * @type {{}} - * @private - */ - var _edges = {}; - this._edges = _edges; - - var metamodel = null; - - var guidancemodel = null; - - //noinspection JSUnusedGlobalSymbols - return { - /** - * Create a new node - * @memberof canvas_widget.EntityManager# - * @param {string} type Type of node - * @param {string} id Entity identifier of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {number} zIndex Position of node on z-axis - * @param {object} json the json representation - * @returns {canvas_widget.AbstractNode} - */ - createNode: function ( - type, - id, - left, - top, - width, - height, - zIndex, - containment, - json, - y - ) { - var node; - AbstractEntity.maxZIndex = Math.max(AbstractEntity.maxZIndex, zIndex); - AbstractEntity.minZIndex = Math.min(AbstractEntity.minZIndex, zIndex); - - if (_viewId && viewNodeTypes.hasOwnProperty(type)) { - node = viewNodeTypes[type]( - id, - left, - top, - width, - height, - zIndex, - containment, - json, - y - ); - } else if (nodeTypes.hasOwnProperty(type)) { - node = new nodeTypes[type]( - id, - left, - top, - width, - height, - zIndex, - containment, - json, - y - ); - } - _nodes[id] = node; - - EntityManagerInstance.storeDataYjs(); - return node; - }, - findObjectNodeByLabel(searchLabel) { - const re = new RegExp(searchLabel, "gi"); - for (const [id, node] of Object.entries(_nodes)) { - const currentNode = y.getMap("nodes").get(id).toJSON(); - for (const [key, property] of Object.entries(currentNode)) { - if (key.match(id)) { - if (property.match(re)) { - return node; - } - } - } - } - return null; - }, - /** - * Create model Attributes node - * @returns {canvas_widget.ModelAttributesNode} - */ - createModelAttributesNode: function (y) { - if (_modelAttributesNode === null) { - if (metamodel) - _modelAttributesNode = new ModelAttributesNode( - "modelAttributes", - metamodel.attributes, - y - ); - else - _modelAttributesNode = new ModelAttributesNode( - "modelAttributes", - null, - y - ); - return _modelAttributesNode; - } - return _modelAttributesNode; - }, - /** - * Find nodeby attr - * @memberof attribute_widget.EntityManager# - * @param {string} name Entity name - * @returns {canvas_widget.AbstractNode} - */ - findNodeByAttribute: function (attr, name) { - for (const key in _nodes) { - const node = _nodes[key]; - if (node.getAttribute(attr) === name) { - return node; - } - } - }, - - /** - * Find node by id - * @memberof canvas_widget.EntityManager# - * @param {string} id Entity id - * @returns {canvas_widget.AbstractNode} - */ - findNode: function (id) { - if (_nodes.hasOwnProperty(id)) { - return _nodes[id]; - } - return null; - }, - /** - * Find node or edge by id - * @memberof attribute_widget.EntityManager# - * @param {string} id Entity id - * @returns {*} - */ - find: function (id) { - return this.findNode(id) || this.findEdge(id); - }, - /** - * Delete node by id - * @memberof canvas_widget.EntityManager# - * @param {string} id Entity id - */ - deleteNode: function (id) { - if (_nodes.hasOwnProperty(id)) { - delete _nodes[id]; - } - EntityManagerInstance.storeDataYjs(); - }, - /** - * Get all nodes - * @memberof canvas_widget.EntityManager# - * @returns {object} - */ - getNodes: function () { - return _nodes; - }, - /** - * Get nodes by type - * @memberof canvas_widget.EntityManager# - * @param {string|string[]} type Entity type - * @returns {object} - */ - getNodesByType: function (type) { - var nodeId, - node, - nodesByType = {}; - - if (typeof type === "string") { - type = [type]; - } - - for (nodeId in _nodes) { - if (_nodes.hasOwnProperty(nodeId)) { - node = _nodes[nodeId]; - if (type.indexOf(node.getType()) !== -1) { - nodesByType[nodeId] = node; - } - } - } - return nodesByType; - }, - /** - * Create a new edge - * @memberof canvas_widget.EntityManager# - * @param {string} type Type of edge - * @param {string} id Entity identifier of edge - * @param {canvas_widget.AbstractNode} source Source node - * @param {canvas_widget.AbstractNode} target Target node - * @returns {canvas_widget.AbstractEdge} - */ - //TODO: switch id and type - createEdge: function (type, id, source, target) { - var edge; - - if (_viewId && viewEdgeTypes.hasOwnProperty(type)) { - edge = viewEdgeTypes[type](id, source, target); - } else if (edgeTypes.hasOwnProperty(type)) { - edge = new edgeTypes[type](id, source, target); - } else { - return undefined; - } - source.addOutgoingEdge(edge); - target?.addIngoingEdge(edge); - _edges[id] = edge; - EntityManagerInstance.storeDataYjs(); - return edge; - }, - /** - * Find edge by id - * @memberof canvas_widget.EntityManager# - * @param {string} id Entity id - * @returns {*} - */ - findEdge: function (id) { - if (_edges.hasOwnProperty(id)) { - return _edges[id]; - } - return null; - }, - /** - * Delete edge by id - * @memberof canvas_widget.EntityManager# - * @param {string} id Entity id - */ - deleteEdge: function (id) { - if (_edges.hasOwnProperty(id)) { - delete _edges[id]; - } - EntityManagerInstance.storeDataYjs(); - }, - /** - * Get all edges - * @memberof canvas_widget.EntityManager# - * @returns {object} - */ - getEdges: function () { - return _edges; - }, - /** - * Get edges by type - * @memberof canvas_widget.EntityManager# - * @param {string} type Entity type - * @returns {object} - */ - getEdgesByType: function (type) { - var edgeId, - edge, - edgesByType = {}; - - for (edgeId in _edges) { - if (_edges.hasOwnProperty(edgeId)) { - edge = _edges[edgeId]; - if (edge.getType() === type) { - edgesByType[edgeId] = edge; - } - } - } - return edgesByType; - }, - /** - * Get JSON representation of whole graph - * @memberof canvas_widget.EntityManager# - * @returns {object} - */ - graphToJSON: function () { - var attributesJSON; - var nodesJSON = {}; - var edgesJSON = {}; - attributesJSON = _modelAttributesNode - ? _modelAttributesNode.toJSON() - : {}; - lodash.forEach(_nodes, function (val, key) { - nodesJSON[key] = val.toJSON(); - }); - lodash.forEach(_edges, function (val, key) { - edgesJSON[key] = val.toJSON(); - }); - return { - attributes: attributesJSON, - nodes: nodesJSON, - edges: edgesJSON, - }; - }, - /** - * Create model attributes node by its JSON representation - * @memberof canvas_widget.EntityManager# - * @param {object} json JSON representation - * @returns {canvas_widget.AbstractNode} - */ - createModelAttributesNodeFromJSON: function (json) { - var node = this.createModelAttributesNode(); - if (node) { - node.getLabel().getValue().setValue(json.label.value.value); - for (var attrId in json.attributes) { - if (json.attributes.hasOwnProperty(attrId)) { - var attr = node.getAttribute(attrId); - if (attr) { - attr.setValueFromJSON(json.attributes[attrId]); - } - } - } - } - return node; - }, - /** - * Create a new node by its JSON representation - * @memberof canvas_widget.EntityManager# - * @param {string} type Type of node - * @param {string} id Entity identifier of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {object} json JSON representation - * @param {number} zIndex Position of node on z-axis - * @returns {canvas_widget.AbstractNode} - */ - createNodeFromJSON: function ( - type, - id, - left, - top, - width, - height, - zIndex, - containment, - json, - y - ) { - var node = this.createNode( - type, - id, - left, - top, - width, - height, - zIndex, - containment, - json, - y - ); - if (node) { - node.getLabel().getValue().setValue(json.label.value.value); - for (var attrId in json.attributes) { - if (json.attributes.hasOwnProperty(attrId)) { - var attr = node.getAttribute(attrId); - if (attr) { - attr.setValueFromJSON(json.attributes[attrId]); - } else { - var newId = attrId.replace(/[^\[\]]*/, id); - attr = node.getAttribute(newId); - if (attr) { - attr.setValueFromJSON(json.attributes[attrId]); - } - } - } - } - } - return node; - }, - /** - * Create a new node by its JSON representation - * @memberof canvas_widget.EntityManager# - * @param {string} type Type of edge - * @param {string} id Entity identifier of edge - * @param {canvas_widget.AbstractNode} source Source node entity id - * @param {canvas_widget.AbstractNode} target Target node entity id - * @param {object} json JSON representation - * @returns {canvas_widget.AbstractEdge} - */ - createEdgeFromJSON: function (type, id, source, target, json) { - const sourceNode = this.findNode(source); - const targetNode = this.findNode(target); - var edge = this.createEdge(type, id, sourceNode, targetNode); - if (edge) { - edge.getLabel().getValue().setValue(json.label.value.value); - for (var attrId in json.attributes) { - if (json.attributes.hasOwnProperty(attrId)) { - var attr = edge.getAttribute(attrId); - if (attr) { - attr.setValueFromJSON(json.attributes[attrId]); - } - } - } - } - return edge; - }, - /** - * Generate the 'Add node..' context menu options - * @param canvas Canvas to add node to - * @param left Position of node on x-axis - * @param top Position of node on <-axis - * @returns {object} Menu items - */ - generateAddNodeMenu: function (canvas, left, top) { - function makeAddNodeCallback(nodeType, width, height, containment) { - return function () { - canvas.createNode( - nodeType, - left, - top, - width, - height, - 32000, - containment - ); - }; - } - var items = {}, - nodeType, - _nodeTypes; - - if (_viewId && _layer === CONFIG.LAYER.MODEL) { - _nodeTypes = viewNodeTypes; - } else { - _nodeTypes = nodeTypes; - } - - for (nodeType in _nodeTypes) { - if (_nodeTypes.hasOwnProperty(nodeType)) { - if ( - _layer === CONFIG.LAYER.META && - !_viewId && - (nodeType === "ViewObject" || nodeType === "ViewRelationship") - ) - continue; - if ( - _layer === CONFIG.LAYER.META && - _viewId && - (nodeType === "Object" || - nodeType === "Relationship" || - nodeType === "Enumeration" || - nodeType === "Abstract Class") - ) - continue; - - items[nodeType] = { - name: ".." + nodeType, - callback: makeAddNodeCallback( - nodeType, - _nodeTypes[nodeType].DEFAULT_WIDTH, - _nodeTypes[nodeType].DEFAULT_HEIGHT, - _nodeTypes[nodeType].CONTAINMENT - ), - }; - } - } - return items; - }, - /** - * generates the context menu for the show and hide operations on node types - * @returns {object} - */ - generateVisibilityNodeMenu: function (visibility) { - var _applyVisibilityCallback = function (nodeType, vis) { - return function () { - if (vis !== "show" && vis !== "hide") return; - - var nodes; - if (_viewId && _layer === CONFIG.LAYER.MODEL) { - nodes = that.getNodesByViewType(nodeType); - } else { - nodes = that.getNodesByType(nodeType); - } - for (var nKey in nodes) { - if (nodes.hasOwnProperty(nKey)) { - nodes[nKey][vis](); - } - } - if (vis === "hide") { - this.data("show" + nodeType + "Disabled", true); - } else { - this.data("show" + nodeType + "Disabled", false); - } - - return false; - }; - }; - - var that = this; - var items = {}, - nodeType, - _nodeTypes; - - if (_viewId && _layer === CONFIG.LAYER.MODEL) { - _nodeTypes = viewNodeTypes; - } else { - _nodeTypes = nodeTypes; - } - - for (nodeType in _nodeTypes) { - if (_nodeTypes.hasOwnProperty(nodeType)) { - if ( - _layer === CONFIG.LAYER.META && - !_viewId && - (nodeType === "ViewObject" || nodeType === "ViewRelationship") - ) - continue; - if ( - _layer === CONFIG.LAYER.META && - _viewId && - (nodeType === "Object" || - nodeType === "Relationship" || - nodeType === "Enumeration" || - nodeType === "Abstract Class") - ) - continue; - - items[visibility + nodeType] = { - name: ".." + nodeType, - callback: _applyVisibilityCallback(nodeType, visibility), - disabled: (function (nodeType) { - return function () { - if (visibility === "hide") - return this.data(visibility + nodeType + "Disabled"); - else return !this.data(visibility + nodeType + "Disabled"); - }; - })(nodeType), - }; - } - } - return items; - }, - /** - * generates a the context menu for the show and hide operations on edge types - * @returns {object} - */ - generateVisibilityEdgeMenu: function (visibility) { - function _applyVisibilityCallback(edgeType, vis) { - return function () { - if (vis !== "show" && vis !== "hide") return; - var edges; - if (_viewId && _layer === CONFIG.LAYER.MODEL) { - edges = that.getEdgesByViewType(edgeType); - } else { - edges = that.getEdgesByType(edgeType); - } - for (var eKey in edges) { - if (edges.hasOwnProperty(eKey)) { - edges[eKey][vis](); - } - } - if (vis === "hide") { - this.data("show" + edgeType + "Disabled", true); - } else { - this.data("show" + edgeType + "Disabled", false); - } - }; - } - var that = this; - var items = {}, - edgeType, - _edgeTypes; - - if (_viewId && _layer === CONFIG.LAYER.MODEL) { - _edgeTypes = viewEdgeTypes; - } else { - _edgeTypes = edgeTypes; - } - - for (edgeType in _edgeTypes) { - if (_edgeTypes.hasOwnProperty(edgeType)) { - items[visibility + edgeType] = { - name: ".." + edgeType, - callback: _applyVisibilityCallback(edgeType, visibility), - disabled: (function (edgeType) { - return function () { - if (visibility === "hide") - return this.data(visibility + edgeType + "Disabled"); - else return !this.data(visibility + edgeType + "Disabled"); - }; - })(edgeType), - }; - } - } - return items; - }, - /** - * Generate the 'Connect to..' context menu options for the passed node - * @param {canvas_widget.AbstractNode} node - */ - generateConnectToMenu: function (node) { - function makeTargetNodeCallback(connectionType, targetNodeId) { - return function (/*key, opt*/) { - node - .getCanvas() - .createEdge(connectionType, node.getEntityId(), targetNodeId); - }; - } - - var connectionType, - sourceNodeTypes, - targetNodeTypes, - targetNodeType, - connectionItems, - targetNodeTypeItems, - targetNodeItems, - i, - numOfRelations, - j, - numOfTargetTypes, - targetNodes, - targetNodeId, - targetNode, - targetAppearance, - sourceAppearance = node.getAppearance(); - - connectionItems = {}; - for (connectionType in relations) { - if (relations.hasOwnProperty(connectionType)) { - targetNodeTypeItems = {}; - for ( - i = 0, numOfRelations = relations[connectionType].length; - i < numOfRelations; - i++ - ) { - sourceNodeTypes = relations[connectionType][i].sourceTypes; - targetNodeTypes = relations[connectionType][i].targetTypes; - if ( - sourceNodeTypes.indexOf(node.getType()) !== -1 || - (_layer === CONFIG.LAYER.MODEL && - _viewId && - sourceNodeTypes.indexOf(node.getCurrentViewType()) !== -1) - ) { - for ( - j = 0, numOfTargetTypes = targetNodeTypes.length; - j < numOfTargetTypes; - j++ - ) { - targetNodeType = targetNodeTypes[j]; - targetNodeItems = {}; - if (_viewId && _layer === CONFIG.LAYER.MODEL) { - targetNodes = this.getNodesByViewType(targetNodeType); - } else { - targetNodes = this.getNodesByType(targetNodeType); - } - for (targetNodeId in targetNodes) { - if (targetNodes.hasOwnProperty(targetNodeId)) { - targetNode = targetNodes[targetNodeId]; - if (targetNode === node) continue; - if ( - _layer === CONFIG.LAYER.MODEL && - _viewId && - targetNode.getCurrentViewType() === null - ) - continue; - targetAppearance = targetNode.getAppearance(); - if ( - !targetNode - .getNeighbors() - .hasOwnProperty(node.getEntityId()) - ) { - targetNodeItems[ - connectionType + targetNodeType + i + targetNodeId - ] = { - name: - ".." + - (targetNode.getLabel().getValue().getValue() || - targetNode.getType()), - callback: makeTargetNodeCallback( - connectionType, - targetNodeId - ), - distanceSquare: - Math.pow( - targetAppearance.left - sourceAppearance.left, - 2 - ) + - Math.pow( - targetAppearance.top - sourceAppearance.top, - 2 - ), - targetNodeId: - connectionType + targetNodeType + i + targetNodeId, - }; - } - } - } - if (lodash.size(targetNodeItems) > 0) { - var targetNodeItemsTmp = lodash.sortBy( - targetNodeItems, - "distanceSquare" - ); - targetNodeItems = {}; - for ( - var k = 0, numOfItems = targetNodeItemsTmp.length; - k < numOfItems; - k++ - ) { - targetNodeItems[k + targetNodeItemsTmp[k].targetNodeId] = - targetNodeItemsTmp[k]; - } - targetNodeTypeItems[connectionType + targetNodeType + i] = { - name: "..to " + targetNodeType + "..", - items: targetNodeItems, - }; - } - } - } - } - if (lodash.size(targetNodeTypeItems) > 0) { - connectionItems[connectionType] = { - name: "..with " + connectionType + "..", - items: targetNodeTypeItems, - }; - } - } - } - - return { - name: "Connect..", - items: connectionItems, - disabled: (function (connectionItems) { - return lodash.size(connectionItems) === 0; - })(connectionItems), - }; - }, - generateGuidanceMetamodel: function () { - var metamodel = this.generateMetaModel(); - var actionNodeLabels = []; - var createEntityNodeLabels = []; - //Create guidance metamodel - var guidanceMetamodel = { - attributes: {}, - nodes: {}, - edges: {}, - }; - - //Create initial node - var initialNode = { - label: guidancemodel.INITIAL_NODE_LABEL, - shape: { - shape: "", - color: "", - defaultWidth: 200, - defaultHeight: 60, - containment: false, - customShape: startActivityNodeHtml, - customAnchors: "", - }, - attributes: {}, - }; - - //Add a label attribute to the initial node - initialNode.attributes[Util.generateRandomId()] = { - key: "label", - value: "string", - }; - - guidanceMetamodel.nodes[Util.generateRandomId()] = initialNode; - - //Create final node - var finalNode = { - label: guidancemodel.ACTIVITY_FINAL_NODE_LABEL, - shape: { - shape: "circle", - color: "", - defaultWidth: 50, - defaultHeight: 50, - containment: false, - customShape: activityFinalNodeHtml, - customAnchors: ["Perimeter", { shape: "Circle", anchorCount: 60 }], - }, - attributes: {}, - }; - - guidanceMetamodel.nodes[Util.generateRandomId()] = finalNode; - - //Create merge node - var mergeNode = { - label: guidancemodel.MERGE_NODE_LABEL, - shape: { - shape: "diamond", - color: "yellow", - defaultWidth: 0, - defaultHeight: 0, - containment: false, - customShape: "", - customAnchors: "", - }, - attributes: {}, - }; - - guidanceMetamodel.nodes[Util.generateRandomId()] = mergeNode; - - //Create 'call activity node' - var callActivityNode = { - label: guidancemodel.CALL_ACTIVITY_NODE_LABEL, - shape: { - shape: "rounded_rectangle", - color: "", - defaultWidth: 100, - defaultHeight: 50, - containment: false, - customShape: callActivityNodeHtml, - customAnchors: "", - }, - attributes: {}, - }; - - actionNodeLabels.push(guidancemodel.CALL_ACTIVITY_NODE_LABEL); - - //Add a label attribute to the call activity node - callActivityNode.attributes[Util.generateRandomId()] = { - key: "label", - value: "string", - }; - - guidanceMetamodel.nodes[Util.generateRandomId()] = callActivityNode; - - //Create concurrency node - var concurrencyNode = { - label: guidancemodel.CONCURRENCY_NODE_LABEL, - shape: { - shape: "rectangle", - color: "black", - defaultWidth: 10, - defaultHeight: 200, - containment: false, - customShape: "", - customAnchors: "", - }, - attributes: {}, - }; - - guidanceMetamodel.nodes[Util.generateRandomId()] = concurrencyNode; - - var flowEdgeRelations = []; - var dataFlowEdgeRelations = []; - - var nodes = metamodel.nodes; - for (var nodeId in nodes) { - if (nodes.hasOwnProperty(nodeId)) { - var node = nodes[nodeId]; - - var createObjectNodeToEntityNodeRelation = { - sourceTypes: [], - targetTypes: [], - }; - //Generate the 'create object node' - var label = guidancemodel.getCreateObjectNodeLabelForType( - node.label - ); - createObjectNodeToEntityNodeRelation.sourceTypes.push(label); - actionNodeLabels.push(label); - createEntityNodeLabels.push(label); - var id = Util.generateRandomId(); - guidanceMetamodel.nodes[id] = { - label: label, - attributes: {}, - shape: { - shape: "rounded_rectangle", - color: "", - defaultWidth: 100, - defaultHeight: 50, - containment: false, - customShape: lodash.template(actionNodeHtml)({ - label: node.label, - icon: "plus", - }), - customAnchors: "", - }, - }; - - //Generate the 'entity node' - var entityLabel = guidancemodel.getEntityNodeLabelForType( - node.label - ); - createObjectNodeToEntityNodeRelation.targetTypes.push(label); - id = Util.generateRandomId(); - guidanceMetamodel.nodes[id] = { - label: entityLabel, - attributes: {}, - shape: { - shape: "rectangle", - color: "", - defaultWidth: 100, - defaultHeight: 50, - containment: false, - customShape: lodash.template(entityNodeHtml)({ - icon: "square", - label: node.label, - }), - customAnchors: "", - }, - }; - - //Generate the 'set property node' - setPropertyLabel = guidancemodel.getSetPropertyNodeLabelForType( - node.label - ); - actionNodeLabels.push(setPropertyLabel); - id = Util.generateRandomId(); - guidanceMetamodel.nodes[id] = { - label: setPropertyLabel, - attributes: {}, - shape: { - shape: "", - defaultWidth: 130, - defaultHeight: 50, - containment: false, - customShape: lodash.template(setPropertyNodeHtml)(), - customAnchors: "", - }, - }; - - var options = {}; - for (var attributeId in node.attributes) { - var attribute = node.attributes[attributeId]; - options[attribute.key] = attribute.key; - } - - guidanceMetamodel.nodes[id].attributes[Util.generateRandomId()] = { - key: "Property", - value: "Value", - options: options, - }; - - //Define the 'create object node' to 'entity node' relation - dataFlowEdgeRelations.push({ - sourceTypes: [label], - targetTypes: [entityLabel], - }); - - //Define the 'entity node' to 'set property node' relation - dataFlowEdgeRelations.push({ - sourceTypes: [entityLabel], - targetTypes: [setPropertyLabel], - }); - - //Define the 'entity node' to 'create relationship node' relation - for (var edgeId in metamodel.edges) { - var edge = metamodel.edges[edgeId]; - for (var relationId in edge.relations) { - var relation = edge.relations[relationId]; - if ( - relation.sourceTypes.indexOf(node.label) > -1 || - relation.targetTypes.indexOf(node.label) > -1 - ) { - dataFlowEdgeRelations.push({ - sourceTypes: [entityLabel], - targetTypes: - guidancemodel.getCreateRelationshipNodeLabelForType( - edge.label - ), - }); - break; - } - } - } - } - } - var edgesByLabel = {}; - - var edges = metamodel.edges; - for (var edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - var edge = edges[edgeId]; - //Generate 'create relationship node' - var label = guidancemodel.getCreateRelationshipNodeLabelForType( - edge.label - ); - actionNodeLabels.push(label); - createEntityNodeLabels.push(label); - edgesByLabel[edge.label] = edge; - - var id = Util.generateRandomId(); - guidanceMetamodel.nodes[id] = { - label: label, - attributes: {}, - shape: { - shape: "rounded_rectangle", - color: "", - defaultWidth: 100, - defaultHeight: 50, - containment: false, - customShape: lodash.template(actionNodeHtml)({ - label: edge.label, - icon: "plus", - }), - customAnchors: "", - }, - }; - - //Generate 'entity node' - var entityLabel = guidancemodel.getEntityNodeLabelForType( - edge.label - ); - - var id = Util.generateRandomId(); - guidanceMetamodel.nodes[id] = { - label: entityLabel, - attributes: {}, - shape: { - shape: "rectangle", - color: "black", - defaultWidth: 100, - defaultHeight: 50, - containment: false, - customShape: lodash.template(entityNodeHtml)({ - icon: "exchange", - label: edge.label, - }), - customAnchors: "", - }, - }; - - //Generate the 'set property node' - if (Object.keys(edge.attributes).length > 0) { - var setPropertyLabel = - guidancemodel.getSetPropertyNodeLabelForType(edge.label); - actionNodeLabels.push(setPropertyLabel); - id = Util.generateRandomId(); - guidanceMetamodel.nodes[id] = { - label: setPropertyLabel, - attributes: {}, - shape: { - shape: "", - defaultWidth: 0, - defaultHeight: 0, - containment: false, - customShape: lodash.template(setPropertyNodeHtml)({ - type: setPropertyLabel, - color: "white", - }), - customAnchors: "", - }, - }; - - var options = {}; - for (var attributeId in edge.attributes) { - var attribute = edge.attributes[attributeId]; - options[attribute.key] = attribute.key; - } - - guidanceMetamodel.nodes[id].attributes[Util.generateRandomId()] = - { - key: "Property", - value: "Value", - options: options, - }; - } - - //Define the 'create relationship node' to 'entity node' relation - dataFlowEdgeRelations.push({ - sourceTypes: [label], - targetTypes: [entityLabel], - }); - - //Define the 'entity node' to 'set property node' relation - dataFlowEdgeRelations.push({ - sourceTypes: [entityLabel], - targetTypes: [setPropertyLabel], - }); - } - } - - //Create the flow edge - - //Relations between all action nodes - flowEdgeRelations = flowEdgeRelations.concat({ - sourceTypes: actionNodeLabels, - targetTypes: actionNodeLabels.concat([ - guidancemodel.MERGE_NODE_LABEL, - guidancemodel.ACTIVITY_FINAL_NODE_LABEL, - guidancemodel.CONCURRENCY_NODE_LABEL, - ]), - }); - - //Relations for the initial node - flowEdgeRelations = flowEdgeRelations.concat({ - sourceTypes: [guidancemodel.INITIAL_NODE_LABEL], - targetTypes: [ - guidancemodel.CALL_ACTIVITY_NODE_LABEL, - guidancemodel.MERGE_NODE_LABEL, - guidancemodel.CONCURRENCY_NODE_LABEL, - ].concat(createEntityNodeLabels), - }); - - //Relations for the merge node - flowEdgeRelations = flowEdgeRelations.concat({ - sourceTypes: [guidancemodel.MERGE_NODE_LABEL], - targetTypes: [ - guidancemodel.ACTIVITY_FINAL_NODE_LABEL, - guidancemodel.MERGE_NODE_LABEL, - guidancemodel.CONCURRENCY_NODE_LABEL, - ].concat(actionNodeLabels), - }); - - //Relations for the concurrency node - flowEdgeRelations = flowEdgeRelations.concat({ - sourceTypes: [guidancemodel.CONCURRENCY_NODE_LABEL], - targetTypes: [ - guidancemodel.ACTIVITY_FINAL_NODE_LABEL, - guidancemodel.CONCURRENCY_NODE_LABEL, - guidancemodel.MERGE_NODE_LABEL, - ].concat(actionNodeLabels), - }); - - //Create the action flow edge - guidanceMetamodel.edges[Util.generateRandomId()] = { - label: "Action flow edge", - shape: { - arrow: "unidirassociation", - shape: "curved", - color: "black", - overlay: "", - overlayPosition: "top", - overlayRotate: true, - }, - relations: flowEdgeRelations, - }; - - //Create the data flow edge - var dataFlowEdge = { - label: "Data flow edge", - shape: { - arrow: "unidirassociation", - shape: "curved", - color: "black", - overlay: "", - overlayPosition: "top", - overlayRotate: true, - }, - attributes: {}, - relations: dataFlowEdgeRelations, - }; - - dataFlowEdge.attributes[Util.generateRandomId()] = { - key: "Destination", - value: "Value", - options: { - Source: "Source", - Target: "Target", - }, - }; - guidanceMetamodel.edges[Util.generateRandomId()] = dataFlowEdge; - - //Create the association edge - guidanceMetamodel.edges[Util.generateRandomId()] = { - label: "Association edge", - shape: { - arrow: "unidirassociation", - shape: "curved", - color: "", - dashstyle: "4 2", - overlay: "", - overlayPosition: "hidden", - overlayRotate: true, - }, - relations: [ - { - sourceTypes: [guidancemodel.CALL_ACTIVITY_NODE_LABEL], - targetTypes: [guidancemodel.INITIAL_NODE_LABEL], - }, - ], - }; - - return guidanceMetamodel; - }, - generateLogicalGuidanceRepresentation: function (m) { - const dataMap = y.getMap("data"); - var graph = new graphlib.Graph(); - var model; - if (m) model = m; - else model = dataMap.get("guidancemodel"); - if (!model) return null; - var nodes = model.nodes; - var edges = model.edges; - //Returns successor node which belong to the action flow (everything except entity nodes) - var getFlowSuccessors = function (nodeId) { - var targets = []; - var labels = []; - for (var edgeId in edges) { - var edge = edges[edgeId]; - if (edge.source == nodeId) { - //var targetType = nodes[edge.target].type - if (edge.type == "Action flow edge") { - targets.push(edge.target); - labels.push(edge.label.value.value); - } - } - } - return { - targets: targets, - labels: labels, - }; - }; - - var getEntitySuccessor = function (nodeId) { - for (var edgeId in edges) { - var edge = edges[edgeId]; - if (edge.source == nodeId) { - var targetType = nodes[edge.target].type; - if ((targetType = guidancemodel.isEntityNodeLabel(targetType))) - return edge.target; - } - } - return ""; - }; - - var getEntityPredecessorsForCreateRelationshipAction = function ( - nodeId - ) { - var entities = { - Source: "", - Target: "", - }; - for (var edgeId in edges) { - var edge = edges[edgeId]; - if (edge.target == nodeId) { - var sourceType = nodes[edge.source].type; - if ((sourceType = guidancemodel.isEntityNodeLabel(sourceType))) { - var destination = getAttributeValue(edge, "Destination"); - entities[destination] = edge.source; - } - } - } - return entities; - }; - - var getEntityPredecessorForSetPropertyAction = function (nodeId) { - for (var edgeId in edges) { - var edge = edges[edgeId]; - if (edge.target == nodeId) { - var sourceType = nodes[edge.source].type; - if ((sourceType = guidancemodel.isEntityNodeLabel(sourceType))) { - return edge.source; - } - } - } - return ""; - }; - - var getInitialNodeForCallActivityAction = function (nodeId) { - for (var edgeId in edges) { - var edge = edges[edgeId]; - if (edge.source == nodeId && edge.type == "Association edge") { - return edge.target; - } - } - return ""; - }; - - var getAttributeValue = function (node, attributeName) { - for (var attributeId in node.attributes) { - var attribute = node.attributes[attributeId]; - if (attribute.name == attributeName) return attribute.value.value; - } - return ""; - }; - - for (var nodeId in nodes) { - var node = nodes[nodeId]; - var type = node.type; - var subType = ""; - - if (type == guidancemodel.INITIAL_NODE_LABEL) { - var successors = getFlowSuccessors(nodeId); - graph.setNode(nodeId, { - type: "INITIAL_NODE", - name: getAttributeValue(node, "label"), - }); - for (var i = 0; i < successors.targets.length; i++) { - graph.setEdge( - nodeId, - successors.targets[i], - successors.labels[i] - ); - } - } else if (type == guidancemodel.MERGE_NODE_LABEL) { - var successors = getFlowSuccessors(nodeId); - graph.setNode(nodeId, { - type: "MERGE_NODE", - }); - for (var i = 0; i < successors.targets.length; i++) { - graph.setEdge( - nodeId, - successors.targets[i], - successors.labels[i] - ); - } - } else if (type == guidancemodel.CONCURRENCY_NODE_LABEL) { - var successors = getFlowSuccessors(nodeId); - graph.setNode(nodeId, { - type: "CONCURRENCY_NODE", - }); - for (var i = 0; i < successors.targets.length; i++) { - graph.setEdge( - nodeId, - successors.targets[i], - successors.labels[i] - ); - } - } else if (type == guidancemodel.ACTIVITY_FINAL_NODE_LABEL) { - graph.setNode(nodeId, { - type: "ACTIVITY_FINAL_NODE", - }); - } else if ((subType = guidancemodel.isCreateObjectNodeLabel(type))) { - var successors = getFlowSuccessors(nodeId); - graph.setNode(nodeId, { - type: "CREATE_OBJECT_ACTION", - objectType: subType, - createdObjectId: getEntitySuccessor(nodeId), - }); - for (var i = 0; i < successors.targets.length; i++) { - graph.setEdge( - nodeId, - successors.targets[i], - successors.labels[i] - ); - } - } else if ( - (subType = guidancemodel.isCreateRelationshipNodeLabel(type)) - ) { - var entities = - getEntityPredecessorsForCreateRelationshipAction(nodeId); - var successors = getFlowSuccessors(nodeId); - graph.setNode(nodeId, { - type: "CREATE_RELATIONSHIP_ACTION", - relationshipType: subType, - createdRelationshipId: getEntitySuccessor(nodeId), - sourceObjectId: entities["Source"], - targetObjectId: entities["Target"], - }); - for (var i = 0; i < successors.targets.length; i++) { - graph.setEdge( - nodeId, - successors.targets[i], - successors.labels[i] - ); - } - } else if ((subType = guidancemodel.isSetPropertyNodeLabel(type))) { - var successors = getFlowSuccessors(nodeId); - graph.setNode(nodeId, { - type: "SET_PROPERTY_ACTION", - entityType: subType, - propertyName: getAttributeValue(node, "Property"), - sourceObjectId: getEntityPredecessorForSetPropertyAction(nodeId), - }); - for (var i = 0; i < successors.targets.length; i++) { - graph.setEdge( - nodeId, - successors.targets[i], - successors.labels[i] - ); - } - } else if (type == guidancemodel.CALL_ACTIVITY_NODE_LABEL) { - var successors = getFlowSuccessors(nodeId); - graph.setNode(nodeId, { - type: "CALL_ACTIVITY_ACTION", - initialNodeId: getInitialNodeForCallActivityAction(nodeId), - }); - for (var i = 0; i < successors.targets.length; i++) { - graph.setEdge( - nodeId, - successors.targets[i], - successors.labels[i] - ); - } - } - } - return graphlib.json.write(graph); - }, - generateGuidanceRules: function () { - var guidanceRules = { objectToolRules: [] }; - var nodes = guidancemodel.guidancemodel.nodes; - var edges = guidancemodel.guidancemodel.edges; - for (var nodeId in nodes) { - var node = nodes[nodeId]; - var type = node.type; - - if (guidancemodel.isObjectToolType(type)) { - var srcObjectType = - guidancemodel.getObjectTypeForObjectToolType(type); - var destObjectType = null; - var relationshipType = null; - var relevantEdges = []; - var label = ""; - //Get the label attribute - for (var attributeId in node.attributes) { - if (node.attributes[attributeId].name == "label") - label = node.attributes[attributeId].value.value; - } - var edgeId; - for (edgeId in edges) { - if (edges[edgeId].source == nodeId) - relevantEdges.push(edges[edgeId]); - } - for (var i = 0; i < relevantEdges.length; i++) { - var edge = relevantEdges[i]; - var target = nodes[edge.target]; - if (guidancemodel.isObjectContextType(target.type)) { - destObjectType = - guidancemodel.getObjectTypeForObjectContextType(target.type); - } else if (guidancemodel.isRelationshipContextType(target.type)) { - relationshipType = - guidancemodel.getRelationshipTypeForRelationshipContextType( - target.type - ); - } - } - if (destObjectType !== null && relationshipType !== null) { - var objectToolRule = { - srcObjectType: srcObjectType, - destObjectType: destObjectType, - relationshipType: relationshipType, - label: label, - }; - guidanceRules.objectToolRules.push(objectToolRule); - } - } - } - return guidanceRules; - }, - /** - * Generate the JSON Representation of the meta-model for a new editor instance based on the current graph - * @returns {{nodes: {}, edges: {}}} JSON representation of meta model - */ - generateMetaModel: function () { - /** - * Determine the type of the concrete classes (ObjectNodes) of the class diagram contained in the sub graph rooted by the passed node - * @param node Node to start with - * @param [visitedNodes] List of node that already have been visited - * @returns {object} - */ - function getConcreteObjectNodeTypes(node, visitedNodes) { - var edgeId, - edge, - ingoingEdges, - source, - type, - classTypes = []; - - if (!visitedNodes) visitedNodes = []; - - if (visitedNodes.indexOf(node) !== -1) return []; - - visitedNodes.push(node); - - type = node.getLabel().getValue().getValue(); - if (node instanceof ObjectNode && classTypes.indexOf(type) === -1) { - classTypes.push(type); - } - - ingoingEdges = node.getIngoingEdges(); - for (edgeId in ingoingEdges) { - if (ingoingEdges.hasOwnProperty(edgeId)) { - edge = ingoingEdges[edgeId]; - source = edge.getSource(); - if ( - (edge instanceof GeneralisationEdge && - source instanceof ObjectNode) || - (edge instanceof GeneralisationEdge && - source instanceof AbstractClassNode) - ) { - classTypes = classTypes.concat( - getConcreteObjectNodeTypes(source, visitedNodes) - ); - } - } - } - return classTypes; - } - - /** - * Determine the attributes of the passed node by traversing the underlying class diagram - * @param node Node to start with - * @param [visitedNodes] List of node that already have been visited - * @returns {object} - */ - function getNodeAttributes(node, visitedNodes) { - var nodeAttributes, attributeId, attribute; - var edgeId, edge, edges; - var source, target; - var neighbor, options; - var attributes = {}; - var obj = {}; - - if (!visitedNodes) visitedNodes = []; - - if (visitedNodes.indexOf(node) !== -1) return {}; - - visitedNodes.push(node); - - //Traverse edges to check for inheritance and linked enums - edges = node.getOutgoingEdges(); - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - source = edge.getSource(); - target = edge.getTarget(); - - //Does the node inherit attributes from a parent node? - if ( - (edge instanceof GeneralisationEdge && - target instanceof AbstractClassNode) || - (edge instanceof GeneralisationEdge && - node instanceof ObjectNode && - target instanceof ObjectNode) || - (edge instanceof GeneralisationEdge && - node instanceof RelationshipNode && - target instanceof RelationshipNode) || - (edge instanceof GeneralisationEdge && - node instanceof EnumNode && - target instanceof EnumNode) - ) { - Util.merge(attributes, getNodeAttributes(target, visitedNodes)); - - //Is there an enum linked to the node - } else if ( - (edge instanceof BiDirAssociationEdge && - ((target === node && - (neighbor = source) instanceof EnumNode) || - (source === node && - (neighbor = target) instanceof EnumNode))) || - (edge instanceof UniDirAssociationEdge && - (neighbor = target) instanceof EnumNode) - ) { - options = {}; - nodeAttributes = {}; - Util.merge(nodeAttributes, getNodeAttributes(neighbor, [])); - for (attributeId in nodeAttributes) { - if (nodeAttributes.hasOwnProperty(attributeId)) { - attribute = nodeAttributes[attributeId]; - options[attribute.value] = attribute.value; - } - } - obj = {}; - obj[neighbor.getEntityId()] = { - key: edge.getLabel().getValue().getValue(), - value: neighbor.getLabel().getValue().getValue(), - options: options, - }; - Util.merge(attributes, obj); - } - } - } - //Compute node attributes - nodeAttributes = node.getAttribute("[attributes]").getAttributes(); - for (attributeId in nodeAttributes) { - if (nodeAttributes.hasOwnProperty(attributeId)) { - attribute = nodeAttributes[attributeId]; - if (node instanceof RelationshipNode) { - obj = {}; - obj[attributeId] = { - key: attribute.getKey().getValue(), - value: attribute.getValue().getValue(), - position: attribute.getValue2().getValue(), - }; - Util.merge(attributes, obj); - } else if (node instanceof EnumNode) { - obj = {}; - obj[attributeId] = { - value: attribute.getValue().getValue(), - }; - Util.merge(attributes, obj); - } else { - obj = {}; - obj[attributeId] = { - key: attribute.getKey().getValue(), - value: attribute.getValue().getValue(), - }; - Util.merge(attributes, obj); - } - } - } - return attributes; - } - - var metamodel = { - attributes: {}, - nodes: {}, - edges: {}, - }; - - var nodeId, node; - var attributes; - var edge, edgeId, edges; - var source, target; - var neighbor; - var groupSource, groupTarget; - var groupNeighbor; - var shape; - var sourceTypes, targetTypes, concreteTypes; - var groupSourceTypes, groupTargetTypes, groupConcreteTypes; - var relations; - var groupEdge, groupEdgeId, groupEdges; - - for (nodeId in _nodes) { - if (_nodes.hasOwnProperty(nodeId)) { - node = _nodes[nodeId]; - if (node instanceof ObjectNode) { - if ( - node.getLabel().getValue().getValue() === "Model Attributes" - ) { - attributes = getNodeAttributes(node); - metamodel.attributes = attributes; - } else { - attributes = getNodeAttributes(node); - edges = node.getEdges(); - shape = null; - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - source = edge.getSource(); - target = edge.getTarget(); - if ( - (edge instanceof BiDirAssociationEdge && - ((target === node && - (neighbor = source) instanceof NodeShapeNode) || - (source === node && - (neighbor = target) instanceof NodeShapeNode))) || - (edge instanceof UniDirAssociationEdge && - (neighbor = target) instanceof NodeShapeNode) - ) { - shape = { - shape: neighbor - .getAttribute(neighbor.getEntityId() + "[shape]") - .getValue() - .getValue(), - color: neighbor - .getAttribute(neighbor.getEntityId() + "[color]") - .getValue() - .getValue(), - defaultWidth: parseInt( - neighbor - .getAttribute( - neighbor.getEntityId() + "[defaultWidth]" - ) - .getValue() - .getValue() - ), - defaultHeight: parseInt( - neighbor - .getAttribute( - neighbor.getEntityId() + "[defaultHeight]" - ) - .getValue() - .getValue() - ), - containment: neighbor - .getAttribute( - neighbor.getEntityId() + "[containment]" - ) - .getValue() - .getValue(), - customShape: neighbor - .getAttribute( - neighbor.getEntityId() + "[customShape]" - ) - .getValue() - .getValue(), - customAnchors: neighbor - .getAttribute( - neighbor.getEntityId() + "[customAnchors]" - ) - .getValue() - .getValue(), - }; - } - } - } - metamodel.nodes[nodeId] = { - label: node.getLabel().getValue().getValue(), - attributes: attributes, - shape: shape || { - shape: "rectangle", - color: "white", - containment: false, - customShape: "", - customAnchors: "", - defaultWidth: 0, - defaultHeight: 0, - }, - }; - } - } else if (node instanceof RelationshipNode) { - attributes = getNodeAttributes(node); - edges = node.getEdges(); - sourceTypes = []; - targetTypes = []; - relations = []; - shape = null; - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - source = edge.getSource(); - target = edge.getTarget(); - if ( - edge instanceof BiDirAssociationEdge && - ((target === node && - (neighbor = source) instanceof ObjectNode) || - (source === node && - (neighbor = target) instanceof ObjectNode)) - ) { - concreteTypes = getConcreteObjectNodeTypes(neighbor); - sourceTypes = sourceTypes.concat(concreteTypes); - targetTypes = targetTypes.concat(concreteTypes); - } else if ( - edge instanceof UniDirAssociationEdge && - source === node && - target instanceof ObjectNode - ) { - targetTypes = targetTypes.concat( - getConcreteObjectNodeTypes(target) - ); - } else if ( - edge instanceof UniDirAssociationEdge && - target === node && - source instanceof ObjectNode - ) { - sourceTypes = sourceTypes.concat( - getConcreteObjectNodeTypes(source) - ); - } else if ( - edge instanceof BiDirAssociationEdge && - ((target === node && - (neighbor = source) instanceof AbstractClassNode) || - (source === node && - (neighbor = target) instanceof AbstractClassNode)) - ) { - concreteTypes = getConcreteObjectNodeTypes(neighbor); - sourceTypes = sourceTypes.concat(concreteTypes); - targetTypes = targetTypes.concat(concreteTypes); - } else if ( - edge instanceof UniDirAssociationEdge && - source === node && - target instanceof AbstractClassNode - ) { - targetTypes = targetTypes.concat( - getConcreteObjectNodeTypes(target) - ); - } else if ( - edge instanceof UniDirAssociationEdge && - target === node && - source instanceof AbstractClassNode - ) { - sourceTypes = sourceTypes.concat( - getConcreteObjectNodeTypes(source) - ); - } else if ( - (edge instanceof BiDirAssociationEdge && - ((target === node && - (neighbor = source) instanceof EdgeShapeNode) || - (source === node && - (neighbor = target) instanceof EdgeShapeNode))) || - (edge instanceof UniDirAssociationEdge && - source === node && - (neighbor = target) instanceof EdgeShapeNode) - ) { - shape = { - arrow: neighbor - .getAttribute(neighbor.getEntityId() + "[arrow]") - .getValue() - .getValue(), - shape: neighbor - .getAttribute(neighbor.getEntityId() + "[shape]") - .getValue() - .getValue(), - color: neighbor - .getAttribute(neighbor.getEntityId() + "[color]") - .getValue() - .getValue(), - overlay: neighbor - .getAttribute(neighbor.getEntityId() + "[overlay]") - .getValue() - .getValue(), - overlayPosition: neighbor - .getAttribute( - neighbor.getEntityId() + "[overlayPosition]" - ) - .getValue() - .getValue(), - overlayRotate: neighbor - .getAttribute( - neighbor.getEntityId() + "[overlayRotate]" - ) - .getValue() - .getValue(), - }; - } else if ( - edge instanceof GeneralisationEdge && - target === node && - (neighbor = source) instanceof RelationshipGroupNode - ) { - groupEdges = neighbor.getEdges(); - groupSourceTypes = []; - groupTargetTypes = []; - for (groupEdgeId in groupEdges) { - if (groupEdges.hasOwnProperty(groupEdgeId)) { - groupEdge = groupEdges[groupEdgeId]; - groupSource = groupEdge.getSource(); - groupTarget = groupEdge.getTarget(); - if ( - groupEdge instanceof BiDirAssociationEdge && - ((groupTarget === neighbor && - (groupNeighbor = groupSource) instanceof - ObjectNode) || - (groupSource === neighbor && - (groupNeighbor = groupTarget) instanceof - ObjectNode)) - ) { - groupConcreteTypes = - getConcreteObjectNodeTypes(groupNeighbor); - groupSourceTypes = - groupSourceTypes.concat(groupConcreteTypes); - groupTargetTypes = - groupTargetTypes.concat(groupConcreteTypes); - } else if ( - groupEdge instanceof UniDirAssociationEdge && - groupSource === neighbor && - groupTarget instanceof ObjectNode - ) { - groupTargetTypes = groupTargetTypes.concat( - getConcreteObjectNodeTypes(groupTarget) - ); - } else if ( - groupEdge instanceof UniDirAssociationEdge && - groupTarget === neighbor && - groupSource instanceof ObjectNode - ) { - groupSourceTypes = groupSourceTypes.concat( - getConcreteObjectNodeTypes(groupSource) - ); - } else if ( - groupEdge instanceof BiDirAssociationEdge && - ((groupTarget === neighbor && - (groupNeighbor = groupSource) instanceof - AbstractClassNode) || - (groupSource === neighbor && - (groupNeighbor = groupTarget) instanceof - AbstractClassNode)) - ) { - groupConcreteTypes = - getConcreteObjectNodeTypes(groupNeighbor); - groupSourceTypes = - groupSourceTypes.concat(groupConcreteTypes); - groupTargetTypes = - groupTargetTypes.concat(groupConcreteTypes); - } else if ( - groupEdge instanceof UniDirAssociationEdge && - groupSource === neighbor && - groupTarget instanceof AbstractClassNode - ) { - groupTargetTypes = groupTargetTypes.concat( - getConcreteObjectNodeTypes(groupTarget) - ); - } else if ( - groupEdge instanceof UniDirAssociationEdge && - groupTarget === neighbor && - groupSource instanceof AbstractClassNode - ) { - groupSourceTypes = groupSourceTypes.concat( - getConcreteObjectNodeTypes(groupSource) - ); - } - } - } - - if ( - groupSourceTypes.length > 0 && - groupTargetTypes.length > 0 - ) { - relations.push({ - sourceTypes: groupSourceTypes, - targetTypes: groupTargetTypes, - }); - } - } - } - } - - if (sourceTypes.length > 0 && targetTypes.length > 0) { - relations.push({ - sourceTypes: sourceTypes, - targetTypes: targetTypes, - }); - } - - metamodel.edges[nodeId] = { - label: node.getLabel().getValue().getValue(), - shape: shape || { - arrow: "bidirassociation", - shape: "straight", - color: "black", - overlay: "", - overlayPosition: "top", - overlayRotate: true, - }, - relations: relations, - attributes: attributes, - }; - } - } - } - return metamodel; - }, - /** - * Store current graph representation in the ROLE space - * @returns {Deferred} - */ - storeData: function () { - var resourceSpace = new openapp.oo.Resource(openapp.param.space()); - - var data = this.graphToJSON(); - - var resourcesToSave = []; - var promises = []; - - //In the guidance model editor update the guidance model - if (guidancemodel.isGuidanceEditor()) { - resourcesToSave.push({ - typeName: CONFIG.NS.MY.GUIDANCEMODEL, - representation: data, - }); - } - //In the metamodel editor create the guidance metamodel needed for the guidance editor - else if (!metamodel.hasOwnProperty("nodes")) { - resourcesToSave.push({ - typeName: CONFIG.NS.MY.METAMODELPREVIEW, - representation: this.generateMetaModel(), - }); - resourcesToSave.push({ - typeName: CONFIG.NS.MY.GUIDANCEMETAMODEL, - representation: this.generateGuidanceMetamodel(), - }); - resourcesToSave.push({ - typeName: CONFIG.NS.MY.MODEL, - representation: data, - }); - } - //In the model editor just update the model - else { - resourcesToSave.push({ - typeName: CONFIG.NS.MY.MODEL, - representation: data, - }); - } - - var recreateResource = function (type, representation) { - var deferred = $.Deferred(); - var innerDeferred = $.Deferred(); - //noinspection JSUnusedGlobalSymbols - resourceSpace.getSubResources({ - relation: openapp.ns.role + "data", - type: type, - onEach: function (doc) { - doc.del(); - }, - onAll: function () { - innerDeferred.resolve(); - }, - }); - innerDeferred.then(function () { - resourceSpace.create({ - relation: openapp.ns.role + "data", - type: type, - representation: representation, - callback: function () { - deferred.resolve(); - }, - }); - }); - return deferred.promise(); - }; - - for (var i = 0; i < resourcesToSave.length; i++) { - var item = resourcesToSave[i]; - promises.push(recreateResource(item.typeName, item.representation)); - } - - return $.when.apply($, promises); - }, - storeDataYjs: function () { - var data = this.graphToJSON(); - const dataMap = y.getMap("data"); - if (guidancemodel.isGuidanceEditor()) { - dataMap.set("guidancemodel", data); - } else if (!metamodel) { - dataMap.set("metamodelpreview", this.generateMetaModel()); - dataMap.set("guidancemetamodel", this.generateGuidanceMetamodel()); - dataMap.set("model", data); - } else { - dataMap.set("model", data); - } - }, - /** - * Delete the Model Attribute Node - */ - deleteModelAttribute: function () { - _modelAttributesNode = null; - }, - /** - * resets the EntityManager - */ - reset: function () { - _nodes = {}; - _edges = {}; - this.deleteModelAttribute(); - }, - /** - * initializes the node types - * @param vls the vvs - */ - initNodeTypes: function (vls) { - nodeTypes = _initNodeTypes(vls); - }, - /** - * initializes the view edge types - * @param vls the vvs - */ - initEdgeTypes: function (vls) { - var res = _initEdgeTypes(vls); - edgeTypes = res.edgeTypes; - relations = res.relations; - }, - /** - * initializes both the node types- and the edge types Object - * @param vls the vvs - */ - initModelTypes: function (vls) { - this.initNodeTypes(vls); - this.initEdgeTypes(vls); - }, - /** - * Get the node type by its name - * @param type the name of the node type - * @returns {object} - */ - getNodeType: function (type) { - return nodeTypes.hasOwnProperty(type) ? nodeTypes[type] : null; - }, - /** - * Get the edge type bt its name - * @param {string} type the name of the edge type - * @returns {*} - */ - getEdgeType: function (type) { - return edgeTypes.hasOwnProperty(type) ? edgeTypes[type] : null; - }, - /** - * initializes the node types of a view - * @param vvs - */ - initViewNodeTypes: function (vvs) { - //delete the old view type references - for (var nodeTypeName in nodeTypes) { - if (nodeTypes.hasOwnProperty(nodeTypeName)) { - delete nodeTypes[nodeTypeName].VIEWTYPE; - } - } - viewNodeTypes = _initNodeTypes(vvs); - }, - /** - * initializes the edge types of a view - * @param vvs - */ - initViewEdgeTypes: function (vvs) { - //delete the old view type references - for (var edgeTypeName in edgeTypes) { - if (edgeTypes.hasOwnProperty(edgeTypeName)) { - delete edgeTypes[edgeTypeName].VIEWTYPE; - } - } - var res = _initEdgeTypes(vvs); - viewEdgeTypes = res.edgeTypes; - relations = res.relations; - }, - /** - * initializes the node and edge types of view - * @param vvs - */ - initViewTypes: function (vvs) { - this.setViewId(vvs.id); - this.initViewNodeTypes(vvs); - this.initViewEdgeTypes(vvs); - }, - /** - * get a view node type - * @param {string} type the name of the view type - * @returns {*} - */ - getViewNodeType: function (type) { - return viewNodeTypes.hasOwnProperty(type) ? viewNodeTypes[type] : null; - }, - /** - * get a view edge type - * @param {string} type the name of the view edge type - * @returns {*} - */ - getViewEdgeType: function (type) { - return viewEdgeTypes.hasOwnProperty(type) ? viewEdgeTypes[type] : null; - }, - /** - * set the identifier of the view - * @param {string} viewId - */ - setViewId: function (viewId) { - _viewId = viewId; - }, - /** - * get the identifier of the view - * @returns {*} - */ - getViewId: function () { - return _viewId; - }, - /** - * get nodes by view type - * @param {string} type the name of the view type - * @returns {object} a map of objects with key as identifier and value as Node - */ - getNodesByViewType: function (type) { - if (viewNodeTypes.hasOwnProperty(type)) { - return this.getNodesByType( - viewNodeTypes[type].getTargetNodeType().TYPE - ); - } - return null; - }, - /** - * get edges by view type - * @param {string}type the view type - * @returns {*} - */ - getEdgesByViewType: function (type) { - if (viewEdgeTypes.hasOwnProperty(type)) { - return this.getEdgesByType( - viewEdgeTypes[type].getTargetEdgeType().TYPE - ); - } - return null; - }, - /** - * Get the current layer you are operating on - * @returns {string} CONFIG.LAYER.META or CONFIG.LAYER.MODEL - */ - getLayer: function () { - return _layer; - }, - /** - * Get the relations between nodes and edges types - * @returns {{}} - */ - getRelations: function () { - return relations; - }, - setGuidance: function (guidance) { - guidancemodel = guidance; - }, - init: function (mm) { - metamodel = mm; - if (metamodel && metamodel.hasOwnProperty("nodes")) { - nodeTypes = _initNodeTypes(metamodel); - _layer = CONFIG.LAYER.MODEL; - } else { - _layer = CONFIG.LAYER.META; - - nodeTypes[ObjectNode.TYPE] = ObjectNode; - nodeTypes[AbstractClassNode.TYPE] = AbstractClassNode; - nodeTypes[RelationshipNode.TYPE] = RelationshipNode; - nodeTypes[RelationshipGroupNode.TYPE] = RelationshipGroupNode; - nodeTypes[EnumNode.TYPE] = EnumNode; - nodeTypes[NodeShapeNode.TYPE] = NodeShapeNode; - nodeTypes[EdgeShapeNode.TYPE] = EdgeShapeNode; - - //add view types - nodeTypes[ViewObjectNode.TYPE] = ViewObjectNode; - nodeTypes[ViewRelationshipNode$1.TYPE] = ViewRelationshipNode$1; - } - - if (metamodel && metamodel.hasOwnProperty("edges")) { - var res = _initEdgeTypes(metamodel); - edgeTypes = res.edgeTypes; - relations = res.relations; - } else { - edgeTypes[GeneralisationEdge.TYPE] = GeneralisationEdge; - edgeTypes[BiDirAssociationEdge.TYPE] = BiDirAssociationEdge; - edgeTypes[UniDirAssociationEdge.TYPE] = UniDirAssociationEdge; - - relations[BiDirAssociationEdge.TYPE] = BiDirAssociationEdge.RELATIONS; - relations[UniDirAssociationEdge.TYPE] = - UniDirAssociationEdge.RELATIONS; - relations[GeneralisationEdge.TYPE] = GeneralisationEdge.RELATIONS; - } - }, - }; - } -}; - -const EntityManagerInstance = new EntityManager$1(); - -/** - * Node - * @class canvas_widget.makeNode - * @memberof canvas_widget - * @constructor - * @param type Type of node - * @param $shape - * @param anchors - * @param attributes - * @returns {Node} - */ -function makeNode(type, $shape, anchors, attributes) { - /** - * Node - * @class canvas_widget.Node - * @extends canvas_widget.AbstractNode - * @constructor - * @param {string} id Entity identifier of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {number} zIndex Position of node on z-axis - * @param {boolean} containment containment - */ - class Node extends AbstractNode { - constructor(id, left, top, width, height, zIndex, containment) { - super(id, type, left, top, width, height, zIndex, containment); - var that = this; - - var currentViewType = null; - - this.setCurrentViewType = function (type) { - currentViewType = type; - }; - - this.getCurrentViewType = function () { - return currentViewType; - }; - - /** - * jQuery object of node template - * @type {jQuery} - * @private - */ - var _$template = $shape.clone(); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = AbstractNode.prototype.get$node - .call(this) - .append(_$template); - - /** - * Options for new connections - * @type {object} - */ - var _anchorOptions = anchors; - - this.nodeSelector = getQuerySelectorFromNode(_$node); - - var init = function () { - var attribute, attributeId, attrObj; - attrObj = {}; - for (attributeId in attributes) { - if (attributes.hasOwnProperty(attributeId)) { - attribute = attributes[attributeId]; - var key = attribute.key.toLowerCase(); - switch (attribute.value) { - case "boolean": - attrObj[attributeId] = new BooleanAttribute( - id + "[" + attribute.key.toLowerCase() + "]", - attribute.key, - that - ); - break; - case "string": - attrObj[attributeId] = new SingleValueAttribute( - id + "[" + attribute.key.toLowerCase() + "]", - attribute.key, - that - ); - if ( - attribute.key.toLowerCase() === "label" || - attribute.key.toLowerCase() === "title" || - attribute.key.toLowerCase() === "name" - ) { - that.setLabel(attrObj[attributeId]); - } - break; - case "integer": - attrObj[attributeId] = new IntegerAttribute( - id + "[" + attribute.key.toLowerCase() + "]", - attribute.key, - that - ); - break; - case "file": - attrObj[attributeId] = new FileAttribute( - id + "[" + attribute.key.toLowerCase() + "]", - attribute.key, - that - ); - break; - case "quiz": - attrObj[attributeId] = new QuizAttribute( - id + "[" + attribute.key.toLowerCase() + "]", - attribute.key, - that - ); - if ( - attribute.key.toLowerCase() === "label" || - attribute.key.toLowerCase() === "title" || - attribute.key.toLowerCase() === "name" - ) { - that.setLabel(attrObj[attributeId]); - } - default: - if (attribute.options) { - attrObj[attributeId] = new SingleSelectionAttribute( - id + "[" + attribute.key.toLowerCase() + "]", - attribute.key, - that, - attribute.options - ); - } - } - _$node.find("." + key).append(attrObj[attributeId].get$node()); - } - } - that.setAttributes(attrObj); - }; - - /** - * Get anchor options for new connections - * @returns {Object} - */ - this.getAnchorOptions = function () { - return _anchorOptions; - }; - - /** Set anchor options for new connections - * - */ - this.setAnchorOptions = function (anchors) { - _anchorOptions = anchors; - }; - - /** - * Bind source node events for edge tool - */ - this.makeSource = () => { - _$node.addClass("source"); - window.jsPlumbInstance.addEndpoint(_$node.get(0), { - connectorPaintStyle: { fill: "black", strokeWidth: 4 }, - source: true, - endpoint: { - type: "Rectangle", - options: { - width: _$node.width() + 50, - height: _$node.height() + 50, - }, - }, - paintStyle: { fill: "transparent" }, - anchor: AnchorLocations.Center, - deleteOnEmpty: true, - uuid: id + "_eps1", - //maxConnections:1, - uniqueEndpoint: false, - deleteEndpointsOnDetach: true, - onMaxConnections: function (info /*, originalEvent*/) { - console.log( - "element is ", - info.element, - "maxConnections is", - info.maxConnections - ); - }, - }); - }; - - /** - * Bind target node events for edge tool - */ - this.makeTarget = () => { - _$node.addClass("target"); - window.jsPlumbInstance.addEndpoint(_$node.get(0), { - target: true, - endpoint: { - type: "Rectangle", - options: { - width: _$node.width() + 50, - height: _$node.height() + 50, - }, - }, - uuid: id + "_ept1", - paintStyle: { fill: "transparent" }, - anchor: AnchorLocations.Center, - uniqueEndpoint: false, - //maxConnections:1, - deleteOnEmpty: true, - onMaxConnections: function (info /*, originalEvent*/) { - console.log( - "user tried to drop connection", - info.connection, - "on element", - info.element, - "with max connections", - info.maxConnections - ); - }, - }); - - //local user wants to create an edge selected from the pallette - window.jsPlumbInstance.bind("beforeDrop", function (info) { - var allConn = window.jsPlumbInstance.getConnections({ - target: info.targetId, - source: info.sourceId, - }); - var length = allConn.length; - //if true => Detected a duplicated edge - if (length > 0) return false; //don't create the edge - else return true; //no duplicate create the edge - }); - }; - - /** - * Unbind events for edge tool - */ - this.unbindEdgeToolEvents = function () { - try { - _$node.removeClass("source target"); - jsPlumbInstance.getEndpoints(_$node.get(0)).forEach((endpoint) => { - // We need to remove the endpoint that was created to enable node connection by dragging - // since we are not using the edge tool anymore - if (endpoint.connections.length === 0) { - jsPlumbInstance.deleteEndpoint(endpoint); - } - }); - } catch (error) { - console.error(error); - } - }; - - /** - * Get JSON representation of the node - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractNode.prototype.toJSON.call(this); - json.type = type; - return json; - }; - - /** - * set a new shape for the node - * @param $shape - */ - this.set$shape = function ($shape) { - _$template.remove(); - var _$shape = $shape.clone(); - - var attributes = that.getAttributes(); - for (var attrKey in attributes) { - if (attributes.hasOwnProperty(attrKey)) { - var attribute = attributes[attrKey]; - var $tmp = _$shape.find("." + attribute.getName().toLowerCase()); - if ($tmp.length > 0) { - //initialize the value again - if (attribute.getValue().hasOwnProperty("init")) - attribute.getValue().init(); - $tmp.append(attribute.get$node()); - break; - } - } - } - _$template = _$shape; - _$node.append(_$shape); - }; - - this.get$node = function () { - return _$node; - }; - - init(); - - this.registerYMap = function () { - AbstractNode.prototype.registerYMap.call(this); - var labelAttr = that.getLabel(); - if (labelAttr) labelAttr.registerYType(); - var attr = that.getAttributes(); - for (var key in attr) { - if (attr.hasOwnProperty(key)) { - var val = attr[key].getValue(); - if (val.hasOwnProperty("registerYType")) { - val.registerYType(); - } - } - } - }; - } - nodeSelector; - /** - * Get the jquery shape object from the node type - * @static - * @returns {*} - */ - static get$shape() { - return $shape; - } - /** - * Get the anchors of the node type - * @static - * @returns {*} - */ - static getAnchors() { - return anchors; - } - static getAttributes() { - return attributes; - } - } - - return Node; -} - -/** - * AbstractNode - * @class canvas_widget.AbstractNode - * @extends canvas_widget.AbstractEntity - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of node - * @param {string} type Type of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {boolean} containment containment - * @param {number} zIndex Position of node on z-axis - */ - -/** - * ObjectNode - * @class canvas_widget.ObjectNode - * @extends canvas_widget.AbstractNode - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {number} zIndex Position of node on z-axis - */ -class ObjectNode extends AbstractNode { - static TYPE = "Object"; - static DEFAULT_WIDTH = 150; - static DEFAULT_HEIGHT = 100; - constructor(id, left, top, width, height, zIndex, json, y) { - super(id, ObjectNode.TYPE, left, top, width, height, zIndex, json, y); - var that = this; - - /** - * jQuery object of node template - * @type {jQuery} - * @private - */ - var _$template = $(lodash.template(objectNodeHtml)({ type: that.getType() })); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = AbstractNode.prototype.get$node - .call(this) - .append(_$template) - .addClass("object"); - - /** - * jQuery object of DOM node representing the attributes - * @type {jQuery} - * @private - */ - var _$attributeNode = _$node.find(".attributes"); - - /** - * Attributes of node - * @type {Object} - * @private - */ - var _attributes = this.getAttributes(); - - /** - * Get JSON representation of the node - * @returns {Object} - */ - this.toJSON = function () { - return AbstractNode.prototype.toJSON.call(this); - }; - var attr = new KeySelectionValueListAttribute( - "[attributes]", - "Attributes", - this, - { - string: "String", - boolean: "Boolean", - integer: "Integer", - file: "File", - quiz: "Questions", - } - ); - this.addAttribute(attr); - - this.registerYMap = function () { - AbstractNode.prototype.registerYMap.call(this); - that.getLabel().getValue().registerYType(); - attr.registerYMap(); - }; - - _$node.find(".label").append(this.getLabel().get$node()); - - for (var attributeKey in _attributes) { - if (_attributes.hasOwnProperty(attributeKey)) { - _$attributeNode.append(_attributes[attributeKey].get$node()); - } - } - - this.unregisterCallbacks = function () { - that.getAttribute("[attributes]").unregisterCallbacks(); - }; - - this.setContextMenuItemCallback(function () { - return { - addShape: { - name: "Add Node Shape", - callback: function () { - var canvas = that.getCanvas(), - appearance = that.getAppearance(); - - //noinspection JSAccessibilityCheck - const id = canvas.createNode( - NodeShapeNode.TYPE, - appearance.left + appearance.width + 50, - appearance.top, - 150, - 100 - ); - canvas.createEdge( - BiDirAssociationEdge.TYPE, - that.getEntityId(), - id - ); - }, - disabled: function () { - var edges = that.getEdges(), - edge, - edgeId; - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if ( - (edge instanceof BiDirAssociationEdge && - ((edge.getTarget() === that && - edge.getSource() instanceof NodeShapeNode) || - (edge.getSource() === that && - edge.getTarget() instanceof NodeShapeNode))) || - (edge instanceof UniDirAssociationEdge && - edge.getTarget() instanceof NodeShapeNode) - ) { - return true; - } - } - } - return false; - }, - }, - sepConvertTo: "---------", - convertTo: { - name: "Convert to..", - items: { - abstractClassNode: { - name: "..Abstract Class", - callback: function () { - var canvas = that.getCanvas(), - appearance = that.getAppearance(), - nodeId; - - //noinspection JSAccessibilityCheck - nodeId = canvas.createNode( - AbstractClassNode.TYPE, - appearance.left, - appearance.top, - appearance.width, - appearance.height, - that.getZIndex(), - that.toJSON() - ); - var edges = that.getOutgoingEdges(), - edge, - edgeId; - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - canvas.createEdge( - edge.getType(), - nodeId, - edge.getTarget().getEntityId(), - edge.toJSON() - ); - } - } - - edges = that.getIngoingEdges(); - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if (edge.getSource() !== edge.getTarget()) { - canvas.createEdge( - edge.getType(), - edge.getSource().getEntityId(), - nodeId, - edge.toJSON() - ); - } - } - } - - that.triggerDeletion(); - }, - }, - relationshipNode: { - name: "..Relationship", - callback: function () { - var canvas = that.getCanvas(), - appearance = that.getAppearance(), - nodeId; - - //noinspection JSAccessibilityCheck - nodeId = canvas.createNode( - RelationshipNode.TYPE, - appearance.left, - appearance.top, - appearance.width, - appearance.height, - that.getZIndex(), - that.toJSON() - ); - var edges = that.getOutgoingEdges(), - edge, - edgeId; - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - canvas.createEdge( - edge.getType(), - nodeId, - edge.getTarget().getEntityId(), - edge.toJSON() - ); - } - } - - edges = that.getIngoingEdges(); - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if (edge.getSource() !== edge.getTarget()) { - canvas.createEdge( - edge.getType(), - edge.getSource().getEntityId(), - nodeId, - edge.toJSON() - ); - } - } - } - - that.triggerDeletion(); - }, - }, - relationshipGroupNode: { - name: "..Relationship Group", - callback: function () { - var canvas = that.getCanvas(), - appearance = that.getAppearance(), - nodeId; - - //noinspection JSAccessibilityCheck - nodeId = canvas.createNode( - RelationshipGroupNode.TYPE, - appearance.left, - appearance.top, - appearance.width, - appearance.height, - that.getZIndex(), - that.toJSON() - ); - var edges = that.getOutgoingEdges(), - edge, - edgeId; - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - canvas.createEdge( - edge.getType(), - nodeId, - edge.getTarget().getEntityId(), - edge.toJSON() - ); - } - } - - edges = that.getIngoingEdges(); - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if (edge.getSource() !== edge.getTarget()) { - canvas.createEdge( - edge.getType(), - edge.getSource().getEntityId(), - nodeId, - edge.toJSON() - ); - } - } - } - - that.triggerDeletion(); - }, - }, - }, - }, - sep: "---------", - }; - }); - } -} - -/** - * Abstract Class Node - * @class canvas_widget.AbstractClassNode - * @extends canvas_widget.AbstractNode - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {number} zIndex Position of node on z-axis - */ -class AbstractClassNode extends AbstractNode { - static TYPE = "Abstract Class"; - static DEFAULT_WIDTH = 150; - static DEFAULT_HEIGHT = 100; - - constructor(id, left, top, width, height, zIndex, json) { - super(id, AbstractClassNode.TYPE, left, top, width, height, zIndex, json); - - var that = this; - - /** - * jQuery object of node template - * @type {jQuery} - * @private - */ - var _$template = $( - lodash.template(abstractClassNodeHtml)({ type: that.getType() }) - ); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = AbstractNode.prototype.get$node - .call(this) - .append(_$template) - .addClass("class"); - - /** - * jQuery object of DOM node representing the attributes - * @type {jQuery} - * @private - */ - var _$attributeNode = _$node.find(".attributes"); - - /** - * Attributes of node - * @type {Object} - * @private - */ - var _attributes = this.getAttributes(); - - /** - * Get JSON representation of the node - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractNode.prototype.toJSON.call(this); - json.type = AbstractClassNode.TYPE; - return json; - }; - - var attr = new KeySelectionValueListAttribute( - "[attributes]", - "Attributes", - this, - { - string: "String", - boolean: "Boolean", - integer: "Integer", - file: "File", - quiz: "Questions", - } - ); - this.addAttribute(attr); - - this.registerYMap = function () { - AbstractNode.prototype.registerYMap.call(this); - that.getLabel().getValue().registerYType(); - attr.registerYMap(); - }; - - this.unregisterCallbacks = function () { - that.getAttribute("[attributes]").unregisterCallbacks(); - }; - - _$node.find(".label").append(this.getLabel().get$node()); - - for (var attributeKey in _attributes) { - if (_attributes.hasOwnProperty(attributeKey)) { - _$attributeNode.append(_attributes[attributeKey].get$node()); - } - } - - this.setContextMenuItemCallback(function () { - return { - convertTo: { - name: "Convert to..", - items: { - objectNode: { - name: "..Object", - callback: function () { - var canvas = that.getCanvas(), - appearance = that.getAppearance(), - nodeId; - - //noinspection JSAccessibilityCheck - nodeId = canvas.createNode( - ObjectNode.TYPE, - appearance.left, - appearance.top, - appearance.width, - appearance.height, - that.getZIndex(), - that.getContainment(), - that.toJSON() - ); - var edges = that.getOutgoingEdges(), - edge, - edgeId; - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - canvas.createEdge( - edge.getType(), - nodeId, - edge.getTarget().getEntityId(), - edge.toJSON() - ); - } - } - - edges = that.getIngoingEdges(); - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if (edge.getSource() !== edge.getTarget()) { - canvas.createEdge( - edge.getType(), - edge.getSource().getEntityId(), - nodeId, - edge.toJSON() - ); - } - } - } - - that.triggerDeletion(); - }, - }, - relationshipNode: { - name: "..Relationship", - callback: function () { - var canvas = that.getCanvas(), - appearance = that.getAppearance(), - nodeId; - - //noinspection JSAccessibilityCheck - nodeId = canvas.createNode( - RelationshipNode.TYPE, - appearance.left, - appearance.top, - appearance.width, - appearance.height, - that.getZIndex(), - that.getContainment(), - that.toJSON() - ); - var edges = that.getOutgoingEdges(), - edge, - edgeId; - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - canvas.createEdge( - edge.getType(), - nodeId, - edge.getTarget().getEntityId(), - edge.toJSON() - ); - } - } - - edges = that.getIngoingEdges(); - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if (edge.getSource() !== edge.getTarget()) { - canvas.createEdge( - edge.getType(), - edge.getSource().getEntityId(), - nodeId, - edge.toJSON() - ); - } - } - } - - that.triggerDeletion(); - }, - }, - relationshipGroupNode: { - name: "..Relationship Group", - callback: function () { - var canvas = that.getCanvas(), - appearance = that.getAppearance(), - nodeId; - - //noinspection JSAccessibilityCheck - nodeId = canvas.createNode( - RelationshipGroupNode.TYPE, - appearance.left, - appearance.top, - appearance.width, - appearance.height, - that.getZIndex(), - that.getContainment(), - that.toJSON() - ); - var edges = that.getOutgoingEdges(), - edge, - edgeId; - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - canvas.createEdge( - edge.getType(), - nodeId, - edge.getTarget().getEntityId(), - edge.toJSON() - ); - } - } - - edges = that.getIngoingEdges(); - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if (edge.getSource() !== edge.getTarget()) { - canvas.createEdge( - edge.getType(), - edge.getSource().getEntityId(), - nodeId, - edge.toJSON() - ); - } - } - } - - that.triggerDeletion(); - }, - }, - }, - }, - sep: "---------", - }; - }); - } -} - -/** - * RelationshipNode - * @class canvas_widget.RelationshipNode - * @extends canvas_widget.AbstractNode - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {number} zIndex Position of node on z-axis - */ -class RelationshipNode extends AbstractNode { - static TYPE = "Relationship"; - static DEFAULT_WIDTH = 150; - static DEFAULT_HEIGHT = 100; - - constructor(id, left, top, width, height, zIndex, json) { - super(id, "Relationship", left, top, width, height, zIndex, json); - var that = this; - - /** - * jQuery object of node template - * @type {jQuery} - * @private - */ - var _$template = $( - lodash.template(relationshipNodeHtml)({ type: that.getType() }) - ); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var $node = AbstractNode.prototype.get$node - .call(this) - .append(_$template) - .addClass("relation"); - - /** - * jQuery object of DOM node representing the attributes - * @type {jQuery} - * @private - */ - var _$attributeNode = $node.find(".attributes"); - - /** - * Attributes of node - * @type {Object} - * @private - */ - var _attributes = this.getAttributes(); - - /** - * Get JSON representation of the node - * @returns {Object} - */ - this.toJSON = function () { - return AbstractNode.prototype.toJSON.call(this); - }; - - var attr = new KeySelectionValueSelectionValueListAttribute( - "[attributes]", - "Attributes", - this, - { - string: "String", - boolean: "Boolean", - integer: "Integer", - file: "File", - }, - { hidden: "Hide", top: "Top", center: "Center", bottom: "Bottom" } - ); - this.addAttribute(attr); - - this.registerYMap = function () { - AbstractNode.prototype.registerYMap.call(this); - that.getLabel().getValue().registerYType(); - attr.registerYMap(); - }; - - this.unregisterCallbacks = function () { - that.getAttribute("[attributes]").unregisterCallbacks(); - }; - - $node.find(".label").append(this.getLabel().get$node()); - - for (var attributeKey in _attributes) { - if (_attributes.hasOwnProperty(attributeKey)) { - _$attributeNode.append(_attributes[attributeKey].get$node()); - } - } - - this.setContextMenuItemCallback(function () { - return { - addShape: { - name: "Add Edge Shape", - callback: function () { - var canvas = that.getCanvas(), - appearance = that.getAppearance(); - - //noinspection JSAccessibilityCheck - canvas - .createNode( - EdgeShapeNode.TYPE, - appearance.left + appearance.width + 50, - appearance.top, - 150, - 100 - ) - .done(function (nodeId) { - canvas.createEdge( - BiDirAssociationEdge.TYPE, - that.getEntityId(), - nodeId - ); - }); - }, - disabled: function () { - var edges = that.getEdges(), - edge, - edgeId; - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if ( - (edge instanceof BiDirAssociationEdge && - ((edge.getTarget() === that && - edge.getSource() instanceof EdgeShapeNode) || - (edge.getSource() === that && - edge.getTarget() instanceof EdgeShapeNode))) || - (edge instanceof UniDirAssociationEdge && - edge.getTarget() instanceof EdgeShapeNode) - ) { - return true; - } - } - } - return false; - }, - }, - sepConvertTo: "---------", - convertTo: { - name: "Convert to..", - items: { - abstractNode: { - name: "..Abstract Class Node", - callback: function () { - var canvas = that.getCanvas(), - appearance = that.getAppearance(), - nodeId; - - //noinspection JSAccessibilityCheck - nodeId = canvas.createNode( - AbstractClassNode.TYPE, - appearance.left, - appearance.top, - appearance.width, - appearance.height, - that.getZIndex(), - that.toJSON() - ); - var edges = that.getOutgoingEdges(), - edge, - edgeId; - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - canvas.createEdge( - edge.getType(), - nodeId, - edge.getTarget().getEntityId(), - edge.toJSON() - ); - } - } - - edges = that.getIngoingEdges(); - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if (edge.getSource() !== edge.getTarget()) { - canvas.createEdge( - edge.getType(), - edge.getSource().getEntityId(), - nodeId, - edge.toJSON() - ); - } - } - } - - that.triggerDeletion(); - }, - }, - objectNode: { - name: "..Object Node", - callback: function () { - var canvas = that.getCanvas(), - appearance = that.getAppearance(), - nodeId; - - //noinspection JSAccessibilityCheck - nodeId = canvas.createNode( - ObjectNode.TYPE, - appearance.left, - appearance.top, - appearance.width, - appearance.height, - that.getZIndex(), - that.toJSON() - ); - var edges = that.getOutgoingEdges(), - edge, - edgeId; - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - canvas.createEdge( - edge.getType(), - nodeId, - edge.getTarget().getEntityId(), - edge.toJSON() - ); - } - } - - edges = that.getIngoingEdges(); - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if (edge.getSource() !== edge.getTarget()) { - canvas.createEdge( - edge.getType(), - edge.getSource().getEntityId(), - nodeId, - edge.toJSON() - ); - } - } - } - - that.triggerDeletion(); - }, - }, - relationshipGroupNode: { - name: "..Relationship Group", - callback: function () { - var canvas = that.getCanvas(), - appearance = that.getAppearance(), - nodeId; - - //noinspection JSAccessibilityCheck - nodeId = canvas.createNode( - RelationshipGroupNode.TYPE, - appearance.left, - appearance.top, - appearance.width, - appearance.height, - that.getZIndex(), - that.toJSON() - ); - var edges = that.getOutgoingEdges(), - edge, - edgeId; - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - canvas.createEdge( - edge.getType(), - nodeId, - edge.getTarget().getEntityId(), - edge.toJSON() - ); - } - } - - edges = that.getIngoingEdges(); - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if (edge.getSource() !== edge.getTarget()) { - canvas.createEdge( - edge.getType(), - edge.getSource().getEntityId(), - nodeId, - edge.toJSON() - ); - } - } - } - - that.triggerDeletion(); - }, - }, - }, - }, - sep: "---------", - }; - }); - } -} - -/** - * Abstract Class Node - * @class canvas_widget.EdgeShapeNode - * @extends canvas_widget.AbstractNode - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {number} zIndex Position of node on z-axis - */ -class EdgeShapeNode extends AbstractNode { - static TYPE = "Edge Shape"; - static DEFAULT_WIDTH = 150; - static DEFAULT_HEIGHT = 150; - - constructor(id, left, top, width, height, zIndex, json) { - super(id, EdgeShapeNode.TYPE, left, top, width, height, zIndex, json); - var that = this; - - /** - * jQuery object of node template - * @type {jQuery} - * @private - */ - var _$template = $(lodash.template(edgeShapeNodeHtml)({ type: that.getType() })); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = AbstractNode.prototype.get$node - .call(this) - .append(_$template) - .addClass("class"); - - /** - * jQuery object of DOM node representing the attributes - * @type {jQuery} - * @private - */ - var _$attributeNode = _$node.find(".attributes"); - - /** - * Attributes of node - * @type {Object} - * @private - */ - var _attributes = this.getAttributes(); - - /** - * Get JSON representation of the node - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractNode.prototype.toJSON.call(this); - json.type = EdgeShapeNode.TYPE; - return json; - }; - - var attrArrow = new SingleSelectionAttribute( - this.getEntityId() + "[arrow]", - "Arrow", - this, - { - bidirassociation: "---", - unidirassociation: "-->", - generalisation: "--▷", - diamond: "-◁▷", - } - ); - var attrShape = new SingleSelectionAttribute( - this.getEntityId() + "[shape]", - "Shape", - this, - { straight: "Straight", curved: "Curved", segmented: "Segmented" } - ); - var attrColor = new SingleColorValueAttribute( - this.getEntityId() + "[color]", - "Color", - this - ); - var attrOverlay = new SingleValueAttribute( - this.getEntityId() + "[overlay]", - "Overlay Text", - this - ); - var attrOverlayPos = new SingleSelectionAttribute( - this.getEntityId() + "[overlayPosition]", - "Overlay Position", - this, - { hidden: "Hide", top: "Top", center: "Center", bottom: "Bottom" } - ); - var attrOverlayRotate = new BooleanAttribute( - this.getEntityId() + "[overlayRotate]", - "Autoflip Overlay", - this - ); - - this.addAttribute(attrArrow); - this.addAttribute(attrShape); - this.addAttribute(attrColor); - this.addAttribute(attrOverlay); - this.addAttribute(attrOverlayPos); - this.addAttribute(attrOverlayRotate); - - this.registerYMap = function (map, disableYText) { - AbstractNode.prototype.registerYMap.call(this, map); - attrArrow.getValue().registerYType(); - attrShape.getValue().registerYType(); - attrOverlayPos.getValue().registerYType(); - attrOverlayRotate.getValue().registerYType(); - that.getLabel().getValue().registerYType(); - attrColor.getValue().registerYType(); - attrOverlay.getValue().registerYType(); - }; - - _$node.find(".label").append(this.getLabel().get$node()); - - for (var attributeKey in _attributes) { - if (_attributes.hasOwnProperty(attributeKey)) { - _$attributeNode.append(_attributes[attributeKey].get$node()); - } - } - } -} - -/** - * makeEdge - * @class canvas_widget.makeEdge - * @memberof canvas_widget - * @constructor - * @param {string} type Type of edge - * @param arrowType - * @param shapeType - * @param color - * @param dashstyle - * @param overlay - * @param overlayPosition - * @param overlayRotate - * @param attributes - * @returns {Edge} - */ -function makeEdge( - type, - arrowType, - shapeType, - color, - dashstyle, - overlay, - overlayPosition, - overlayRotate, - attributes -) { - var shape = shapes.hasOwnProperty(shapeType) - ? shapes[shapeType] - : lodash.values(shapes)[0]; - color = color - ? $colorTestElement.css("color", "#000000").css("color", color).css("color") - : "#000000"; - - /** - * Edge - * @class canvas_widget.Edge - * @extends canvas_widget.AbstractEdge - * @constructor - * @param {string} id Entity identifier of edge - * @param {canvas_widget.AbstractNode} source Source node - * @param {canvas_widget.AbstractNode} target Target node - */ - class Edge extends AbstractEdge { - constructor(id, source, target) { - super(id, type, source, target, overlayRotate); - var that = this; - - var currentViewType = null; - - /** - * Set the currently applied view type - * @param {string} type - */ - this.setCurrentViewType = function (type) { - currentViewType = type; - }; - - /** - * Get the currently applied view type - * @returns {string} the view type - */ - this.getCurrentViewType = function () { - return currentViewType; - }; - - /** - * Stores jsPlumb overlays for the edge - * @type {Array} - */ - var overlays = []; - - /** - * make jsPlumb overlay - * @param text - * @returns {Function} - */ - var makeOverlayFunction = function (text) { - return function () { - return $("
          ").append( - $("
          ") - .addClass("edge_label fixed") - .css("color", color) - .text(text) - ); - }; - }; - - /** - * make a jsPlumb overlay for a attribute - * @param attribute - * @returns {Function} - */ - var makeAttributeOverlayFunction = function (attribute) { - return function () { - const $node = $("
          ").append( - $("
          ").addClass("edge_label").append(attribute.get$node()) - ); - return $node.get(0); - }; - }; - var init = function () { - var attribute, attributeId, attrObj; - - if (Arrows().hasOwnProperty(arrowType)) { - overlays.push(Arrows(color)[arrowType]); - } - - if (overlay) { - switch (overlayPosition) { - case "top": - overlays.push({ - type: "Custom", - options: { - create: makeOverlayFunction(overlay), - location: 0.9, - id: "label", - }, - }); - break; - case "bottom": - overlays.push({ - type: "Custom", - options: { - create: makeOverlayFunction(overlay), - location: 0.1, - id: "label", - }, - }); - break; - default: - case "center": - overlays.push({ - type: "Custom", - options: { - create: makeOverlayFunction(overlay), - location: 0.5, - id: "label", - }, - }); - break; - } - } - - attrObj = {}; - for (attributeId in attributes) { - if (attributes.hasOwnProperty(attributeId)) { - attribute = attributes[attributeId]; - switch (attribute.value) { - case "boolean": - attrObj[attributeId] = new BooleanAttribute( - id + "[" + attribute.key.toLowerCase() + "]", - attribute.key, - that - ); - break; - case "string": - attrObj[attributeId] = new SingleValueAttribute( - id + "[" + attribute.key.toLowerCase() + "]", - attribute.key, - that - ); - break; - case "integer": - attrObj[attributeId] = new IntegerAttribute( - id + "[" + attribute.key.toLowerCase() + "]", - attribute.key, - that - ); - break; - case "file": - attrObj[attributeId] = new FileAttribute( - id + "[" + attribute.key.toLowerCase() + "]", - attribute.key, - that - ); - break; - default: - if (attribute.options) { - attrObj[attributeId] = new SingleSelectionAttribute( - id + "[" + attribute.key.toLowerCase() + "]", - attribute.key, - that, - attribute.options - ); - } - } - - switch (attribute.position) { - case "top": - overlays.push({ - type: "Custom", - options: { - create: makeAttributeOverlayFunction(attrObj[attributeId]), - location: 1, - id: "label " + attributeId, - }, - }); - break; - case "center": - overlays.push({ - type: "Custom", - options: { - create: makeAttributeOverlayFunction(attrObj[attributeId]), - location: 0.5, - id: "label " + attributeId, - }, - }); - break; - case "bottom": - overlays.push({ - type: "Custom", - options: { - create: makeAttributeOverlayFunction(attrObj[attributeId]), - location: 0, - id: "label " + attributeId, - }, - }); - break; - } - } - } - that.setAttributes(attrObj); - - overlays.push({ - type: "Custom", - options: { - create: function () { - that.get$overlay().hide().find(".type").addClass(shapeType); - return that.get$overlay().get(0); - }, - location: 0.5, - id: "label", - }, - }); - - if (overlay) { - that - .get$overlay() - .find("input[name='Label']") - .css("visibility", "hidden"); - } - - that.setDefaultPaintStyle({ - stroke: color, - strokeWidth: 4, - }); - }; - - /** - * Connect source and target node and draw the edge on canvas - */ - this.connect = function () { - var source = this.getSource(); - var target = this.getTarget(); - var connectOptions = { - source: source.get$node().get(0), - target: target.get$node().get(0), - paintStyle: that.getDefaultPaintStyle(), - endpoint: "Dot", - anchors: [source.getAnchorOptions(), target.getAnchorOptions()], - connector: shape, - overlays: overlays, - cssClass: this.getEntityId(), - }; - - if (source === target) { - connectOptions.anchors = ["TopCenter", "LeftMiddle"]; - } - - source.addOutgoingEdge(this); - target.addIngoingEdge(this); - this.setJsPlumbConnection( - window.jsPlumbInstance.connect(connectOptions) - ); - - this.repaintOverlays(); - lodash.each(EntityManagerInstance.getEdges(), function (e) { - e.setZIndex(); - }); - }; - - /** - * Get JSON representation of the edge - * @returns {object} - */ - this.toJSON = function () { - var json = AbstractEdge.prototype.toJSON.call(this); - json.type = type; - return json; - }; - - /** - * restyles the edge - * @param arrowType - * @param color - * @param shapeType - * @param dashstyle - * @param overlay - * @param overlayPosition - * @param overlayRotate - * @param attributes - */ - this.restyle = function ( - arrowType, - color, - shapeType, - dashstyle, - overlay, - overlayPosition, - overlayRotate, - attributes - ) { - overlays = []; - - color = color - ? $colorTestElement - .css("color", "black") - .css("color", color) - .css("color") - : "black"; - - if (Arrows().hasOwnProperty(arrowType)) { - overlays.push(Arrows(color)[arrowType]); - } - - if (overlay) { - switch (overlayPosition) { - case "top": - overlays.push({ - type: "Custom", - options: { - create: makeOverlayFunction(overlay), - location: 0.9, - id: "label", - }, - }); - break; - case "bottom": - overlays.push({ - type: "Custom", - options: { - create: makeOverlayFunction(overlay), - location: 0.1, - id: "label", - }, - }); - break; - default: - case "center": - overlays.push({ - type: "Custom", - options: { - create: makeOverlayFunction(overlay), - location: 0.5, - id: "label", - }, - }); - break; - } - } - - overlays.push({ - type: "Custom", - options: { - create: function () { - that.get$overlay().hide().find(".type").addClass(shapeType); - return that.get$overlay().get(0); - }, - location: 0.5, - id: "label", - }, - }); - - if (overlay) { - that - .get$overlay() - .find("input[name='Label']") - .css("visibility", "hidden"); - } - - for (var attributeId in attributes) { - if (attributes.hasOwnProperty(attributeId)) { - var attribute = attributes[attributeId]; - switch (attribute.position) { - case "top": - overlays.push({ - type: "Custom", - options: { - create: makeAttributeOverlayFunction( - that.getAttribute(attributeId) - ), - location: 1, - id: "label " + attributeId, - }, - }); - break; - case "center": - overlays.push({ - type: "Custom", - options: { - create: makeAttributeOverlayFunction( - that.getAttribute(attributeId) - ), - location: 0.5, - id: "label " + attributeId, - }, - }); - break; - case "bottom": - overlays.push({ - type: "Custom", - options: { - create: makeAttributeOverlayFunction( - that.getAttribute(attributeId) - ), - location: 0, - id: "label " + attributeId, - }, - }); - break; - } - } - } - - var paintStyle = { - strokeStyle: color, - lineWidth: 2, - dashstyle: dashstyle, - }; - - that.setDefaultPaintStyle(paintStyle); - that.setRotateOverlay(overlayRotate); - - if (that.getJsPlumbConnection()) { - //if the edge is drawn on the canvas - that.getJsPlumbConnection().removeAllOverlays(); - for (var i = 0; i < overlays.length; i++) { - that.getJsPlumbConnection().addOverlay(overlays[i]); - } - that.getJsPlumbConnection().setPaintStyle(paintStyle); - that.repaintOverlays(); - } - }; - - this.registerYMap = function () { - AbstractEdge.prototype.registerYMap.call(this); - - var attr = that.getAttributes(); - for (var key in attr) { - if (attr.hasOwnProperty(key)) { - var val = attr[key].getValue(); - if (val.hasOwnProperty("registerYType")) { - val.registerYType(); - } - } - } - }; - - init(); - } - /** - * Get the arrow type of the edge type - * @static - * @returns {*} - */ - static getArrowType() { - return arrowType; - } - /** - * Get the shape type of the edge type - * @static - * @returns {*} - */ - static getShapeType() { - return shapeType; - } - /** - * Get the color of the edge type - * @static - * @returns {*} - */ - static getShape() { - return shape; - } - static getColor() { - return color; - } - /** - * Get the overlay of the edge type - * @static - * @returns {*} - */ - static getOverlay() { - return overlay; - } - /** - * Get the overlay position of the edge type - * @static - * @returns {*} - */ - static getOverlayPosition() { - return overlayPosition; - } - /** - * Get the overlay rotate of the edge type - * @static - * @returns {*} - */ - static getOverlayRotate() { - return overlayRotate; - } - /** - * Get the attribute definition of the edge type - * @static - * @returns {*} - */ - static getAttributes() { - return attributes; - } - static getType() { - return type; - } - static getArrowOverlays() { - var overlays = []; - if (Arrows().hasOwnProperty(arrowType)) { - overlays.push(Arrows(color)[arrowType]); - } - return overlays; - } - } - - return Edge; -} - -/** - * AbstractNode - * @class canvas_widget.AbstractNode - * @extends canvas_widget.AbstractEntity - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of node - * @param {string} type Type of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {boolean} containment containment - * @param {number} zIndex Position of node on z-axis - */ - -/** - * Abstract Class Node - * @class canvas_widget.RelationshipGroupNode - * @extends canvas_widget.AbstractNode - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {number} zIndex Position of node on z-axis - */ -class RelationshipGroupNode extends AbstractNode { - static TYPE = "Relation"; - static DEFAULT_WIDTH = 150; - static DEFAULT_HEIGHT = 100; - constructor(id, left, top, width, height, zIndex) { - super(id, RelationshipGroupNode.TYPE, left, top, width, height, zIndex); - var that = this; - - /** - * jQuery object of node template - * @type {jQuery} - * @private - */ - var _$template = $( - lodash.template(relationshipGroupNodeHtml)({ type: that.getType() }) - ); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = AbstractNode.prototype.get$node - .call(this) - .append(_$template) - .addClass("class"); - - /** - * jQuery object of DOM node representing the attributes - * @type {jQuery} - * @private - */ - var _$attributeNode = _$node.find(".attributes"); - - /** - * Attributes of node - * @type {Object} - * @private - */ - var _attributes = this.getAttributes(); - - /** - * Get JSON representation of the node - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractNode.prototype.toJSON.call(this); - json.type = RelationshipGroupNode.TYPE; - return json; - }; - - this.registerYMap = function () { - AbstractNode.prototype.registerYMap.call(this); - that.getLabel().getValue().registerYType(); - }; - - _$node.find(".label").append(this.getLabel().get$node()); - - for (var attributeKey in _attributes) { - if (_attributes.hasOwnProperty(attributeKey)) { - _$attributeNode.append(_attributes[attributeKey].get$node()); - } - } - } -} - -/** - * SelectionValue - * @class canvas_widget.SelectionValue - * @extends canvas_widget.AbstractValue - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier - * @param {string} name Name of attribute - * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {canvas_widget.AbstractNode|canvas_widget.AbstractEdge} rootSubjectEntity Topmost entity in the chain of entity the attribute is assigned to - * @param {Object} options Selection options - */ -class SelectionValue extends AbstractValue { - constructor( - id, - name, - subjectEntity, - rootSubjectEntity, - options, - useAttributeHtml - ) { - super(id, name, subjectEntity, rootSubjectEntity); - - var that = this; - - useAttributeHtml = - typeof useAttributeHtml !== "undefinded" ? useAttributeHtml : false; - - /** - * Value - * @type {string} - * @private - */ - var _value = lodash.keys(options)[0]; - - if (useAttributeHtml) { - selectionValueHtml = attributeSelectionValueHtml; - } - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = $( - lodash.template(selectionValueHtml)({ - name: name, - options: options, - }) - ); - - if (useAttributeHtml) { - _$node.off(); - } - - /** - * Inter widget communication wrapper - * @type {Object} - * @private - */ - y = y || window.y; - var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); - - /** - * Apply a Value Change Operation - * @param {operations.ot.ValueChangeOperation} operation - */ - var processValueChangeOperation = function (operation) { - that.setValue(operation.getValue()); - }; - - /** - * Set value - * @param {string} value - */ - this.setValue = function (value) { - _value = value; - if (useAttributeHtml) { - _$node.val(value); - if (value == "Quiz") { - Object.values(rootSubjectEntity.getAttributes()).forEach((value) => { - if (value instanceof QuizAttribute) { - value.showTable(); - } - }); - } else - Object.values(rootSubjectEntity.getAttributes()).forEach((value) => { - if (value instanceof QuizAttribute) { - value.hideTable(); - } - }); - } else _$node.text(options[value]); - }; - - /** - * Get value - * @returns {string} - */ - this.getValue = function () { - return _value; - }; - - /** - * Get jQuery object of DOM node representing the value - * @returns {jQuery} - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the edge - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractValue.prototype.toJSON.call(this); - json.value = _value; - return json; - }; - - /** - * Set value by its JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - this.setValue(json.value); - }; - - this.registerYType = function () { - //observer - that - .getRootSubjectEntity() - .getYMap() - .observeDeep(function ([event]) { - const array = Array.from(event.changes.keys.entries()); - array.forEach(([key, change]) => { - const updated = event.currentTarget.get(key); - if ( - updated?.type !== "update" || - !(updated?.entityId === that.getEntityId()) - ) - return; - var operation = new ValueChangeOperation( - updated.entityId, - updated.value, - updated.type, - updated.position, - updated.jabberId - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.getOTOperation() - ); - processValueChangeOperation(operation); - - //Only the local user Propagates the activity and saves the state of the model - if ( - _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID] === - operation.getJabberId() - ) { - const activityMap = y.getMap("activity"); - - activityMap.set( - ActivityOperation.TYPE, - new ActivityOperation( - "ValueChangeActivity", - that.getEntityId(), - _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], - ValueChangeOperation.getOperationDescription( - that.getSubjectEntity().getName(), - that.getRootSubjectEntity().getType(), - that.getRootSubjectEntity().getLabel().getValue().getValue() - ), - { - value: operation.getValue(), - subjectEntityName: that.getSubjectEntity().getName(), - rootSubjectEntityType: that - .getRootSubjectEntity() - .getType(), - rootSubjectEntityId: that - .getRootSubjectEntity() - .getEntityId(), - } - ).toJSON() - ); - - //its a view type and create a reference to the origin - if (updated.entityId.indexOf("[target]") != -1) { - ViewTypesUtil.createReferenceToOrigin( - that.getRootSubjectEntity() - ); - //CVG - Promise.resolve().then(function () { return ClosedViewGeneration; }).then(function (CVG) { - CVG(rootSubjectEntity); - }); - } - //trigger the save - EntityManagerInstance.storeDataYjs(); - } else { - //the remote users propagtes the change to their local attribute widget - //TODO(PENDING): can be replaced with yjs as well - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.ATTRIBUTE, - operation.getOTOperation() - ); - } - }); - }); - }; - } -} - -/** - * IntegerAttribute - * @class canvas_widget.IntegerAttribute - * @extends canvas_widget.AbstractAttribute - * @memberof canvas_widget - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to - */ -class IntegerAttribute extends AbstractAttribute { - constructor(id, name, subjectEntity, useAttributeHtml) { - super(id, name, subjectEntity); - useAttributeHtml = - typeof useAttributeHtml !== "undefined" ? useAttributeHtml : false; - - /*** - * Value object of value - * @type {canvas_widget.IntegerValue} - * @private - */ - var _value = new IntegerValue( - id, - name, - this, - this.getRootSubjectEntity(), - useAttributeHtml - ); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(integerAttributeHtml)()); - - /** - * Set Value object of value - * @param {canvas_widget.IntegerValue} value - */ - this.setValue = function (value) { - _value = value; - _$node.val(value); - }; - - /** - * Get Value object of value - * @return {canvas_widget.IntegerValue} value - */ - this.getValue = function () { - return _value; - }; - - /** - * jQuery object of DOM node representing the attribute - * @type {jQuery} - * @private - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the attribute - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.value = _value.toJSON(); - return json; - }; - - /** - * Set attribute value by its JSON representation - * @param {Object} json - */ - this.setValueFromJSON = function (json) { - _value.setValueFromJSON(json.value); - }; - - _$node.find(".name").text(this.getName()); - _$node.find(".value").append(_value.get$node()); - } -} - -/** - * SingleSelectionAttribute - * @class canvas_widget.SingleSelectionAttribute - * @extends canvas_widget.AbstractAttribute - * @memberof canvas_widget - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {Object} options Selection options as key value object - */ - -class SingleSelectionAttribute extends AbstractAttribute { - constructor(id, name, subjectEntity, options, useAttributeHtml) { - super(id, name, subjectEntity); - useAttributeHtml = - typeof useAttributeHtml !== "undefinded" ? useAttributeHtml : false; - var that = this; - /*** - * Value object of value - * @type {canvas_widget.SelectionValue} - * @private - */ - var _value = new SelectionValue( - id, - name, - this, - this.getRootSubjectEntity(), - options, - useAttributeHtml - ); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(singleSelectionAttributeHtml)()); - - /** - * Set Value object of value - * @param {canvas_widget.SelectionValue} value - */ - this.setValue = function (value) { - _value = value; - _$node.val(value); - }; - - /** - * Get Value object of value - * @return {canvas_widget.SelectionValue} value - */ - this.getValue = function () { - return _value; - }; - - /** - * jQuery object of DOM node representing the attribute - * @type {jQuery} - * @private - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get the options object for the Attribute - * @returns {Object} - */ - this.getOptionValue = function () { - return options.hasOwnProperty(_value.getValue()) - ? options[_value.getValue()] - : null; - }; - - /** - * Get JSON representation of the attribute - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.value = _value.toJSON(); - json.option = that.getOptionValue(); - return json; - }; - - this.getOptions = function () { - return options; - }; - - /** - * Set attribute value by its JSON representation - * @param {Object} json - */ - this.setValueFromJSON = function (json) { - _value.setValueFromJSON(json.value); - }; - - _$node.find(".name").text(this.getName()); - _$node.find(".value").append(_value.get$node()); - } -} - -/** - * IntegerValue - * @class canvas_widget.IntegerValue - * @extends canvas_widget.AbstractValue - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier - * @param {string} name Name of attribute - * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {canvas_widget.AbstractNode|canvas_widget.AbstractEdge} rootSubjectEntity Topmost entity in the chain of entity the attribute is assigned to - */ -class IntegerValue extends AbstractValue { - constructor(id, name, subjectEntity, rootSubjectEntity, useAttributeHtml) { - super(id, name, subjectEntity, rootSubjectEntity); - var that = this; - - if (useAttributeHtml) integerValueHtml = attributeIntegerValueHtml; - - /** - * Value - * @type {number} - * @private - */ - var _value = 0; - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(integerValueHtml)({ value: _value })); - - /** - * Inter widget communication wrapper - * @type {Object} - * @private - */ - y = y || window.y; - var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); - - /** - * Apply a Value Change Operation - * @param {operations.ot.ValueChangeOperation} operation - */ - var processValueChangeOperation = function (operation) { - that.setValue(operation.getValue()); - }; - - var init = function () { - _$node.off(); - }; - - /** - * Set value - * @param {number} value - */ - this.setValue = function (value) { - _value = value; - if (useAttributeHtml) _$node.val(value); - else _$node.text(value); - }; - - /** - * Get value - * @returns {number} - */ - this.getValue = function () { - return _value; - }; - - /** - * Get jQuery object of DOM node representing the value - * @returns {jQuery} - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the edge - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractValue.prototype.toJSON.call(this); - json.value = _value; - return json; - }; - - /** - * Set value by its JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - this.setValue(json?.value); - }; - - this.registerYType = function () { - //observer - that - .getRootSubjectEntity() - .getYMap() - .observe(function (event) { - const array = Array.from(event.changes.keys.entries()); - array.forEach(([key, change]) => { - if (change.action !== "update") return; - // check if key is the entity id - if (key !== that.getEntityId()) return; - const data = event.target.get(key); - var operation = new ValueChangeOperation( - data.entityId, - data.value, - data.type, - data.position, - data.jabberId - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.getOTOperation() - ); - processValueChangeOperation(operation); - - //Only the local user Propagates the activity - if ( - _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID] === - operation.getJabberId() - ) { - EntityManagerInstance.storeDataYjs(); - const activityMap = y.getMap("activity"); - - activityMap.set( - ActivityOperation.TYPE, - new ActivityOperation( - "ValueChangeActivity", - that.getEntityId(), - _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], - ValueChangeOperation.getOperationDescription( - that.getSubjectEntity().getName(), - that.getRootSubjectEntity().getType(), - that.getRootSubjectEntity().getLabel().getValue().getValue() - ), - { - value: operation.getValue(), - subjectEntityName: that.getSubjectEntity().getName(), - rootSubjectEntityType: that - .getRootSubjectEntity() - .getType(), - rootSubjectEntityId: that - .getRootSubjectEntity() - .getEntityId(), - } - ).toJSON() - ); - } else { - //the remote users propagtes the change to their local attribute widget - //TODO(PENDING): can be replaced with yjs as well - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.ATTRIBUTE, - operation.getOTOperation() - ); - } - }); - }); - }; - - init(); - } -} - -/** - * SingleValueAttribute - * @class canvas_widget.SingleValueAttribute - * @extends canvas_widget.AbstractAttribute - * @memberof canvas_widget - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to - */ -class SingleValueAttribute extends AbstractAttribute { - value; - constructor(id, name, subjectEntity, y) { - y = y || window.y; - if (!y) { - throw new Error("y is undefined"); - } - super(id, name, subjectEntity); - - /*** - * Value object of value - * @type {canvas_widget.Value} - * @private - */ - var _value = new Value(id, name, this, this.getRootSubjectEntity(), y); - this.value = _value; - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(canvasSingleValueAttributeHtml)()); - - /** - * Set Value object of value - * @param {canvas_widget.Value} value - */ - this.setValue = function (value) { - _value = value; - this.value = value; - }; - - /** - * Get Value object of value - * @returns {canvas_widget.Value} - */ - this.getValue = function () { - return _value; - }; - - /** - * jQuery object of DOM node representing the attribute - * @type {jQuery} - * @private - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the attribute - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.value = _value.toJSON(); - return json; - }; - - /** - * Set attribute value by its JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - _value.setValueFromJSON(json.value); - }; - - this.registerYType = function () { - _value.registerYType(); - }; - - _$node.find(".name").text(this.getName()); - _$node.find(".value").append(_value.get$node()); - } -} - -/** - * SingleValueListAttribute - * @class canvas_widget.SingleValueListAttribute - * @extends canvas_widget.AbstractAttribute - * @memberof canvas_widget - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to - */ -class SingleValueListAttribute extends AbstractAttribute { - static TYPE = "SingleValueListAttribute"; - constructor(id, name, subjectEntity) { - super(id, name, subjectEntity); - var that = this; - - /** - * List of attributes - * @type {Object} - * @private - */ - var _list = {}; - - /** - * jQuery object of DOM node representing the attribute - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(singleValueListAttributeHtml)()); - y = y || window.y; - /** - * Inter widget communication wrapper - * @type {Object} - */ - var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); - - /** - * Apply an Attribute Add Operation - * @param {operations.ot.AttributeAddOperation} operation - */ - var processAttributeAddOperation = function (operation) { - var attribute = new SingleValueAttribute( - operation.getEntityId() + "[value]", - "Attribute", - that - ); - attribute.registerYType(); - that.addAttribute(attribute); - _$node.find(".list").append(attribute.get$node()); - }; - - /** - * Apply an Attribute Delete Operation - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var processAttributeDeleteOperation = function (operation) { - var attribute = that.getAttribute(operation.getEntityId()); - if (attribute) { - that.deleteAttribute(attribute.getEntityId()); - attribute.get$node().remove(); - } - }; - /** - * Propagate an Attribute Add Operation to the remote users and the local widgets - * @param {operations.ot.AttributeAddOperation} operation - */ - var propagateAttributeAddOperation = function (operation) { - processAttributeAddOperation(operation); - EntityManagerInstance.storeDataYjs(); - }; - - /** - * Propagate an Attribute Delete Operation to the remote users and the local widgets - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var propagateAttributeDeleteOperation = function (operation) { - processAttributeDeleteOperation(operation); - var ynode = that.getRootSubjectEntity().getYMap(); - ynode.delete(operation.getEntityId()); - EntityManagerInstance.storeDataYjs(); - }; - - /** - * Callback for a remote Attrbute Add Operation - * @param {operations.ot.AttributeAddOperation} operation - */ - var remoteAttributeAddCallback = function (operation) { - if ( - operation instanceof AttributeAddOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - processAttributeAddOperation(operation); - } - }; - - /** - * Callback for a remote Attribute Delete Operation - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var remoteAttributeDeleteCallback = function (operation) { - if ( - operation instanceof AttributeDeleteOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - processAttributeDeleteOperation(operation); - } - }; - - var localAttributeAddCallback = function (operation) { - if ( - operation instanceof AttributeAddOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - propagateAttributeAddOperation(operation); - } - }; - - /** - * Callback for a local Attribute Delete Operation - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var localAttributeDeleteCallback = function (operation) { - if ( - operation instanceof AttributeDeleteOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - propagateAttributeDeleteOperation(operation); - } - }; - - /** - * Add attribute to attribute list - * @param {canvas_widget.AbstractAttribute} attribute - */ - this.addAttribute = function (attribute) { - var id = attribute.getEntityId(); - if (!_list.hasOwnProperty(id)) { - _list[id] = attribute; - } - }; - - /** - * Get attribute of attribute list by its entity id - * @param id - * @returns {canvas_widget.AbstractAttribute} - */ - this.getAttribute = function (id) { - if (_list.hasOwnProperty(id)) { - return _list[id]; - } - return null; - }; - - /** - * Delete attribute from attribute list by its entity id - * @param {string} id - */ - this.deleteAttribute = function (id) { - if (_list.hasOwnProperty(id)) { - delete _list[id]; - } - }; - - /** - * Get attribute list - * @returns {Object} - */ - this.getAttributes = function () { - return _list; - }; - - /** - * Set attribute list - * @param {Object} list - */ - this.setAttributes = function (list) { - _list = list; - }; - - /** - * Get jQuery object of the DOM node representing the attribute (list) - * @returns {jQuery} - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the attribute (list) - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.type = SingleValueListAttribute.TYPE; - var attr = {}; - lodash.forEach(this.getAttributes(), function (val, key) { - attr[key] = val.toJSON(); - }); - json.list = attr; - return json; - }; - - /** - * Set attribute list by its JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - lodash.forEach(json.list, function (val, key) { - var attribute = new SingleValueAttribute(key, key, that, y); - attribute.setValueFromJSON(json.list[key]); - that.addAttribute(attribute); - _$node.find(".list").append(attribute.get$node()); - }); - }; - - /** - * Register inter widget communication callbacks - */ - this.registerCallbacks = function () { - _iwcw.registerOnDataReceivedCallback(localAttributeAddCallback); - _iwcw.registerOnDataReceivedCallback(localAttributeDeleteCallback); - }; - - /** - * Unregister inter widget communication callbacks - */ - this.unregisterCallbacks = function () { - _iwcw.unregisterOnDataReceivedCallback(localAttributeAddCallback); - _iwcw.unregisterOnDataReceivedCallback(localAttributeDeleteCallback); - }; - - _$node.find(".name").text(this.getName()); - - for (var attributeId in _list) { - if (_list.hasOwnProperty(attributeId)) { - _$node.find(".list").append(_list[attributeId].get$node()); - } - } - - if (_iwcw) { - that.registerCallbacks(); - } - this.registerYMap = function (disableYText) { - var ymap = that.getRootSubjectEntity().getYMap(); - - var attrs = that.getAttributes(); - for (var key in attrs) { - if (attrs.hasOwnProperty(key)) { - var attr = attrs[key]; - attr.getValue().registerYType(); - } - } - - ymap.observe(function (event) { - var operation; - - const array = Array.from(event.changes.keys.entries()); - array.forEach(([key, change]) => { - if (key.indexOf("[value]") != -1) { - switch (change.action) { - case "add": { - if (event.currentTarget.get("modifiedBy") === window.y.clientID) - return; - - operation = new AttributeAddOperation( - key.replace(/\[\w*\]/g, ""), - that.getEntityId(), - that.getRootSubjectEntity().getEntityId(), - that.constructor.name - ); - remoteAttributeAddCallback(operation); - break; - } - case "delete": { - operation = new AttributeDeleteOperation( - key, - that.getEntityId(), - that.getRootSubjectEntity().getEntityId(), - that.constructor.name - ); - remoteAttributeDeleteCallback(operation); - } - } - } - }); - }); - }; - } -} - -/** - * Value - * @class canvas_widget.Value - * @extends canvas_widget.AbstractValue - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier - * @param {string} name Name of attribute - * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {canvas_widget.AbstractNode|canvas_widget.AbstractEdge} rootSubjectEntity Topmost entity in the chain of entity the attribute is assigned to - */ -class Value extends AbstractValue { - value = ""; - constructor(id, name, subjectEntity, rootSubjectEntity, y) { - super(id, name, subjectEntity, rootSubjectEntity); - y = y || window.y; - if (!y) throw new Error("y is undefined"); - IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); - var _ytext = null; - - const yMap = rootSubjectEntity.getYMap(); - if (!yMap) { - throw new Error("yMap is undefined"); - } - y.transact(() => { - if (yMap?.has(id)) { - _ytext = rootSubjectEntity.getYMap().get(id); - if (!(_ytext instanceof Text)) { - _ytext = new Text(); - rootSubjectEntity.getYMap().set(id, _ytext); - } - } else { - _ytext = new Text(); - rootSubjectEntity.getYMap().set(id, _ytext); - } - rootSubjectEntity.getYMap().set("modifiedBy", window.y.clientID); - }); - - var that = this; - /** - * Value - * @type {string} - * @private - */ - var _value = ""; - this.value = _value; - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(valueHtml)({ name: name })); - - /** - * Set value - * @param {string} value - */ - this.setValue = function (value) { - _value = value; - _$node.val(value).trigger("blur"); - - this.value = _ytext.toString(); - }; - - /** - * Get value - * @returns {string} - */ - this.getValue = function () { - return _value; - }; - - /** - * Get jQuery object of DOM node representing the value - * @returns {jQuery} - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the edge - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractValue.prototype.toJSON.call(this); - json.value = _value; - return json; - }; - - /** - * Set value by its JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - this.setValue(json.value); - }; - - this.registerYType = function () { - _ytext.observe( - lodash.debounce(function (event) { - _value = _ytext.toString().replace(/\n/g, ""); - that.setValue(_value); - if (event.currentTarget.get("modifiedBy") === window.y.clientID) { - EntityManagerInstance.storeDataYjs(); - const userMap = y.getMap("users"); - const jabberId = userMap.get(event.currentTarget.doc.clientID); - - const activityMap = y.getMap("activity"); - activityMap.set( - ActivityOperation.TYPE, - new ActivityOperation( - "ValueChangeActivity", - that.getEntityId(), - jabberId, - ValueChangeOperation.getOperationDescription( - that.getSubjectEntity().getName(), - that.getRootSubjectEntity().getType(), - that.getRootSubjectEntity().getLabel().getValue().getValue() - ), - { - value: _value, - subjectEntityName: that.getSubjectEntity().getName(), - rootSubjectEntityType: that.getRootSubjectEntity().getType(), - rootSubjectEntityId: that - .getRootSubjectEntity() - .getEntityId(), - } - ).toJSON() - ); - } - }, 500) - ); - }; - - this.getYText = function () { - return _ytext; - }; - - //automatically determines the size of input - _$node - .autoGrowInput({ - comfortZone: 10, - minWidth: 40, - maxWidth: 1000, - }) - .trigger("blur"); - } -} - -/** - * QuizAttribute - * @class attribute_widget.SingleValueAttribute - * @memberof attribute_widget - * @extends attribute_widget.AbstractAttribute - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {attribute_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to - */ -class QuizAttribute extends AbstractAttribute { - constructor(id, name, subjectEntity) { - super(id, name, subjectEntity); - /*** - * Value object of value - * @type {attribute_widget.Value} - * @private - */ - var _value = new Value(id, name, this, this.getRootSubjectEntity()); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(singleQuizAttributeHtml)({ id: id })); - - /** - * Set Value object of value - * @param {attribute_widget.Value} value - */ - this.setValue = function (value) { - _value = value; - }; - - /** - * Get Value object of value - * @returns {attribute_widget.Value} - */ - this.getValue = function () { - return _value; - }; - - /** - * jQuery object of DOM node representing the attribute - * @type {jQuery} - * @public - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the attribute - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.value = _value.toJSON(); - return json; - }; - - /** - * Set attribute value by its JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - _value.setValueFromJSON(json.value); - }; - - this.registerYType = function () { - _value.registerYType(); - }; - - _$node.find(".name").text(this.getName()); - _$node.find(".value").append(_value.get$node()); - - function addRow() { - var table = _$node.find("#table")[0]; - var rows = table.rows.length; - var row = table.insertRow(table.rows.length); - var cell0 = row.insertCell(0); - var cell1 = row.insertCell(1); - var cell2 = row.insertCell(2); - var cell3 = row.insertCell(3); - var input0 = document.createElement("input"); - var input1 = document.createElement("input"); - var input2 = document.createElement("input"); - var input3 = document.createElement("input"); - input0.id = rows + "0"; - input1.id = rows + "1"; - input2.id = rows + "2"; - input3.id = rows + "3"; - input1.type = "text"; - input2.type = "text"; - input3.type = "text"; - cell0.appendChild(input0); - cell1.appendChild(input1); - cell2.appendChild(input2); - cell3.appendChild(input3); - } - - this.showTable = function () { - _$node.find("#table")[0].style.visibility = "visible"; - _$node.find("#b")[0].style.visibility = "visible"; - _$node.find("#c")[0].style.visibility = "visible"; - _$node.find("#submit")[0].style.visibility = "visible"; - _$node.find("#display")[0].style.visibility = "visible"; - }; - - this.hideTable = function () { - _$node.find("#table")[0].style.visibility = "hidden"; - _$node.find("#b")[0].style.visibility = "hidden"; - _$node.find("#c")[0].style.visibility = "hidden"; - _$node.find("#submit")[0].style.visibility = "hidden"; - _$node.find("#display")[0].style.visibility = "hidden"; - }; - - _$node.find("#b").click(function () { - addRow(); - }); - - // remove rows from table - _$node.find("#c").click(function () { - var table = _$node.find("#table")[0]; - var rows = table.rows.length; - table.deleteRow(rows - 1); - }); - - // write table input into attribute field - _$node.find("#submit").click(function () { - var table = _$node.find("#table")[0]; - var Json = {}; - Json["topic"] = _$node.find("#topic")[0].value; - var Sequence = []; - var Questions = []; - var Intents = []; - var Hints = []; - var row = table.rows.length; - for (var i = 2; i < row; i++) { - if ( - _$node.find("#" + i.toString() + "1")[0].value == "" || - _$node.find("#" + i.toString() + "2")[0].value == "" - ) { - continue; - } - Sequence.push(_$node.find("#" + i.toString() + "0")[0].value); - Questions.push(_$node.find("#" + i.toString() + "1")[0].value); - Intents.push(_$node.find("#" + i.toString() + "2")[0].value); - if (_$node.find("#" + i.toString() + "3")[0].value == "") { - Hints.push("No Hint Available for this Question"); - } else Hints.push(_$node.find("#" + i.toString() + "3")[0].value); - } - Json["Questions"] = Questions; - Json["Sequence"] = Sequence; - Json["Intents"] = Intents; - Json["Hints"] = Hints; - console.log(JSON.stringify(Json)); - _$node.find(".val")[0].value = JSON.stringify(Json); - var field = _$node.find(".val")[0]; - field.dispatchEvent(new Event("input")); - }); - - // take content from attribute field and display as table - _$node.find("#display").click(function () { - var table = _$node.find("#table")[0]; - var Json = _$node.find(".val")[0].value; - console.log(Json); - var content = JSON.parse(Json); - _$node.find("#topic")[0].value = content.topic; - var rowNumb = content.Questions.length; - console.log(rowNumb); - var currRows = table.rows.length - 2; - console.log(currRows); - if (currRows < rowNumb) { - for (currRows; currRows < rowNumb; currRows++) { - addRow(); - } - } - for (var i = 2; i < rowNumb + 2; i++) { - if (_$node.find("#" + i.toString() + "0")[0].value == null) { - break; - } - _$node.find("#" + i.toString() + "0")[0].value = - content.Sequence[i - 2]; - _$node.find("#" + i.toString() + "1")[0].value = - content.Questions[i - 2]; - _$node.find("#" + i.toString() + "2")[0].value = content.Intents[i - 2]; - _$node.find("#" + i.toString() + "3")[0].value = content.Hints[i - 2]; - } - }); - } -} - -/** - * KeySelectionValueAttribute - * @class canvas_widget.KeySelectionValueAttribute - * @extends canvas_widget.AbstractAttribute - * @memberof canvas_widget - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {Object} options Selection options - */ -class KeySelectionValueAttribute extends AbstractAttribute { - constructor(id, name, subjectEntity, options) { - super(id, name, subjectEntity); - - var _ymap = null; - - //noinspection UnnecessaryLocalVariableJS - /** - * Selection options - * @type {Object} - * @private - */ - var _options = options; - - /** - * Value object of key - * @type {canvas_widget.Value} - * @private - */ - var _key = new Value(id + "[key]", "", this, this.getRootSubjectEntity()); - - /*** - * Value object of value - * @type {canvas_widget.Value} - * @private - */ - var _value = new SelectionValue( - id + "[value]", - "", - this, - this.getRootSubjectEntity(), - _options - ); - - /** - * jQuery object of the DOM node representing the attribute - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(keySelectionValueAttributeHtml)({ id: id })); - - //noinspection JSUnusedGlobalSymbols - /** - * Set Value object of key - * @param {canvas_widget.Value} key - */ - this.setKey = function (key) { - _key = key; - }; - - /** - * Get Value object of key - * @returns {canvas_widget.Value} - */ - this.getKey = function () { - return _key; - }; - - /** - * Set Value object of value - * @param {canvas_widget.Value} value - */ - this.setValue = function (value) { - _value = value; - }; - - /** - * Get Value object of value - * @returns {canvas_widget.Value} - */ - this.getValue = function () { - return _value; - }; - - /** - * Get jQuery object of the DOM node representing the attribute - * @returns {jQuery} - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the attribute - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.key = _key.toJSON(); - json.value = _value.toJSON(); - return json; - }; - - /** - * Set value of key and value by their JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - _key.setValueFromJSON(json.key); - _value.setValueFromJSON(json.value); - }; - - this.registerYMap = function () { - _key.registerYType(); - _value.registerYType(); - }; - - this.getYMap = function () { - return _ymap; - }; - - _$node.find(".key").append(_key.get$node()); - _$node.find(".value").append(_value.get$node()); - } -} - -/** - * ConditionListAttribute - * @class canvas_widget.ConditionListAttribute - * @extends canvas_widget.AbstractAttribute - * @memberof canvas_widget - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {Object} options Selection options - * @param {Object} options2 Selection options - */ -class ConditionListAttribute extends AbstractAttribute { - static TYPE = "ConditionListAttribute"; - constructor(id, name, subjectEntity, options, options2, y) { - y = y || window.y; - super(id, name, subjectEntity); - var that = this; - - /** - * Selection options - * @type {Object} - * @private - */ - var _options = options; - - /** - * Selection options - * @type {Object} - * @private - */ - var _options2 = options2; - - /** - * List of attributes - * @type {Object} - * @private - */ - var _list = {}; - - /** - * jQuery object of DOM node representing the attribute - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(listHtml)()); - - /** - * Inter widget communication wrapper - * @type {Object} - */ - var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); - - /** - * Apply an Attribute Add Operation - * @param {operations.ot.AttributeAddOperation} operation - * @param {YText} ytext - */ - var processAttributeAddOperation = function (operation) { - var attribute = new ConditionPredicateAttribute( - operation.getEntityId(), - "Attribute", - that, - _options, - _options2 - ); - attribute.registerYMap(); - that.addAttribute(attribute); - _$node.find(".list").append(attribute.get$node()); - }; - - /** - * Propagate an Attribute Add Operation to the remote users and the local widgets - * @param {operations.ot.AttributeAddOperation} operation - */ - var propagateAttributeAddOperation = function (operation) { - processAttributeAddOperation(operation); - EntityManagerInstance.storeDataYjs(); - }; - - /** - * Apply an Attribute Delete Operation - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var processAttributeDeleteOperation = function (operation) { - var attribute = that.getAttribute(operation.getEntityId()); - if (attribute) { - that.deleteAttribute(attribute.getEntityId()); - attribute.get$node().remove(); - } - EntityManagerInstance.storeDataYjs(); - }; - - /** - * Propagate an Attribute Delete Operation to the remote users and the local widgets - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var propagateAttributeDeleteOperation = function (operation) { - processAttributeDeleteOperation(operation); - var ymap = that.getRootSubjectEntity().getYMap(); - ymap.delete(operation.getEntityId() + "[val]"); - }; - - /** - * Callback for a remote Attrbute Add Operation - * @param {operations.ot.AttributeAddOperation} operation - */ - var remoteAttributeAddCallback = function (operation) { - if ( - operation instanceof AttributeAddOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - processAttributeAddOperation(operation); - } - }; - - /** - * Callback for a remote Attribute Delete Operation - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var remoteAttributeDeleteCallback = function (operation) { - if ( - operation instanceof AttributeDeleteOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - processAttributeDeleteOperation(operation); - } - }; - - /** - * Callback for a local Attribute Add Operation - * @param {operations.ot.AttributeAddOperation} operation - */ - var localAttributeAddCallback = function (operation) { - if ( - operation instanceof AttributeAddOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - propagateAttributeAddOperation(operation); - } - }; - - /** - * Callback for a local Attribute Delete Operation - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var localAttributeDeleteCallback = function (operation) { - if ( - operation instanceof AttributeDeleteOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - propagateAttributeDeleteOperation(operation); - } - }; - - /** - * Add attribute to attribute list - * @param {canvas_widget.AbstractAttribute} attribute - */ - this.addAttribute = function (attribute) { - var id = attribute.getEntityId(); - if (!_list.hasOwnProperty(id)) { - _list[id] = attribute; - } - }; - - /** - * Get attribute of attribute list by its entity id - * @param id - * @returns {canvas_widget.AbstractAttribute} - */ - this.getAttribute = function (id) { - if (_list.hasOwnProperty(id)) { - return _list[id]; - } - return null; - }; - - /** - * Delete attribute from attribute list by its entity id - * @param {string} id - */ - this.deleteAttribute = function (id) { - if (_list.hasOwnProperty(id)) { - delete _list[id]; - } - }; - - /** - * Get attribute list - * @returns {Object} - */ - this.getAttributes = function () { - return _list; - }; - - /** - * Set attribute list - * @param {Object} list - */ - this.setAttributes = function (list) { - _list = list; - }; - - /** - * Get jQuery object of the DOM node representing the attribute (list) - * @returns {jQuery} - */ - this.get$node = function () { - return _$node; - }; - - this.setOptions = function (options) { - _options = options; - }; - - /** - * Get JSON representation of the attribute (list) - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.type = ConditionListAttribute.TYPE; - var attr = {}; - lodash.forEach(this.getAttributes(), function (val, key) { - attr[key] = val.toJSON(); - }); - json.list = attr; - return json; - }; - - /** - * Set attribute list by its JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - lodash.forEach(json.list, function (val, key) { - var attribute = new ConditionPredicateAttribute( - key, - key, - that, - _options, - _options2 - ); - attribute.setValueFromJSON(json.list[key]); - that.addAttribute(attribute); - _$node.find(".list").append(attribute.get$node()); - }); - }; - - /** - * Register inter widget communication callbacks - */ - this.registerCallbacks = function () { - _iwcw.registerOnDataReceivedCallback(localAttributeAddCallback); - _iwcw.registerOnDataReceivedCallback(localAttributeDeleteCallback); - }; - - /** - * Unregister inter widget communication callbacks - */ - this.unregisterCallbacks = function () { - _iwcw.unregisterOnDataReceivedCallback(localAttributeAddCallback); - _iwcw.unregisterOnDataReceivedCallback(localAttributeDeleteCallback); - }; - - _$node.find(".name").text(this.getName()); - - for (var attributeId in _list) { - if (_list.hasOwnProperty(attributeId)) { - _$node.find(".list").append(_list[attributeId].get$node()); - } - } - - this.registerYMap = function () { - var ymap = that.getRootSubjectEntity().getYMap(); - var attrs = that.getAttributes(); - for (var key in attrs) { - if (attrs.hasOwnProperty(key)) { - attrs[key].registerYMap(); - } - } - - ymap.observe(function (event) { - const array = Array.from(event.changes.keys.entries()); - array.forEach(([key, change]) => { - if (key.indexOf("[value]") != -1) { - var operation; - event.currentTarget.get(key); - switch (change.action) { - case "add": { - if (eventWasTriggeredByMe(event)) return; - const jabberId = event.currentTarget.get("jabberId"); - if (jabberId === _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]) - return; - operation = new AttributeAddOperation( - key.replace(/\[\w*\]/g, ""), - that.getEntityId(), - that.getRootSubjectEntity().getEntityId(), - that.constructor.name - ); - remoteAttributeAddCallback(operation); - - break; - } - case "delete": { - operation = new AttributeDeleteOperation( - key.replace(/\[\w*\]/g, ""), - that.getEntityId(), - that.getRootSubjectEntity().getEntityId(), - that.constructor.name - ); - remoteAttributeDeleteCallback(operation); - break; - } - } - } else if (key.indexOf("updateConditionOption") != -1) { - that.setOptions(event.value); - } - }); - }); - }; - - if (_iwcw) { - that.registerCallbacks(); - } - } -} - -/** - * RenamingAttribute - * @class canvas_widget.ConditionPredicateAttribute - * @memberof canvas_widget - * @extends canvas_widget.AbstractAttribute - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {Object} options Selection options - * @constructor - */ -class RenamingAttribute extends AbstractAttribute { - static TYPE = "RenamingAttribute"; - constructor(id, name, subjectEntity, options) { - super(id, name, subjectEntity); - - //noinspection UnnecessaryLocalVariableJS - /** - * Selection options - * @type {Object} - * @private - */ - var _options = options; - - /** - * Value object of key - * @type {canvas_widget.Value} - * @private - */ - var _key = new Value( - id + "[val]", - "Attribute Name", - this, - this.getRootSubjectEntity() - ); - - /*** - * Value object of ref - * @type {canvas_widget.Value} - * @private - */ - var _ref = new Value( - id + "[ref]", - "Attribute Reference", - this, - this.getRootSubjectEntity() - ); - - /*** - * Value object of vis - * @type {canvas_widget.Value} - * @private - */ - var _vis = new SelectionValue( - id + "[vis]", - "Attribute Visibility", - this, - this.getRootSubjectEntity(), - _options - ); - - /** - * jQuery object of the DOM node representing the attribute - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(renamingAttrHTML)()); - - //noinspection JSUnusedGlobalSymbols - /** - * Set Value object of key - * @param {canvas_widget.Value} key - */ - this.setKey = function (key) { - _key = key; - }; - - /** - * Get Value object of key - * @returns {canvas_widget.Value} - */ - this.getKey = function () { - return _key; - }; - - /** - * Get Value object of value - * @returns {canvas_widget.Value} - */ - this.getRef = function () { - return _ref; - }; - - /** - * Get Visibility object of value - * @returns {canvas_widget.Value} - */ - this.getVis = function () { - return _vis; - }; - - //noinspection JSUnusedGlobalSymbols - /** - * Set Value object of value - * @param {canvas_widget.Value} value - */ - this.setVis = function (value) { - _vis = value; - }; - - /** - * Get jQuery object of the DOM node representing the attribute - * @returns {jQuery} - */ - this.get$node = function () { - return _$node; - }; - - /** - * Set value of key and value by their JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - _key.setValueFromJSON(json.val); - _ref.setValueFromJSON(json.ref); - _vis.setValueFromJSON(json.vis || { value: "" }); - }; - - /** - * Get JSON representation of the attribute - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.val = _key.toJSON(); - json.ref = _ref.toJSON(); - json.vis = _vis.toJSON(); - return json; - }; - _$node.find(".val").append(_key.get$node()); - _$node.find(".ref").append(_ref.get$node()).hide(); - _$node.find(".vis").append(_vis.get$node()); - - this.registerYMap = function () { - _key.registerYType(); - _ref.registerYType(); - _vis.registerYType(); - }; - } -} - -/** - * KeySelectionValueSelectionValueListAttribute - * @class canvas_widget.KeySelectionValueSelectionValueListAttribute - * @extends canvas_widget.AbstractAttribute - * @memberof canvas_widget - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {Object} options Selection options - * @param {Object} options2 Selection options - */ -class KeySelectionValueSelectionValueListAttribute extends AbstractAttribute { - static TYPE = "KeySelectionValueSelectionValueListAttribute"; - - constructor(id, name, subjectEntity, options, options2) { - super(id, name, subjectEntity); - var that = this; - - /** - * Selection options - * @type {Object} - * @private - */ - var _options = options; - - /** - * Selection options - * @type {Object} - * @private - */ - var _options2 = options2; - - /** - * List of attributes - * @type {Object} - * @private - */ - var _list = {}; - - /** - * jQuery object of DOM node representing the attribute - * @type {jQuery} - * @private - */ - var _$node = $( - lodash.template(keySelectionValueSelectionValueListAttributeHtml)() - ); - - /** - * Inter widget communication wrapper - * @type {Object} - */ - y = y || window.y; - var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); - - /** - * Apply an Attribute Add Operation - * @param {operations.ot.AttributeAddOperation} operation - */ - var processAttributeAddOperation = function (operation) { - var attribute = new KeySelectionValueSelectionValueAttribute( - operation.getEntityId(), - "Attribute", - that, - _options, - _options2 - ); - attribute.registerYType(); - that.addAttribute(attribute); - if (_$node.find(".list").find("#" + attribute.getEntityId()).length == 0) - _$node.find(".list").append(attribute.get$node()); - EntityManagerInstance.storeDataYjs(); - }; - - /** - * Apply an Attribute Delete Operation - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var processAttributeDeleteOperation = function (operation) { - var attribute = that.getAttribute(operation.getEntityId()); - if (attribute) { - that.deleteAttribute(attribute.getEntityId()); - attribute.get$node().remove(); - } - EntityManagerInstance.storeDataYjs(); - }; - - /** - * Propagate an Attribute Add Operation to the remote users and the local widgets - * @param {operations.ot.AttributeAddOperation} operation - */ - var propagateAttributeAddOperation = function (operation) { - processAttributeAddOperation(operation); - }; - - /** - * Propagate an Attribute Delete Operation to the remote users and the local widgets - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var propagateAttributeDeleteOperation = function (operation) { - processAttributeDeleteOperation(operation); - var ynode = that.getRootSubjectEntity().getYMap(); - ynode.delete(operation.getEntityId() + "[key]"); - }; - - /** - * Callback for a remote Attrbute Add Operation - * @param {operations.ot.AttributeAddOperation} operation - */ - var remoteAttributeAddCallback = function (operation) { - if ( - operation instanceof AttributeAddOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - processAttributeAddOperation(operation); - } - }; - - /** - * Callback for a remote Attribute Delete Operation - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var remoteAttributeDeleteCallback = function (operation) { - if ( - operation instanceof AttributeDeleteOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.ATTRIBUTE, - operation.getOTOperation() - ); - processAttributeDeleteOperation(operation); - } - }; - - var localAttributeAddCallback = function (operation) { - if ( - operation instanceof AttributeAddOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - propagateAttributeAddOperation(operation); - } - }; - - /** - * Callback for a local Attribute Delete Operation - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var localAttributeDeleteCallback = function (operation) { - if ( - operation instanceof AttributeDeleteOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - propagateAttributeDeleteOperation(operation); - } - }; - - /** - * Add attribute to attribute list - * @param {canvas_widget.AbstractAttribute} attribute - */ - this.addAttribute = function (attribute) { - var id = attribute.getEntityId(); - if (!_list.hasOwnProperty(id)) { - _list[id] = attribute; - } - }; - - /** - * Get attribute of attribute list by its entity id - * @param id - * @returns {canvas_widget.AbstractAttribute} - */ - this.getAttribute = function (id) { - if (_list.hasOwnProperty(id)) { - return _list[id]; - } - return null; - }; - - /** - * Delete attribute from attribute list by its entity id - * @param {string} id - */ - this.deleteAttribute = function (id) { - if (_list.hasOwnProperty(id)) { - _list[id]; - - delete _list[id]; - } - }; - - /** - * Get attribute list - * @returns {Object} - */ - this.getAttributes = function () { - return _list; - }; - - /** - * Set attribute list - * @param {Object} list - */ - this.setAttributes = function (list) { - _list = list; - }; - - /** - * Get jQuery object of the DOM node representing the attribute (list) - * @returns {jQuery} - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the attribute (list) - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.type = KeySelectionValueSelectionValueListAttribute.TYPE; - var attr = {}; - lodash.forEach(this.getAttributes(), function (val, key) { - attr[key] = val.toJSON(); - }); - json.list = attr; - return json; - }; - - /** - * Set attribute list by its JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - lodash.forEach(json.list, function (val, key) { - var attribute = new KeySelectionValueSelectionValueAttribute( - key, - key, - that, - _options, - _options2 - ); - attribute.setValueFromJSON(json.list[key]); - that.addAttribute(attribute); - if ( - _$node.find(".list").find("#" + attribute.getEntityId()).length == 0 - ) - _$node.find(".list").append(attribute.get$node()); - }); - }; - - /** - * Register inter widget communication callbacks - */ - this.registerCallbacks = function () { - _iwcw.registerOnDataReceivedCallback(localAttributeAddCallback); - _iwcw.registerOnDataReceivedCallback(localAttributeDeleteCallback); - }; - - /** - * Unregister inter widget communication callbacks - */ - this.unregisterCallbacks = function () { - _iwcw.unregisterOnDataReceivedCallback(localAttributeAddCallback); - _iwcw.unregisterOnDataReceivedCallback(localAttributeDeleteCallback); - }; - - _$node.find(".name").text(this.getName()); - - for (var attributeId in _list) { - if (_list.hasOwnProperty(attributeId)) { - _$node.find(".list").append(_list[attributeId].get$node()); - } - } - - if (_iwcw) { - that.registerCallbacks(); - } - - this.registerYMap = function () { - var ymap = that.getRootSubjectEntity().getYMap(); - var attrs = that.getAttributes(); - for (var key in attrs) { - if (attrs.hasOwnProperty(key)) { - var attr = attrs[key]; - attr.registerYType(); - } - } - - ymap.observe(function (event) { - const array = Array.from(event.changes.keys.entries()); - array.forEach(([key, change]) => { - if (key.indexOf("[key]") != -1) { - var operation; - event.currentTarget.get(key); - switch (change.action) { - case "add": { - const jabberId = event.currentTarget.get("jabberId"); - if (jabberId === _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]) - return; - operation = new AttributeAddOperation( - key.replace(/\[\w*\]/g, ""), - that.getEntityId(), - that.getRootSubjectEntity().getEntityId(), - that.constructor.name - ); - remoteAttributeAddCallback(operation); - break; - } - case "delete": { - operation = new AttributeDeleteOperation( - key.replace(/\[\w*\]/g, ""), - that.getEntityId(), - that.getRootSubjectEntity().getEntityId(), - that.constructor.name - ); - remoteAttributeDeleteCallback(operation); - break; - } - } - } - }); - }); - }; - } -} - -/** - * RenamingListAttribute - * @class canvas_widget.RenamingListAttribute - * @extends canvas_widget.AbstractAttribute - * @memberof canvas_widget - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {Object} options Selection options - */ -class RenamingListAttribute extends AbstractAttribute { - static TYPE = "RenamingListAttribute"; - constructor(id, name, subjectEntity, options, y) { - y = y || window.y; - super(id, name, subjectEntity); - var that = this; - - /** - * Selection options - * @type {Object} - * @private - */ - var _options = options; - - /** - * List of attributes - * @type {Object} - * @private - */ - var _list = {}; - - /** - * jQuery object of DOM node representing the attribute - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(listHtml)()); - - /** - * Inter widget communication wrapper - * @type {Object} - */ - var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); - - /** - * Apply an Attribute Add Operation - * @param {operations.ot.AttributeAddOperation} operation - * @param { YText} ytext - */ - var processAttributeAddOperation = function (operation) { - var attribute = new RenamingAttribute( - operation.getEntityId(), - "Attribute", - that, - _options - ); - that.addAttribute(attribute); - attribute.registerYMap(); - _$node.find(".list").append(attribute.get$node()); - EntityManagerInstance.storeDataYjs(); - return attribute; - }; - - /** - * Propagate an Attribute Add Operation to the remote users and the local widgets - * @param {operations.ot.AttributeAddOperation} operation - */ - this.propagateAttributeAddOperation = function (operation) { - return processAttributeAddOperation(operation); - }; - - /** - * Apply an Attribute Delete Operation - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var processAttributeDeleteOperation = function (operation) { - var attribute = that.getAttribute(operation.getEntityId()); - if (attribute) { - that.deleteAttribute(attribute.getEntityId()); - attribute.get$node().remove(); - } - }; - - /** - * Propagate an Attribute Delete Operation to the remote users and the local widgets - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var propagateAttributeDeleteOperation = function (operation) { - processAttributeDeleteOperation(operation); - var ymap = that.getRootSubjectEntity().getYMap(); - ymap.delete(operation.getEntityId() + "[val]"); - EntityManagerInstance.storeDataYjs(); - }; - - /** - * Callback for a remote Attrbute Add Operation - * @param {operations.ot.AttributeAddOperation} operation - */ - var remoteAttributeAddCallback = function (operation) { - if ( - operation instanceof AttributeAddOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - processAttributeAddOperation(operation); - subjectEntity.showAttributes(); - } - }; - - /** - * Callback for a remote Attribute Delete Operation - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var remoteAttributeDeleteCallback = function (operation) { - if ( - operation instanceof AttributeDeleteOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - processAttributeDeleteOperation(operation); - } - }; - - /** - * Callback for a local Attribute Add Operation - * @param {operations.ot.AttributeAddOperation} operation - */ - var localAttributeAddCallback = function (operation) { - if ( - operation instanceof AttributeAddOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - propagateAttributeAddOperation(operation); - } - }; - - /** - * Callback for a local Attribute Delete Operation - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var localAttributeDeleteCallback = function (operation) { - if ( - operation instanceof AttributeDeleteOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - propagateAttributeDeleteOperation(operation); - } - }; - - /** - * Add attribute to attribute list - * @param {canvas_widget.AbstractAttribute} attribute - */ - this.addAttribute = function (attribute) { - var id = attribute.getEntityId(); - if (!_list.hasOwnProperty(id)) { - _list[id] = attribute; - } - }; - - /** - * Get attribute of attribute list by its entity id - * @param id - * @returns {canvas_widget.AbstractAttribute} - */ - this.getAttribute = function (id) { - if (_list.hasOwnProperty(id)) { - return _list[id]; - } - return null; - }; - - /** - * Delete attribute from attribute list by its entity id - * @param {string} id - */ - this.deleteAttribute = function (id) { - if (_list.hasOwnProperty(id)) { - delete _list[id]; - } - }; - - /** - * Get attribute list - * @returns {Object} - */ - this.getAttributes = function () { - return _list; - }; - - /** - * Set attribute list - * @param {Object} list - */ - this.setAttributes = function (list) { - _list = list; - }; - - /** - * Get jQuery object of the DOM node representing the attribute (list) - * @returns {jQuery} - */ - this.get$node = function () { - return _$node; - }; - - this.setOptions = function (options) { - _options = options; - }; - - /** - * Get JSON representation of the attribute (list) - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.type = RenamingListAttribute.TYPE; - var attr = {}; - lodash.forEach(this.getAttributes(), function (val, key) { - attr[key] = val.toJSON(); - }); - json.list = attr; - return json; - }; - - /** - * Set attribute list by its JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - lodash.forEach(json.list, function (val, key) { - var attribute = new RenamingAttribute(key, key, that, _options); - attribute.setValueFromJSON(json.list[key]); - that.addAttribute(attribute); - _$node.find(".list").append(attribute.get$node()); - }); - }; - - /** - * Register inter widget communication callbacks - */ - this.registerCallbacks = function () { - _iwcw.registerOnDataReceivedCallback(localAttributeAddCallback); - _iwcw.registerOnDataReceivedCallback(localAttributeDeleteCallback); - }; - - /** - * Unregister inter widget communication callbacks - */ - this.unregisterCallbacks = function () { - _iwcw.unregisterOnDataReceivedCallback(localAttributeAddCallback); - _iwcw.unregisterOnDataReceivedCallback(localAttributeDeleteCallback); - }; - - _$node.find(".name").text(this.getName()); - - for (var attributeId in _list) { - if (_list.hasOwnProperty(attributeId)) { - _$node.find(".list").append(_list[attributeId].get$node()); - } - } - - if (_iwcw) { - that.registerCallbacks(); - } - this.registerYMap = function () { - var ymap = that.getRootSubjectEntity().getYMap(); - var attrs = that.getAttributes(); - for (var key in attrs) { - if (attrs.hasOwnProperty(key)) { - var attr = attrs[key]; - attr.registerYMap(); - } - } - - ymap.observe(function (event) { - const array = Array.from(event.changes.keys.entries()); - array.forEach(([key, change]) => { - if (key.indexOf("[val]") != -1) { - event.currentTarget.get(key); - switch (change.action) { - case "add": { - // var yUserId = event.object.map[key][0]; - // if (yUserId === y.clientID) return; - const operation = new AttributeAddOperation( - key.replace(/\[\w*\]/g, ""), - that.getEntityId(), - that.getRootSubjectEntity().getEntityId(), - that.constructor.name - ); - remoteAttributeAddCallback(operation); - - break; - } - case "delete": { - const operation = new AttributeDeleteOperation( - key.replace(/\[\w*\]/g, ""), - that.getEntityId(), - that.getRootSubjectEntity().getEntityId(), - that.constructor.name - ); - remoteAttributeDeleteCallback(operation); - break; - } - } - } - }); - }); - }; - } -} - -/** - * ConditionPredicateAttribute - * @class attribute_widget.ConditionPredicateAttribute - * @memberof attribute_widget - * @extends attribute_widget.AbstractAttribute - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {Object} options Selection options - * @param {Object} options2 Selection options - * @constructor - */ -class ConditionPredicateAttribute extends AbstractAttribute { - static TYPE = "ConditionPredicateAttribute"; - constructor(id, name, subjectEntity, options, options2) { - super(id, name, subjectEntity); - - //noinspection UnnecessaryLocalVariableJS - /** - * Selection options - * @type {Object} - * @private - */ - var _options = options; - - //noinspection UnnecessaryLocalVariableJS - /** - * Selection options - * @type {Object} - * @private - */ - var _options2 = options2; - - //var _options3 = options3; - /** - * Value object of key - * @type {attribute_widget.Value} - * @private - */ - var _key = new Value( - id + "[value]", - "Attribute Value", - this, - this.getRootSubjectEntity() - ); - - /*** - * Value object of value - * @type {attribute_widget.Value} - * @private - */ - var _value = new SelectionValue( - id + "[property]", - "Attribute Name", - this, - this.getRootSubjectEntity(), - _options - ); - - /*** - * Value object of value - * @type {attribute_widget.Value} - * @private - */ - var _value2 = new SelectionValue( - id + "[operator]", - "Logical Operator", - this, - this.getRootSubjectEntity(), - _options2 - ); - - /** - * jQuery object of the DOM node representing the attribute - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(condition_predicateHtml)()); - - //noinspection JSUnusedGlobalSymbols - /** - * Set Value object of key - * @param {attribute_widget.Value} key - */ - this.setKey = function (key) { - _key = key; - }; - - /** - * Get Value object of key - * @returns {attribute_widget.Value} - */ - this.getKey = function () { - return _key; - }; - - /** - * Set Value object of value - * @param {attribute_widget.Value} value - */ - this.setValue = function (value) { - _value = value; - }; - - /** - * Get Value object of value - * @returns {attribute_widget.Value} - */ - this.getValue = function () { - return _value; - }; - - //noinspection JSUnusedGlobalSymbols - /** - * Set Value object of value - * @param {attribute_widget.Value} value - */ - this.setValue2 = function (value) { - _value2 = value; - }; - - /** - * Get Value object of value - * @returns {attribute_widget.Value} - */ - this.getValue2 = function () { - return _value2; - }; - - /** - * Get jQuery object of the DOM node representing the attribute - * @returns {jQuery} - */ - this.get$node = function () { - return _$node; - }; - - /** - * Set value of key and value by their JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - _key.setValueFromJSON(json.val); - _value.setValueFromJSON(json.property); - _value2.setValueFromJSON(json.operator || { value: "" }); - }; - /** - * Get JSON representation of the attribute - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.val = _key.toJSON(); - json.property = _value.toJSON(); - json.operator = _value2.toJSON(); - return json; - }; - _$node.find(".val").append(_key.get$node()); - _$node.find(".property").append(_value.get$node()); - _$node.find(".operator").append(_value2.get$node()); - //_$node.find(".operator2").append(_value3.get$node()); - this.registerYMap = function () { - _key.registerYType(); - _value.registerYType(); - _value2.registerYType(); - }; - } -} - -/** - * SingleColorValueAttribute - * @class canvas_widget.SingleColorValueAttribute - * @extends canvas_widget.AbstractAttribute - * @memberof canvas_widget - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to - */ -class SingleColorValueAttribute extends AbstractAttribute { - constructor(id, name, subjectEntity) { - super(id, name, subjectEntity); - - /*** - * Value object of value - * @type {canvas_widget.Value} - * @private - */ - var _value = new Value(id, name, this, this.getRootSubjectEntity()); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(singleColorValueAttributeHtml)()); - - /** - * Set Value object of value - * @param {canvas_widget.Value} value - */ - this.setValue = function (value) { - _value = value; - }; - - /** - * Get Value object of value - * @returns {canvas_widget.Value} - */ - this.getValue = function () { - return _value; - }; - - /** - * jQuery object of DOM node representing the attribute - * @type {jQuery} - * @private - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the attribute - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.value = _value.toJSON(); - return json; - }; - - /** - * Set attribute value by its JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - _value.setValueFromJSON(json.value); - }; - - _$node.find(".name").text(this.getName()); - _$node.find(".value").append(_value.get$node()); - } -} - -/** - * KeySelectionValueSelectionValueAttribute - * @class canvas_widget.KeySelectionValueSelectionValueAttribute - * @extends canvas_widget.AbstractAttribute - * @memberof canvas_widget - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {Object} options Selection options - * @param {Object} options2 Selection options - */ -class KeySelectionValueSelectionValueAttribute extends AbstractAttribute { - constructor(id, name, subjectEntity, options, options2) { - super(id, name, subjectEntity); - - //noinspection UnnecessaryLocalVariableJS - /** - * Selection options - * @type {Object} - * @private - */ - var _options = options; - - //noinspection UnnecessaryLocalVariableJS - /** - * Selection options - * @type {Object} - * @private - */ - var _options2 = options2; - - /** - * Value object of key - * @type {canvas_widget.Value} - * @private - */ - var _key = new Value(id + "[key]", "", this, this.getRootSubjectEntity()); - - /*** - * Value object of value - * @type {canvas_widget.Value} - * @private - */ - var _value = new SelectionValue( - id + "[value]", - "", - this, - this.getRootSubjectEntity(), - _options - ); - - /*** - * Value object of value - * @type {canvas_widget.Value} - * @private - */ - var _value2 = new SelectionValue( - id + "[value2]", - "", - this, - this.getRootSubjectEntity(), - _options2 - ); - - /** - * jQuery object of the DOM node representing the attribute - * @type {jQuery} - * @private - */ - var _$node = $( - lodash.template(keySelectionValueSelectionValueAttributeHtml)({ id: id }) - ); - - //noinspection JSUnusedGlobalSymbols - /** - * Set Value object of key - * @param {canvas_widget.Value} key - */ - this.setKey = function (key) { - _key = key; - }; - - /** - * Get Value object of key - * @returns {canvas_widget.Value} - */ - this.getKey = function () { - return _key; - }; - - /** - * Set Value object of value - * @param {canvas_widget.Value} value - */ - this.setValue = function (value) { - _value = value; - }; - - /** - * Get Value object of value - * @returns {canvas_widget.Value} - */ - this.getValue = function () { - return _value; - }; - - /** - * Set Value object of value - * @param {canvas_widget.Value} value - */ - this.setValue2 = function (value) { - _value2 = value; - }; - - /** - * Get Value object of value - * @returns {canvas_widget.Value} - */ - this.getValue2 = function () { - return _value2; - }; - - /** - * Get jQuery object of the DOM node representing the attribute - * @returns {jQuery} - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the attribute - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.key = _key.toJSON(); - json.value = _value.toJSON(); - json.value2 = _value2.toJSON(); - return json; - }; - - /** - * Set value of key and value by their JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - _key.setValueFromJSON(json.key); - _value.setValueFromJSON(json.value); - _value2.setValueFromJSON(json.value2 || { value: "" }); - }; - - this.registerYType = function () { - _key.registerYType(); - _value.registerYType(); - _value2.registerYType(); - }; - - _$node.find(".key").append(_key.get$node()); - _$node.find(".value").append(_value.get$node()); - } -} - -/** - * KeySelectionValueListAttribute - * @class canvas_widget.KeySelectionValueListAttribute - * @extends canvas_widget.AbstractAttribute - * @memberof canvas_widget - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {Object} options Selection options - */ -class KeySelectionValueListAttribute extends AbstractAttribute { - static TYPE = "KeySelectionValueListAttribute"; - constructor(id, name, subjectEntity, options) { - super(id, name, subjectEntity); - var that = this; - - /** - * Selection options - * @type {Object} - * @private - */ - var _options = options; - - /** - * List of attributes - * @type {Object} - * @private - */ - var _list = {}; - - /** - * jQuery object of DOM node representing the attribute - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(keySelectionValueListAttributeHtml)()); - - /** - * Inter widget communication wrapper - * @type {Object} - */ - y = y || window.y; - var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); - - /** - * Apply an Attribute Add Operation - * @param {operations.ot.AttributeAddOperation} operation - */ - var processAttributeAddOperation = function (operation) { - var attribute = new KeySelectionValueAttribute( - operation.getEntityId(), - "Attribute", - that, - _options - ); - attribute.registerYMap(); - that.addAttribute(attribute); - if (_$node.find(".list").find("#" + attribute.getEntityId()).length == 0) - _$node.find(".list").append(attribute.get$node()); - }; - - /** - * Apply an Attribute Delete Operation - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var processAttributeDeleteOperation = function (operation) { - var attribute = that.getAttribute(operation.getEntityId()); - if (attribute) { - that.deleteAttribute(attribute.getEntityId()); - attribute.get$node().remove(); - } - }; - - /** - * Propagate an Attribute Add Operation to the remote users and the local widgets - * @param {operations.ot.AttributeAddOperation} operation - */ - var propagateAttributeAddOperation = function (operation) { - processAttributeAddOperation(operation); - EntityManagerInstance.storeDataYjs(); - }; - - /** - * Propagate an Attribute Delete Operation to the remote users and the local widgets - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var propagateAttributeDeleteOperation = function (operation) { - processAttributeDeleteOperation(operation); - var ymap = that.getRootSubjectEntity().getYMap(); - ymap.delete(operation.getEntityId() + "[key]"); - EntityManagerInstance.storeDataYjs(); - }; - - /** - * Callback for a remote Attrbute Add Operation - * @param {operations.ot.AttributeAddOperation} operation - */ - var remoteAttributeAddCallback = function (operation) { - if ( - operation instanceof AttributeAddOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - processAttributeAddOperation(operation); - } - }; - - /** - * Callback for a remote Attribute Delete Operation - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var remoteAttributeDeleteCallback = function (operation) { - if ( - operation instanceof AttributeDeleteOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - processAttributeDeleteOperation(operation); - } - }; - - var localAttributeAddCallback = function (operation) { - if ( - operation instanceof AttributeAddOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - propagateAttributeAddOperation(operation); - } - }; - /** - * Callback for a local Attribute Delete Operation - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var localAttributeDeleteCallback = function (operation) { - if ( - operation instanceof AttributeDeleteOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - propagateAttributeDeleteOperation(operation); - } - }; - - /** - * Add attribute to attribute list - * @param {canvas_widget.AbstractAttribute} attribute - */ - this.addAttribute = function (attribute) { - var id = attribute.getEntityId(); - if (!_list.hasOwnProperty(id)) { - _list[id] = attribute; - } - }; - - /** - * Get attribute of attribute list by its entity id - * @param id - * @returns {canvas_widget.AbstractAttribute} - */ - this.getAttribute = function (id) { - if (_list.hasOwnProperty(id)) { - return _list[id]; - } - return null; - }; - - /** - * Delete attribute from attribute list by its entity id - * @param {string} id - */ - this.deleteAttribute = function (id) { - if (_list.hasOwnProperty(id)) { - delete _list[id]; - } - }; - - /** - * Get attribute list - * @returns {Object} - */ - this.getAttributes = function () { - return _list; - }; - - /** - * Set attribute list - * @param {Object} list - */ - this.setAttributes = function (list) { - _list = list; - }; - - /** - * Get jQuery object of the DOM node representing the attribute (list) - * @returns {jQuery} - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the attribute (list) - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.type = KeySelectionValueListAttribute.TYPE; - var attr = {}; - lodash.forEach(this.getAttributes(), function (val, key) { - attr[key] = val.toJSON(); - }); - json.list = attr; - return json; - }; - - /** - * Set attribute list by its JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - lodash.forEach(json.list, function (val, key) { - var attribute = new KeySelectionValueAttribute( - key, - key, - that, - _options - ); - attribute.setValueFromJSON(json.list[key]); - that.addAttribute(attribute); - if ( - _$node.find(".list").find("#" + attribute.getEntityId()).length == 0 - ) - _$node.find(".list").append(attribute.get$node()); - }); - }; - - /** - * Register inter widget communication callbacks - */ - this.registerCallbacks = function () { - _iwcw.registerOnDataReceivedCallback(localAttributeAddCallback); - _iwcw.registerOnDataReceivedCallback(localAttributeDeleteCallback); - }; - - /** - * Unregister inter widget communication callbacks - */ - this.unregisterCallbacks = function () { - _iwcw.unregisterOnDataReceivedCallback(localAttributeAddCallback); - _iwcw.unregisterOnDataReceivedCallback(localAttributeDeleteCallback); - }; - - _$node.find(".name").text(this.getName()); - - for (var attributeId in _list) { - if (_list.hasOwnProperty(attributeId)) { - _$node.find(".list").append(_list[attributeId].get$node()); - } - } - - if (_iwcw) { - that.registerCallbacks(); - } - - this.registerYMap = function () { - var ymap = that.getRootSubjectEntity().getYMap(); - var attrs = that.getAttributes(); - for (var key in attrs) { - if (attrs.hasOwnProperty(key)) { - var attr = attrs[key]; - attr.getKey().registerYType(); - attr.getValue().registerYType(); - } - } - - ymap.observe(function (event) { - const array = Array.from(event.changes.keys.entries()); - array.forEach(([key, change]) => { - if (key.indexOf("[key]") != -1) { - var operation; - switch (change.action) { - case "add": { - // var yUserId = event.object.map[key][0]; - // if (yUserId === y.clientID) return; - operation = new AttributeAddOperation( - key.replace(/\[\w*\]/g, ""), - that.getEntityId(), - that.getRootSubjectEntity().getEntityId(), - that.constructor.name - ); - remoteAttributeAddCallback(operation); - - break; - } - case "delete": { - operation = new AttributeDeleteOperation( - key.replace(/\[\w*\]/g, ""), - that.getEntityId(), - that.getRootSubjectEntity().getEntityId(), - that.constructor.name - ); - remoteAttributeDeleteCallback(operation); - break; - } - } - } - }); - }); - }; - } -} - -/** - * Abstract Class Node - * @class canvas_widget.ModelAttributesNode - * @extends canvas_widget.AbstractNode - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of node - * @param {object} [attr] model attributes - */ -class ModelAttributesNode extends AbstractNode { - static TYPE = "ModelAttributesNode"; - - constructor(id, attr, y) { - super(id, ModelAttributesNode.TYPE, 0, 0, 0, 0, 0, null, null, y); - y = y || window.y; - if (!y) { - throw new Error("y is not defined"); - } - /** - * jQuery object of node template - * @type {jQuery} - * @private - */ - var _$template = $(lodash.template(modelAttributesNodeHtml)()); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = AbstractNode.prototype.get$node - .call(this) - .append(_$template) - .addClass("class"); - - /** - * jQuery object of DOM node representing the attributes - * @type {jQuery} - * @private - */ - var _$attributeNode = _$node.find(".attributes"); - - /** - * Attributes of node - * @type {Object} - * @private - */ - var _attributes = this.getAttributes(); - - /** - * Get JSON representation of the node - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractNode.prototype.toJSON.call(this); - json.type = ModelAttributesNode.TYPE; - return json; - }; - - if (attr) { - for (var attrKey in attr) { - if (attr.hasOwnProperty(attrKey)) { - switch (attr[attrKey].value) { - case "boolean": - this.addAttribute( - new BooleanAttribute( - this.getEntityId() + - "[" + - attr[attrKey].key.toLowerCase() + - "]", - attr[attrKey].key, - this - ) - ); - break; - case "string": - this.addAttribute( - new SingleValueAttribute( - this.getEntityId() + - "[" + - attr[attrKey].key.toLowerCase() + - "]", - attr[attrKey].key, - this - ) - ); - break; - case "integer": - this.addAttribute( - new IntegerAttribute( - this.getEntityId() + - "[" + - attr[attrKey].key.toLowerCase() + - "]", - attr[attrKey].key, - this - ) - ); - break; - case "file": - this.addAttribute( - new FileAttribute( - this.getEntityId() + - "[" + - attr[attrKey].key.toLowerCase() + - "]", - attr[attrKey].key, - this - ) - ); - break; - default: - if (attr[attrKey].options) { - this.addAttribute( - new SingleSelectionAttribute( - this.getEntityId() + - "[" + - attr[attrKey].key.toLowerCase() + - "]", - attr[attrKey].key, - this, - attr[attrKey].options - ) - ); - } - break; - } - } - } - } else { - this.addAttribute( - new SingleValueAttribute(this.getEntityId() + "[name]", "Name", this, y) - ); - this.addAttribute( - new SingleMultiLineValueAttribute( - this.getEntityId() + "[description]", - "Description", - this, - y - ) - ); - } - - this.getLabel().getValue().setValue("Model Attributes"); - - _$node.find(".label").text("Model Attributes"); - _$node.hide(); - - for (var attributeKey in _attributes) { - if (_attributes.hasOwnProperty(attributeKey)) { - _$attributeNode.append(_attributes[attributeKey].get$node()); - } - } - - this.registerYMap = function () { - AbstractNode.prototype.registerYMap.call(this); - var attrs = this.getAttributes(); - for (var key in attrs) { - if (attrs.hasOwnProperty(key)) { - var attr = attrs[key]; - if ( - attr instanceof SingleValueAttribute || - attr instanceof SingleMultiLineValueAttribute - ) { - attr.getValue().registerYType(); - } else if ( - !(attr instanceof FileAttribute) && - !(attr instanceof SingleValueAttribute) && - !(attr instanceof SingleMultiLineValueAttribute) - ) { - attr.getValue().registerYType(); - } - } - } - }; - } -} - -/** - * ViewObjectNode - * @class canvas_widget.ViewObjectNode - * @extends canvas_widget.AbstractNode - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {number} zIndex Position of node on z-axis - * @param {object} jsonFromResource the ViewObjectNode is created from a json - */ -class ViewObjectNode extends AbstractNode { - static TYPE = "ViewObject"; - static DEFAULT_WIDTH = 150; - static DEFAULT_HEIGHT = 100; - constructor(id, left, top, width, height, zIndex, json) { - var that = this; - - super(id, "ViewObject", left, top, width, height, zIndex, json); - - /** - * jQuery object of node template - * @type {jQuery} - * @private - */ - var _$template = $( - lodash.template(viewobjectNodeHtml)({ type: that.getType() }) - ); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = AbstractNode.prototype.get$node - .call(this) - .append(_$template) - .addClass("viewobject"); - - /** - * jQuery object of DOM node representing the attributes - * @type {jQuery} - * @private - */ - var _$attributeNode = _$node.find(".attributes"); - - /** - * Attributes of node - * @type {Object} - * @private - */ - this.getAttributes(); - - /** - * Get JSON representation of the node - * @returns {Object} - */ - this.toJSON = function () { - return AbstractNode.prototype.toJSON.call(this); - }; - - this.createConditionListAttribute = function (refAttrs) { - var targetAttrList = {}; - if (refAttrs && refAttrs.constructor.name === "RenamingListAttribute") { - var attrs = refAttrs.getAttributes(); - for (var key in attrs) { - if (attrs.hasOwnProperty(key)) { - targetAttrList[key] = attrs[key].getKey().getValue(); - } - } - } else { - for (var key in refAttrs) { - if (refAttrs.hasOwnProperty(key)) { - targetAttrList[key] = refAttrs[key].val.value; - } - } - } - var conditionListAttr = new ConditionListAttribute( - "[condition]", - "Conditions", - that, - targetAttrList, - LogicalOperator - ); - that.addAttribute(conditionListAttr); - _$attributeNode.append(conditionListAttr.get$node()); - conditionListAttr.get$node().hide(); - return conditionListAttr; - }; - - this.registerYMap = function () { - AbstractNode.prototype.registerYMap.call(this); - that.getLabel().getValue().registerYType(); - renamingList.registerYMap(); - if (cla) cla.registerYMap(); - targetAttribute.getValue().registerYType(); - conjSelection.getValue().registerYType(); - }; - - this.showAttributes = function () { - if (renamingList.get$node().is(":hidden")) renamingList.get$node().show(); - if (conjSelection.get$node().is(":hidden")) - conjSelection.get$node().show(); - if (cla.get$node().is(":hidden")) cla.get$node().show(); - if (!targetAttribute.get$node().is(":hidden")) - targetAttribute.get$node().hide(); - }; - - var targetAttribute, renamingList, conjSelection, cla; - _$node.find(".label").append(this.getLabel().get$node()); - if (window.hasOwnProperty("y")) { - const dataMap = y.getMap("data"); - var model = dataMap.get("model"); - if (model) { - var selectionValues = - ViewTypesUtil.GetAllNodesOfBaseModelAsSelectionList2(model.nodes, [ - "Object", - ]); - targetAttribute = new SingleSelectionAttribute( - id + "[target]", - "Target", - that, - selectionValues - ); - that.addAttribute(targetAttribute); - _$attributeNode.prepend(targetAttribute.get$node()); - } - if (json) - cla = that.createConditionListAttribute( - json.attributes["[attributes]"].list - ); - else cla = that.createConditionListAttribute(); - } - - renamingList = new RenamingListAttribute( - "[attributes]", - "Attributes", - that, - { - show: "Visible", - hide: "Hidden", - } - ); - that.addAttribute(renamingList); - _$attributeNode.append(renamingList.get$node()); - renamingList.get$node().hide(); - - conjSelection = new SingleSelectionAttribute( - id + "[conjunction]", - "Conjunction", - that, - LogicalConjunctions - ); - that.addAttribute(conjSelection); - _$attributeNode.append(conjSelection.get$node()); - conjSelection.get$node().hide(); - - if (json && conjSelection && cla && renamingList && targetAttribute) - that.showAttributes(); - - this.setContextMenuItemCallback(function () { - var viewId = $("#lblCurrentView").text(); - return { - addShape: { - name: "Add Node Shape", - callback: function () { - var canvas = that.getCanvas(), - appearance = that.getAppearance(); - - //noinspection JSAccessibilityCheck - canvas - .createNode( - NodeShapeNode.TYPE, - appearance.left + appearance.width + 50, - appearance.top, - 150, - 100 - ) - .done(function (nodeId) { - canvas.createEdge( - BiDirAssociationEdge.TYPE, - that.getEntityId(), - nodeId, - null, - null, - viewId - ); - }); - }, - disabled: function () { - var edges = that.getEdges(), - edge, - edgeId; - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if ( - (edge instanceof BiDirAssociationEdge && - ((edge.getTarget() === that && - edge.getSource() instanceof NodeShapeNode) || - (edge.getSource() === that && - edge.getTarget() instanceof NodeShapeNode))) || - (edge instanceof UniDirAssociationEdge && - edge.getTarget() instanceof NodeShapeNode) - ) { - return true; - } - } - } - return false; - }, - }, - sep: "---------", - }; - }); - } -} - -/** - * ViewRelationshipNode - * @class canvas_widget.ViewRelationshipNode - * @extends canvas_widget.AbstractNode - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {number} zIndex Position of node on z-axis - * @param {object} json indicates if the ViewObjectNode is created from a json - - */ -let ViewRelationshipNode$1 = class ViewRelationshipNode extends AbstractNode { - static TYPE = "ViewRelationship"; - static DEFAULT_WIDTH = 150; - static DEFAULT_HEIGHT = 100; - constructor(id, left, top, width, height, zIndex, json) { - super(id, "ViewRelationship", left, top, width, height, zIndex, json); - var that = this; - - /** - * jQuery object of node template - * @type {jQuery} - * @private - */ - var _$template = $( - lodash.template(viewrelationshipNodeHtml$1)({ - type: that.getType(), - }) - ); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = AbstractNode.prototype.get$node - .call(this) - .append(_$template) - .addClass("viewrelationship"); - - /** - * jQuery object of DOM node representing the attributes - * @type {jQuery} - * @private - */ - var _$attributeNode = _$node.find(".attributes"); - - /** - * Attributes of node - * @type {Object} - * @private - */ - this.getAttributes(); - - /** - * Get JSON representation of the node - * @returns {Object} - */ - this.toJSON = function () { - return AbstractNode.prototype.toJSON.call(this); - }; - - this.registerYMap = function () { - AbstractNode.prototype.registerYMap.call(this); - that.getLabel().getValue().registerYType(); - attributeList.registerYMap(); - if (cla) cla.registerYMap(); - attribute.getValue().registerYType(); - conjSelection.getValue().registerYType(); - }; - - this.showAttributes = function () { - if (renamingList.get$node().is(":hidden")) renamingList.get$node().show(); - if (conjSelection.get$node().is(":hidden")) - conjSelection.get$node().show(); - if (cla.get$node().is(":hidden")) cla.get$node().show(); - if (!targetAttribute.get$node().is(":hidden")) - targetAttribute.get$node().hide(); - }; - - this.createConditionListAttribute = function (refAttrs) { - var targetAttrList = {}; - if (refAttrs && refAttrs.constructor.name === "RenamingListAttribute") { - var attrs = refAttrs.getAttributes(); - for (var key in attrs) { - if (attrs.hasOwnProperty(key)) { - targetAttrList[key] = attrs[key].getKey().getValue(); - } - } - } else { - for (var key in refAttrs) { - if (refAttrs.hasOwnProperty(key)) { - targetAttrList[key] = refAttrs[key].val.value; - } - } - } - var conditionListAttr = new ConditionListAttribute( - "[condition]", - "Conditions", - that, - targetAttrList, - LogicalOperator - ); - that.addAttribute(conditionListAttr); - _$attributeNode.append(conditionListAttr.get$node()); - conditionListAttr.get$node().hide(); - return conditionListAttr; - }; - - this.registerYMap = function () { - AbstractNode.prototype.registerYMap.call(this); - that.getLabel().getValue().registerYType(); - renamingList.registerYMap(); - if (cla) cla.registerYMap(); - targetAttribute.getValue().registerYType(); - conjSelection.getValue().registerYType(); - }; - - var targetAttribute, renamingList, conjSelection, cla; - _$node.find(".label").append(this.getLabel().get$node()); - if (window.hasOwnProperty("y")) { - const dataMap = y.getMap("data"); - var model = dataMap.get("model"); - if (model) { - var selectionValues = - ViewTypesUtil.GetAllNodesOfBaseModelAsSelectionList2(model.nodes, [ - "Relationship", - ]); - targetAttribute = new SingleSelectionAttribute( - id + "[target]", - "Reference", - that, - selectionValues - ); - that.addAttribute(targetAttribute); - _$attributeNode.prepend(targetAttribute.get$node()); - - if (json) - cla = that.createConditionListAttribute( - json.attributes["[attributes]"].list - ); - else cla = that.createConditionListAttribute(); - } - } - - renamingList = new RenamingListAttribute( - "[attributes]", - "Attributes", - that, - { - hidden: "Show", - top: "Show Top", - center: "Show Center", - bottom: "Show Bottom", - hide: "Hide", - } - ); - that.addAttribute(renamingList); - _$attributeNode.append(renamingList.get$node()); - renamingList.get$node().hide(); - - conjSelection = new SingleSelectionAttribute( - id + "[conjunction]", - "Conjunction", - that, - LogicalConjunctions - ); - that.addAttribute(conjSelection); - _$attributeNode.append(conjSelection.get$node()); - conjSelection.get$node().hide(); - - if (json && conjSelection && cla && renamingList && targetAttribute) - that.showAttributes(); - - this.setContextMenuItemCallback(function () { - var viewId = $("#lblCurrentView").text(); - return { - addShape: { - name: "Add Edge Shape", - callback: function () { - var canvas = that.getCanvas(), - appearance = that.getAppearance(), - nodeId; - - canvas.createNode( - EdgeShapeNode.TYPE, - appearance.left + appearance.width + 50, - appearance.top, - 150, - 100 - ); - canvas.createEdge( - BiDirAssociationEdge.TYPE, - that.getEntityId(), - nodeId, - null, - null, - viewId - ); - }, - disabled: function () { - var edges = that.getEdges(), - edge, - edgeId; - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if ( - (edge instanceof BiDirAssociationEdge && - ((edge.getTarget() === that && - edge.getSource() instanceof EdgeShapeNode) || - (edge.getSource() === that && - edge.getTarget() instanceof EdgeShapeNode))) || - (edge instanceof UniDirAssociationEdge && - edge.getTarget() instanceof EdgeShapeNode) - ) { - return true; - } - } - } - return false; - }, - }, - sep: "---------", - }; - }); - } -}; - -/** - * BiDirAssociationEdge - * @class canvas_widget.BiDirAssociationEdge - * @extends canvas_widget.AbstractEdge - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of edge - * @param {canvas_widget.AbstractNode} source Source node - * @param {canvas_widget.AbstractNode} target Target node - */ - -/** - * GeneralisationEdge - * @class GeneralisationEdge - * @extends AbstractEdge - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of edge - * @param {canvas_widget.AbstractNode} source Source node - * @param {canvas_widget.AbstractNode} target Target node - */ -class GeneralisationEdge extends AbstractEdge { - static TYPE = "Generalisation"; - static RELATIONS = [ - { - sourceTypes: [ObjectNode.TYPE], - targetTypes: [ObjectNode.TYPE, AbstractClassNode.TYPE], - }, - { - sourceTypes: [RelationshipNode.TYPE], - targetTypes: [RelationshipNode.TYPE, AbstractClassNode.TYPE], - }, - { - sourceTypes: [RelationshipGroupNode.TYPE], - targetTypes: [RelationshipNode.TYPE, ViewRelationshipNode$1.TYPE], - }, - { - sourceTypes: [AbstractClassNode.TYPE], - targetTypes: [AbstractClassNode.TYPE], - }, - { - sourceTypes: [EnumNode.TYPE], - targetTypes: [EnumNode.TYPE], - }, - ]; - - constructor(id, source, target) { - super(id, GeneralisationEdge.TYPE, source, target); - var that = this; - - /** - * Connect source and target node and draw the edge on canvas - */ - this.connect = function () { - var source = this.getSource(); - var target = this.getTarget(); - var connectOptions = { - source: source.get$node().get(0), - target: target.get$node().get(0), - paintStyle: { - stroke: "black", - strokeWidth: 4, - }, - endpoint: "Dot", - anchors: [source.getAnchorOptions(), target.getAnchorOptions()], - connector: { - type: StraightConnector.type, - options: { gap: 0 }, - }, - overlays: [ - { - type: "Arrow", - options: { - width: 20, - length: 25, - location: 1, - foldback: 1, - paintStyle: { - fill: "#ffffff", - outlineWidth: 2, - dashstyle: "black", - }, - }, - }, - { - type: "Custom", - options: { - create: function () { - return that.get$overlay().get(0); - }, - location: 0.5, - id: "label", - }, - }, - ], - cssClass: this.getEntityId(), - }; - - if (source === target) { - connectOptions.anchor = ["TopCenter", "LeftMiddle"]; - } - - source.addOutgoingEdge(this); - target.addIngoingEdge(this); - this.setJsPlumbConnection(window.jsPlumbInstance.connect(connectOptions)); - - this.repaintOverlays(); - lodash.each(EntityManagerInstance.getEdges(), function (e) { - e.setZIndex(); - }); - }; - - this.get$overlay().find(".type").addClass("segmented"); - } -} - -/** - * UniDirAssociationEdge - * @class canvas_widget.UniDirAssociationEdge - * @extends canvas_widget.AbstractEdge - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of edge - * @param {canvas_widget.AbstractNode} source Source node - * @param {canvas_widget.AbstractNode} target Target node - */ -class UniDirAssociationEdge extends AbstractEdge { - static TYPE = "Uni-Dir-Association"; - static RELATIONS = [ - { - sourceTypes: [ObjectNode.TYPE], - targetTypes: [ - EnumNode.TYPE, - NodeShapeNode.TYPE, - RelationshipNode.TYPE, - RelationshipGroupNode.TYPE, - ViewRelationshipNode$1.TYPE, - ], - }, - { - sourceTypes: [RelationshipNode.TYPE], - targetTypes: [ - EnumNode.TYPE, - EdgeShapeNode.TYPE, - ObjectNode.TYPE, - AbstractClassNode.TYPE, - ViewObjectNode.TYPE, - ], - }, - { - sourceTypes: [RelationshipGroupNode.TYPE], - targetTypes: [ObjectNode.TYPE, AbstractClassNode.TYPE], - }, - { - sourceTypes: [AbstractClassNode.TYPE], - targetTypes: [ - EnumNode.TYPE, - RelationshipNode.TYPE, - RelationshipGroupNode.TYPE, - ], - }, - { - sourceTypes: [ViewObjectNode.TYPE], - targetTypes: [ - EnumNode.TYPE, - NodeShapeNode.TYPE, - RelationshipNode.TYPE, - RelationshipGroupNode.TYPE, - ViewRelationshipNode$1.TYPE, - ], - }, - { - sourceTypes: [ViewRelationshipNode$1.TYPE], - targetTypes: [ - EnumNode.TYPE, - EdgeShapeNode.TYPE, - ObjectNode.TYPE, - AbstractClassNode.TYPE, - ViewObjectNode.TYPE, - ], - }, - ]; - - constructor(id, source, target) { - super(id, UniDirAssociationEdge.TYPE, source, target); - var that = this; - - /** - * Connect source and target node and draw the edge on canvas - */ - this.connect = function () { - var source = this.getSource(); - var target = this.getTarget(); - var connectOptions = { - source: source.get$node().get(0), - target: target.get$node().get(0), - paintStyle: { - stroke: "black", - strokeWidth: 4, - }, - endpoint: "Dot", - anchors: [source.getAnchorOptions(), target.getAnchorOptions()], - connector: { - type: StraightConnector.type, - options: { gap: 0 }, - }, - overlays: [ - { - type: "Arrow", - options: { - width: 20, - length: 30, - location: 1, - foldback: 0.5, - paintStyle: { - fill: "#ffffff", - outlineWidth: 2, - outlineStroke: "black", - }, - }, - }, - { - type: "Custom", - options: { - create: function () { - return that.get$overlay().get(0); - }, - location: 0.5, - id: "label", - }, - }, - ], - cssClass: this.getEntityId(), - }; - - if (source === target) { - connectOptions.anchors = ["TopCenter", "LeftMiddle"]; - } - - source.addOutgoingEdge(this); - target.addIngoingEdge(this); - this.setJsPlumbConnection(window.jsPlumbInstance.connect(connectOptions)); - - this.repaintOverlays(); - lodash.each(EntityManagerInstance.getEdges(), function (e) { - e.setZIndex(); - }); - }; - - this.get$overlay().find(".type").addClass("segmented"); - - /*this.setContextMenuItems({ - sep0: "---------", - convertToBiDirAssociationEdge: { - name: "Convert to Bi-Dir. Assoc. Edge", - callback: function(){ - var canvas = that.getCanvas(); - - //noinspection JSAccessibilityCheck - canvas.createEdge(require('canvas_widget/BiDirAssociationEdge').TYPE,that.getSource().getEntityId(),that.getTarget().getEntityId(),that.toJSON()); - - that.triggerDeletion(); - - } - } - });*/ - } -} - -class BiDirAssociationEdge extends AbstractEdge { - static TYPE = "Bi-Dir-Association"; - static RELATIONS = [ - { - sourceTypes: [ObjectNode.TYPE], - targetTypes: [ - EnumNode.TYPE, - NodeShapeNode.TYPE, - RelationshipNode.TYPE, - RelationshipGroupNode.TYPE, - ViewRelationshipNode$1.TYPE, - ], - }, - { - sourceTypes: [RelationshipNode.TYPE], - targetTypes: [ - EnumNode.TYPE, - EdgeShapeNode.TYPE, - ObjectNode.TYPE, - AbstractClassNode.TYPE, - ViewObjectNode.TYPE, - ], - }, - { - sourceTypes: [RelationshipGroupNode.TYPE], - targetTypes: [ObjectNode.TYPE, AbstractClassNode.TYPE], - }, - { - sourceTypes: [AbstractClassNode.TYPE], - targetTypes: [ - EnumNode.TYPE, - RelationshipNode.TYPE, - RelationshipGroupNode.TYPE, - ], - }, - { - sourceTypes: [EnumNode.TYPE], - targetTypes: [ - ObjectNode.TYPE, - RelationshipNode.TYPE, - AbstractClassNode.TYPE, - ], - }, - { - sourceTypes: [NodeShapeNode.TYPE], - targetTypes: [ObjectNode.TYPE], - }, - { - sourceTypes: [EdgeShapeNode.TYPE], - targetTypes: [RelationshipNode.TYPE], - }, - { - sourceTypes: [ViewObjectNode.TYPE], - targetTypes: [ - EnumNode.TYPE, - NodeShapeNode.TYPE, - RelationshipNode.TYPE, - RelationshipGroupNode.TYPE, - ViewRelationshipNode$1.TYPE, - ], - }, - { - sourceTypes: [ViewRelationshipNode$1.TYPE], - targetTypes: [ - EnumNode.TYPE, - EdgeShapeNode.TYPE, - ObjectNode.TYPE, - AbstractClassNode.TYPE, - ViewObjectNode.TYPE, - ], - }, - ]; - constructor(id, source, target) { - super(id, BiDirAssociationEdge.TYPE, source, target); - var that = this; - - /** - * Connect source and target node and draw the edge on canvas - */ - this.connect = function () { - var source = this.getSource(); - var target = this.getTarget(); - var connectOptions = { - source: source.get$node().get(0), - target: target.get$node().get(0), - paintStyle: { - stroke: "black", - strokeWidth: 4, - }, - endpoint: "Dot", - anchors: [source.getAnchorOptions(), target.getAnchorOptions()], - connector: { - type: StraightConnector.type, - options: { gap: 0 }, - }, - overlays: [ - { - type: "Custom", - options: { - create: function () { - return that.get$overlay().get(0); - }, - location: 0.5, - id: "label", - }, - }, - ], - cssClass: this.getEntityId(), - }; - - if (source === target) { - connectOptions.anchors = ["TopCenter", "LeftMiddle"]; - } - - source.addOutgoingEdge(this); - target.addIngoingEdge(this); - this.setJsPlumbConnection(window.jsPlumbInstance.connect(connectOptions)); - - this.repaintOverlays(); - lodash.each(EntityManagerInstance.getEdges(), function (e) { - e.setZIndex(); - }); - }; - - this.get$overlay().find(".type").addClass("segmented"); - } -} - -//noinspection JSUnusedGlobalSymbols - /** - * AbstractCanvasTool - * @class canvas_widget.AbstractCanvasTool - * @memberof canvas_widget - * @constructor - * @param {string} [name] Name of tool - * @param {string} [className] Class name assigned to canvas node when tool is mounted - * @param {string} [description] Description of tool - */ - class AbstractCanvasTool { - constructor(name, className, description) { - /** - * Canvas that the tool is added to - * @type {canvas_widget.AbstractCanvas} - * @private - */ - var _canvas = null; - - /** - * Name of tool - * @type {string} - * @private - */ - var _name = name || "AbstractTool"; - - /** - * Class name assigned to canvas node when tool is mounted - * @type {string} - * @private - */ - var _className = className || "tool-abstract"; - - /** - * Description of tool - * @type {string} - * @private - */ - var _description = description || "An abstract canvas tool"; - - /** - * Set canvas that the tool is added to - * @param {canvas_widget.AbstractCanvas} canvas - */ - this.setCanvas = function (canvas) { - if (!canvas) throw new Error("Canvas is null"); - _canvas = canvas; - }; - - /** - * Get canvas that the tool is added to - * @returns {canvas_widget.AbstractCanvas} - */ - this.getCanvas = function () { - return _canvas; - }; - - /** - * Get name of tool - * @returns {string} - */ - this.getName = function () { - return _name; - }; - - //noinspection JSUnusedGlobalSymbols - /** - * Get class name assigned to canvas node when tool is mounted - * @returns {string} - */ - this.getClassName = function () { - return _className; - }; - - /** - * Get description of tool - * @returns {string} - */ - this.getDescription = function () { - return _description; - }; - - /** - * Mount the tool on canvas - * @private - */ - this._mount = function () { - _canvas.get$canvas().addClass(_className); - }; - - /** - * Unmount the tool from canvas - * @private - */ - this._unmount = function () { - _canvas.get$canvas().removeClass(_className); - }; - } - /** - * Mount the tool on canvas - */ - mount() { - this._mount(); - } - /** - * Unmount the tool from canvas - */ - unmount() { - this._unmount(); - } - } - -/** - * NodeTool - * @class canvas_widget.NodeTool - * @extends canvas_widget.AbstractCanvasTool - * @memberof canvas_widget - * @constructor - */ -class NodeTool extends AbstractCanvasTool { - constructor( - name, - className, - description, - containment, - defaultWidth, - defaultHeight - ) { - super(name, className || "tool-node", description || "Add a node"); - - var _defaultWidth = defaultWidth || 100, - _defaultHeight = defaultHeight || 50; - - /** - * Mount the tool on canvas - */ - this.mount = function (defaultLabel, defaultAttributeValues) { - var $canvas = this.getCanvas().get$canvas(); - var that = this; - AbstractCanvasTool.prototype.mount.call(this); - - //Enable Node Addition - $canvas.on("mouseup.nodeadd", function (ev) { - var offsetCanvas; - - if (ev.which != 1) return; - - offsetCanvas = $canvas.offset(); // current offset of the canvas relative to the document - var zoom = that.getCanvas().getZoom(); - var nodeX = (ev.pageX - offsetCanvas.left) / zoom - _defaultWidth / 2; // center position of the node - var nodeY = (ev.pageY - offsetCanvas.top) / zoom - _defaultHeight / 2; // center position of the node - - that - .getCanvas() - .createNode( - that.getName(), - nodeX, - nodeY, - _defaultWidth, - _defaultHeight, - null, - containment, - null, - null, - null, - defaultLabel, - defaultAttributeValues - ); - that.getCanvas().resetTool(); - }); - - $canvas.bind("contextmenu", function (ev) { - if (ev.target == this) { - ev.preventDefault(); - that.getCanvas().resetTool(); - return false; - } - return true; - }); - - $canvas.find(".node").bind("contextmenu", function (ev) { - ev.preventDefault(); - that.getCanvas().resetTool(); - that.getCanvas().select(EntityManagerInstance.findNode($(this).attr("id"))); - return false; - }); - }; - - /** - * Unmount the tool from canvas - */ - this.unmount = function () { - var $canvas = this.getCanvas().get$canvas(); - AbstractCanvasTool.prototype.unmount.call(this); - - //Disable Node Addition - $canvas.off("mouseup.nodeadd"); - - $canvas.unbind("contextmenu"); - $canvas.find(".node").unbind("contextmenu"); - }; - } -} - -/** - * AbstractClassNodeTool - * @class canvas_widget.ClassNodeTool - * @extends canvas_widget.NodeTool - * @memberof canvas_widget - * @constructor - */ -class AbstractClassNodeTool extends NodeTool{ - constructor() { - super( - AbstractClassNode.TYPE, - null, - null, - null, - AbstractClassNode.DEFAULT_WIDTH, - AbstractClassNode.DEFAULT_HEIGHT - ); - } -} - -/** - * EdgeTool - * @class canvas_widget.EdgeTool - * @extends canvas_widget.AbstractCanvasTool - * @memberof canvas_widget - * @constructor - * @param {string} name Name of tool - * @param {string[]} relations Array of valid relations of node types the edge can connect - * @param {string} [className] Class name assigned to canvas node when tool is mounted - * @param {string} [description] Description of tool - */ -class EdgeTool extends AbstractCanvasTool { - constructor(name, relations, className, description) { - super(name, className || "tool-edge", description || "Add an edge"); - const jsPlumbInstance = window.jsPlumbInstance; - - var _relations = relations; - - /** - * Mount the tool on canvas - */ - this.mount = function () { - AbstractCanvasTool.prototype.mount.call(this); - function makeNeighborhoodFilter(nodeId) { - return function (n) { - return ( - n.getEntityId() !== nodeId && - !n.getNeighbors().hasOwnProperty(nodeId) - ); - }; - } - - function makeMakeTargetCallback() { - return function (node) { - node.makeTarget(); - node.unlowlight(); - }; - } - - var that = this; - - var $canvas = this.getCanvas().get$canvas(); - - //Bind Node Events - var nodes = EntityManagerInstance.getNodes(); - var nodeId, node, nodeType, strGetNodesByType; - var i, numOfRelations; - - for (nodeId in nodes) { - if (nodes.hasOwnProperty(nodeId)) { - node = nodes[nodeId]; - node.lowlight(); - if ( - EntityManagerInstance.getViewId() === undefined || - EntityManagerInstance.getLayer() === CONFIG.LAYER.META - ) { - nodeType = node.getType(); - strGetNodesByType = "getNodesByType"; - } else { - nodeType = node.getCurrentViewType(); - strGetNodesByType = "getNodesByViewType"; - } - for ( - i = 0, numOfRelations = _relations.length; - i < numOfRelations; - i++ - ) { - if (relations[i].sourceTypes.indexOf(nodeType) !== -1) { - if ( - lodash.size( - lodash.filter( - EntityManagerInstance[strGetNodesByType](relations[i].targetTypes), - makeNeighborhoodFilter(node.getEntityId()) - ) - ) > 0 - ) { - node.makeSource(); - node.unbindMoveToolEvents(); - node.unlowlight(); - break; - } - } - } - } - } - - jsPlumbInstance.bind("beforeDrag", function (info) { - var sourceNode = EntityManagerInstance.findNode(info.sourceId), - sourceType, - i, - numOfRelations, - strGetNodesByType; - if (sourceNode) { - if ( - EntityManagerInstance.getViewId() === undefined || - EntityManagerInstance.getLayer() === CONFIG.LAYER.META - ) { - sourceType = sourceNode.getType(); - strGetNodesByType = "getNodesByType"; - } else { - sourceType = sourceNode.getCurrentViewType(); - strGetNodesByType = "getNodesByViewType"; - } - - for ( - i = 0, numOfRelations = _relations.length; - i < numOfRelations; - i++ - ) { - if (relations[i].sourceTypes.indexOf(sourceType) !== -1) { - lodash.each( - lodash.filter( - EntityManagerInstance[strGetNodesByType](relations[i].targetTypes), - makeNeighborhoodFilter(sourceNode.getEntityId()) - ), - makeMakeTargetCallback() - ); - } - } - } - $(info.source).addClass("current"); - $canvas.addClass("dragging"); - return true; - }); - jsPlumbInstance.bind("beforeDrop", function () { - $canvas.removeClass("dragging"); - $(".node.current").removeClass("current"); - return true; - }); - jsPlumbInstance.bind("beforeDetach", function (info) { - if (info.connection?.pending) { - $(".node.current").removeClass("current"); - $canvas.removeClass("dragging"); - } - return true; - }); - - jsPlumbInstance.bind("connection", function (info, originalEvent) { - if (typeof originalEvent !== "undefined") { - //Was the connection established using Drag'n Drop? - // If so we delete the connection and form it manually again - if (info.connection) { - jsPlumbInstance.deleteConnection(info.connection, { - fireEvent: false, - }); - } - - that - .getCanvas() - .createEdge(that.getName(), info.sourceId, info.targetId); - } - return true; - }); - - $canvas.bind("contextmenu", function (ev) { - if (ev.target == this) { - ev.preventDefault(); - that.getCanvas().resetTool(); - return false; - } - return true; - }); - - $canvas.find(".node").bind("contextmenu", function (ev) { - ev.preventDefault(); - that.getCanvas().resetTool(); - that.getCanvas().select(EntityManagerInstance.findNode($(this).attr("id"))); - return false; - }); - }; - - /** - * Unmount the tool from canvas - */ - this.unmount = function () { - AbstractCanvasTool.prototype.unmount.call(this, arguments); - - var $canvas = this.getCanvas().get$canvas(); - - //Unbind Node Events - //TODO Not very nicely implemented. Iterates over all nodes again like it was in MoveTool - var nodes = EntityManagerInstance.getNodes(); - var nodeId, node; - for (nodeId in nodes) { - if (nodes.hasOwnProperty(nodeId)) { - node = nodes[nodeId]; - node.unlowlight(); - node.unbindEdgeToolEvents(); - node.bindMoveToolEvents(); - } - } - - //Disable Edge Dragging - // $canvas.find(".node").each(function () { - // var $this = $(this); - // try { - // const nodeSelector = getQuerySelectorFromNode($this); - // jsPlumbInstance.removeSourceSelector(nodeSelector); - // jsPlumbInstance.removeTargetSelector(nodeSelector); - // } catch (error) { - // console.error(error); - // } - // }); - jsPlumbInstance.unbind("connectionDrag"); - jsPlumbInstance.unbind("beforeDrop"); - jsPlumbInstance.unbind("connection"); - - $canvas.unbind("contextmenu"); - $canvas.find(".node").unbind("contextmenu"); - }; - } -} - -/** - * BiDirAssociationEdgeTool - * @class canvas_widget.BiDirAssociationEdgeTool - * @extends canvas_widget.EdgeTool - * @memberof canvas_widget - * @constructor - */ -class BiDirAssociationEdgeTool extends EdgeTool { - constructor() { - super(BiDirAssociationEdge.TYPE, BiDirAssociationEdge.RELATIONS); - } -} - -function DagreLayout() { - return { - apply: function () { - var node, edge, e, appearance, relX, relY, x, y; - var g = new dagre.graphlib.Graph(); - g.setGraph({}); - g.setDefaultEdgeLabel(function () { - return {}; - }); - var nodes = EntityManagerInstance.getNodes(); - - for (var nodeId in nodes) { - if (nodes.hasOwnProperty(nodeId)) { - node = nodes[nodeId]; - appearance = node.getAppearance(); - g.setNode(nodeId, { - width: appearance.width, - height: appearance.height, - }); - } - } - var edges = EntityManagerInstance.getEdges(); - for (var edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - g.setEdge( - edge.getSource().getEntityId(), - edge.getTarget().getEntityId() - ); - } - } - dagre.layout(g, { - rankdir: "BT", - align: "UL", - ranker: "tight-tree", - marginx: 9000, - marginy: 9000, - }); - - relX = 4500 - g.graph().width / 2; - relY = 4500 - g.graph().height / 2; - g.nodes().forEach(function (v) { - e = EntityManagerInstance.findNode(v); - if (e) { - appearance = e.getAppearance(); - node = g.node(v); - x = relX + node.x; - y = relY + node.y; - if (appearance.top !== x || appearance.top !== y) e.moveAbs(x, y); - } - }); - }, - }; -} + /** + * Entity id of source node + * @type {String} + * @private + */ + var _source = source; + + /** + * Entity id of target node + * @type {String} + * @private + */ + var _target = target; + + /** + * JSON representation of edge + * @type {Object} + * @private + */ + var _json = json; + + /** + * Create OTOperation for operation + * @returns {operations.ot.OTOperation} + */ + var createOTOperation = function () { + return new OTOperation( + CONFIG.ENTITY.EDGE + ":" + that.getEntityId(), + JSON.stringify({ + type: _type, + source: _source, + target: _target, + json: _json, + viewId: _viewId, + oType: _oType, + jabberId: _jabberId, + }), + CONFIG.OPERATION.TYPE.INSERT, + CONFIG.IWC.POSITION.EDGE.ADD + ); + }; + + /** + * Get type of edge to add + * @returns {String} + */ + this.getType = function () { + return _type; + }; + + /** + * Get entity id of source node + * @returns {String} + */ + this.getSource = function () { + return _source; + }; + + /** + * Get entity id of target node + * @returns {String} + */ + this.getTarget = function () { + return _target; + }; + + /** + * get the identifier of the view + * @returns {string} + */ + this.getViewId = function () { + return _viewId; + }; + + /** + * Get the jabber id + * @returns {string} + */ + this.getJabberId = function () { + return _jabberId; + }; + + /** + * Get JSON representation of edge + * @return {Object} + */ + this.getJSON = function () { + return _json; + }; + + /** + * Get corresponding ot operation + * @returns {operations.ot.OTOperation} + * @private + */ + this.getOTOperation = function () { + var otOperation = EntityOperation.prototype.getOTOperation.call(this); + if (otOperation === null) { + otOperation = createOTOperation(); + this.setOTOperation(otOperation); + } + return otOperation; + }; + + /** + * Adjust the passed operation in the history of operation + * when this operation is applied remotely after the passed operation + * on an graph instance stored in the passed EntityManager + * @param {canvas_widget.EntityManager} EntityManager + * @param {EntityOperation} operation Remote operation + * @returns {EntityOperation} + */ + this.adjust = function (EntityManager, operation) { + return operation; + }; + + /** + * Compute the inverse of the operation + * @returns {EdgeDeleteOperation} + */ + this.inverse = function () { + return new EdgeDeleteOperation( + this.getEntityId(), + this.getType(), + this.getSource(), + this.getTarget() + ); + }; + } + static getOperationDescription( + edgeType, + edgeLabel, + sourceNodeType, + sourceNodeLabel, + targetNodeType, + targetNodeLabel, + viewId + ) { + if (!edgeLabel && !viewId) { + return ( + "..created a new " + + edgeType + + " between " + + sourceNodeType + + " " + + sourceNodeLabel + + " and " + + targetNodeType + + " " + + targetNodeLabel + ); + } else if (!viewId) { + return ( + "..created " + + edgeType + + " " + + edgeLabel + + " between " + + sourceNodeType + + " " + + sourceNodeLabel + + " and " + + targetNodeType + + " " + + targetNodeLabel + ); + } else { + return ( + "..created " + + edgeType + + " " + + edgeLabel + + " between " + + sourceNodeType + + " " + + sourceNodeLabel + + " and " + + targetNodeType + + " " + + targetNodeLabel + + " in View " + + viewId + ); + } + } + toJSON = function () { + return { + id: this.getEntityId(), + type: this.getType(), + source: this.getSource(), + target: this.getTarget(), + json: this.getJSON(), + viewId: this.getViewId(), + oType: this.getOriginType(), + jabberId: this.getJabberId(), + }; + }; +} + +/** + * AttributeAddOperation + * @class operations.ot.AttributeAddOperation + * @memberof operations.ot + * @extends operations.ot.EntityOperation + * @param {String} entityId Entity id of the entity this activity works on + * @param {String} subjectEntityId Id of the entity the attribute is assigned to + * @param {String} rootSubjectEntityId Id of topmost entity in the chain of entities the attribute is assigned to + * @param {String} type Type of attribute to add + * @constructor + */ +class AttributeAddOperation extends EntityOperation { + static TYPE = "AttributeAddOperation"; + getSubjectEntityId; + getRootSubjectEntityId; + getType; + getData; + toJSON; + constructor( + entityId, + subjectEntityId, + rootSubjectEntityId, + type, + data = null + ) { + super( + EntityOperation.TYPES.AttributeAddOperation, + entityId, + CONFIG.ENTITY.ATTR + ); + var that = this; + + /** + * Id of the entity the attribute is assigned to + * @type {String} + * @private + */ + var _subjectEntityId = subjectEntityId; + + /** + * Id of topmost entity in the chain of entities the attribute is assigned to + * @type {String} + * @private + */ + var _rootSubjectEntityId = rootSubjectEntityId; + + /** + * Type of attribute to add + * @type {String} + * @private + */ + var _type = type; + + var _data = data; + + /** + * Create OTOperation for operation + * @returns {operations.ot.OTOperation} + */ + var createOTOperation = function () { + return new OTOperation( + CONFIG.ENTITY.ATTR + ":" + that.getEntityId(), + JSON.stringify({ + type: _type, + subjectEntityId: _subjectEntityId, + rootSubjectEntityId: _rootSubjectEntityId, + data: _data, + }), + CONFIG.OPERATION.TYPE.INSERT, + CONFIG.IWC.POSITION.ATTR.ADD + ); + }; + + /** + * Get id of the entity the attribute is assigned to + * @returns {*} + */ + this.getSubjectEntityId = function () { + return _subjectEntityId; + }; + + /** + * Get id of topmost entity in the chain of entities the attribute is assigned to + * @returns {*} + */ + this.getRootSubjectEntityId = function () { + return _rootSubjectEntityId; + }; + + /** + * Get type of attribute to add + * @returns {*} + */ + this.getType = function () { + return _type; + }; + + /** + * Get corresponding ot operation + * @returns {operations.ot.OTOperation} + * @private + */ + this.getOTOperation = function () { + var otOperation = EntityOperation.prototype.getOTOperation.call(this); + if (otOperation === null) { + otOperation = createOTOperation(); + that.setOTOperation(otOperation); + } + return otOperation; + }; + + this.getData = function () { + return _data; + }; + + /** + * Adjust the passed operation in the history of operation + * when this operation is applied remotely after the passed operation + * on an graph instance stored in the passed EntityManager + * @param {canvas_widget.EntityManager} EntityManager + * @param {EntityOperation} operation Remote operation + * @returns {EntityOperation} + */ + this.adjust = function (EntityManager, operation) { + return operation; + }; + + /** + * Compute the inverse of the operation + * @returns {AttributeDeleteOperation} + */ + this.inverse = function () { + return new AttributeDeleteOperation( + that.getEntityId(), + that.getSubjectEntityId(), + that.getRootSubjectEntityId(), + that.getType() + ); + }; + + this.toJSON = function () { + return { + entityId: this.getEntityId(), + type: this.getType(), + subjectEntityId: this.getSubjectEntityId(), + rootSubjectEntityId: this.getRootSubjectEntityId(), + data: this.getData(), + }; + }; + } +} + +/** + * AttributeDeleteOperation + * @class operations.ot.AttributeDeleteOperation + * @memberof operations.ot + * @extends operations.ot.EntityOperation + * @param {String} entityId Entity id of the entity this activity works on + * @param {String} subjectEntityId Id of the entity the attribute is assigned to + * @param {String} rootSubjectEntityId Id of topmost entity in the chain of entities the attribute is assigned to + * @param {String} type Type of attribute to delete + * @constructor + */ +class AttributeDeleteOperation extends EntityOperation { + static TYPE = "AttributeDeleteOperation"; + getSubjectEntityId; + getRootSubjectEntityId; + getType; + toJSON; + constructor(entityId, subjectEntityId, rootSubjectEntityId, type) { + super( + EntityOperation.TYPES.AttributeDeleteOperation, + entityId, + CONFIG.ENTITY.ATTR + ); + var that = this; + + /** + * Id of the entity the attribute is assigned to + * @type {String} + * @private + */ + var _subjectEntityId = subjectEntityId; + + /** + * Id of topmost entity in the chain of entities the attribute is assigned to + * @type {String} + * @private + */ + var _rootSubjectEntityId = rootSubjectEntityId; + + /** + * Type of attribute to add + * @type {String} + * @private + */ + var _type = type; + + /** + * Create OTOperation for operation + * @returns {operations.ot.OTOperation} + */ + var createOTOperation = function () { + return new OTOperation( + CONFIG.ENTITY.ATTR + ":" + that.getEntityId(), + JSON.stringify({ + type: _type, + subjectEntityId: _subjectEntityId, + rootSubjectEntityId: _rootSubjectEntityId, + }), + CONFIG.OPERATION.TYPE.UPDATE, + CONFIG.IWC.POSITION.ATTR.DEL + ); + }; + + /** + * Get id of the entity the attribute is assigned to + * @returns {*} + */ + this.getSubjectEntityId = function () { + return _subjectEntityId; + }; + + /** + * Get id of topmost entity in the chain of entities the attribute is assigned to + * @returns {*} + */ + this.getRootSubjectEntityId = function () { + return _rootSubjectEntityId; + }; + + /** + * Get type of attribute to add + * @returns {*} + */ + this.getType = function () { + return _type; + }; + + /** + * Get corresponding ot operation + * @returns {operations.ot.OTOperation} + * @private + */ + this.getOTOperation = function () { + var otOperation = EntityOperation.prototype.getOTOperation.call(this); + if (otOperation === null) { + otOperation = createOTOperation(); + that.setOTOperation(otOperation); + } + return otOperation; + }; + + /** + * Adjust the passed operation in the history of operation + * when this operation is applied remotely after the passed operation + * on an graph instance stored in the passed EntityManager + * @param {canvas_widget.EntityManager} EntityManager + * @param {operations.ot.EntityOperation} operation Remote operation + * @returns {operations.ot.EntityOperation} + */ + this.adjust = function (EntityManager, operation) { + switch (operation.getOperationType()) { + case EntityOperation.TYPES.AttributeAddOperation: + case EntityOperation.TYPES.AttributeDeleteOperation: + if ( + that.getRootSubjectEntityId() === operation.getRootSubjectEntityId() + ) { + return null; + } + break; + case EntityOperation.TYPES.ValueChangeOperation: + if (operation.getEntityIdChain().indexOf(this.getEntityId()) !== -1) { + return null; + } + break; + } + + return operation; + }; + + /** + * Compute the inverse of the operation + * @returns {operations.ot.AttributeAddOperation} + */ + this.inverse = function () { + return new AttributeAddOperation( + this.getEntityId(), + this.getSubjectEntityId(), + this.getRootSubjectEntityId(), + this.getType() + ); + }; + this.toJSON = function () { + return { + entityId: this.getEntityId(), + type: this.getType(), + subjectEntityId: this.getSubjectEntityId(), + rootSubjectEntityId: this.getRootSubjectEntityId(), + }; + }; + } +} + +/** + * NodeMoveOperation + * @class operations.ot.NodeMoveOperation + * @memberof operations.ot + * @extends operations.ot.EntityOperation + * @param {String} entityId Entity id of the entity this activity works on + * @param {number} offsetX Offset in x-direction + * @param {number} offsetY Offset in y-direction + * @param {string} optional: jabberId the jabberId of the user (is automatically set by propagateNodeMoveOperation) + * @constructor + */ +class NodeMoveOperation extends EntityOperation { + static TYPE = "NodeMoveOperation"; + getOffsetX; + getOffsetY; + getJabberId; + setJabberId; + constructor(entityId, offsetX, offsetY, jabberId) { + super( + EntityOperation.TYPES.NodeMoveOperation, + entityId, + CONFIG.ENTITY.NODE + ); + var that = this; + + /** + * Offset in x-direction + * @type {number} + * @private + */ + var _offsetX = offsetX; + + /** + * Offset in y-direction + * @type {number} + * @private + */ + var _offsetY = offsetY; + + /** + * jabber id of the user + * @type {string} + * @private + */ + var _jabberId = jabberId; + + /** + * Create OTOperation for operation + * @returns {operations.ot.OTOperation} + */ + var createOTOperation = function () { + return new OTOperation( + CONFIG.ENTITY.NODE + ":" + that.getEntityId(), + JSON.stringify({ + offsetX: _offsetX, + offsetY: _offsetY, + jabberId: _jabberId, + }), + CONFIG.OPERATION.TYPE.UPDATE, + CONFIG.IWC.POSITION.NODE.POS + ); + }; + + /** + * Get offset in x-direction + * @returns {number} + */ + this.getOffsetX = function () { + return _offsetX; + }; + + /** + * Get offset in y-direction + * @returns {number} + */ + this.getOffsetY = function () { + return _offsetY; + }; + + /** + * Get the JabberId + * @returns {string} + */ + this.getJabberId = function () { + return _jabberId; + }; + /** + * Set the JabberId + * @param {string} jabberId + */ + this.setJabberId = function (jabberId) { + _jabberId = jabberId; + }; + + /** + * Get corresponding ot operation + * @returns {operations.ot.OTOperation} + * @private + */ + this.getOTOperation = function () { + var otOperation = EntityOperation.prototype.getOTOperation.call(this); + if (otOperation === null) { + otOperation = createOTOperation(); + this.setOTOperation(otOperation); + } + return otOperation; + }; + + /** + * Adjust the passed operation in the history of operation + * when this operation is applied remotely after the passed operation + * on an graph instance stored in the passed EntityManager + * @param {canvas_widget.EntityManager} EntityManager + * @param {EntityOperation} operation Remote operation + * @returns {EntityOperation} + */ + this.adjust = function (EntityManager, operation) { + return operation; + }; + + /** + * Compute the inverse of the operation + * @returns {NodeMoveOperation} + */ + this.inverse = function () { + return new NodeMoveOperation( + this.getEntityId(), + -this.getOffsetX(), + -this.getOffsetY(), + this.getJabberId() + ); + }; + } + static getOperationDescription(nodeType, nodeLabel, viewId) { + if (!nodeLabel && !viewId) { + return "..moved " + nodeType; + } else if (!viewId) { + return "..moved " + nodeType + " " + nodeLabel; + } else { + return "..moved " + nodeType + " " + nodeLabel + " in View " + viewId; + } + } + toJSON = function () { + return { + id: this.getEntityId(), + offsetX: this.getOffsetX(), + offsetY: this.getOffsetY(), + jabberId: this.getJabberId(), + }; + }; +} + +/** + * NodeMoveZOperation + * @class operations.ot.NodeMoveZOperation + * @memberof operations.ot + * @extends operations.ot.EntityOperation + * @param {String} entityId Entity id of the entity this activity works on + * @param {number} offsetZ Offset in z-direction + * @param {string} optional: jabberId the jabberId of the user (is automatically set by propagateNodeMoveOperation) + * @constructor + */ +class NodeMoveZOperation extends EntityOperation { + static TYPE = "NodeMoveZOperation"; + getOffsetZ; + getJabberId; + setJabberId; + constructor(entityId, offsetZ, jabberId) { + super( + EntityOperation.TYPES.NodeMoveZOperation, + entityId, + CONFIG.ENTITY.NODE + ); + var that = this; + + /** + * Offset in y-direction + * @type {number} + * @private + */ + var _offsetZ = offsetZ; + + /** + * the jabberId + * @type {string} + * @private + */ + var _jabberId = jabberId; + + /** + * Create OTOperation for operation + * @returns {operations.ot.OTOperation} + */ + var createOTOperation = function () { + return new OTOperation( + CONFIG.ENTITY.NODE + ":" + that.getEntityId(), + JSON.stringify({ + offsetZ: _offsetZ, + jabberId: _jabberId, + }), + CONFIG.OPERATION.TYPE.UPDATE, + CONFIG.IWC.POSITION.NODE.Z + ); + }; + + /** + * Get offset in z-direction + * @returns {number} + */ + this.getOffsetZ = function () { + return _offsetZ; + }; + + this.getJabberId = function () { + return _jabberId; + }; + + this.setJabberId = function (jabberId) { + _jabberId = jabberId; + }; + + /** + * Get corresponding ot operation + * @returns {operations.ot.OTOperation} + * @private + */ + this.getOTOperation = function () { + var otOperation = EntityOperation.prototype.getOTOperation.call(this); + if (otOperation === null) { + otOperation = createOTOperation(); + this.setOTOperation(otOperation); + } + return otOperation; + }; + + /** + * Adjust the passed operation in the history of operation + * when this operation is applied remotely after the passed operation + * on an graph instance stored in the passed EntityManager + * @param {canvas_widget.EntityManager} EntityManager + * @param {EntityOperation} operation Remote operation + * @returns {EntityOperation} + */ + this.adjust = function (EntityManager, operation) { + return operation; + }; + + /** + * Compute the inverse of the operation + * @returns {NodeMoveZOperation} + */ + this.inverse = function () { + return new NodeMoveZOperation( + this.getEntityId(), + -this.getOffsetZ(), + this.getJabberId() + ); + }; + } + static getOperationDescription(nodeType, nodeLabel, viewId) { + if (!nodeLabel && !viewId) { + return "..moved " + nodeType + " on on Z-Axis"; + } else if (!viewId) { + return "..moved " + nodeType + " " + nodeLabel + " on Z-Axis"; + } else { + return ( + "..moved " + + nodeType + + " " + + nodeLabel + + " in View " + + viewId + + " on Z-Axis" + ); + } + } + toJSON = function () { + return { + id: this.getEntityId(), + offsetZ: this.getOffsetZ(), + jabberId: this.getJabberId(), + }; + }; +} + +/** + * NodeResizeOperation + * @class operations.ot.NodeResizeOperation + * @memberof operations.ot + * @extends operations.ot.EntityOperation + * @param {String} entityId Entity id of the entity this activity works on + * @param {number} offsetX Offset in x-direction + * @param {number} offsetY Offset in y-direction + * @param {string} optional: jabberId the jabberId of the user (is automatically set by propagateNodeMoveOperation) + * @constructor + */ +class NodeResizeOperation extends EntityOperation { + static TYPE = "NodeResizeOperation"; + getOffsetX + getOffsetY + getJabberId + setJabberId + constructor(entityId, offsetX, offsetY, jabberId) { + super( + EntityOperation.TYPES.NodeResizeOperation, + entityId, + CONFIG.ENTITY.NODE + ); + var that = this; + + var _jabberId = jabberId; + + /** + * Offset in x-direction + * @type {number} + * @private + */ + var _offsetX = offsetX; + + /** + * Offset in y-direction + * @type {number} + * @private + */ + var _offsetY = offsetY; + + /** + * Create OTOperation for operation + * @returns {operations.ot.OTOperation} + */ + var createOTOperation = function () { + return new OTOperation( + CONFIG.ENTITY.NODE + ":" + that.getEntityId(), + JSON.stringify({ + offsetX: _offsetX, + offsetY: _offsetY, + jabberId: _jabberId, + }), + CONFIG.OPERATION.TYPE.UPDATE, + CONFIG.IWC.POSITION.NODE.DIM + ); + }; + + /** + * Get offset in x-direction + * @returns {number} + */ + this.getOffsetX = function () { + return _offsetX; + }; + + /** + * Get offset in y-direction + * @returns {number} + */ + this.getOffsetY = function () { + return _offsetY; + }; + + this.getJabberId = function () { + return _jabberId; + }; + + this.setJabberId = function (jabberId) { + _jabberId = jabberId; + }; + + /** + * Get corresponding ot operation + * @returns {operations.ot.OTOperation} + * @private + */ + this.getOTOperation = function () { + var otOperation = EntityOperation.prototype.getOTOperation.call(this); + if (otOperation === null) { + otOperation = createOTOperation(); + this.setOTOperation(otOperation); + } + return otOperation; + }; + + /** + * Adjust the passed operation in the history of operation + * when this operation is applied remotely after the passed operation + * on an graph instance stored in the passed EntityManager + * @param {canvas_widget.EntityManager} EntityManager + * @param {EntityOperation} operation Remote operation + * @returns {EntityOperation} + */ + this.adjust = function (EntityManager, operation) { + return operation; + }; + + /** + * Compute the inverse of the operation + * @returns {NodeResizeOperation} + */ + this.inverse = function () { + return new NodeResizeOperation( + this.getEntityId(), + -this.getOffsetX(), + -this.getOffsetY(), + this.getJabberId() + ); + }; + } + static getOperationDescription(nodeType, nodeLabel, viewId) { + if (!nodeLabel && !viewId) { + return "..resized " + nodeType; + } else if (!viewId) { + return "..resized " + nodeType + " " + nodeLabel; + } else { + return "..resized " + nodeType + " " + nodeLabel + " in View " + viewId; + } + } + toJSON=function() { + return { + id: this.getEntityId(), + offsetX: this.getOffsetX(), + offsetY: this.getOffsetY(), + jabberId: this.getJabberId(), + }; + } +} + +/** + * ValueChangeOperation + * @class operations.ot.ValueChangeOperation + * @memberof operations.ot + * @extends operations.ot.EntityOperation + * @param entityId Entity id of the entity this activity works on + * @param {string} value Char that has been added resp. deleted + * @param {string} type Type of operation (insertion resp. deletion) + * @param {number} position Position where the char has been added resp. deleted + * @constructor + */ +class ValueChangeOperation extends EntityOperation { + static TYPE = "ValueChangeOperation"; + getJabberId; + setJabberId; + getFromView; + setFromView; + getValue; + getType; + setPosition; + getPosition; + setRemote; + getRemote; + setEntityIdChain; + getEntityIdChain; + getRootSubjectEntityId; + constructor( + entityId, + value, + type, + position, + jabberId = null, + fromView = null + ) { + if (!entityId) throw new Error("Entity id is required"); + super( + EntityOperation.TYPES.ValueChangeOperation, + entityId, + CONFIG.ENTITY.VAL + ); + var that = this; + + var _fromView = fromView; + + var _jabberId = jabberId; + + /** + * Char that has been added resp. deleted + * @type {string} + * @private + */ + var _value = value; + + /** + * Type of operation (insertion resp. deletion) + * @type {string} + * @private + */ + var _type = type; + + /** + * Position where the char has been added resp. deleted + * @type {number} + * @private + */ + var _position = position; + + /** + * Is the change issued by a remote user + * @type {boolean} + * @private + */ + var _remote = true; + + /** + * Chain of entities the value is assigned to + * @type {string[]} + * @private + */ + var _entityIdChain = []; + + /** + * Create OTOperation for operation + * @returns {operations.ot.OTOperation} + */ + var createOTOperation = function () { + return new OTOperation( + CONFIG.ENTITY.VAL + ":" + that.getEntityId(), + _value, + _type, + _position, + _jabberId, + _fromView + ); + }; + + this.getJabberId = function () { + return _jabberId; + }; + this.setJabberId = function (jabberId) { + _jabberId = jabberId; + }; + + this.getFromView = function () { + return _fromView; + }; + + this.setFromView = function (fromView) { + _fromView = fromView; + }; + /** + * Get char that has been added resp. deleted + * @returns {string} + */ + this.getValue = function () { + return _value; + }; + + /** + * Get type of operation (insertion resp. deletion) + * @returns {string} + */ + this.getType = function () { + return _type; + }; + + /** + * Set type of operation (insertion resp. deletion) + * @param position + */ + this.setPosition = function (position) { + _position = position; + }; + + /** + * Get position where the char has been added resp. deleted + * @returns {number} + */ + this.getPosition = function () { + return _position; + }; + + /** + * Set if the change is issued by a remote user + * @param remote + */ + this.setRemote = function (remote) { + _remote = remote; + }; + + /** + * Get if the change is issued by a remote user + * @returns {boolean} + */ + this.getRemote = function () { + return _remote; + }; + + /** + * Set chain of entities the value is assigned to + * @param {string[]} entityIdChain + */ + this.setEntityIdChain = function (entityIdChain) { + _entityIdChain = entityIdChain; + }; + + /** + * Get chain of entities the value is assigned to + * @returns {string[]} + */ + this.getEntityIdChain = function () { + return _entityIdChain; + }; + + /** + * Get topmost entity in the chain of entity the value is assigned to + * @returns {string} + */ + this.getRootSubjectEntityId = function () { + return _entityIdChain[0]; + }; + + /** + * Get corresponding ot operation + * @returns {operations.ot.OTOperation} + * @private + */ + this.getOTOperation = function () { + var otOperation = EntityOperation.prototype.getOTOperation.call(this); + if (otOperation === null) { + otOperation = createOTOperation(); + this.setOTOperation(otOperation); + } + return otOperation; + }; + + /** + * Adjust the passed operation in the history of operation + * when this operation is applied remotely after the passed operation + * on an graph instance stored in the passed EntityManager + * @param {canvas_widget.EntityManager} EntityManager + * @param {operations.ot.EntityOperation} operation Remote operation + * @returns {operations.ot.EntityOperation} + */ + this.adjust = function (EntityManager, operation) { + switch (operation.getOperationType()) { + case EntityOperation.TYPES.ValueChangeOperation: + if (this.getEntityId() === operation.getEntityId()) { + if ( + (this.getPosition() === operation.getPosition && + this.getValue() === operation.getValue && + this.getType() === CONFIG.OPERATION.TYPE.INSERT && + operation.getType() === CONFIG.OPERATION.TYPE.DELETE) || + (this.getType() === CONFIG.OPERATION.TYPE.DELETE && + operation.getType() === CONFIG.OPERATION.TYPE.INSERT) + ) { + return null; + } + if (this.getPosition() <= operation.getPosition()) { + switch (this.getType()) { + case CONFIG.OPERATION.TYPE.INSERT: + operation.setPosition(operation.getPosition() + 1); + break; + case CONFIG.OPERATION.TYPE.DELETE: + operation.setPosition(operation.getPosition() - 1); + break; + } + } + } + break; + } + + return operation; + }; + + /** + * Compute the inverse of the operation + * @returns {ValueChangeOperation} + */ + this.inverse = function () { + var newType, + ValueChangeOperation = ValueChangeOperation; + + switch (this.getType()) { + case CONFIG.OPERATION.TYPE.INSERT: + newType = CONFIG.OPERATION.TYPE.DELETE; + break; + case CONFIG.OPERATION.TYPE.DELETE: + newType = CONFIG.OPERATION.TYPE.INSERT; + break; + case CONFIG.OPERATION.TYPE.UPDATE: + newType = CONFIG.OPERATION.TYPE.UPDATE; + break; + } + return new ValueChangeOperation( + this.getEntityId(), + this.getValue(), + newType, + this.getPosition() + ); + }; + this.toJSON = function () { + return { + entityId: this.getEntityId(), + value: this.getValue(), + position: this.getPosition(), + type: this.getType(), + jabberId: this.getJabberId(), + }; + }; + } + + static getOperationDescription(valueKey, entityType, entityName, viewId) { + if (!viewId) + return ( + ".. changed " + + valueKey + + " of " + + entityType + + (entityName ? " " : "") + + entityName + ); + else + return ( + ".. changed " + + valueKey + + " of " + + entityType + + (entityName ? " " : "") + + entityName + + " in View " + + viewId + ); + } +} + +EntitySelectOperation.TYPE = "EntitySelectOperation"; + +/** + * Entity Select Operation + * @class operations.non_ot.EntitySelectOperation + * @memberof operations.non_ot + * @constructor + * @param {string} selectedEntityId Entity id of the selected entity + * @param {string} selectedEntityType + * @param {string} jabberId + */ + +function EntitySelectOperation(selectedEntityId, selectedEntityType, jabberId) { + /** + * Entity id of the selected entity + * @type {string} + * @private + */ + var _selectedEntityId = selectedEntityId; + + var _jabberId = jabberId; + + var _selectedEntityType = selectedEntityType; + + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var _nonOTOperation = null; + + /** + * Get entity id of the selected entity + * @returns {string} + */ + this.getSelectedEntityId = function () { + return _selectedEntityId; + }; + + this.getSelectedEntityType = function () { + return _selectedEntityType; + }; + + this.getJabberId = function () { + return _jabberId; + }; + + /** + * Set corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + */ + this.setNonOTOperation = function (nonOTOperation) { + _nonOTOperation = nonOTOperation; + }; + + /** + * Get corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + */ + this.getNonOTOperation = function () { + return _nonOTOperation; + }; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (_nonOTOperation === null) { + _nonOTOperation = new NonOTOperation( + EntitySelectOperation.TYPE, + JSON.stringify({ + selectedEntityId: _selectedEntityId, + selectedEntityType: _selectedEntityType, + }) + ); + } + return _nonOTOperation; + }; +} + +EntitySelectOperation.prototype.toJSON = function () { + return { + selectedEntityId: this.getSelectedEntityId(), + selectedEntityType: this.getSelectedEntityType(), + jabberId: this.getJabberId(), + }; +}; + +/** + * ToolSelectOperation + * @class operations.non_ot.ToolSelectOperation.non_ot.ToolSelectOperation + * @memberof operations.non_ot + * @constructor + * @param {string} toolName Name of selected tool + * @param label + * @param {map} defaultAttributeValues Map containing default values for the attributes of a node. + */ +class ToolSelectOperation { + static TYPE = "ToolSelectOperation"; + /** + * Name of selected tool + * @type {string} + */ + selectedToolName; + + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + nonOTOperation; + + /** + * Default label of selected tool + * @type {string} + */ + defaultLabel; + + /** + * May be used to set default values for node attributes. + * @type {map} + */ + defaultAttributeValues; + + /** + * Get name of selected tool + * @returns {string} + */ + getSelectedToolName; + + /** + * Get default label of selected tool + * @returns {string} + */ + getDefaultLabel; + + /** + * Get default values for node attributes. + * @returns {map} + */ + getDefaultAttributeValues; + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + toNonOTOperation; + constructor(toolName, label, defaultAttributeValues = {}) { + /** + * Name of selected tool + * @type {string} + */ + var selectedToolName = toolName; + + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var nonOTOperation = null; + + /** + * Default label of selected tool + * @type {string} + */ + var defaultLabel = label; + + /** + * May be used to set default values for node attributes. + * @type {map} + */ + var defaultAttributeValues = defaultAttributeValues; + + /** + * Get name of selected tool + * @returns {string} + */ + this.getSelectedToolName = function () { + return selectedToolName; + }; + + /** + * Get default label of selected tool + * @returns {string} + */ + this.getDefaultLabel = function () { + return defaultLabel; + }; + + /** + * Get default values for node attributes. + * @returns {map} + */ + this.getDefaultAttributeValues = function () { + return defaultAttributeValues; + }; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (nonOTOperation === null) { + nonOTOperation = new NonOTOperation( + ToolSelectOperation.TYPE, + JSON.stringify({ selectedToolName: selectedToolName }) + ); + } + return nonOTOperation; + }; + } +} + +/** + * ActivityOperation + * @class operations.non_ot.ActivityOperation + * @memberof operations.non_ot + * @constructor + * @param {string} type Type of activity + * @param {string} entityId Entity id of the entity this activity works on + * @param {string} sender JabberId of the user who issued this activity + * @param {string} text Text of this activity which is displayed in the activity widget + * @param {object} data Additional data for the activity + */ +class ActivityOperation { + static TYPE = "ActivityOperation"; + constructor(type, entityId, sender, text, data) { + /** + * Type of activity + * @type {string} + * @private + */ + var _type = type; + + /** + * Entity id of the entity this activity works on + * @type {string} + * @private + */ + var _entityId = entityId; + + /** + * JabberId of the user who issued this activity + * @type {string} + * @private + */ + var _sender = sender; + + /** + * Text of this activity which is displayed in the activity widget + * @type {string} + * @private + */ + var _text = text; + + /** + * Additional data for the activity + * @type {Object} + * @private + */ + var _data = data; + + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var _nonOTOperation = null; + + /** + * Get type of activity + * @returns {string} + */ + this.getType = function () { + return _type; + }; + + /** + * Get entity id of the entity this activity works on + * @returns {string} + */ + this.getEntityId = function () { + return _entityId; + }; + + /** + * Get JabberId of the user who issued this activity + * @returns {string} + */ + this.getSender = function () { + return _sender; + }; + + /** + * Get text of this activity which is displayed in the activity widget + * @returns {string} + */ + this.getText = function () { + return _text; + }; + + /** + * Get additional data for the activity + * @returns {Object} + */ + this.getData = function () { + return _data; + }; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (_nonOTOperation === null) { + _nonOTOperation = new NonOTOperation( + ActivityOperation.TYPE, + JSON.stringify({ + type: _type, + entityId: _entityId, + sender: _sender, + text: _text, + data: _data, + }) + ); + } + return _nonOTOperation; + }; + } + toJSON() { + return { + type: this.getType(), + entityId: this.getEntityId(), + sender: this.getSender(), + text: this.getText(), + data: this.getData(), + }; + } +} + +ExportMetaModelOperation.TYPE = "ExportMetaModelOperation"; + +/** + * Export Image Operation + * @class operations.non_ot.ExportMetaModelOperation + * @memberof operations.non_ot + * @constructor + * @param {string} requestingComponent Name of requesting Component + * @param {string} data Meta model + */ +function ExportMetaModelOperation(requestingComponent, data) { + /** + * Name of requesting Component + * @type {string} + * @private + */ + var _requestingComponent = requestingComponent; + /** + * Meta model + * @type {object} + * @private + */ + var _data = data; + + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var _nonOTOperation = null; + + /** + * Get name of requesting Component + * @returns {string} + */ + this.getRequestingComponent = function () { + return _requestingComponent; + }; + + /** + * Get data URL of image + * @returns {object} + */ + this.getData = function () { + return _data; + }; + + /** + * Get exported JSON representation of the graph + * @param {object} data + */ + this.setData = function (data) { + _data = data; + }; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (_nonOTOperation === null) { + _nonOTOperation = new NonOTOperation( + ExportMetaModelOperation.TYPE, + JSON.stringify({ + requestingComponent: _requestingComponent, + data: _data, + }) + ); + } + return _nonOTOperation; + }; +} + +ExportLogicalGuidanceRepresentationOperation.TYPE = + "ExportLogicalGuidanceRepresentationOperation"; + +/** + * Export Image Operation + * @class operations.non_ot.ExportLogicalGuidanceRepresentationOperation + * @memberof operations.non_ot + * @constructor + * @param {string} requestingComponent Name of requesting Component + * @param {string} data Meta model + */ +function ExportLogicalGuidanceRepresentationOperation( + requestingComponent, + data +) { + /** + * Name of requesting Component + * @type {string} + * @private + */ + var _requestingComponent = requestingComponent; + /** + * Guidance rules + * @type {object} + * @private + */ + var _data = data; + + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var _nonOTOperation = null; + + /** + * Get name of requesting Component + * @returns {string} + */ + this.getRequestingComponent = function () { + return _requestingComponent; + }; + + /** + * Get data URL of image + * @returns {object} + */ + this.getData = function () { + return _data; + }; + + /** + * Get exported JSON representation of the graph + * @param {object} data + */ + this.setData = function (data) { + _data = data; + }; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (_nonOTOperation === null) { + _nonOTOperation = new NonOTOperation( + ExportLogicalGuidanceRepresentationOperation.TYPE, + JSON.stringify({ + requestingComponent: _requestingComponent, + data: _data, + }) + ); + } + return _nonOTOperation; + }; +} + +ExportImageOperation.TYPE = "ExportImageOperation"; + +/** + * Export Image Operation + * @class operations.non_ot.ExportImageOperation + * @memberof operations.non_ot + * @constructor + * @param {string} requestingComponent Name of requesting Component + * @param {string} data Data URL of image + */ +function ExportImageOperation(requestingComponent, data) { + /** + * Name of requesting Component + * @type {string} + * @private + */ + var _requestingComponent = requestingComponent; + /** + * Data URL of image + * @type {object} + * @private + */ + var _data = data; + + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var _nonOTOperation = null; + + /** + * Get name of requesting Component + * @returns {string} + */ + this.getRequestingComponent = function () { + return _requestingComponent; + }; + + /** + * Get data URL of image + * @returns {object} + */ + this.getData = function () { + return _data; + }; + + /** + * Get exported JSON representation of the graph + * @param {object} data + */ + this.setData = function (data) { + _data = data; + }; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (_nonOTOperation === null) { + _nonOTOperation = new NonOTOperation( + ExportImageOperation.TYPE, + JSON.stringify({ + requestingComponent: _requestingComponent, + data: _data, + }) + ); + } + return _nonOTOperation; + }; +} + +/** + * SetViewTypesOperation + * @class operations.non_ot.WidgetEnterOperation + * @memberof operations.non_ot + * @constructor + * @param {boolean} flag enable (true)/disable(false) the view types of the vml in the palette widget + */ +class SetViewTypesOperation { + static TYPE = "SetViewTypesOperation"; + _flag; + nonOTOperation; + /** + * Get name of selected tool + * @returns {string} + */ + getFlag = function () { + return this._flag; + }; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + toNonOTOperation = function () { + if (this.nonOTOperation === null) { + this.nonOTOperation = new NonOTOperation( + SetViewTypesOperation.TYPE, + JSON.stringify({ flag: this._flag }) + ); + } + return this.nonOTOperation; + }; + + constructor(flag) { + /** + * Enable or disable the view types of the vml + * @type {boolean} + * @private + */ + this._flag = flag; + + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + this.nonOTOperation = null; + } +} + +/** + * InitModelTypesOperation + * @class operations.non_ot.InitModelTypesOperation + * @memberof operations.non_ot + * @constructor + * @param {string} vls the visual language specification + * @param {bool} startViewGeneration + */ +class InitModelTypesOperation { + static TYPE = "InitModelTypesOperation"; + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + nonOTOperation = null; + _vls; + _startViewGeneration; + getVLS = function () { + return this._vls; + }; + + /** + * Get name of selected tool + * @returns {string} + */ + getViewGenerationFlag = function () { + return this._startViewGeneration; + }; + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + toNonOTOperation = function () { + if (this.nonOTOperation === null) { + this.nonOTOperation = new NonOTOperation( + InitModelTypesOperation.TYPE, + JSON.stringify({ + vls: this._vls, + startViewGeneration: this._startViewGeneration, + }) + ); + } + return this.nonOTOperation; + }; + constructor(vls, startViewGeneration) { + /** + * Name of selected tool + * @type {string} + */ + this._vls = vls; + + this._startViewGeneration = startViewGeneration; + } +} + +ViewInitOperation.TYPE = "ViewInitOperation"; + +/** + * ViewInitOperation + * @class operations.non_ot.ViewInitOperation + * @memberof operations.non_ot + * @constructor + * @param {object} data the view as json + * @param {object} viewpoint the viewpoint vls as json + */ +function ViewInitOperation(data, viewpoint) { + /** + * Name of selected tool + * @type {string} + */ + var _data = data; + + var _viewpoint = viewpoint; + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var nonOTOperation = null; + + /** + * Get name of selected tool + * @returns {string} + */ + this.getData = function () { + return _data; + }; + + this.getViewpoint = function () { + return _viewpoint; + }; + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (nonOTOperation === null) { + nonOTOperation = new NonOTOperation( + ViewInitOperation.TYPE, + JSON.stringify({ data: _data, viewpoint: _viewpoint }) + ); + } + return nonOTOperation; + }; +} + +/** + * DeleteViewOperation + * @class operations.non_ot.DeleteViewOperation + * @memberof operations.non_ot + * @constructor + * @param {string} viewId identifier of the view + */ +class DeleteViewOperation { + static TYPE = "DeleteViewOperation"; + constructor(viewId) { + /** + * Name of selected tool + * @type {string} + */ + var _viewId = viewId; + + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var nonOTOperation = null; + + /** + * Get the list with node ids to delete + * @returns {string} + */ + this.getViewId = function () { + return _viewId; + }; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (nonOTOperation === null) { + nonOTOperation = new NonOTOperation( + DeleteViewOperation.TYPE, + JSON.stringify({ viewId: _viewId }) + ); + } + return nonOTOperation; + }; + } +} + +SetModelAttributeNodeOperation.TYPE = "SetModelAttributeNodeOperation"; + +/** + * SetModelAttributeNodeOperation + * @class operations.non_ot.SetModelAttributeNodeOperation + * @memberof operations.non_ot + * @constructor + */ +function SetModelAttributeNodeOperation() { + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var nonOTOperation = null; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (nonOTOperation === null) { + nonOTOperation = new NonOTOperation( + SetModelAttributeNodeOperation.TYPE, + JSON.stringify({ empty: "empty" }) + ); + } + return nonOTOperation; + }; +} + +UpdateViewListOperation.TYPE = "UpdateViewListOperation"; + +/** + * UpdateViewListOperation + * @class operations.non_ot.UpdateViewListOperation + * @memberof operations.non_ot + * @constructor + */ +function UpdateViewListOperation() { + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var nonOTOperation = null; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (nonOTOperation === null) { + nonOTOperation = new NonOTOperation( + UpdateViewListOperation.TYPE, + JSON.stringify({}) + ); + } + return nonOTOperation; + }; +} + +ShowGuidanceBoxOperation.TYPE = "ShowGuidanceBoxOperation"; + +/** + * ToolGuidanceOperation + * @class operations.non_ot.ToolGuidanceOperation + * @memberof operations.non_ot + * @constructor + * @param {string} toolName Name of selected tool + */ +function ShowGuidanceBoxOperation(label, guidance, entityId) { + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var nonOTOperation = null; + var _label = label; + var _guidance = guidance; + var _entityId = entityId; + + this.getLabel = function () { + return _label; + }; + + this.getGuidance = function () { + return _guidance; + }; + + this.getEntityId = function () { + return _entityId; + }; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (nonOTOperation === null) { + nonOTOperation = new NonOTOperation( + ShowGuidanceBoxOperation.TYPE, + JSON.stringify({ + label: _label, + guidance: _guidance, + entityId: _entityId, + }) + ); + } + return nonOTOperation; + }; +} + +CanvasViewChangeOperation.TYPE = "CanvasViewChangeOperation"; + +/** + * Entity Select Operation + * @class operations.non_ot.EntitySelectOperation + * @memberof operations.non_ot + * @constructor + * @param {string} selectedEntityId Entity id of the selected entity + */ +function CanvasViewChangeOperation(left, top, width, height, zoom) { + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var _nonOTOperation = null; + + this.getLeft = function () { + return left; + }; + + this.getTop = function () { + return top; + }; + + this.getWidth = function () { + return width; + }; + + this.getHeight = function () { + return height; + }; + + this.getZoom = function () { + return zoom; + }; + + /** + * Set corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + */ + this.setNonOTOperation = function (nonOTOperation) { + _nonOTOperation = nonOTOperation; + }; + + /** + * Get corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + */ + this.getNonOTOperation = function () { + return _nonOTOperation; + }; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (_nonOTOperation === null) { + _nonOTOperation = new NonOTOperation( + CanvasViewChangeOperation.TYPE, + JSON.stringify({ + left: left, + top: top, + width: width, + height: height, + zoom: zoom, + }) + ); + } + return _nonOTOperation; + }; +} + +RevokeSharedActivityOperation.TYPE = "RevokeSharedActivityOperation"; + +/** + * Entity Select Operation + * @class operations.non_ot.EntitySelectOperation + * @memberof operations.non_ot + * @constructor + * @param {string} selectedEntityId Entity id of the selected entity + */ +function RevokeSharedActivityOperation(id) { + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var _nonOTOperation = null; + + this.getId = function () { + return id; + }; + + /** + * Set corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + */ + this.setNonOTOperation = function (nonOTOperation) { + _nonOTOperation = nonOTOperation; + }; + + /** + * Get corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + */ + this.getNonOTOperation = function () { + return _nonOTOperation; + }; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (_nonOTOperation === null) { + _nonOTOperation = new NonOTOperation( + RevokeSharedActivityOperation.TYPE, + JSON.stringify({ + id: id, + }) + ); + } + return _nonOTOperation; + }; +} + +RevokeSharedActivityOperation.prototype.toJSON = function () { + return { id: this.getId() }; +}; + +CollaborateInActivityOperation.TYPE = "CollaborateInActivityOperation"; + +/** + * Entity Select Operation + * @class operations.non_ot.EntitySelectOperation + * @memberof operations.non_ot + * @constructor + * @param {string} selectedEntityId Entity id of the selected entity + */ +function CollaborateInActivityOperation(id) { + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var _nonOTOperation = null; + + this.getId = function () { + return id; + }; + + /** + * Set corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + */ + this.setNonOTOperation = function (nonOTOperation) { + _nonOTOperation = nonOTOperation; + }; + + /** + * Get corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + */ + this.getNonOTOperation = function () { + return _nonOTOperation; + }; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (_nonOTOperation === null) { + _nonOTOperation = new NonOTOperation( + CollaborateInActivityOperation.TYPE, + JSON.stringify({ + id: id, + }) + ); + } + return _nonOTOperation; + }; +} + +MoveCanvasOperation.TYPE = "MoveCanvasOperation"; + +/** + * Entity Select Operation + * @class operations.non_ot.EntitySelectOperation + * @memberof operations.non_ot + * @constructor + * @param {string} selectedEntityId Entity id of the selected entity + */ +function MoveCanvasOperation(objectId, transition) { + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var _nonOTOperation = null; + + this.getObjectId = function () { + return objectId; + }; + + this.getTransition = function () { + return transition; + }; + + /** + * Set corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + */ + this.setNonOTOperation = function (nonOTOperation) { + _nonOTOperation = nonOTOperation; + }; + + /** + * Get corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + */ + this.getNonOTOperation = function () { + return _nonOTOperation; + }; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (_nonOTOperation === null) { + _nonOTOperation = new NonOTOperation( + MoveCanvasOperation.TYPE, + JSON.stringify({ + objectId: objectId, + transition: transition, + }) + ); + } + return _nonOTOperation; + }; +} + +/** + * Entity Select Operation + * @class operations.non_ot.EntitySelectOperation + * @memberof operations.non_ot + * @constructor + * @param {string} data + */ +class GuidanceStrategyOperation { + static TYPE = "GuidanceStrategyOperation"; + constructor(data) { + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var _nonOTOperation = null; + + this.getData = function () { + return data; + }; + + /** + * Set corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + */ + this.setNonOTOperation = function (nonOTOperation) { + _nonOTOperation = nonOTOperation; + }; + + /** + * Get corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + */ + this.getNonOTOperation = function () { + return _nonOTOperation; + }; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (_nonOTOperation === null) { + _nonOTOperation = new NonOTOperation( + GuidanceStrategyOperation.TYPE, + JSON.stringify({ + data: data, + }) + ); + } + return _nonOTOperation; + }; + } + toJSON() { + return { data: this.getData() }; + } +} + +UpdateMetamodelOperation.TYPE = "UpdateMetamodelOperation"; + +/** + * UpdateMetamodelOperation + * @class operations.non_ot.UpdateMetamodelOperation + * @memberof operations.non_ot + * @constructor + */ +function UpdateMetamodelOperation(metaModelingRoomName, modelingRoomName) { + /** + * Room name of metamodel is created + * @type {string} + */ + var _metaModelingRoomName = metaModelingRoomName; + + /** + * Room name to upload created metamodel + * @type {string} + */ + var _modelingRoomName = modelingRoomName; + + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var _nonOTOperation = null; + + /** + * Get metamodeling room name + * @returns {string} + */ + this.getMetaModelingRoomName = function () { + return _metaModelingRoomName; + }; + + /** + * Get modeling room name + * @returns {string} + */ + this.getModelingRoomName = function () { + return _modelingRoomName; + }; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (_nonOTOperation === null) { + _nonOTOperation = new NonOTOperation( + UpdateMetamodelOperation.TYPE, + JSON.stringify({ empty: "empty" }) + ); + } + return _nonOTOperation; + }; +} +UpdateMetamodelOperation.prototype.toJSON = function () { + return {}; +}; + +/** + * OperationFactory + * @class operations.OperationFactory + * @memberof operations.ot + * @constructor + */ +function OperationFactory() { + return { + /** + * Creates an Operation from a received NonOTOperation + * @memberof operations.OperationFactory# + * @param operation + * @returns {operations.non_ot.ToolSelectOperation|EntitySelectOperation|ToolSelectOperation} + */ + createOperationFromNonOTOperation: function (operation) { + var type = operation.getType(), + data, + resOperation; + + try { + data = JSON.parse(operation.getData()); + } catch (e) { + console.error( + "Not able to parse data to JSON. Check the corresponding operation" + ); + return null; + } + + switch (type) { + case EntitySelectOperation.TYPE: + resOperation = new EntitySelectOperation( + data.selectedEntityId, + data.selectedEntityType, + data.jabberId + ); + resOperation.setNonOTOperation(operation); + break; + case ToolSelectOperation.TYPE: + resOperation = new ToolSelectOperation( + data.selectedToolName, + data.name, + data.defaultAttributeValues + ); + break; + case ActivityOperation.TYPE: + resOperation = new ActivityOperation( + data.type, + data.entityId, + data.sender, + data.text, + data.data + ); + break; + case ExportMetaModelOperation.TYPE: + resOperation = new ExportMetaModelOperation( + data.requestingComponent, + data.data + ); + break; + case ExportLogicalGuidanceRepresentationOperation.TYPE: + resOperation = new ExportLogicalGuidanceRepresentationOperation( + data.requestingComponent, + data.data + ); + break; + case ExportImageOperation.TYPE: + resOperation = new ExportImageOperation( + data.requestingComponent, + data.data + ); + break; + case SetViewTypesOperation.TYPE: + resOperation = new SetViewTypesOperation(data.flag); + break; + case InitModelTypesOperation.TYPE: + resOperation = new InitModelTypesOperation( + data.vls, + data.startViewGeneration + ); + break; + case ViewInitOperation.TYPE: + resOperation = new ViewInitOperation(data.data, data.viewpoint); + break; + case DeleteViewOperation.TYPE: + resOperation = new DeleteViewOperation(data.viewId); + break; + case ShowGuidanceBoxOperation.TYPE: + resOperation = new ShowGuidanceBoxOperation( + data.label, + data.guidance, + data.entityId + ); + break; + case SetModelAttributeNodeOperation.TYPE: + resOperation = new SetModelAttributeNodeOperation(); + break; + case UpdateViewListOperation.TYPE: + resOperation = new UpdateViewListOperation(); + break; + case CanvasViewChangeOperation.TYPE: + resOperation = new CanvasViewChangeOperation( + data.left, + data.top, + data.width, + data.height, + data.zoom + ); + resOperation.setNonOTOperation(operation); + break; + case RevokeSharedActivityOperation.TYPE: + resOperation = new RevokeSharedActivityOperation(data.id); + break; + case CollaborateInActivityOperation.TYPE: + resOperation = new CollaborateInActivityOperation(data.id); + break; + case MoveCanvasOperation.TYPE: + resOperation = new MoveCanvasOperation( + data.objectId, + data.transition + ); + break; + case GuidanceStrategyOperation.TYPE: + resOperation = new GuidanceStrategyOperation(data.data); + resOperation.setNonOTOperation(operation); + break; + case UpdateMetamodelOperation.TYPE: + resOperation = new UpdateMetamodelOperation( + data.metamodelingRoomName, + data.modelingRoomName + ); + break; + default: + resOperation = new NonOTOperation(type, data); + break; + } + return resOperation; + }, + /** + * Creates an entity operation from a received OTOperation + * @memberof operations.OperationFactory# + * @param operation + * @returns {EntityOperation} + */ + createOperationFromOTOperation: function (operation) { + var value; + var entityType; + var entityId; + var components = operation.getName().split(":"); + + var resOperation; + + if (components.length === 2) { + entityType = components[0]; + entityId = components[1]; + + switch (entityType) { + case CONFIG.ENTITY.NODE: + try { + value = JSON.parse(operation.getValue()); + } catch (e) { + return null; + } + switch (operation.getPosition()) { + case CONFIG.IWC.POSITION.NODE.ADD: + switch (operation.getType()) { + case CONFIG.OPERATION.TYPE.INSERT: + resOperation = new NodeAddOperation( + entityId, + value.type, + value.left, + value.top, + value.width, + value.height, + value.zIndex, + value.containment, + value.json, + value.viewId, + value.oType, + value.jabberId + ); + break; + case CONFIG.OPERATION.TYPE.UPDATE: + resOperation = new NodeDeleteOperation( + entityId, + value.type, + value.left, + value.top, + value.width, + value.height, + value.zIndex, + value.containment, + value.json + ); + break; + } + break; + case CONFIG.IWC.POSITION.NODE.POS: + resOperation = new NodeMoveOperation( + entityId, + value.offsetX, + value.offsetY, + value.jabberId + ); + break; + case CONFIG.IWC.POSITION.NODE.Z: + resOperation = new NodeMoveZOperation( + entityId, + value.offsetZ, + value.jabberId + ); + break; + case CONFIG.IWC.POSITION.NODE.DIM: + resOperation = new NodeResizeOperation( + entityId, + value.offsetX, + value.offsetY, + value.jabberId + ); + break; + } + break; + case CONFIG.ENTITY.EDGE: + try { + value = JSON.parse(operation.getValue()); + } catch (e) { + return null; + } + switch (operation.getType()) { + case CONFIG.OPERATION.TYPE.INSERT: + resOperation = new EdgeAddOperation( + entityId, + value.type, + value.source, + value.target, + value.json, + value.viewId, + value.oType, + value.jabberId + ); + break; + case CONFIG.OPERATION.TYPE.UPDATE: + resOperation = new EdgeDeleteOperation( + entityId, + value.type, + value.source, + value.target, + value.json + ); + break; + } + break; + case CONFIG.ENTITY.ATTR: + try { + value = JSON.parse(operation.getValue()); + } catch (e) { + return null; + } + switch (operation.getType()) { + case CONFIG.OPERATION.TYPE.INSERT: + resOperation = new AttributeAddOperation( + entityId, + value.subjectEntityId, + value.rootSubjectEntityId, + value.type, + value.data + ); + break; + case CONFIG.OPERATION.TYPE.UPDATE: + resOperation = new AttributeDeleteOperation( + entityId, + value.subjectEntityId, + value.rootSubjectEntityId, + value.type + ); + break; + } + break; + case CONFIG.ENTITY.VAL: + resOperation = new ValueChangeOperation( + entityId, + operation.getValue(), + operation.getType(), + operation.getPosition(), + null + ); + break; + } + } + if (resOperation !== null) { + resOperation.setOTOperation(operation); + } + return resOperation; + }, + }; +} + +var OperationFactory$1 = OperationFactory(); + +class OpenAppProvider { + openapp; + gadgets; + constructor() { + var openapp = {}; + this.openapp = openapp; + openapp["event"] = {}; + var gadgets = "undefined" !== typeof this.gadgets ? this.gadgets : {}; + this.gadgets = gadgets; + gadgets.openapp = gadgets.openapp || {}; + var usePostMessage = + "undefined" !== typeof window && + "undefined" !== typeof window.parent && + "undefined" !== typeof window.postMessage && + "undefined" !== typeof JSON && + "undefined" !== typeof JSON.parse && + "undefined" !== typeof JSON.stringify, + usePubSub = + !usePostMessage && + "undefined" !== typeof gadgets && + "undefined" !== typeof gadgets.pubsub && + "undefined" !== typeof gadgets.pubsub.subscribe && + "undefined" !== typeof gadgets.pubsub.unsubscribe && + "undefined" !== typeof gadgets.pubsub.publish, + init = { postParentOnly: true }, + ownData, + doCallback, + onMessage; + usePostMessage + ? ((onMessage = function (a) { + if ( + "string" === typeof a.data && + '{"OpenApplicationEvent":{' === a.data.slice(0, 25) + ) { + var b = JSON.parse(a.data).OpenApplicationEvent; + if ( + "openapp" === b.event && + !0 === b.welcome && + a.source === window.parent + ) { + for (var d in b.message) { + b.message.hasOwnProperty(d) && (init[d] = b.message[d]); + } + } else { + (b.source = a.source), + (b.origin = a.origin), + (b.toJSON = function () { + var a = {}, + b; + for (b in this) { + this.hasOwnProperty(b) && + "function" !== typeof this[b] && + "source" !== b && + "origin" !== b && + (a[b] = this[b]); + } + return a; + }), + "function" === typeof doCallback && + // @ts-ignore + !0 === doCallback(b, b.message) && + window.parent.postMessage( + JSON.stringify({ + OpenApplicationEvent: { event: "openapp", receipt: !0 }, + }), + "*" + ); + } + } + }), + // @ts-ignore + "undefined" !== typeof window.attachEvent + ? // @ts-ignore + window.attachEvent("onmessage", onMessage) + : window.addEventListener("message", onMessage, !1), + "undefined" !== typeof window.parent && + window.parent.postMessage( + JSON.stringify({ + OpenApplicationEvent: { event: "openapp", hello: !0 }, + }), + "*" + )) + : usePubSub && + (onMessage = function (a, b) { + b.source = void 0; + b.origin = void 0; + b.sender = a; + "function" === typeof doCallback && + // @ts-ignore + !0 === doCallback(b, b.message) && + gadgets.pubsub.publish("openapp-recieve", !0); + }); + gadgets.openapp.RDF = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; + gadgets.openapp.connect = function (a) { + doCallback = a; + usePubSub && gadgets.pubsub.subscribe("openapp", onMessage); + }; + gadgets.openapp.disconnect = function () { + usePubSub && gadgets.pubsub.unsubscribe("openapp"); + doCallback = null; + }; + gadgets.openapp.publish = function (a, b) { + a.event = a.event || "select"; + a.type = a.type || "namespaced-properties"; + a.sharing = a.sharing || "public"; + a.date = a.date || new Date(); + a.message = b || a.message; + if (usePostMessage) { + if (!1 === init.postParentOnly && null === ownData) { + // @ts-ignore + ownData = { sender: "unknown", viewer: "unknown" }; + if ( + "undefined" !== typeof window.location && + "string" === typeof window.location.search && + "function" === typeof window.unescape + ) { + var d = window.location.search.substring(1).split("&"), + c, + e = {}; + if (!(1 == d.length && "" === d[0])) { + for (var f = 0; f < d.length; f++) { + (c = d[f].split("=")), + 2 == c.length && (e[c[0]] = window.unescape(c[1])); + } + } + // @ts-ignore + "string" === typeof e.url && (ownData.sender = e.url); + } + if ( + // @ts-ignore + "undefined" !== typeof opensocial && + // @ts-ignore + "function" === typeof opensocial.newDataRequest + ) { + // @ts-ignore + d = opensocial.newDataRequest(); + // @ts-ignore + d.add( + // @ts-ignore + d.newFetchPersonRequest(opensocial.IdSpec.PersonId.VIEWER), + "viewer" + ); + var g = this; + // @ts-ignore + d.send(function (c) { + c = c.get("viewer").getData(); + "object" === typeof c && + null !== c && + "function" === typeof c.getId && + ((c = c.getId()), + // @ts-ignore + "string" === typeof c && (ownData.viewer = c)); + g.publish(a, b); + }); + return; + } + } + null !== ownData && + // @ts-ignore + ("string" === typeof ownData.sender && (a.sender = ownData.sender), + // @ts-ignore + "string" === typeof ownData.viewer && (a.viewer = ownData.viewer)); + // @ts-ignore + d = JSON.stringify({ OpenApplicationEvent: a }); + // @ts-ignore + if ("undefined" !== window.parent) { + if ((window.parent.postMessage(d, "*"), !init.postParentOnly)) { + c = window.parent.frames; + // @ts-ignore + for (e = 0; e < c.length; e++) { + // @ts-ignore + c[e].postMessage(d, "*"); + } + } + } else { + window.postMessage(d, "*"); + } + } else { + usePubSub && gadgets.pubsub.publish("openapp", a); + } + }; + openapp["io"] = {}; + openapp["io"].createXMLHttpRequest = function () { + if ("undefined" !== typeof XMLHttpRequest) { + return new XMLHttpRequest(); + } + // @ts-ignore + if ("undefined" !== typeof ActiveXObject) { + // @ts-ignore + return new ActiveXObject("Microsoft.XMLHTTP"); + } + throw { + name: "XMLHttpRequestError", + message: "XMLHttpRequest not supported", + }; + }; + openapp["io"].makeRequest = function (a, b, d) { + gadgets.io.makeRequest( + a, + function (c) { + var e, f, g, h, j, k, l, p; + if (null === document.getElementById("oauthPersonalize")) { + e = document.createElement("div"); + f = document.createElement("input"); + g = document.createElement("input"); + h = document.createElement("div"); + j = document.createElement("input"); + k = document.createElement("div"); + l = document.createElement("span"); + p = document.createElement("input"); + e.id = "oauthPersonalize"; + f.id = "oauthPersonalizeButton"; + g.id = "oauthPersonalizeDenyButton"; + h.id = "oauthPersonalizeDone"; + j.id = "oauthPersonalizeDoneButton"; + k.id = "oauthPersonalizeComplete"; + l.id = "oauthPersonalizeMessage"; + p.id = "oauthPersonalizeHideButton"; + f.id = "oauthPersonalizeButton"; + e.style.display = "none"; + h.style.display = "none"; + k.style.display = "none"; + f.type = "button"; + g.type = "button"; + j.type = "button"; + p.type = "button"; + f.value = "Continue"; + g.value = "Ignore"; + j.value = "Done"; + p.value = "Hide"; + e.appendChild( + document.createTextNode( + "In order to provide the full functionality of this tool, access to your personal data is being requested." + ) + ); + h.appendChild( + document.createTextNode( + "If you have provided authorization and are still reading this, click the Done button." + ) + ); + var m = document.getElementById("openappDialog"); + null == m && + ((m = document.createElement("div")), + null != document.body.firstChild + ? document.body.insertBefore(m, document.body.firstChild) + : document.body.appendChild(m)); + m.appendChild(e); + m.appendChild(h); + m.appendChild(k); + e.appendChild(f); + e.appendChild(g); + h.appendChild(j); + k.appendChild(l); + k.appendChild(p); + g.onclick = function () { + e.style.display = "none"; + }; + p.onclick = function () { + k.style.display = "none"; + }; + } + if (c.oauthApprovalUrl) { + var r = function () { + q && (window.clearInterval(q), (q = null)); + // @ts-ignore + n && (n.close(), (n = null)); + // @ts-ignore + document.getElementById("oauthPersonalizeDone").style.display = + "none"; + // @ts-ignore + document.getElementById( + "oauthPersonalizeComplete" + ).style.display = "block"; + openapp["io"].makeRequest(a, b, d); + return !1; + }, + s = function () { + // @ts-ignore + if (!n || n.closed) { + (n = null), r(); + } + }, + t = c.oauthApprovalUrl, + n = null, + q = null; + c = { + createOpenerOnClick: function () { + return function () { + // @ts-ignore + if ((n = window.open(t, "_blank", "width=450,height=500"))) { + // @ts-ignore + (q = window.setInterval(s, 100)), + // @ts-ignore + (document.getElementById( + "oauthPersonalize" + ).style.display = "none"), + // @ts-ignore + (document.getElementById( + "oauthPersonalizeDone" + ).style.display = "block"); + } + return !1; + }; + }, + createApprovedOnClick: function () { + return r; + }, + }; + // @ts-ignore + document.getElementById("oauthPersonalizeButton").onclick = + c.createOpenerOnClick(); + // @ts-ignore + document.getElementById("oauthPersonalizeDoneButton").onclick = + c.createApprovedOnClick(); + f = "Please wait."; + document.all + ? // @ts-ignore + (document.getElementById("oauthPersonalizeMessage").innerText = + f) + : // @ts-ignore + (document.getElementById( + "oauthPersonalizeMessage" + ).textContent = f); + // @ts-ignore + document.getElementById("oauthPersonalize").style.display = "block"; + } else { + c.oauthError + ? ((f = + "The authorization was not completed successfully. (" + + c.oauthError + + ")"), + document.all + ? // @ts-ignore + (document.getElementById( + "oauthPersonalizeMessage" + ).innerText = f) + : // @ts-ignore + (document.getElementById( + "oauthPersonalizeMessage" + ).textContent = f), + // @ts-ignore + (document.getElementById( + "oauthPersonalizeComplete" + ).style.display = "block")) + : ((f = + "You have now granted authorization. To revoke authorization, go to your Privacy settings."), + document.all + ? // @ts-ignore + (document.getElementById( + "oauthPersonalizeMessage" + ).innerText = f) + : // @ts-ignore + (document.getElementById( + "oauthPersonalizeMessage" + ).textContent = f), + b(c)); + } + }, + d + ); + }; + openapp["ns"] = {}; + openapp["ns"].rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; + openapp["ns"].rdfs = "http://www.w3.org/2000/01/rdf-schema#"; + openapp["ns"].dcterms = "http://purl.org/dc/terms/"; + openapp["ns"].foaf = "http://xmlns.com/foaf/0.1/"; + openapp["ns"].rest = "http://purl.org/openapp/"; + openapp["ns"].conserve = "http://purl.org/openapp/"; + openapp["ns"].openapp = "http://purl.org/openapp/"; + openapp["ns"].role = "http://purl.org/role/terms/"; + openapp["ns"].widget = "http://purl.org/role/widget/"; + openapp["resource"] = {}; + var linkexp = + /<[^>]*>\s*(\s*;\s*[^\(\)<>@,;:"\/\[\]\?={} \t]+=(([^\(\)<>@,;:"\/\[\]\?={} \t]+)|("[^"]*")))*(,|\$)/g, + paramexp = + /[^\(\)<>@,;:"\/\[\]\?={} \t]+=(([^\(\)<>@,;:"\/\[\]\?={} \t]+)|("[^"]*"))/g; + function unquote(a) { + return '"' === a.charAt(0) && '"' === a.charAt(a.length - 1) + ? a.substring(1, a.length - 1) + : a; + } + function parseLinkHeader(a) { + var b = (a + ",").match(linkexp); + a = {}; + var d = {}, + c = {}, + e, + f, + g, + h, + j, + k; + for (e = 0; e < b.length; e++) { + f = b[e].split(">"); + g = f[0].substring(1); + h = f[1]; + f = {}; + f.href = g; + g = h.match(paramexp); + for (h = 0; h < g.length; h++) { + (j = g[h]), (j = j.split("=")), (k = j[0]), (f[k] = unquote(j[1])); + } + void 0 !== f.rel && "undefined" === typeof f.anchor && (a[f.rel] = f); + void 0 !== f.title && + "undefined" === typeof f.anchor && + (d[f.title] = f); + g = c[f.anchor || ""] || {}; + h = g[f.rel || "http://purl.org/dc/terms/relation"] || []; + h.push({ type: "uri", value: f.href }); + g[f.rel || "http://purl.org/dc/terms/relation"] = h; + c[f.anchor || ""] = g; + } + // @ts-ignore + b = {}; + // @ts-ignore + b.rels = a; + // @ts-ignore + b.titles = d; + // @ts-ignore + b.rdf = c; + return b; + } + var isStringValue = function (a) { + return "" !== a && "string" === typeof a; + }; + openapp["resource"].makeRequest = function (a, b, d, c, e, f) { + var g = openapp["io"].createXMLHttpRequest(), + h, + j = 0; + if ("undefined" !== typeof c) { + for (h in c) { + c.hasOwnProperty(h) && j++; + } + if (0 < j) { + // @ts-ignore + j = ""; + -1 !== b?.indexOf("?") && + ((j = b?.substring(b.indexOf("?"))), + // @ts-ignore + (b = b?.substring(0, b.length - j.length))); + switch (b?.substring(b.length - 1)) { + case "/": + b += ":"; + break; + case ":": + break; + default: + b += "/:"; + } + for (h in c) { + c.hasOwnProperty(h) && + (b = + h === openapp["ns"].rdf + "predicate" + ? b + (";predicate=" + encodeURIComponent(c[h])) + : b + + (";" + + encodeURIComponent(h) + + "=" + + encodeURIComponent(c[h]))); + } + b += j; + } + } + g.open(a, b, !0); + g.setRequestHeader("Accept", "application/json"); + e = e || ""; + if (0 < e.length || "POST" === a || "PUT" === a) { + g.setRequestHeader( + "Content-Type", + "undefined" !== typeof f ? f : "application/json" + ); + } + d = d || function () {}; + g.onreadystatechange = function () { + if (4 === g.readyState) { + var a = { + data: g.responseText, + link: isStringValue(g.getResponseHeader("link")) + ? parseLinkHeader(g.getResponseHeader("link")) + : {}, + }; + isStringValue(g.getResponseHeader("location")) + ? (a["uri"] = g.getResponseHeader("location")) + : isStringValue(g.getResponseHeader("content-base")) + ? (a["uri"] = g.getResponseHeader("content-base")) + : a["link"].hasOwnProperty("http://purl.org/dc/terms/subject") && + (a["uri"] = a["link"]["http://purl.org/dc/terms/subject"].href); + isStringValue(g.getResponseHeader("content-location")) && + (a["contentUri"] = g.getResponseHeader("content-location")); + isStringValue(g.getResponseHeader("content-type")) && + "application/json" === + g.getResponseHeader("content-type").split(";")[0] && + (a.data = JSON.parse(a.data)); + a["subject"] = + "undefined" !== typeof g.responseText + ? a.data.hasOwnProperty("") + ? a.data[""] + : a.data[a["uri"]] || {} + : {}; + d(a); + } + }; + g.send(e); + }; + // @ts-ignore + "undefined" === typeof openapp_forceXhr && + "undefined" !== typeof gadgets && + "undefined" !== typeof gadgets.io && + "undefined" !== typeof gadgets.io.makeRequest && + (openapp["resource"].makeRequest = function (a, b, d, c, e, f) { + var g = {}, + h, + j = 0; + if ("undefined" !== typeof c) { + for (h in c) { + c.hasOwnProperty(h) && j++; + } + if (0 < j) { + // @ts-ignore + j = ""; + -1 !== b.indexOf("?") && + ((j = b.substring(b.indexOf("?"))), + // @ts-ignore + (b = b.substring(0, b.length - j.length))); + switch (b.substring(b.length - 1)) { + case "/": + b += ":"; + break; + case ":": + break; + default: + b += "/:"; + } + for (h in c) { + c.hasOwnProperty(h) && + (b = + h === openapp["ns"].rdf + "predicate" + ? b + (";predicate=" + encodeURIComponent(c[h])) + : b + + (";" + + encodeURIComponent(h) + + "=" + + encodeURIComponent(c[h]))); + } + b += j; + } + } + g[gadgets.io.RequestParameters.GET_FULL_HEADERS] = !0; + g[gadgets.io.RequestParameters.CONTENT_TYPE] = + gadgets.io.ContentType.TEXT; + g[gadgets.io.RequestParameters.AUTHORIZATION] = + gadgets.io.AuthorizationType.OAUTH; + g[gadgets.io.RequestParameters.OAUTH_SERVICE_NAME] = "openapp"; + g[gadgets.io.RequestParameters.OAUTH_USE_TOKEN] = "always"; + g[gadgets.io.RequestParameters.METHOD] = a; + g[gadgets.io.RequestParameters.HEADERS] = + g[gadgets.io.RequestParameters.HEADERS] || {}; + "undefined" !== typeof e && + null !== e && + ((g[gadgets.io.RequestParameters.HEADERS]["Content-Type"] = + "undefined" !== typeof f ? f : "application/json"), + (g[gadgets.io.RequestParameters.POST_DATA] = e)); + g[gadgets.io.RequestParameters.HEADERS].Accept = "application/json"; + d = d || function () {}; + openapp["io"].makeRequest( + b, + function (a) { + var b = { + data: a.data, + link: + "undefined" !== typeof a.headers.link + ? parseLinkHeader(a.headers.link[0]) + : {}, + }; + a.headers.hasOwnProperty("location") + ? (b["uri"] = a.headers.location[0]) + : a.headers.hasOwnProperty("content-base") + ? (b["uri"] = a.headers["content-base"][0]) + : // @ts-ignore + b["link"].hasOwnProperty("http://purl.org/dc/terms/subject") && + // @ts-ignore + (b["uri"] = b["link"]["http://purl.org/dc/terms/subject"].href); + a.headers.hasOwnProperty("content-location") && + (b["contentUri"] = a.headers["content-location"][0]); + a.headers.hasOwnProperty("content-type") && + "application/json" === + a.headers["content-type"][0].split(";")[0] && + (b.data = gadgets.json.parse(b.data)); + b["subject"] = + "undefined" !== typeof a.data + ? b.data.hasOwnProperty("") + ? b.data[""] + : b.data[b["uri"]] || {} + : {}; + d(b); + }, + g + ); + }); + openapp["resource"].get = function (a, b, d) { + return openapp["resource"].makeRequest( + "GET", + a, + b, + d || { + "http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate": + openapp["ns"].conserve + "info", + } + ); + }; + openapp["resource"].post = function (a, b, d, c, e) { + return openapp["resource"].makeRequest("POST", a, b, d, c, e); + }; + openapp["resource"].put = function (a, b, d, c, e) { + return openapp["resource"].makeRequest("PUT", a, b, d, c, e); + }; + openapp["resource"].del = function (a, b, d) { + return openapp["resource"].makeRequest("DELETE", a, b, d); + }; + openapp["resource"].context = function (a) { + return { + sub: function (b) { + var d = {}; + return { + control: function (a, b) { + d[a] = b; + return this; + }, + type: function (a) { + return this.control(openapp["ns"].rdf + "type", a); + }, + seeAlso: function (a) { + return this.control(openapp["ns"].rdfs + "seeAlso", a); + }, + list: function () { + var c = [], + e = a["subject"][b], + f, + g, + h, + j, + k, + l; + if ("undefined" === typeof e) { + return c; + } + h = 0; + a: for (; h < e.length; h++) { + f = e[h]; + g = a.data[f.value]; + for (j in d) { + if (d.hasOwnProperty(j)) { + if (!g.hasOwnProperty(j)) { + continue a; + } + l = !1; + for (k = 0; k < g[j].length; k++) { + if (g[j][k].value === d[j]) { + l = !0; + break; + } + } + if (!l) { + continue a; + } + } + } + // @ts-ignore + c.push({ data: a.data, link: {}, uri: f.value, subject: g }); + } + return c; + }, + create: function (c) { + if (!a["link"].rdf.hasOwnProperty(b)) { + throw ( + "The context does not support the requested relation: " + b + ); + } + var e = a["uri"]; + d[openapp["ns"].rdf + "predicate"] = b; + openapp["resource"].post( + e, + function (a) { + c(a); + }, + d + ); + }, + }; + }, + metadata: function () { + return openapp["resource"] + .context(a) + .content(openapp["ns"].rest + "metadata"); + }, + representation: function () { + return openapp["resource"] + .context(a) + .content(openapp["ns"].rest + "representation"); + }, + content: function (b) { + return { + get: function (d) { + openapp["resource"].get( + a["uri"], + function (a) { + d(a); + }, + { "http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate": b } + ); + }, + mediaType: function (d) { + var c = null; + return { + string: function (a) { + c = a; + return this; + }, + json: function (a) { + c = JSON.stringify(a); + return this; + }, + put: function (e) { + openapp["resource"].put( + a["uri"], + function (a) { + "function" === typeof e && e(a); + }, + { + "http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate": b, + }, + c, + d + ); + }, + }; + }, + string: function (a) { + return this.mediaType("text/plain").string(a); + }, + json: function (a) { + return this.mediaType("application/json").json(a); + }, + graph: function () { + var d = {}, + c = ""; + return { + subject: function (a) { + c = a; + return this; + }, + resource: function (a, b) { + d[c] = d[c] || {}; + d[c][a] = d[c][a] || []; + d[c][a].push({ value: b, type: "uri" }); + return this; + }, + literal: function (a, b, g, h) { + d[c] = d[c] || {}; + d[c][a] = d[c][a] || []; + d[c][a].push({ + value: b, + type: "literal", + lang: g, + datatype: h, + }); + return this; + }, + put: function (c) { + openapp["resource"].put( + a["uri"], + function (a) { + "function" === typeof c && c(a); + }, + { + "http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate": b, + }, + JSON.stringify(d) + ); + }, + }; + }, + }; + }, + properties: function () { + var b = {}, + d; + for (d in a["subject"]) { + a["subject"].hasOwnProperty(d) && (b[d] = a["subject"][d][0].value); + } + return b; + }, + string: function () { + return "string" === typeof a.data + ? a.data + : gadgets.json.stringify(a.data); + }, + json: function () { + return "string" === typeof a.data ? null : a.data; + }, + followSeeAlso: function () { + var b = a["subject"][openapp["ns"].rdfs + "seeAlso"], + d = 0, + c, + e; + if ("undefined" !== typeof b) { + b = b[0].value; + for ( + e = 0; + e < b.length && + e < a["uri"].length && + b.charAt(e) === a["uri"].charAt(e); + e++ + ) { + "/" === b.charAt(e) && d++; + } + for (c = d; e < b.length; e++) { + "/" === b.charAt(e) && c++; + } + return 3 > d || 4 < c + ? this + : openapp["resource"].context({ + data: a.data, + link: {}, + uri: b, + subject: a.data[b], + }); + } + return this; + }, + }; + }; + openapp["resource"].content = function (a) { + return { + properties: function () { + return openapp["resource"].context(a).properties(); + }, + string: function () { + return openapp["resource"].context(a).string(); + }, + json: function () { + return openapp["resource"].context(a).json(); + }, + }; + }; + openapp["oo"] = {}; + openapp["oo"].Resource = function (a, b, d) { + this.uri = a; + this.context = b; + this.info = d; + }; + var OARP = openapp["oo"].Resource.prototype; + OARP.getURI = function () { + return this.uri; + }; + OARP._call = function (a) { + var b = this; + null == this.context + ? null == this._deferred + ? ((this._deferred = [a]), + openapp["resource"].get(this.uri, function (a) { + b.context = a; + a = b._deferred; + delete b._deferred; + for (var c = 0; c < a.length; c++) { + a[c].call(b); + } + })) + : this._deferred.push(a) + : a.call(b); + }; + OARP.refresh = function (a) { + delete this.context; + delete this.info; + a && + this._call(function () { + a(); + }); + }; + OARP.getSubResources = function (a) { + this._call(function () { + for ( + var b = + null != a.type + ? openapp["resource"] + .context(this.context) + .sub(a.relation) + .type(a.type) + .list() + : openapp["resource"] + .context(this.context) + .sub(a.relation) + .list(), + d = [], + c = 0; + c < b.length; + c++ + ) { + var e = b[c].uri; + if (a.followReference) { + var f = + this.context.data[e]["http://www.w3.org/2002/07/owl#sameAs"]; + null != f && 0 < f.length && (e = f[0].value); + } + f = new openapp["oo"].Resource(e, null, b[c]); + null == a.followReference && + ((f._referenceLoaded = !0), + (e = this.context.data[e]["http://www.w3.org/2002/07/owl#sameAs"]), + null != e && 0 < e.length && (f._reference = e[0].value)); + if (a.onEach) { + a.onEach(f); + } + a.onAll && d.push(f); + } + if (a.onAll) { + a.onAll(d); + } + }); + }; + OARP.followReference = function (a) { + this._referenceLoaded + ? a( + null != this._reference + ? new openapp["oo"].Resource(this._reference) + : this + ) + : this._call(function () { + var b = + this.context.data[this.uri][ + "http://www.w3.org/2002/07/owl#sameAs" + ]; + null != b && 0 < b.length + ? a(new openapp["oo"].Resource(b[0].value)) + : a(this); + }); + }; + OARP.getReference = function (a) { + this._referenceLoaded + ? a(this._reference) + : this._call(function () { + var b = this.context.subject[openapp["ns"].rdfs + "seeAlso"]; + null != b && 0 < b.length + ? a(this.context.subject[openapp["ns"].rdfs + "seeAlso"][0].value) + : a(); + }); + }; + OARP.getMetadata = function (a, b) { + this._call(function () { + openapp["resource"] + .context(this.context) + .metadata() + .get(function (d) { + switch (a || "properties") { + case "properties": + b(openapp["resource"].context(d).properties()); + break; + case "graph": + b(openapp["resource"].content(d).graph()); + break; + case "rdfjson": + b(openapp["resource"].content(d).json()); + } + }); + }); + }; + OARP.getInfo = function (a) { + if (a) { + this.context || this.info + ? a( + openapp["resource"] + .context(this.context || this.info) + .properties() + ) + : this._call(function () { + a( + openapp["resource"] + .context(this.context || this.info) + .properties() + ); + }); + } else { + if (this.context || this.info) { + return openapp["resource"] + .context(this.context || this.info) + .properties(); + } + } + }; + OARP.getRepresentation = function (a, b) { + this._call(function () { + openapp["resource"] + .context(this.context) + .representation() + .get(function (d) { + switch (a || "text/html") { + case "properties": + b(openapp["resource"].context(d).properties()); + break; + case "graph": + b(openapp["resource"].content(d).graph()); + break; + case "rdfjson": + b(openapp["resource"].content(d).json()); + break; + case "text/html": + b(openapp["resource"].content(d).string()); + } + }); + }); + }; + OARP.setMetadata = function (a, b, d) { + var c = {}; + switch (b || "properties") { + case "properties": + b = {}; + for (var e in a) { + b[e] = [{ type: "literal", value: a[e] }]; + } + c[this.context.uri] = b; + break; + case "rdfjson": + c = a; + break; + case "graph": + // @ts-ignore + graph.put(d); + return; + } + openapp["resource"].put( + this.context.uri, + d, + { + "http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate": + openapp["ns"].rest + "metadata", + }, + JSON.stringify(c) + ); + }; + OARP.setRepresentation = function (a, b, d) { + this._call(function () { + var c = openapp["resource"] + .context(this.context) + .representation() + .mediaType(b); + "string" === typeof a ? c.string(a).put(d) : c.json(a).put(d); + }); + }; + OARP.create = function (a) { + this._call(function () { + var b = openapp["resource"] + .context(this.context) + .sub(a.relation || openapp["ns"].role + "data"); + null != a.referenceTo && (b = b.seeAlso(a.referenceTo)); + null != a.type && (b = b.type(a.type)); + b.create(function (b) { + var c = new openapp["oo"].Resource(b["uri"], b); + a.metadata + ? c.setMetadata(a.metadata, a.format, function () { + a.representation + ? c.setRepresentation( + a.representation, + a.medieType || "application/json", + function () { + a.callback(c); + } + ) + : a.callback(c); + }) + : a.representation + ? c.setRepresentation( + a.representation, + a.medieType || "application/json", + function () { + a.callback(c); + } + ) + : a.callback(c); + }); + }); + }; + OARP.del = function (a) { + openapp["resource"].del(this.uri, a); + }; + openapp["param"] = {}; + var parseQueryParams = function (a) { + var b, + d, + c = {}; + if (0 > a.indexOf("?")) { + return {}; + } + a = a.substr(a.indexOf("?") + 1).split("&"); + if (!(1 == a.length && "" === a[0])) { + for (d = 0; d < a.length; d++) { + (b = a[d].split("=")), + 2 == b.length && (c[b[0]] = window.unescape(b[1])); + } + } + return c; + }, + parseOpenAppParams = function (a) { + var b = {}, + d = {}, + c, + e; + for (c in a) { + a.hasOwnProperty(c) && + "openapp['ns']." === c.substring(0, 11) && + (b[c.substr(11)] = a[c]); + } + for (c in a) { + a.hasOwnProperty(c) && + ((e = c.split(".")), + 3 === e.length && + "openapp" === e[0] && + b.hasOwnProperty(e[1]) && + (d[b[e[1]] + e[2]] = a[c])); + } + return d; + }, + _openAppParams = parseOpenAppParams( + parseQueryParams(parseQueryParams(window.location.href)["url"] || "") + ); + openapp["param"].get = function (a) { + return _openAppParams[a]; + }; + openapp["param"].space = function () { + return openapp["param"].get("http://purl.org/role/terms/space"); + }; + openapp["param"].user = function () { + return openapp["param"].get("http://purl.org/role/terms/user"); + }; + } +} + +const openapp$2 = new OpenAppProvider().openapp; +/** + * Util + * @class Util + * @name Util + * @constructor + */ +var Util = { + /** + * Generate random hex string + * @param {number} [length] Length of string (Default=24) + * @returns {string} + */ + generateRandomId: function (length) { + var chars = "1234567890abcdef"; + var numOfChars = chars.length; + var i, rand; + var res = ""; + + if (typeof length === "undefined") length = 24; + + for (i = 0; i < length; i++) { + rand = Math.floor(Math.random() * numOfChars); + res += chars[rand]; + } + return res; + }, + + generateAnonymousUser: function () { + const user = {}; + var id = this.generateRandomId(); + user[CONFIG.NS.PERSON.TITLE] = "Anonymous"; + user[CONFIG.NS.PERSON.JABBERID] = id; + user[CONFIG.NS.PERSON.MBOX] = id + "@anonym.com"; + user.globalId = -1; + user.self = true; + return user; + }, + + /** + * Wait for delay milliseconds then return + * @param delay + * @returns {promise} + */ + delay: function (delay) { + var deferred = jQuery.Deferred(); + setTimeout(function () { + deferred.resolve(); + }, delay); + return deferred.promise(); + }, + + /** + * Union the two passed objects into a new object (on a duplicate key, the first object has priority) + * @param {object} obj1 + * @param {object} obj2 + * @returns {object} + */ + union: function (obj1, obj2) { + var res = {}, + i; + for (i in obj1) { + if (obj1.hasOwnProperty(i)) { + res[i] = obj1[i]; + } + } + for (i in obj2) { + if (obj2.hasOwnProperty(i) && !obj1.hasOwnProperty(i)) { + res[i] = obj2[i]; + } + } + return res; + }, + + /** + * Merge the elements of the second object into the first (on a duplicate key, the first object has priority) + * @param {object} obj1 + * @param {object} obj2 + * @returns {object} + */ + merge: function (obj1, obj2) { + var i; + for (i in obj2) { + if (obj2.hasOwnProperty(i) && !obj1.hasOwnProperty(i)) { + obj1[i] = obj2[i]; + } + } + return obj1; + }, + + /** + * Converts an async function that expects a callback as last parameter into a promise + * @param func + * @returns {promise} + */ + toPromise: function (func) { + return function () { + //noinspection JSAccessibilityCheck + var args = Array.prototype.slice.call(arguments); + var deferred = jQuery.Deferred(); + args.push(function () { + deferred.resolve.apply(this, arguments); + }); + func.apply(this, args); + return deferred.promise(); + }; + }, + + COLORS: [ + "#8AFFC8", //türkis + "#8A9FFF", //light blue + "#FF8A8A", //Rot + "#FFC08A", //Orange + "#FF8AD2", //Pink + "#8AEBFF", //Blue + "#C68AFF", //Lila + "#8EFF8A", //green + ], + + /** + * Map an integer to one of ten colors + * @param id + * @returns {string} + */ + getColor: function (id) { + return this.COLORS[id % this.COLORS.length]; + }, + + /*function hashCode(s){ + return s.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0); + };*/ + /** + * Returns the id of the given user (will be its index in the user list) + * @param {*} user + * @param {*} y the shared yjs document + * @returns + */ + getGlobalId: function (user, y) { + var mbox = user.user[CONFIG.NS.PERSON.MBOX]; // mailbox of the user + const userMap = y.getMap("users"); + var users = Array.from(userMap.values()); // get all users + var id = users.indexOf(mbox); + if (id === -1) { + id = users.length; + userMap.set(y.clientID, mbox); + } + return id; + }, + + /** + * Get the current state of the primary document store + * @returns {*} + * @constructor + */ + GetCurrentBaseModel: function () { + var resourceSpace = new openapp$2.oo.Resource(openapp$2.param.space()); + var deferred = jQuery.Deferred(); + resourceSpace.getSubResources({ + relation: openapp$2.ns.role + "data", + type: CONFIG.NS.MY.MODEL, + onAll: function (data) { + if (data === null || data.length === 0) { + deferred.resolve([]); + } else { + data[0].getRepresentation("rdfjson", function (representation) { + if (!representation) { + deferred.resolve([]); + } else { + deferred.resolve(representation); + } + }); + } + }, + }); + return deferred.promise(); + }, + + getSpaceTitle: function (url) { + return url + .substring(url.lastIndexOf("spaces/")) + .replace(/spaces|#\S*|\?\S*|\//g, ""); + }, +}; + +/** + * Provides messaging functionality. + * @param {Array} categories - (currently not implemented) categories of widgets that shall process the intent (e.g. ["editor","proxy" ]) + * @param {String} origin - The origin (i.e. the url where your application script lives) is needed for messaging + * @param {} y - A reference to yjs' Y object for global messaging + */ +class Client { + //console.log(y); + _y; + _componentName = "unknown"; + + //private variables + _connected = false; + _categories; + _callback; + + // Needed for HTML5 messaging + _origin; + + constructor(componentName, categories, origin, y) { + //console.log(y); + this._y = y; + + this._componentName = componentName; + this._categories = categories; + // Needed for HTML5 messaging + this._origin = origin; + } + + /** + * Connect widget to messaging. This sets up the callback function and creates + * an event listener for HTML5 messaging and a yjs observer for global messaging. + * If yjs is not available only local messaging is set up. + * @param {function} callback - The callback function used for receiving messages. + */ + connect(callback) { + this._callback = callback; + var handler = this.receiveMessage.bind(this); + //Todo + const widgetTageName = getWidgetTagName(this._componentName); + try { + const _node = document.querySelector(widgetTageName); + + if (!_node) { + throw new Error( + "html tag not found in document. Please make sure that you added the " + + widgetTageName + + " to the document. Hint: do not use the shadow dom." + ); + } + _node.addEventListener("syncmeta-message", handler); + } catch (error) { + console.error(error); + } + + + if (this._y) { + // If yjs is available also connect a global listener + const intents = this._y.getMap("intents"); + if (intents) intents.observe(handler); + } + } + + /** + * Disconnect the widget from messaging. This removes the event listener + * and the callback for both local and global messaging. If yjs is not available, + * only local messaging will be available. + */ + disconnect() { + //THISELEMENT.removeEventListener("syncmeta-message", this.receiveMessage, false); + this._callback = null; + + if (!(this._y === null || this._y === undefined)) { + this._y.getMap("intents").unobserve(this.receiveMessage); + } + } + + /** + * Publishes an intent, + * @param {intent} - The intent about to be published, this object contains all information. + */ + publish(intent) { + if (util.validateIntent(intent)) { + if (intent.flags[0] === util.FLAGS.PUBLISH_GLOBAL) { + this.publishGlobal(intent, this._y); + } else if (intent.flags[0] === util.FLAGS.PUBLISH_LOCAL) { + this.publishLocal(intent, this._origin); + } + } + } + + publishLocal(intent, origin) { + //Find iframe and post message + const widgets = []; + for (const el of document.querySelectorAll("*")) { + if (el.tagName.match(/-widget$/i)) { + widgets.push(el); + } + } + + widgets.forEach(function (widget) { + const receiverTagName = getWidgetTagName(intent.receiver.toLowerCase()); + if (widget.tagName.toLowerCase() === receiverTagName.toLowerCase()) { + const event = new CustomEvent("syncmeta-message", { + detail: { + intent, + origin, + }, + }); + widget.dispatchEvent(event); + } + }); + } + + publishGlobal(intent, y) { + //y.share.intents.push(intent); + y.getMap("intents").set(intent.receiver, intent); + } + + /** + * Unpack events and pre process them. This unwraps HTML5 messages and manages the yjs map + * used for global messaging. + * @param {Event} event - The event that activated the callback + */ + receiveMessage(event) { + // Local messaging events + if (event.type === "syncmeta-message") { + //Unpack message events + if (event instanceof CustomEvent) { + this._callback(event.detail.intent); + } + } else if (event.type === "add" || event.type == "update") { + //Unpack yjs event and remove from map + var intent = event.object.get(event.name); + event.object.delete(event.name); + console.log(intent); + this._callback(intent); + } + } +} + +//======================= IWC.util ============================== + +class util { + /** + * Used to determine whether global or local messaging should be used. + * Local messaging uses HTML5 messaging, global messaging uses yjs. + */ + static FLAGS = { + PUBLISH_LOCAL: "PUBLISH_LOCAL", + PUBLISH_GLOBAL: "PUBLISH_GLOBAL", + }; + + /** + * Check intent for correctness. + */ + static validateIntent(intent) { + if (typeof intent.sender != "string") { + throw new Error( + "Intent object must possess property 'component' of type 'String'" + ); + } + if (typeof intent.data != "string") { + throw new Error( + "Intent object must possess property 'data' of type 'String'" + ); + } + if (typeof intent.dataType != "string") { + throw new Error( + "Intent object must possess property 'dataType' of type 'String'" + ); + } + return true; + } +} + +var PAYLOAD_DATA_TYPE = { + OT_OPERATION: "OTOperation", + NON_OT_OPERATION: "NonOTOperation", +}; + +class IWCWrapper { + /** + * Inter-widget communication wrapper + * @class IWCWrapper + * @constructor + * @param componentName Name of component (widget) using the wrapper + */ + + /** + * Set if local messages should be buffered + * @type {boolean} + */ + BUFFER_ENABLED = false; + + /** + * Interval for sending buffered local messages + * @type {number} + */ + INTERVAL_SEND = 25; + + Space = null; + + //noinspection JSMismatchedCollectionQueryUpdate + /** + * Buffer for local messages + * @type {Array} + * @private + */ + _messageBuffer = []; + + //noinspection JSMismatchedCollectionQueryUpdate + /** + * Set of registered Callbacks for local data receive events + * @type {Array} + * @private + */ + _onDataReceivedCallbacks = []; + + _onDataReceivedCallers = []; + + /** + * Stores (for each user) the times an inocming messages has been received to drop duplicate (same time) messages + * @type {object} + * @private + */ + _times = {}; + + /** + * Inter widget communication client + * @type {iwc.Client} + * @private + */ + _iwc; + /** + * Disconnect the iwc client + * @memberof IWCWrapper# + */ + disconnect; + /** + * Connect the iwc client + * @memberof IWCWrapper# + */ + connect; + sendLocalMessage; + sendLocalOTOperation; + sendLocalNonOTOperation; + getUserColor; + registerOnDataReceivedCallback; + unregisterOnDataReceivedCallback; + getUser; + getMembers; + getSpaceTitle; + setSpace; + componentName; + + /** + * Encapsulates the passed message information into the Android Intent-like format required by the iwc client + * @param {string} receiver Component name of the receiving component (widget), empty string for remote messages + * @param {string|string[]} flags Single flag or array of flags to indicate if the messages should be propagate locally or remotely + * @param {string} action Type of data (DATA, DATA_ARRAY, SYNC) + * @param {object} payload Message Payload + * @returns {Object} + */ + encapsulateMessage(receiver, flags, action, payload) { + var i, numOfFlags, flag; + // @ts-ignore + var validatedFlags = []; + + if (flags instanceof Array) { + for (i = 0, numOfFlags = flags.length; i < numOfFlags; i++) { + flag = flags[i]; + if ( + flag === CONFIG.IWC.FLAG.PUBLISH_LOCAL || + flag === CONFIG.IWC.FLAG.PUBLISH_GLOBAL + ) { + // @ts-ignore + validatedFlags.push(flag); + } + } + } else if (typeof flags === "string") { + if ( + flags === CONFIG.IWC.FLAG.PUBLISH_LOCAL || + flags === CONFIG.IWC.FLAG.PUBLISH_GLOBAL + ) { + // @ts-ignore + validatedFlags.push(flags); + } + } else { + throw "Parameter flags has wrong type. Array or String expected."; + } + + if (typeof action !== "string") { + throw "Parameter action has wrong type. String expected."; + } + + receiver = receiver || ""; + + return { + receiver: receiver, + sender: this.componentName, + data: "", + dataType: "", + action: action, + flags: validatedFlags, + extras: { + payload: payload, + time: new Date().getTime(), + }, + }; + } + + /** + * Send all buffered local messages encapsulated in one message + */ + sendBufferedMessages() { + var intent; + var data = null; + + for (var receiver in this._messageBuffer) { + if (this._messageBuffer.hasOwnProperty(receiver)) { + data = this._messageBuffer[receiver].splice( + 0, + this._messageBuffer[receiver].length + ); + //sendBufferTimer.pause(); + if (data.length == 1) { + intent = this.encapsulateMessage( + receiver, + CONFIG.IWC.FLAG.PUBLISH_LOCAL, + CONFIG.IWC.ACTION.DATA, + data[0] + ); + if (util.validateIntent(intent)) { + //console.log("=== " + intent.flags.toString().replace(/PUBLISH_/g, "") + " INTENT TRANSMITTED AT COMPONENT " + componentName + " ==="); + //console.log(intent); + + this._iwc.publish(intent); + } + } else if (data.length > 1) { + intent = this.encapsulateMessage( + receiver, + CONFIG.IWC.FLAG.PUBLISH_LOCAL, + CONFIG.IWC.ACTION.DATA_ARRAY, + data + ); + if (util.validateIntent(intent)) { + //console.log("=== " + intent.flags.toString().replace(/PUBLISH_/g, "") + " INTENT TRANSMITTED AT COMPONENT " + componentName + " ==="); + //console.log(intent); + + this._iwc.publish(intent); + } + } + } + } + //sendBufferTimer.resume(); + } + + /** + * Callback for received local messages + * @param {object} intent Message content in Android Intent-like format required by the iwc client + */ + onIntentReceivedCallback(_self, intent) { + //some CAE widgets still use the old iwc.js library + //then it happens that intent are not parsed and processes correctly by the new iwc and then + //the complete message as string is returned + //this workaround should help for now to make it work with syncmeta + if (typeof intent === "string") { + try { + intent = JSON.parse(intent); + if (intent.hasOwnProperty("OpenApplicationEvent")) { + intent = intent["OpenApplicationEvent"]; + if (intent.hasOwnProperty("message")) intent = intent.message; + } + } catch (e) { + return; + } + } + + if ( + !intent.hasOwnProperty("extras") || + !intent.extras.hasOwnProperty("payload") + ) { + return; + } + + var payload = intent.extras.payload, + senderTime = intent.extras.time, + senderTimes = _self._times[intent.sender]; + + var i, numOfSenderTimes, numOfMessages; + + function handleMessage(payload) { + var type, data, sender, operation, resOperation, i, numOfCallbacks; + + if ( + !payload || + !payload.hasOwnProperty("type") || + !payload.hasOwnProperty("data") + ) { + return; + } + type = payload.type; + data = payload.data; + sender = payload.sender; + switch (type) { + case PAYLOAD_DATA_TYPE.OT_OPERATION: + operation = new OTOperation( + data.name, + data.value, + data.type, + data.position + ); + operation.setSender(sender); + resOperation = + OperationFactory$1.createOperationFromOTOperation(operation); + //adjustHistory(remoteOp); + for ( + i = 0, numOfCallbacks = _self._onDataReceivedCallbacks.length; + i < numOfCallbacks; + i++ + ) { + if (typeof _self._onDataReceivedCallbacks[i] === "function") { + var caller = _self._onDataReceivedCallers[i] || _self; + _self._onDataReceivedCallbacks[i].call(caller, resOperation); + } + } + break; + case PAYLOAD_DATA_TYPE.NON_OT_OPERATION: + operation = new NonOTOperation(data.type, data.data); + operation.setSender(sender); + resOperation = + OperationFactory$1.createOperationFromNonOTOperation(operation); + //adjustHistory(remoteOp); + for ( + i = 0, numOfCallbacks = _self._onDataReceivedCallbacks.length; + i < numOfCallbacks; + i++ + ) { + if (typeof _self._onDataReceivedCallbacks[i] === "function") { + var caller = _self._onDataReceivedCallers[i] || _self; + _self._onDataReceivedCallbacks[i].call(caller, resOperation); + } + } + break; + } + } + + if (intent.flags.indexOf(CONFIG.IWC.FLAG.PUBLISH_GLOBAL) !== -1) return; + + if (typeof senderTimes === "undefined") { + senderTimes = _self._times[intent.sender] = []; + } else { + for ( + i = 0, numOfSenderTimes = senderTimes.length; + i < numOfSenderTimes; + i++ + ) { + if (senderTime === senderTimes[i]) { + return; + } + } + } + + senderTimes.push(senderTime); + + //console.log("=== " + intent.flags.toString().replace(/PUBLISH_/g,"") + " INTENT RECEIVED AT COMPONENT " + componentName + " ==="); + //console.log(intent); + + switch (intent.action) { + case CONFIG.IWC.ACTION.DATA: + handleMessage(payload); + break; + case CONFIG.IWC.ACTION.DATA_ARRAY: + for (i = 0, numOfMessages = payload.length; i < numOfMessages; i++) { + handleMessage(payload[i]); + } + break; + } + } + + constructor(componentName, y) { + this.componentName = componentName; + this._iwc = new Client(componentName, "*", null, y); + window._iwc_instance_ = this._iwc; + + //var sendBufferTimer; + //if(BUFFER_ENABLED) sendBufferTimer = new IWCWrapper.PausableInterval(sendBufferedMessages, INTERVAL_SEND); + if (this.BUFFER_ENABLED) + setInterval(this.sendBufferedMessages, this.INTERVAL_SEND); + + this.connect = () => + this._iwc.connect((intent) => + this.onIntentReceivedCallback(this, intent) + ); + this.disconnect = () => this._iwc.disconnect; + + /** + * Send data locally to an other component + * @memberof IWCWrapper# + * @param {string} receiver Component name of receiving component, empty string for broadcast + * @param {object} data Data to send + */ + this.sendLocalMessage = function (receiver, data) { + var intent; + + if (!receiver || receiver === "") return; + + if (this.BUFFER_ENABLED) { + //sendBufferTimer.pause(); + if (this._messageBuffer.hasOwnProperty(receiver)) { + this._messageBuffer[receiver].push(data); + } else { + this._messageBuffer[receiver] = [data]; + } + //sendBufferTimer.resume(); + } else { + intent = this.encapsulateMessage( + receiver, + CONFIG.IWC.FLAG.PUBLISH_LOCAL, + CONFIG.IWC.ACTION.DATA, + data + ); + if (util.validateIntent(intent)) { + //console.log("=== " + intent.flags.toString().replace(/PUBLISH_/g,"") + " INTENT TRANSMITTED AT COMPONENT " + componentName + " ==="); + //console.log(intent); + + this._iwc.publish(intent); + } + } + }; + /** + * Send OTOperation locally to an other component + * @memberof IWCWrapper# + * @param {string} receiver Component name of receiving component, empty string for broadcast + * @param {operations.ot.OTOperation} operation Operation to send + */ + this.sendLocalOTOperation = function (receiver, operation) { + this.sendLocalMessage(receiver, { + type: PAYLOAD_DATA_TYPE.OT_OPERATION, + data: operation.getOperationObject(), + sender: operation.getSender(), + }); + }; + /** + * Send NonOTOperation locally to an other component + * @memberof IWCWrapper# + * @param {string} receiver Component name of receiving component, empty string for broadcast + * @param {operations.non_ot.NonOTOperation} operation Operation to send + */ + this.sendLocalNonOTOperation = function (receiver, operation) { + this.sendLocalMessage(receiver, { + type: PAYLOAD_DATA_TYPE.NON_OT_OPERATION, + data: operation.getOperationObject(), + sender: operation.getSender(), + }); + }; + this.getUserColor = function (jabberId) { + return Util.getColor(this.Space.members[jabberId].globalId); + }; + /** + * Register callback for local data receive events + * @memberof IWCWrapper# + * @param {function} callback + */ + this.registerOnDataReceivedCallback = function (callback, caller) { + if (typeof callback === "function") { + this.unregisterOnDataReceivedCallback(callback); + this._onDataReceivedCallbacks.push(callback); + this._onDataReceivedCallers.push(caller); + } + }; + /** + * Unregister callback for local data receive events + * @memberof IWCWrapper# + * @param {function} callback + */ + this.unregisterOnDataReceivedCallback = function (callback) { + var i, numOfCallbacks; + + if (typeof callback === "function") { + for ( + i = 0, numOfCallbacks = this._onDataReceivedCallbacks.length; + i < numOfCallbacks; + i++ + ) { + if (callback === this._onDataReceivedCallbacks[i]) { + this._onDataReceivedCallbacks.splice(i, 1); + this._onDataReceivedCallers.splice(i, 1); + } + } + } + }; + this.getUser = function () { + if (!this.Space) { + console.error("Space is null"); + this.Space = { user: {} }; + } else if (!this.Space.user) { + console.error("User in space is null, generating new anonymous user"); + this.Space.user = Util.generateAnonymousUser(); + } + return this.Space.user; + }; + this.getMembers = function () { + return this.Space.members; + }; + this.getSpaceTitle = function () { + return this.Space.title; + }; + this.setSpace = function (s) { + this.Space = s; + }; + + return this; + } +} + +/** + * Inter widget communication and OT client module + * @exports IWCW + */ +class IWCW { + static instances = {}; //static variable to store instances of IWCWrapper. One for each widget + constructor() {} + /** + * Instance of IWCWrapper + * @type {IWCWrapper} + */ + + static hasInstance(componentName) { + return componentName in IWCW.instances; + } + + /** + * Get instance of IWCOTWrapper + * @param {string} componentName Name of component (widget) using the wrapper + * @returns {IWCWrapper} + */ + static getInstance(componentName, y) { + if (!this.hasInstance(componentName)) { + y = y || window.y; + if (!y) { + console.error( + "y is null, y is the shared y document that should be passed along when calling getInstance, proceed with caution" + ); + } + IWCW.instances[componentName] = new IWCWrapper(componentName, y); + IWCW.instances[componentName].connect(); + } + return IWCW.instances[componentName]; + } +} + +$.fn.autoGrowInput = function (o) { + o = $.extend( + { + maxWidth: 1000, + minWidth: 0, + comfortZone: 70, + }, + o + ); + + this.filter("input:text").each(function () { + var minWidth = o.minWidth || $(this).width(), + val = "", + input = $(this), + testSubject = $("").css({ + position: "absolute", + top: -9999, + left: -9999, + width: "auto", + fontSize: input.css("fontSize"), + fontFamily: input.css("fontFamily"), + fontWeight: input.css("fontWeight"), + letterSpacing: input.css("letterSpacing"), + whiteSpace: "nowrap", + }), + check = function () { + val = input.val(); + + // Enter new content into testSubject + var escaped = val + .replace(/&/g, "&") + .replace(/\s/g, " ") + .replace(//g, ">"); + testSubject.html(escaped); + + // Calculate new width + whether to change + var testerWidth = testSubject.width(), + newWidth = + testerWidth + o.comfortZone >= minWidth + ? testerWidth + o.comfortZone + : minWidth, + currentWidth = input.width(), + isValidWidthChange = + (newWidth < currentWidth && newWidth >= minWidth) || + (newWidth > minWidth && newWidth < o.maxWidth); + + // Animate width + if (isValidWidthChange) { + input.width(newWidth); + } + }; + + $("body").append(testSubject); + + $(this).bind("keyup keydown blur update", check); + }); + + return this; +}; + +/** + * AbstractEntity + * @class canvas_widget.AbstractEntity + * @memberof canvas_widget + * @constructor + * @param {string} id Identifier of this entity + */ + class AbstractEntity { + static MAX_Z_INDEX = 32000; + static MIN_Z_INDEX = 1; + static CONTEXT_MENU_Z_INDEX = 32000 + 1; + + static maxZIndex = 16000; + static minZIndex = 16000; + constructor(id) { + /** + * Entity identifier + * @type {string} + * @private + */ + var _id = id; + + /** + * Get the entity identifier + * @returns {string} entity id + */ + this.getEntityId = function () { + return _id; + }; + } + } + +const abstractAttributeHtml = "
          "; // replaced by importmap.plugin.js + +/** + * AbstractAttribute + * @class canvas_widget.AbstractAttribute + * @extends canvas_widget.AbstractEntity + * @memberof canvas_widget + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to + */ +class AbstractAttribute extends AbstractEntity { + constructor(id, name, subjectEntity) { + super(id); + + /** + * Entity id + * @type {string} + * @private + */ + var _id = id; + + /** + * Name of Attribute + * @type {string} + * @private + */ + var _name = name; + + /** + * jQuery object of DOM node representing the attribute + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(abstractAttributeHtml)()); + + /** + * Entity the attribute is assigned to + * @type {canvas_widget.AbstractEntity} + * @private + */ + var _subjectEntity = subjectEntity; + + /** + * Set name of the attribute + * @param {string} name + */ + this.setName = function (name) { + _name = name; + }; + + /** + * Get name of the attribute + * @returns {String} + */ + this.getName = function () { + return _name; + }; + + /** + * Get entity the attribute is assigned to + * @returns {canvas_widget.AbstractEntity} + */ + this.getSubjectEntity = function () { + return _subjectEntity; + }; + + /** + * Get topmost entity in the chain of entities the attribute is assigned to + * @returns {canvas_widget.AbstractEdge|canvas_widget.AbstractNode} + */ + this.getRootSubjectEntity = function () { + var rootSubjectEntity = this.getSubjectEntity(); + while (rootSubjectEntity instanceof AbstractAttribute) { + rootSubjectEntity = rootSubjectEntity.getSubjectEntity(); + } + return rootSubjectEntity; + }; + + /** + * Get id of the entity the attribute is assigned to + * @returns {String} + */ + this.getSubjectEntityId = function () { + return _subjectEntity.getEntityId(); + }; + + /** + * Get jQuery object of the DOM node representing the attribute + * @returns {jQuery} + * @private + */ + this._get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the attribute + * @returns {Object} + * @private + */ + this._toJSON = function () { + return { + id: _id, + name: _name, + }; + }; + } + /** + * Get jQuery object of the DOM node representing the attribute + * @returns {jQuery} + */ + get$node() { + return this._get$node(); + } + /** + * Get JSON representation of the attribute + * @returns {Object} + */ + toJSON() { + return this._toJSON(); + } + registerYTypeForValue(map, value) { + var deferred = $.Deferred(); + map.get(value.getEntityId()).then(function (type) { + value.registerYType(type); + deferred.resolve(); + }); + return deferred.promise(); + } +} + +/** + * AbstractValue + * @class canvas_widget.AbstractValue + * @member of canvas_widget + * @constructor + * @param {string} id Entity identifier + * @param {string} name Name of attribute + * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {canvas_widget.AbstractNode|canvas_widget.AbstractEdge} rootSubjectEntity Topmost entity in the chain of entity the attribute is assigned to + */ + class AbstractValue { + constructor(id, name, subjectEntity, rootSubjectEntity) { + var that = this; + + /** + * The entity identifier + * @returns {string} entity id + */ + var _id = id; + + /** + * Name of Attribute + * @type {string} + * @private + */ + var _name = name; + + /** + * Entity the attribute is assigned to + * @type {canvas_widget.AbstractEntity} + * @private + */ + var _subjectEntity = subjectEntity; + + /** + * Topmost entity in the chain of entity the attribute is assigned to + * @type {canvas_widget.AbstractEdge|canvas_widget.AbstractNode} + * @private + */ + var _rootSubjectEntity = rootSubjectEntity; + + /** + * Get the entity identifier + * @returns {string} entity id + */ + this.getEntityId = function () { + return _id; + }; + + /** + * Get name of value + * @returns {string} + */ + this.getName = function () { + return _name; + }; + + /** + * Get entity the attribute is assigned to + * @returns {canvas_widget.AbstractEntity} + */ + this.getSubjectEntity = function () { + return _subjectEntity; + }; + + /** + * Get topmost entity in the chain of entity the attribute is assigned to + * @returns {canvas_widget.AbstractEdge|canvas_widget.AbstractNode} + */ + this.getRootSubjectEntity = function () { + return _rootSubjectEntity; + }; + + /** + * Get JSON representation of the edge + * @returns {Object} + */ + this._toJSON = function () { + return { + id: that.getEntityId(), + name: _name, + }; + }; + } + //noinspection JSAccessibilityCheck + toJSON() { + return this._toJSON(); + } + } + +function Arrows(color){ + return { + //"bidirassociation": {}, //No overlays for bi-dir-association + unidirassociation: { + type: "Arrow", + options: { + width: 20, + length: 30, + location: 1, + foldback: 0.1, + paintStyle: { + fill: "#ffffff", + outlineWidth: 2, + outlineStroke: color, + }, + }, + }, + generalisation: { + type: "Arrow", + options: { + width: 20, + length: 30, + location: 1, + foldback: 1, + paintStyle: { + fill: "#ffffff", + outlineWidth: 2, + outlineStroke: color, + }, + }, + }, + diamond: { + type: "Arrow", + options: { + width: 20, + length: 20, + location: 1, + foldback: 2, + paintStyle: { + fill: "#ffffff", + outlineWidth: 2, + outlineStroke: color, + }, + }, + }, + }; + } + +let booleanValueHtml = "
          <%= value %>
          "; // replaced by importmap.plugin.js +const attributeBooleanValueHtml = "\"\n <% if (value) { %> checked=\"checked\" <% } %> />\n"; // replaced by importmap.plugin.js + +/** + * BooleanValue + * @class canvas_widget.BooleanValue + * @extends canvas_widget.AbstractValue + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier + * @param {string} name Name of attribute + * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {canvas_widget.AbstractNode|canvas_widget.AbstractEdge} rootSubjectEntity Topmost entity in the chain of entity the attribute is assigned to + */ +class BooleanValue extends AbstractValue { + constructor(id, name, subjectEntity, rootSubjectEntity, useAttributeHtml) { + if (useAttributeHtml) booleanValueHtml = attributeBooleanValueHtml; + + super(id, name, subjectEntity, rootSubjectEntity); + var that = this; + /** + * Value + * @type {boolean} + * @private + */ + var _value = false; + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(booleanValueHtml)({ value: _value })); + + /** + * Inter widget communication wrapper + * @type {Object} + * @private + */ + y = y || window.y; + var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); + + /** + * Apply a Value Change Operation + * @param {operations.ot.ValueChangeOperation} operation + */ + var processValueChangeOperation = function (operation) { + that.setValue(operation.getValue()); + }; + + var init = function () { + _$node.off(); + }; + + /** + * Set value + * @param {boolean} value + */ + this.setValue = function (value) { + _value = value; + if (useAttributeHtml) _$node.prop("checked", value); + else _$node.text(value); + }; + + /** + * Get value + * @returns {boolean} + */ + this.getValue = function () { + return _value; + }; + + /** + * Get jQuery object of DOM node representing the value + * @returns {jQuery} + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the edge + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractValue.prototype.toJSON.call(this); + json.value = _value; + return json; + }; + + /** + * Set value by its JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + this.setValue(json.value); + }; + + this.registerYType = function () { + that + .getRootSubjectEntity() + .getYMap() + .observe(function (event) { + const array = Array.from(event.changes.keys.entries()); + array.forEach(function ([key, change]) { + if (change.action !== "update" || key !== that.getEntityId()) { + return; + } + const map = event.currentTarget.get(key); + const json = map; + + var operation = new ValueChangeOperation( + json.entityId, + json.value, + json.type, + json.position, + json.jabberId + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.getOTOperation() + ); + processValueChangeOperation(operation); + + //Only the local user Propagates the activity + if ( + _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID] === + operation.getJabberId() + ) { + const activityMap = y.getMap("activity"); + activityMap.set( + ActivityOperation.TYPE, + new ActivityOperation( + "ValueChangeActivity", + that.getEntityId(), + _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], + ValueChangeOperation.getOperationDescription( + that.getSubjectEntity().getName(), + that.getRootSubjectEntity().getType(), + that.getRootSubjectEntity().getLabel().getValue().getValue() + ), + { + value: operation.getValue(), + subjectEntityName: that.getSubjectEntity().getName(), + rootSubjectEntityType: that + .getRootSubjectEntity() + .getType(), + rootSubjectEntityId: that + .getRootSubjectEntity() + .getEntityId(), + } + ).toJSON() + ); + } else { + //the remote users propagtes the change to their local attribute widget + //TODO(PENDING): can be replace with yjs as well + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.ATTRIBUTE, + operation.getOTOperation() + ); + } + }); + }); + + //Debounce the save function + that + .getRootSubjectEntity() + .getYMap() + .observe( + lodash.debounce(function (event) { + event.keysChanged.forEach(function (key) { + if ( + key == "jabberId" && + key === _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID] + ) + EntityManager.saveState(); + }); + }, 500) + ); + }; + + init(); + } +} + +const booleanAttributeHtml = "
          \n
          \n
          \n
          "; // replaced by importmap.plugin.js + +/** + * BooleanAttribute + * @class canvas_widget.BooleanAttribute + * @extends canvas_widget.AbstractAttribute + * @memberof canvas_widget + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to + */ +class BooleanAttribute extends AbstractAttribute { + constructor(id, name, subjectEntity, useAttributeHtml) { + useAttributeHtml = + typeof useAttributeHtml !== "undefined" ? useAttributeHtml : false; + super(id, name, subjectEntity); + + /*** + * Value object of value + * @type {canvas_widget.BooleanValue} + * @private + */ + var _value = new BooleanValue( + id, + name, + this, + this.getRootSubjectEntity(), + useAttributeHtml + ); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(booleanAttributeHtml)()); + + /** + * Set Value object of value + * @param {canvas_widget.BooleanValue} value + */ + this.setValue = function (value) { + _value = value; + _$node.val(value); + }; + + /** + * Get Value object of value + * @return {canvas_widget.BooleanValue} value + */ + this.getValue = function () { + return _value; + }; + + /** + * jQuery object of DOM node representing the attribute + * @type {jQuery} + * @private + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the attribute + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.value = _value.toJSON(); + return json; + }; + + /** + * Set attribute value by its JSON representation + * @param {Object} json + */ + this.setValueFromJSON = function (json) { + _value.setValueFromJSON(json.value); + }; + + _$node.find(".name").text(this.getName()); + _$node.find(".value").append(_value.get$node()); + } +} + +const openapp$1 = new OpenAppProvider().openapp; + +let fileValueHtml = "
          <%= value %>
          "; // replaced by importmap.plugin.js +const attributeFileValueHtml = "
          \n
          \n \n \n
          \n
          \n \n \n \n \n
          \n
          \n"; // replaced by importmap.plugin.js + +FileValue.prototype = new AbstractValue(); +FileValue.prototype.constructor = FileValue; +/** + * FileValue + * @class canvas_widget.FileValue + * @extends canvas_widget.AbstractValue + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier + * @param {string} name Name of attribute + * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {canvas_widget.AbstractNode|canvas_widget.AbstractEdge} rootSubjectEntity Topmost entity in the chain of entity the attribute is assigned to + */ +function FileValue( + id, + name, + subjectEntity, + rootSubjectEntity, + useAttributeHtml +) { + var that = this; + + if (useAttributeHtml) fileValueHtml = attributeFileValueHtml; + + AbstractValue.call(this, id, name, subjectEntity, rootSubjectEntity); + + /** + * Value + * @type {string} + * @private + */ + var _value = ""; + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node; + + if (useAttributeHtml) _$node = $(lodash.template(fileValueHtml)({ name: name })); + else _$node = $(lodash.template(fileValueHtml)({ value: _value })); + + var _$selectFile = _$node.find(".select_file"); + + var _$manageFile = _$node.find(".manage_file"); + + /** + * Inter widget communication wrapper + * @type {Object} + * @private + */ + y = y || window.y; + var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); + + /** + * Get chain of entities the attribute is assigned to + * @returns {string[]} + */ + var getEntityIdChain = function () { + var chain = [that.getEntityId()], + entity = that; + while (entity instanceof AbstractAttribute) { + chain.unshift(entity.getSubjectEntity().getEntityId()); + entity = entity.getSubjectEntity(); + } + return chain; + }; + + var uploadFile = function (name, type, data) { + var resourceSpace = new openapp$1.oo.Resource(openapp$1.param.space()); + + resourceSpace.create({ + relation: openapp$1.ns.role + "data", + type: "my:ns:file", + representation: { + name: name, + type: type, + data: data, + }, + callback: function (d) { + if (d.uri) { + propagateValueChange(CONFIG.OPERATION.TYPE.UPDATE, d.uri, 0); + } + }, + }); + }; + + /** + * Apply a Value Change Operation + * @param {operations.ot.ValueChangeOperation} operation + */ + var processValueChangeOperation = function (operation) { + that.setValue(operation.getValue()); + }; + + var propagateValueChange = function (type, value, position) { + var operation = new ValueChangeOperation( + that.getEntityId(), + value, + type, + position + ); + propagateValueChangeOperation(operation); + }; + + /** + * Propagate a Value Change Operation to the remote users and the local widgets + * @param {operations.ot.ValueChangeOperation} operation + */ + var propagateValueChangeOperation = function (operation) { + operation.setEntityIdChain(getEntityIdChain()); + processValueChangeOperation(operation); + if (_iwcw.sendRemoteOTOperation(operation)) { + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.ATTRIBUTE, + operation.getOTOperation() + ); + const activityMap = y.getMap("activity"); + + activityMap.set( + ActivityOperation.TYPE, + new ActivityOperation( + "ValueChangeActivity", + that.getEntityId(), + _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], + ValueChangeOperation.getOperationDescription( + that.getSubjectEntity().getName(), + that.getRootSubjectEntity().getType(), + that.getRootSubjectEntity().getLabel().getValue().getValue() + ), + { + value: operation.getValue(), + subjectEntityName: that.getSubjectEntity().getName(), + rootSubjectEntityType: that.getRootSubjectEntity().getType(), + rootSubjectEntityId: that.getRootSubjectEntity().getEntityId(), + } + ).toJSON() + ); + } + }; + + /** + * Callback for a local Value Change Operation + * @param {operations.ot.ValueChangeOperation} operation + */ + var localValueChangeCallback = function (operation) { + if ( + operation instanceof ValueChangeOperation && + operation.getEntityId() === that.getEntityId() + ) { + propagateValueChangeOperation(operation); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.getOTOperation() + ); + } + }; + + var init = function () { + if (!useAttributeHtml) return; + + _$selectFile.find("#file_object").change(function () { + var files = $(this)[0].files, + file; + + if (!files || files.length === 0) return; + file = files[0]; + if (file.size > 1048576) { + alert("Chosen file is too large. Maximum size: 1MB"); + } + }); + + _$selectFile.find("#file_submit").click(function () { + var fileReader, + files = _$selectFile.find("#file_object")[0].files, + file; + + if (!files || files.length === 0) return; + file = files[0]; + + fileReader = new FileReader(); + fileReader.onload = function (e) { + uploadFile(file.name, file.type, e.target.result); + }; + fileReader.readAsDataURL(file); + }); + + _$manageFile.find("#file_delete").click(function () { + //openapp.resource.del(_value); + propagateValueChange(CONFIG.OPERATION.TYPE.UPDATE, "", 0); + }); + + _$selectFile.show(); + _$manageFile.hide(); + }; + + /** + * Set value + * @param {string} value + */ + this.setValue = function (value) { + _value = value; + if (_value === "") { + _$node.text(""); + } else { + $.get(_value + "/:representation").done(function (data) { + _$node.text(data.name); + }); + } + }; + + /** + * Get value + * @returns {string} + */ + this.getValue = function () { + return _value; + }; + + /** + * Get jQuery object of DOM node representing the value + * @returns {jQuery} + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the edge + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractValue.prototype.toJSON.call(this); + json.value = _value; + return json; + }; + + /** + * Set value by its JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + this.setValue(json.value); + }; + + /** + * Register inter widget communication callbacks + */ + this.registerCallbacks = function () { + //_iwcw.registerOnRemoteDataReceivedCallback(remoteValueChangeCallback); + _iwcw.registerOnDataReceivedCallback(localValueChangeCallback); + //_iwcw.registerOnHistoryChangedCallback(historyValueChangeCallback); + }; + + /** + * Unregister inter widget communication callbacks + */ + this.unregisterCallbacks = function () { + //_iwcw.unregisterOnRemoteDataReceivedCallback(remoteValueChangeCallback); + _iwcw.unregisterOnDataReceivedCallback(localValueChangeCallback); + //_iwcw.unregisterOnHistoryChangedCallback(historyValueChangeCallback); + }; + + if (_iwcw) { + that.registerCallbacks(); + } + + init(); +} + +const fileAttributeHtml = "
          \n
          \n
          \n
          "; // replaced by importmap.plugin.js + +/** + * FileAttribute + * @class canvas_widget.FileAttribute + * @extends canvas_widget.AbstractAttribute + * @memberof canvas_widget + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to + */ +class FileAttribute extends AbstractAttribute { + constructor(id, name, subjectEntity, useAttributeHtml) { + useAttributeHtml = + typeof useAttributeHtml !== "undefined" ? useAttributeHtml : false; + super(id, name, subjectEntity); + + /*** + * Value object of value + * @type {canvas_widget.FileValue} + * @private + */ + var _value = new FileValue( + id, + name, + this, + this.getRootSubjectEntity(), + useAttributeHtml + ); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(fileAttributeHtml)()); + + /** + * Set Value object of value + * @param {canvas_widget.FileValue} value + */ + this.setValue = function (value) { + _value = value; + _$node.val(value); + }; + + /** + * Get Value object of value + * @return {canvas_widget.FileValue} value + */ + this.getValue = function () { + return _value; + }; + + /** + * jQuery object of DOM node representing the attribute + * @type {jQuery} + * @private + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the attribute + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.value = _value.toJSON(); + return json; + }; + + /** + * Set attribute value by its JSON representation + * @param {Object} json + */ + this.setValueFromJSON = function (json) { + _value.setValueFromJSON(json.value); + }; + + _$node.find(".name").text(this.getName()); + _$node.find(".value").append(_value.get$node()); + } +} + +const multiLineValueHtml = "
          <%= value %>
          "; // replaced by importmap.plugin.js + +/** + * MultiLineValue + * @class canvas_widget.MultiLineValue + * @extends canvas_widget.AbstractValue + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier + * @param {string} name Name of attribute + * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {canvas_widget.AbstractNode|canvas_widget.AbstractEdge} rootSubjectEntity Topmost entity in the chain of entity the attribute is assigned to + */ +class MultiLineValue extends AbstractValue { + constructor(id, name, subjectEntity, rootSubjectEntity, y) { + super(id, name, subjectEntity, rootSubjectEntity); + var that = this; + + var _ytext = null; + y = y || window.y; + if (y) { + const yMap = rootSubjectEntity.getYMap(); + if (!yMap) { + rootSubjectEntity.registerYMap(); + } + + if (rootSubjectEntity.getYMap()?.has(id)) + _ytext = rootSubjectEntity.getYMap().get(id); + else { + _ytext = new Text(); + rootSubjectEntity.getYMap().set(id, _ytext); + } + } + + /** + * MultiLineValue + * @type {string} + * @private + */ + var _value = ""; + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(multiLineValueHtml)({ value: _value })); + + /** + * Inter widget communication wrapper + * @type {Object} + * @private + */ + y = y || window.y; + var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); + + /** + * Get chain of entities the attribute is assigned to + * @returns {string[]} + */ + var getEntityIdChain = function () { + var chain = [that.getEntityId()], + entity = that; + while (entity instanceof AbstractAttribute) { + chain.unshift(entity.getSubjectEntity().getEntityId()); + entity = entity.getSubjectEntity(); + } + return chain; + }; + + /** + * Propagate a Value Change Operation to the remote users and the local widgets + * @param {operations.ot.ValueChangeOperation} operation + */ + var propagateValueChangeOperation = function (operation) { + operation.setEntityIdChain(getEntityIdChain()); + operation.setRemote(false); + that.setValue(operation.getValue()); + operation.setRemote(true); + const activityMap = y.getMap("activity"); + + activityMap.set( + ActivityOperation.TYPE, + new ActivityOperation( + "ValueChangeActivity", + that.getEntityId(), + _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], + ValueChangeOperation.getOperationDescription( + that.getSubjectEntity().getName(), + that.getRootSubjectEntity().getType(), + that.getRootSubjectEntity().getLabel().getValue().getValue() + ), + { + value: _value, + subjectEntityName: that.getSubjectEntity().getName(), + rootSubjectEntityType: that.getRootSubjectEntity().getType(), + rootSubjectEntityId: that.getRootSubjectEntity().getEntityId(), + } + ) + .toNonOTOperation() + .toJSON() + ); + + /*if(that.getRootSubjectEntity().getYMap()){ + that.getRootSubjectEntity().getYMap().set(that.getEntityId(),operation.toJSON()); + }*/ + }; + + /** + * Callback for a local Value Change Operation + * @param {operations.ot.ValueChangeOperation} operation + */ + var localValueChangeCallback = function (operation) { + if ( + operation instanceof ValueChangeOperation && + operation.getEntityId() === that.getEntityId() + ) { + propagateValueChangeOperation(operation); + } + }; + + /** + * Set value + * @param {string} value + */ + this.setValue = function (value) { + _value = value; + _$node.text(value); + }; + + /** + * Get value + * @returns {string} + */ + this.getValue = function () { + return _value; + }; + + /** + * Get jQuery object of DOM node representing the value + * @returns {jQuery} + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the edge + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractValue.prototype.toJSON.call(this); + json.value = _value; + return json; + }; + + /** + * Set value by its JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + this.setValue(json.value); + }; + + /** + * Register inter widget communication callbacks + */ + this.registerCallbacks = function () { + _iwcw.registerOnDataReceivedCallback(localValueChangeCallback); + //_iwcw.registerOnHistoryChangedCallback(historyValueChangeCallback); + }; + + /** + * Unregister inter widget communication callbacks + */ + this.unregisterCallbacks = function () { + _iwcw.unregisterOnDataReceivedCallback(localValueChangeCallback); + //_iwcw.unregisterOnHistoryChangedCallback(historyValueChangeCallback); + }; + + this.registerYType = function () { + if (!_ytext) throw new Error("_ytext is undefined"); + // _ytext.bind(_$node[0]); + + if (that.getValue() !== _ytext.toString()) { + if (_ytext.toString().length > 0) + _ytext.delete(0, _ytext.toString().length - 1); + _ytext.insert(0, that.getValue()); + } + + _ytext.observe(function (event) { + _value = _ytext.toString(); + + //TODO i can not find out who triggered the delete :-(. Therefore do this only for non delete event types + if (event.type !== "delete") { + y.getMap("users"); + var jabberId = "User"; + const activityMap = y.getMap("activity"); + + activityMap.set( + ActivityOperation.TYPE, + new ActivityOperation( + "ValueChangeActivity", + that.getEntityId(), + jabberId, + ValueChangeOperation.getOperationDescription( + that.getSubjectEntity().getName(), + that.getRootSubjectEntity().getType(), + that.getRootSubjectEntity().getLabel().getValue().getValue() + ), + { + value: "", + subjectEntityName: that.getSubjectEntity().getName(), + rootSubjectEntityType: that.getRootSubjectEntity().getType(), + rootSubjectEntityId: that.getRootSubjectEntity().getEntityId(), + } + ).toJSON() + ); + } + }); + }; + + if (_iwcw) { + that.registerCallbacks(); + } + } +} + +const singleMultiLineValueAttributeHtml = "
          \n
          \n
          \n
          "; // replaced by importmap.plugin.js + +/** + * SingleMultiLineValueAttribute + * @class canvas_widget.SingleMultiLineValueAttribute + * @extends canvas_widget.AbstractAttribute + * @memberof canvas_widget + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to + */ +class SingleMultiLineValueAttribute extends AbstractAttribute { + constructor(id, name, subjectEntity, y) { + super(id, name, subjectEntity); + + /*** + * Value object of value + * @type {canvas_widget.MultiLineValue} + * @private + */ + var _value = new MultiLineValue( + id, + name, + this, + this.getRootSubjectEntity(), + y + ); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(singleMultiLineValueAttributeHtml)()); + + /** + * Set Value object of value + * @param {canvas_widget.MultiLineValue} value + */ + this.setValue = function (value) { + _value = value; + }; + + /** + * Get Value object of value + * @returns {canvas_widget.MultiLineValue} + */ + this.getValue = function () { + return _value; + }; + + /** + * jQuery object of DOM node representing the attribute + * @type {jQuery} + * @private + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the attribute + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.value = _value.toJSON(); + return json; + }; + + /** + * Set attribute value by its JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + _value.setValueFromJSON(json.value); + }; + + _$node.find(".name").text(this.getName()); + _$node.find(".value").append(_value.get$node()); + } +} + +function makeViewEdge( + type, + arrowType, + shapeType, + color, + dashstyle, + overlay, + overlayPosition, + overlayRotate, + attributes, + edgeType, + conditions, + conj +) { + function ViewEdge(id, source, target) { + var viewEdge = new edgeType(id, source, target); + viewEdge.restyle( + arrowType, + color, + shapeType, + dashstyle, + overlay, + overlayPosition, + overlayRotate, + attributes + ); + viewEdge.setCurrentViewType(type); + return viewEdge; + } + + ViewEdge.getConditions = function () { + return conditions; + }; + + ViewEdge.getConditionConj = function () { + return conj; + }; + + ViewEdge.getArrowType = function () { + return arrowType; + }; + ViewEdge.getShapeType = function () { + return shapeType; + }; + ViewEdge.getColor = function () { + return color; + }; + ViewEdge.getOverlay = function () { + return overlay; + }; + ViewEdge.getOverlayPosition = function () { + return overlayPosition; + }; + ViewEdge.getOverlayRotate = function () { + return overlayRotate; + }; + ViewEdge.getAttributes = function () { + return attributes; + }; + ViewEdge.getTargetEdgeType = function () { + return edgeType; + }; + ViewEdge.getType = function () { + return type; + }; + ViewEdge.getArrowOverlays = function () { + var overlays = []; + if (Arrows().hasOwnProperty(arrowType)) { + overlays.push(Arrows(color)[arrowType]); + } + return overlays; + }; + ViewEdge.getShape = function () { + return this.getTargetEdgeType().getShape(); + }; + + return ViewEdge; +} + +function makeViewNode(type, $shape, anchors, attributes, nodeType, conditions, conj) { + + ViewNode.prototype.constructor = ViewNode; + function ViewNode(id, left, top, width, height, zIndex) { + var viewNode = new nodeType(id, left, top, width, height, zIndex); + + viewNode.set$shape($shape); + viewNode.setAnchorOptions(anchors); + viewNode.setCurrentViewType(type); + + return viewNode; + + } + + ViewNode.getConditions = function(){ + return conditions; + }; + + ViewNode.getConditionConj = function(){ + return conj; + }; + + ViewNode.get$shape = function(){ + return $shape; + }; + + ViewNode.getAnchors = function(){ + return anchors; + }; + + ViewNode.getTargetNodeType = function(){ + return nodeType; + }; + return ViewNode; + } + +var LogicalConjunctions = { + "AND" : "&&", + "OR" : "||" + }; + +var LogicalOperator = { + "greater" : ">", + "smaller" : "<", + "equal" : "==", + "greater_eq" : ">=", + "smaller_eq" : "<=", + "nequal" : "!=" + }; + +function ViewTypesUtil() {} + +ViewTypesUtil.GetAllNodesOfBaseModelAsSelectionList = function (nodes) { + var selectionList = {}; + for (var key in nodes) { + if (nodes.hasOwnProperty(key)) { + selectionList[key] = nodes[key].getLabel().getValue().getValue(); + } + } + return selectionList; +}; +ViewTypesUtil.GetAllNodesOfBaseModelAsSelectionList2 = function (nodes, types) { + var selectionList = {}; + selectionList["empty"] = ""; + for (var key in nodes) { + if (nodes.hasOwnProperty(key)) { + if (lodash.indexOf(types, nodes[key].type) != -1) + selectionList[key] = nodes[key].label.value.value; + } + } + return selectionList; +}; + +ViewTypesUtil.createReferenceToOrigin = function (viewtype) { + const dataMap = y.getMap("data"); + var vls = dataMap.get("metamodelpreview"); + var originEntity; + if (vls) { + var targetAttr = viewtype.getAttribute(viewtype.getEntityId() + "[target]"); + var originId = targetAttr.getValue().getValue(); + if (viewtype.getType() === "ViewObject") { + if (vls.nodes.hasOwnProperty(originId)) { + originEntity = vls.nodes[originId]; + //By default the label for the ViewObject is the same as for the Origin + viewtype.getLabel().getValue().setValue(originEntity.label); + } + } else { + if (vls.edges.hasOwnProperty(originId)) { + originEntity = vls.edges[originId]; + //By default the label for the ViewObject is the same as for the Origin + viewtype.getLabel().getValue().setValue(originEntity.label); + } + } + //Initialize the Renaming list Attribute + var originAttrs = originEntity.attributes; + var renamingList = viewtype.getAttribute("[attributes]"); + var optionMap = {}; + for (var attrKey in originAttrs) { + if (originAttrs.hasOwnProperty(attrKey)) { + var attr = originAttrs[attrKey]; + var id = Util.generateRandomId(); + var operation = new AttributeAddOperation( + id, + renamingList.getEntityId(), + viewtype.getEntityId, + "RenamingAttribute" + ); + var renamingAttr = + renamingList.propagateAttributeAddOperation(operation); + renamingAttr.getKey().setValue(attr.key); + renamingAttr.getRef().setValue(attr.key); + optionMap[id] = attr.key; + } + } + //Initialize the Condition list attribute + viewtype.getYMap().set("updateConditionOption", optionMap); + + //targetAttr.get$node().hide(); + renamingList.get$node().show(); + viewtype + .getAttribute(viewtype.getEntityId() + "[conjunction]") + .get$node() + .show(); + viewtype.getAttribute("[condition]").get$node().show(); + } +}; + +const keySelectionValueSelectionValueListAttributeHtml = "
          \n
          \n
            \n
            "; // replaced by importmap.plugin.js + +const singleQuizAttributeHtml = "
            \n
            \n
            \n \n \n \n \n \n \n \n \n \n \n \n
            Assessment Name :
            NrQuestionCorrect IntentOptional Hint
            \n \n +\n \n \n -\n \n \n Submit\n \n \n Display\n \n
            \n"; // replaced by importmap.plugin.js + +const singleValueListAttributeHtml = "
            \n
            \n
              \n
              "; // replaced by importmap.plugin.js + +const canvasSingleValueAttributeHtml = "
              \n
              \n
              \n
              "; // replaced by importmap.plugin.js + +const listHtml = "
              \n
              \n
                \n
                "; // replaced by importmap.plugin.js + +const renamingAttrHTML = "
              • \n
                \n
                \n
                \n
              • "; // replaced by importmap.plugin.js + +const singleSelectionAttributeHtml = "
                \n
                \n
                \n
                "; // replaced by importmap.plugin.js + +const singleColorValueAttributeHtml = "
                \n
                \n
                \n
                "; // replaced by importmap.plugin.js + +const keySelectionValueSelectionValueAttributeHtml = "
              • \">\n
                \n
                \n
              • "; // replaced by importmap.plugin.js + +const keySelectionValueListAttributeHtml = "
                \n
                \n
                  \n
                  "; // replaced by importmap.plugin.js + +const keySelectionValueAttributeHtml = "
                • \">\n
                  \n
                  \n
                • "; // replaced by importmap.plugin.js +const integerAttributeHtml = "
                  \n
                  \n
                  \n
                  "; // replaced by importmap.plugin.js + +let integerValueHtml = "
                  <%= value %>
                  "; // replaced by importmap.plugin.js +const attributeIntegerValueHtml = "\"\n value=\"0\"\n/>\n"; // replaced by importmap.plugin.js + +const valueHtml = "\" class=\"fw-bold\"> \n"; // replaced by importmap.plugin.js + +let selectionValueHtml = "
                  <%= options[_.keys(options)[0]] %>
                  "; // replaced by importmap.plugin.js +const attributeSelectionValueHtml = "\n"; // replaced by importmap.plugin.js + +const viewrelationshipNodeHtml$1 = "
                  \n
                  <%= type %>
                  \n
                  <<ViewRelationship>>
                  \n
                  \n
                  "; // replaced by importmap.plugin.js + +const viewobjectNodeHtml = "
                  \n
                  <%= type %>
                  \n
                  <<ViewObject>>
                  \n
                  \n
                  "; // replaced by importmap.plugin.js + +const nodeShapeNodeHtml = "
                  \n
                  <%= type %>
                  \n
                  <<NodeShape>>
                  \n
                  \n
                  "; // replaced by importmap.plugin.js + +const modelAttributesNodeHtml = "
                  \n
                  \n
                  \n
                  "; // replaced by importmap.plugin.js + +const relationshipGroupNodeHtml = "
                  \n
                  <%= type %>
                  \n
                  <<Relation>>
                  \n
                  \n
                  "; // replaced by importmap.plugin.js + +const enumNodeHtml = "
                  \n
                  <%= type %>
                  \n
                  <<Enumeration>>
                  \n
                  \n
                  "; // replaced by importmap.plugin.js + +const abstractEdgeHtml = "
                  \n
                  <%= type %>
                  \n
                  \n
                  "; // replaced by importmap.plugin.js + +const edgeShapeNodeHtml = "
                  \n
                  <%= type %>
                  \n
                  <<EdgeShape>>
                  \n
                  \n
                  "; // replaced by importmap.plugin.js + +const abstractNodeHtml$1 = "
                  \" class=\"node\">\n
                  "; // replaced by importmap.plugin.js +const awarenessTraceHtml = "
                  \" class=\"trace_awareness\">\n\n \n\n
                  "; // replaced by importmap.plugin.js + +const abstractClassNodeHtml = "
                  \n
                  <%= type %>
                  \n
                  <<abstract>>
                  \n
                  \n
                  \n"; // replaced by importmap.plugin.js + +const relationshipNodeHtml = "
                  \n
                  <%= type %>
                  \n
                  <<Relationship>>
                  \n
                  \n
                  "; // replaced by importmap.plugin.js +const actionNodeHtml = "
                  \n
                  <%= \"<\\%= type %\\>\" %>
                  \n \n \n \n
                  \n \t\n\t\t \n\t\t \n\t\t \t\t\n\t\t \n\t\t
                  fa-2x\"><%= label %>
                  \n
                  \n
                  "; // replaced by importmap.plugin.js +const circleNodeHtml = "
                  \n
                  <%= type %>
                  \n \n \"\n stroke=\"lightgray\"\n stroke-width=\"2\"\n />\n \n
                  \n
                  \n
                  \n\n"; // replaced by importmap.plugin.js +const diamondNodeHtml = "
                  \n
                  <%= type %>
                  \n \n \"\n stroke=\"lightgray\"\n stroke-width=\"2\"\n transform=\"rotate(-45 50 50)\"\n />\n \n
                  \n
                  \n
                  \n\n"; // replaced by importmap.plugin.js +const objectNodeHtml = "
                  \n
                  <%= type %>
                  \n
                  <<Object>>
                  \n
                  \n
                  "; // replaced by importmap.plugin.js +const rectangleNodeHtml = "
                  \n
                  <%= type %>
                  \n \n \"\n stroke=\"lightgray\"\n stroke-width=\"2\"\n />\n \n
                  \n
                  \n
                  \n\n"; // replaced by importmap.plugin.js +const roundedRectangleNodeHtml = "
                  \n
                  <%= type %>
                  \n \n \"\n stroke=\"lightgray\"\n stroke-width=\"2\"\n />\n \n
                  \n
                  \n
                  \n\n"; // replaced by importmap.plugin.js +const startActivityNodeHtml = "
                  \n
                  <%= type %>
                  \n \n \n \n \n \n \n \n \n \n
                  \n \t\n\t\t \n\t\t \n\t\t \t\t\n\t\t \n\t\t
                  \n
                  \n
                  "; // replaced by importmap.plugin.js +const triangleNodeHtml = "
                  \n
                  <%= type %>
                  \n \n \"\n stroke=\"lightgray\"\n stroke-width=\"2\"\n />\n \n
                  \n
                  \n
                  \n\n"; // replaced by importmap.plugin.js +const activityFinalNodeHtml = "
                  \n
                  <%= type %>
                  \n \n \n \n \n
                  \n
                  \n
                  "; // replaced by importmap.plugin.js +const callActivityNodeHtml = "
                  \n
                  <%= type %>
                  \n \n \n \n
                  \n \n \n \n \n \n
                  \n
                  \n
                  "; // replaced by importmap.plugin.js +const entityNodeHtml = "
                  \n
                  <%= \"<\\%= type %\\>\" %>
                  \n \n \n \n \n \n \n \n \n \n
                  \n \t\n\t\t \n\t\t \n\t\t \t\t\n\t\t \n\t\t
                  fa-2x\"><%= label %>
                  \n
                  \n
                  "; // replaced by importmap.plugin.js +const setPropertyNodeHtml = "
                  \n
                  <%= \"<\\%= type %\\>\" %>
                  \n \n \n \n
                  \n \t\n\t\t \n\t\t \n\t\t \t\t\n\t\t \n\t\t
                  \n
                  \n
                  "; // replaced by importmap.plugin.js + +var shapes = { + straight: { + type: StraightConnector.type, + options: { gap: 0 }, + }, + curved: { + type: BezierConnector.type, + options: { gap: 0 }, + }, + segmented: { + type: FlowchartConnector.type, + options: { gap: 0 }, + }, +}; + +function HistoryManager() { + var bufferSize = 20; + + var _canvas = null; + + var latestOp = null; + var undo = []; + var redo = []; + + var $undo = $("#undo"); + + var $redo = $("#redo"); + + var propagateHistoryOperationFromJson = function (json) { + var EntityManager = EntityManager; + var operation = null, + data = null, + entity; + switch (json.TYPE) { + case NodeDeleteOperation.TYPE: { + entity = EntityManager.findNode(json.id); + if (entity) { + entity.triggerDeletion(true); + operation = new NodeDeleteOperation( + json.id, + json.type, + json.left, + json.top, + json.width, + json.height, + json.zIndex, + json.containment, + json.json + ); + } + break; + } + case NodeAddOperation.TYPE: { + _canvas.createNode( + json.type, + json.left, + json.top, + json.width, + json.height, + json.zIndex, + json.containment, + json.json, + json.id, + true + ); + operation = new NodeAddOperation( + json.id, + json.type, + json.left, + json.top, + json.width, + json.height, + json.zIndex, + json.containment, + json.json + ); + break; + } + case EdgeAddOperation.TYPE: { + _canvas.createEdge( + json.type, + json.source, + json.target, + json.json, + json.id, + true + ); + operation = new EdgeAddOperation( + json.id, + json.type, + json.source, + json.target, + json.json + ); + break; + } + case EdgeDeleteOperation.TYPE: { + entity = EntityManager.findEdge(json.id); + if (entity) { + entity.triggerDeletion(true); + operation = new EdgeDeleteOperation( + json.id, + json.type, + json.source, + json.target, + json.json + ); + } + break; + } + case NodeMoveOperation.TYPE: { + entity = EntityManager.findNode(json.id); + if (entity) { + const nodesMap = y.getMap("nodes"); + operation = new NodeMoveOperation( + json.id, + json.offsetX, + json.offsetY + ); + var ymap = nodesMap.get(json.id); + data = operation.toJSON(); + data.historyFlag = true; + ymap.set(NodeMoveOperation.TYPE, data); + } + break; + } + case NodeMoveZOperation.TYPE: { + entity = EntityManager.findNode(json.id); + if (entity) { + operation = new NodeMoveZOperation(json.id, json.offsetZ); + const nodesMap = y.getMap("nodes"); + var ymap = nodesMap.get(json.id); + data = operation.toJSON(); + data.historyFlag = true; + ymap.set(NodeMoveZOperation.TYPE, data); + } + break; + } + case NodeResizeOperation.TYPE: { + entity = EntityManager.findNode(json.id); + if (entity) { + operation = new NodeResizeOperation( + json.id, + json.offsetX, + json.offsetY + ); + const nodesMap = y.getMap("nodes"); + var ymap = nodesMap.get(json.id); + data = operation.toJSON(); + data.historyFlag = true; + ymap.set(NodeResizeOperation.TYPE, data); + } + break; + } + } + return operation; + }; + + return { + init: function (canvas) { + if (!canvas) throw new Error("Canvas is null"); + _canvas = canvas; + }, + add: function (operation) { + if (operation.hasOwnProperty("inverse")) { + var inverseOp = operation.inverse(); + var json = inverseOp.toJSON(); + json.TYPE = inverseOp.constructor.name; + undo.push(json); + redo = []; + $undo.prop("disabled", false); + $redo.prop("disabled", true); + } + if (undo.length > bufferSize) { + undo.shift(); + } + }, + undo: function () { + if (undo.length > 0) { + var jsonOp = undo.pop(); + if (undo.length === 0) { + $undo.prop("disabled", true); + } + var operation = propagateHistoryOperationFromJson(jsonOp); + if (!operation) { + this.undo(); + return; + } else latestOp = operation; + + var inverseOp = operation.inverse(); + var json = inverseOp.toJSON(); + json.TYPE = inverseOp.constructor.name; + + if (redo.length === 0) $redo.prop("disabled", false); + redo.push(json); + } else { + $undo.prop("disabled", true); + } + }, + redo: function () { + if (redo.length > 0) { + var jsonOp = redo.pop(); + if (redo.length === 0) { + $redo.prop("disabled", true); + } + var operation = propagateHistoryOperationFromJson(jsonOp); + if (!operation) { + this.redo(); + return; + } else latestOp = operation; + var inverseOp = operation.inverse(); + var json = inverseOp.toJSON(); + json.TYPE = inverseOp.constructor.name; + + if (undo.length === 0) $undo.prop("disabled", false); + undo.push(json); + } else { + $redo.prop("disabled", true); + } + }, + clean: function (entityId) { + var entityIdFilter = function (value) { + if (value.id === entityId) return false; + else return true; + }; + undo = undo.filter(entityIdFilter); + redo = redo.filter(entityIdFilter); + if (undo.length === 0) { + $undo.prop("disabled", true); + } + if (redo.length === 0) { + $redo.prop("disabled", true); + } + }, + getLatestOperation: function () { + return latestOp; + }, + getUndoList: function () { + return undo; + }, + getRedoList: function () { + return redo; + }, + }; +} + +const HistoryManagerInstance = new HistoryManager(); +Object.freeze(HistoryManagerInstance); + +const openapp = new OpenAppProvider().openapp; + +/** + * Predefined node shapes, first is default + * @type {{circle: *, diamond: *, rectangle: *, triangle: *}} + */ +var nodeShapeTypes = { + circle: circleNodeHtml, + diamond: diamondNodeHtml, + rectangle: rectangleNodeHtml, + rounded_rectangle: roundedRectangleNodeHtml, + triangle: triangleNodeHtml, +}; + +/** + * jQuery object to test for valid color + * @type {$} + */ +var $colorTestElement = $("
                  "); + +/** Determines the current layer of syncmeta. + * can be CONFIG.LAYER.MODEL or CONFIG.LAYER.META*/ +var _layer = null; + +/** + * Different node types + * @type {object} + */ +var nodeTypes = {}; + +var _initNodeTypes = function (vls) { + var _nodeTypes = {}; + + var nodes = vls.nodes, + node, + shape, + anchors; + + // Start creating nodes based on metamodel + for (var nodeId in nodes) { + if (nodes.hasOwnProperty(nodeId)) { + node = nodes[nodeId]; + if (node.shape.customShape) { + shape = node.shape.customShape; + } else { + shape = nodeShapeTypes.hasOwnProperty(node.shape.shape) + ? nodeShapeTypes[node.shape.shape] + : lodash.keys(nodeShapeTypes)[0]; + } + if (node.shape.customAnchors) { + try { + if (node.shape.customAnchors) { + anchors = JSON.parse(node.shape.customAnchors); + } + if (!node.shape.customAnchors instanceof Array) { + anchors = { + type: "Perimeter", + options: { + shape: "Rectangle", + anchorCount: 10, + }, + }; + } + } catch (e) { + anchors = { + type: "Perimeter", + options: { + shape: "Rectangle", + anchorCount: 10, + }, + }; + } + } else { + switch (node.shape.shape) { + case "circle": + anchors = { + type: "Perimeter", + options: { + shape: "Circle", + anchorCount: 10, + }, + }; + break; + case "diamond": + anchors = { + type: "Perimeter", + options: { + shape: "Diamond", + anchorCount: 10, + }, + }; + break; + case "rounded_rectangle": + anchors = { + type: "Perimeter", + options: { + shape: "Rectangle", + anchorCount: 10, + }, + }; + break; + case "triangle": + anchors = { + type: "Perimeter", + options: { + shape: "Triangle", + anchorCount: 10, + }, + }; + break; + default: + case "rectangle": + anchors = { + type: "Perimeter", + options: { + shape: "Rectangle", + anchorCount: 10, + }, + }; + break; + } + } + var color = node.shape.color + ? $colorTestElement + .css("color", "#FFFFFF") + .css("color", node.shape.color) + .css("color") + : "#FFFFFF"; + var $shape = $(lodash.template(shape)({ color: color, type: node.label })); + + if ( + node.hasOwnProperty("targetName") && + !$.isEmptyObject(nodeTypes) && + nodeTypes.hasOwnProperty(node.targetName) + ) { + _nodeTypes[node.label] = makeViewNode( + node.label, + $shape, + anchors, + node.attributes, + nodeTypes[node.targetName], + node.conditions, + node.conjunction + ); + nodeTypes[node.targetName].VIEWTYPE = node.label; + } else { + _nodeTypes[node.label] = makeNode( + node.label, + $shape, + anchors, + node.attributes + ); + } + _nodeTypes[node.label].TYPE = node.label; + _nodeTypes[node.label].DEFAULT_WIDTH = node.shape.defaultWidth; + _nodeTypes[node.label].DEFAULT_HEIGHT = node.shape.defaultHeight; + _nodeTypes[node.label].CONTAINMENT = node.shape.containment; + _nodeTypes[node.label].SHAPE = $shape; + /* + nodeTypes[node.label] = Node(node.label, $shape, anchors, node.attributes, node.jsplumb); + nodeTypes[node.label].TYPE = node.label; + nodeTypes[node.label].SHAPE = $shape; + nodeTypes[node.label].DEFAULT_WIDTH = node.shape.defaultWidth; + nodeTypes[node.label].DEFAULT_HEIGHT = node.shape.defaultHeight;*/ + } + } + return _nodeTypes; +}; + +var _initEdgeTypes = function (vls) { + var _edgeTypes = {}; + var _relations = {}; + var edges = vls.edges, + edge; + for (var edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + + if ( + edge.hasOwnProperty("targetName") && + !$.isEmptyObject(edgeTypes) && + edgeTypes.hasOwnProperty(edge.targetName) + ) { + _edgeTypes[edge.label] = makeViewEdge( + edge.label, + edge.shape.arrow, + edge.shape.shape, + edge.shape.color, + edge.shape.dashstyle, + edge.shape.overlay, + edge.shape.overlayPosition, + edge.shape.overlayRotate, + edge.attributes, + edgeTypes[edge.targetName], + edge.conditions, + edge.conjunction + ); + edgeTypes[edge.targetName].VIEWTYPE = edge.label; + } else { + _edgeTypes[edge.label] = makeEdge( + edge.label, + edge.shape.arrow, + edge.shape.shape, + edge.shape.color, + edge.shape.dashstyle, + edge.shape.overlay, + edge.shape.overlayPosition, + edge.shape.overlayRotate, + edge.attributes + ); + } + + _edgeTypes[edge.label].TYPE = edge.label; + _relations[edge.label] = edge.relations; + } + } + return { + edgeTypes: _edgeTypes, + relations: _relations, + }; +}; + +/** + * contains all view node types of the current view + * @type {{}} + */ +var viewNodeTypes = {}; + +/** + * contains all view edge types of the current view + * @type {{}} + */ +var viewEdgeTypes = {}; + +/** + * Different edge types + * @type {object} + */ +var edgeTypes = {}; +var relations = {}; +/* + if (metamodel && metamodel.hasOwnProperty("edges")) { + var res = _initEdgeTypes(metamodel); + edgeTypes = res.edgeTypes; + relations = res.relations; + } else { + edgeTypes[GeneralisationEdge.TYPE] = GeneralisationEdge; + edgeTypes[BiDirAssociationEdge.TYPE] = BiDirAssociationEdge; + edgeTypes[UniDirAssociationEdge.TYPE] = UniDirAssociationEdge; + + relations[BiDirAssociationEdge.TYPE] = BiDirAssociationEdge.RELATIONS; + relations[UniDirAssociationEdge.TYPE] = UniDirAssociationEdge.RELATIONS; + relations[GeneralisationEdge.TYPE] = GeneralisationEdge.RELATIONS; + }*/ + +/** + * AbstractEdge + * @class canvas_widget.AbstractEdge + * @extends canvas_widget.AbstractEntity + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of edge + * @param {string} type Type of edge + * @param {canvas_widget.AbstractNode} source Source node + * @param {canvas_widget.AbstractNode} target Target node + * @param {boolean} [overlayRotate] Flag if edge overlay should be flipped automatically to avoid being upside down + */ +class AbstractEdge extends AbstractEntity { + constructor(id, type, source, target, overlayRotate, y) { + super(id); + y = y || window.y; + var that = this; + + /** + * Inter widget communication wrapper + * @type {Object} + */ + var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); // y comes from the window object but should in the future be passed through the constructor since we should avoid binding to window + + var _ymap = null; + if (!y) { + throw new Error("y is not defined"); + } + + const edgeMap = y.getMap("edges"); + if (edgeMap.has(id)) { + _ymap = edgeMap.get(id); + } else if (id && type && source && target) { + _ymap = new Map$2(); + edgeMap.set(id, new Map$2()); + y.transact(() => { + _ymap.set("id", id); + _ymap.set("type", type); + _ymap.set("source", source.getEntityId()); + _ymap.set("target", target.getEntityId()); + _ymap.set("jabberId", _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]); + }); + } + + this.getYMap = function () { + return _ymap; + }; + + /** + * Type of edge + * @type {string} + * @private + */ + var _type = type; + + /** + * Label of edge + * @type {canvas_widget.SingleValueAttribute} + * @private + */ + var _label = new SingleValueAttribute(id + "[label]", "Label", this, y); + + /** + * Appearance information of edge + * @type {{source: (canvas_widget.AbstractNode), target: (canvas_widget.AbstractNode)}} + * @private + */ + var _appearance = { + source: source, + target: target, + }; + + /** + * Flag if edge overlay should be flipped automatically to avoid being upside down + * @type {boolean} + * @private + */ + var _overlayRotate = overlayRotate !== false; + + /** + * jQuery object of DOM node representing the edge's overlay + * @type {jQuery} + * @private + */ + var _$overlay = $(lodash.template(abstractEdgeHtml)({ type: type })) + .find(".edge_label") + .append(_label.get$node()) + .parent(); + + /** + * Canvas the edge is drawn on + * @type {canvas_widget.AbstractCanvas} + * @private + */ + var _canvas = null; + + /** + * jsPlumb object representing the edge + * @type {Object} + * @private + */ + var _jsPlumbConnection = null; + + /** + * Attributes of edge + * @type {Object} + * @private + */ + var _attributes = {}; + + /** + * Stores current highlighting color + * @type {string} + * @private + */ + var _highlightColor = null; + + /** + * Callback to generate list of context menu items + * @type {function} + */ + var _contextMenuItemCallback = function () { + return {}; + }; + + //noinspection JSUnusedLocalSymbols + /** + * Apply an Edge Delete Operation + * @param {operations.ot.EdgeDeleteOperation} operation + */ + var processEdgeDeleteOperation = function () { + that.remove(); + }; + + /** + * Propagate an Edge Delete Operation to the remote users and the local widgets + * @param {operations.ot.EdgeDeleteOperation} operation + */ + var propagateEdgeDeleteOperation = function (operation) { + processEdgeDeleteOperation(); + + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.ATTRIBUTE, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.getOTOperation() + ); + const activityMap = y.getMap("activity"); + activityMap.set( + ActivityOperation.TYPE, + new ActivityOperation( + "EdgeDeleteActivity", + operation.getEntityId(), + _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], + EdgeDeleteOperation.getOperationDescription( + that.getType(), + that.getLabel().getValue().getValue() + ), + {} + ).toJSON() + ); + }; + + /** + * Callback for a remote Edge Delete Operation + * @param {operations.ot.EdgeDeleteOperation} operation + */ + this.remoteEdgeDeleteCallback = function (operation) { + if ( + operation instanceof EdgeDeleteOperation && + operation.getEntityId() == that.getEntityId() + ) { + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.ATTRIBUTE, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.getOTOperation() + ); + processEdgeDeleteOperation(); + } + }; + + /** + * Get jQuery object of all DOM nodes belonging to the edge + */ + var getAllAssociatedDOMNodes = function () { + var overlays, + i, + numOfOverlays, + $e = $("." + id); + + if (_jsPlumbConnection) { + overlays = _jsPlumbConnection.getOverlays(); + for (i = 0, numOfOverlays = overlays.length; i < numOfOverlays; i++) { + if (overlays[i] instanceof jsPlumb.Overlays.Custom) { + $e = $e.add(overlays[i].getElement()); + } + } + } else throw new Error("jsPlumbConnection is null"); + return $e; + }; + + /** + * Default paint style of edge + */ + var _defaultPaintStyle; + + /** + * Set the default paint style + * @param paintStyle + */ + this.setDefaultPaintStyle = function (paintStyle) { + _defaultPaintStyle = paintStyle; + }; + + /** + * Get the default paint style + * @returns {*} + */ + this.getDefaultPaintStyle = function () { + return _defaultPaintStyle; + }; + + /** + * Send NodeDeleteOperation for node + */ + this.triggerDeletion = function (historyFlag) { + _canvas.select(null); + var operation = new EdgeDeleteOperation( + id, + that.getType(), + that.getSource().getEntityId(), + that.getTarget().getEntityId() + ); + + if (_ymap) { + propagateEdgeDeleteOperation(operation); + const edgeMap = y.getMap("edges"); + edgeMap.delete(that.getEntityId()); + } else { + propagateEdgeDeleteOperation(operation); + } + if (!historyFlag) HistoryManagerInstance.add(operation); + }; + + //noinspection JSUnusedGlobalSymbols + /** + * Get callback to generate list of context menu items + * @returns {object} + */ + this.getContextMenuItemCallback = function () { + return _contextMenuItemCallback; + }; + + /** + * Set callback to generate list of context menu items + * @param {function} contextMenuItemCallback + */ + this.setContextMenuItemCallback = function (contextMenuItemCallback) { + _contextMenuItemCallback = contextMenuItemCallback; + }; + + /** + * Adds edge to canvas + * @param {canvas_widget.AbstractCanvas} canvas + */ + this.addToCanvas = function (canvas) { + if (!canvas) throw new Error("Canvas is null"); + _canvas = canvas; + }; + + /** + * Get associated canvas + * @returns {canvas_widget.AbstractCanvas} + */ + this.getCanvas = function () { + return _canvas; + }; + + /** + * Removes edge from canvas + */ + this.removeFromCanvas = function () { + _canvas = null; + $.contextMenu("destroy", "." + that.getEntityId()); + window.jsPlumbInstance.deleteConnection(_jsPlumbConnection, { + fireEvent: false, + }); + _jsPlumbConnection = null; + }; + + /** + * Add attribute to edge + * @param {canvas_widget.AbstractAttribute} attribute + */ + this.addAttribute = function (attribute) { + var id = attribute.getEntityId(); + if (!_attributes.hasOwnProperty(id)) { + _attributes[id] = attribute; + } + }; + + /** + * Set edge's attributes + * @param {Object} attributes + */ + this.setAttributes = function (attributes) { + _attributes = attributes; + }; + + /** + * Get edge's attributes + * @returns {Object} + */ + this.getAttributes = function () { + return _attributes; + }; + + /** + * Get attribute by id + * @param {String} id Attribute's entity id + * @returns {canvas_widget.AbstractAttribute} + */ + this.getAttribute = function (id) { + if (_attributes.hasOwnProperty(id)) { + return _attributes[id]; + } + return null; + }; + + /** + * Delete attribute by id + * @param {String} id Attribute's entity id + */ + this.deleteAttribute = function (id) { + if (!_attributes.hasOwnProperty(id)) { + delete _attributes[id]; + } + }; + + /** + * Set edge label + * @param {canvas_widget.SingleValueAttribute} label + */ + this.setLabel = function (label) { + _label = label; + }; + + /** + * Get edge label + * @returns {canvas_widget.SingleValueAttribute} + */ + this.getLabel = function () { + return _label; + }; + + /** + * Get edge type + * @returns {string} + */ + this.getType = function () { + return _type; + }; + + /** + * Get source node + * @returns {canvas_widget.AbstractNode} + */ + this.getSource = function () { + return _appearance.source; + }; + + /** + * Get target node + * @returns {canvas_widget.AbstractNode} + */ + this.getTarget = function () { + //noinspection JSAccessibilityCheck + return _appearance.target; + }; + + /** + * Get jQuery object of DOM node representing the edge's overlay + * @returns {jQuery} + */ + this.get$overlay = function () { + return _$overlay; + }; + + //noinspection JSUnusedGlobalSymbols + /** + * Set flag if edge overlay should be flipped automatically to avoid being upside down + * @param {boolean} rotateOverlay + */ + this.setRotateOverlay = function (rotateOverlay) { + _overlayRotate = rotateOverlay; + }; + + //noinspection JSUnusedGlobalSymbols + /** + * Get flag if edge overlay should be flipped automatically to avoid being upside down + * @return {boolean} rotateOverlay + */ + this.isRotateOverlay = function () { + return _overlayRotate; + }; + + /** + * Set jsPlumb object representing the edge + * @param {Object} jsPlumbConnection + */ + this.setJsPlumbConnection = function (jsPlumbConnection) { + _jsPlumbConnection = jsPlumbConnection; + _defaultPaintStyle = jsPlumbConnection.getPaintStyle(); + }; + + //noinspection JSUnusedGlobalSymbols + /** + * Get jsPlumb object representing the edge + * @return {Object} jsPlumbConnection + */ + this.getJsPlumbConnection = function () { + return _jsPlumbConnection; + }; + + /** + * Repaint edge overlays (adjust angle of fixed overlays) + */ + this.repaintOverlays = function () { + function makeRotateOverlayCallback(angle) { + return function rotateOverlay() { + var $this = $(this), + oldTransform = $this.css("transform", "").css("transform"); + + if (oldTransform === "none") oldTransform = ""; + + $this.css({ + transform: oldTransform + " rotate(" + angle + "rad)", + "-o-transform": oldTransform + " rotate(" + angle + "rad)", + "-ms-transform": oldTransform + " rotate(" + angle + "rad)", + "-moz-transform": oldTransform + " rotate(" + angle + "rad)", + "-webkit-transform": oldTransform + " rotate(" + angle + "rad)", + }); + }; + } + + var i, numOfOverlays, overlays, sourceEndpoint, targetEndpoint, angle; + + if (_jsPlumbConnection) { + sourceEndpoint = _jsPlumbConnection.endpoints[0].endpoint; + targetEndpoint = _jsPlumbConnection.endpoints[1].endpoint; + angle = Math.atan2( + sourceEndpoint.y - targetEndpoint.y, + sourceEndpoint.x - targetEndpoint.x + ); + if (!_overlayRotate || Math.abs(angle) > Math.PI / 2) { + angle += Math.PI; + } + overlays = _jsPlumbConnection.getOverlays(); + for (i = 0, numOfOverlays = overlays.length; i < numOfOverlays; i++) { + if (overlays[i] instanceof jsPlumb.Overlays.Custom) { + $(overlays[i].getElement()) + .find(".fixed") + .not(".segmented") + .each(makeRotateOverlayCallback(angle)); + //Always flip type overlay + $(overlays[i].getElement()) + .find(".fixed.type") + .not(".segmented") + .each( + makeRotateOverlayCallback( + Math.abs(angle - Math.PI) > Math.PI / 2 + ? angle + : angle + Math.PI + ) + ); + } + } + } else throw new Error("jsPlumbConnection is null"); + }; + + /** + * Sets position of edge on z-axis as max of the z-indices of source and target + */ + this.setZIndex = function () { + var $e = getAllAssociatedDOMNodes(), + zIndex = Math.max(source.getZIndex(), target.getZIndex()); + $e.css("zIndex", zIndex); + }; + + /** + * Connect source and target node and draw the edge on canvas + */ + this.connect = function () { + source.addOutgoingEdge(this); + target.addIngoingEdge(this); + //noinspection JSAccessibilityCheck + _jsPlumbConnection = window.jsPlumbInstance.connect({ + source: _appearance.source.get$node().get(0), + target: _appearance.target.get$node().get(0), + paintStyle: { stroke: "black", outlineWidth: 4 }, + endpoint: "Dot", + connector: { type: FlowchartConnector.type }, + anchors: [source.getAnchorOptions(), target.getAnchorOptions()], + overlays: [ + { + type: "Custom", + options: { + create: function () { + return _$overlay.get(0); + }, + location: 0.5, + id: "label", + }, + }, + ], + cssClass: id, + }); + this.repaintOverlays(); + lodash.each(EntityManagerInstance.getEdges(), function (e) { + e.setZIndex(); + }); + }; + + /** + * Lowlight the edge + */ + this.lowlight = function () { + $("." + id).addClass("lowlighted"); + }; + + /** + * Unlowlight the edge + */ + this.unlowlight = function () { + $("." + id).removeClass("lowlighted"); + }; + + /** + * Select the edge + */ + this.select = function () { + var paintStyle = lodash.clone(_defaultPaintStyle), + overlays, + i, + numOfOverlays; + + function makeBold() { + $(this).css("fontWeight", "bold"); + } + this.unhighlight(); + if (_jsPlumbConnection) { + paintStyle.lineWidth = 4; + _jsPlumbConnection.setPaintStyle(paintStyle); + overlays = _jsPlumbConnection.getOverlays(); + for (i = 0, numOfOverlays = overlays.length; i < numOfOverlays; i++) { + if (overlays[i] instanceof jsPlumb.Overlays.Custom) { + $(overlays[i].getElement()).find(".fixed").each(makeBold); + } + } + } else throw new Error("jsPlumbConnection is null"); + }; + + /** + * Unselect the edge + */ + this.unselect = function () { + var overlays, i, numOfOverlays; + + function unmakeBold() { + $(this).css("fontWeight", ""); + } + this.highlight(_highlightColor); + if (_jsPlumbConnection) { + _jsPlumbConnection.setPaintStyle(_defaultPaintStyle); + overlays = _jsPlumbConnection.getOverlays(); + for (i = 0, numOfOverlays = overlays.length; i < numOfOverlays; i++) { + if (overlays[i] instanceof jsPlumb.Overlays.Custom) { + $(overlays[i].getElement()).find(".fixed").each(unmakeBold); + } + } + } + }; + + /** + * Highlight the edge + * @param {String} color + */ + this.highlight = function (color) { + var paintStyle = lodash.clone(_defaultPaintStyle); + + if (color) { + paintStyle.strokeStyle = color; + paintStyle.lineWidth = 4; + if (_jsPlumbConnection) _jsPlumbConnection.setPaintStyle(paintStyle); + else throw new Error("jsPlumbConnection is null"); + } + }; + + /** + * Unhighlight the edge + */ + this.unhighlight = function () { + if (_jsPlumbConnection) { + _jsPlumbConnection.setPaintStyle(_defaultPaintStyle); + } else throw new Error("jsPlumbConnection is null"); + }; + + /** + * Remove the edge + */ + this.remove = function () { + source.deleteOutgoingEdge(this); + target.deleteIngoingEdge(this); + this.removeFromCanvas(); + //this.unregisterCallbacks(); + EntityManagerInstance.deleteEdge(this.getEntityId()); + if (_ymap) { + _ymap = null; + } + }; + + /** + * Get JSON representation of the edge + * @returns {Object} + * @private + */ + this._toJSON = function () { + var attr = {}; + lodash.forEach(this.getAttributes(), function (val, key) { + attr[key] = val.toJSON(); + }); + return { + label: _label.toJSON(), + source: source.getEntityId(), + target: target.getEntityId(), + attributes: attr, + type: _type, + }; + }; + + /** + * Bind events for move tool + */ + this.bindMoveToolEvents = function () { + if (_jsPlumbConnection) { + //Enable Edge Select + $("." + id).on("click", function () { + _canvas.select(that); + }); + + $(_jsPlumbConnection.getOverlay("label").canvas) + .find("input") + .prop("disabled", false) + .css("pointerEvents", ""); + + /*$(_jsPlumbConnection.getOverlay("label").canvas).find("input[type=text]").autoGrowInput({ + comfortZone: 10, + minWidth: 40, + maxWidth: 100 + }).trigger("blur");*/ + } else throw new Error("jsPlumbConnection is null"); + + if (id) { + // view_only is used by the CAE and allows to show a model in the Canvas which is not editable + // therefore, the context menu of every edge must be disabled + const widgetConfigMap = y.getMap("widgetConfig"); + var viewOnly = widgetConfigMap.get("view_only"); + if (viewOnly) return; + } + + //Define Edge Rightclick Menu + $.contextMenu({ + selector: "." + id, + zIndex: AbstractEntity.CONTEXT_MENU_Z_INDEX, + build: function () { + var menuItems = lodash.extend(_contextMenuItemCallback(), { + delete: { + name: "Delete", + callback: function (/*key, opt*/) { + that.triggerDeletion(); + }, + }, + }); + + return { + items: menuItems, + events: { + show: function (/*opt*/) { + _canvas.select(that); + }, + }, + }; + }, + }); + + //$("."+id).contextMenu(true); + }; + + /** + * Unbind events for move tool + */ + this.unbindMoveToolEvents = function () { + if (_jsPlumbConnection) { + //Disable Edge Select + _jsPlumbConnection.unbind("click"); + + $(_jsPlumbConnection.getOverlay("label").canvas) + .find("input") + .prop("disabled", true) + .css("pointerEvents", "none"); + } else throw new Error("jsPlumbConnection is null"); + + //$("."+id).contextMenu(false); + }; + + this._registerYMap = function () { + that.getLabel().getValue().registerYType(); + }; + } + /** + * Get JSON representation of the edge + * @returns {{label: Object, source: string, target: string, attributes: Object, type: string}} + */ + toJSON() { + return this._toJSON(); + } + /** + * Hide a jsPlumb connection + */ + hide() { + var connector = this.getJsPlumbConnection(); + connector.setVisible(false); + } + /** + * Show a jsPlumb connection + */ + show() { + var connector = this.getJsPlumbConnection(); + connector.setVisible(true); + } + registerYMap() { + this._registerYMap(); + } +} + +/** + * AbstractNode + * @class canvas_widget.AbstractNode + * @extends canvas_widget.AbstractEntity + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of node + * @param {string} type Type of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {boolean} containment containment + * @param {number} zIndex Position of node on z-axis + */ +class AbstractNode extends AbstractEntity { + nodeSelector; + _$node; + constructor( + id, + type, + left, + top, + width, + height, + zIndex, + containment, + json, + y + ) { + super(id); + var that = this; + y = y || window.y; + if (!y) { + throw new Error("y is undefined"); + } + + /** + * Inter widget communication wrapper + * @type {Object} + * @private + */ + var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); + /**y-map instances which belongs to the node + * @type {YMap} + * @private + * */ + var _ymap = null; + y = y || window.y; + if (!y) { + throw new Error("y is undefined"); + } + const nodesMap = y.getMap("nodes"); + + if (nodesMap.has(id)) { + _ymap = nodesMap.get(id); + } else { + window.y.transact(() => { + _ymap = new Map$2(); + nodesMap.set(id, _ymap); + _ymap.set("modifiedBy", window.y.clientID); + _ymap.set("left", left); + _ymap.set("top", top); + _ymap.set("width", width); + _ymap.set("height", height); + _ymap.set("zIndex", zIndex); + _ymap.set("containment", containment); + _ymap.set("type", type); + _ymap.set("id", id); + if (json) _ymap.set("json", json); + if (_iwcw.getUser().globalId !== -1) + _ymap.set("jabberId", _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]); + }); + } + + this.getYMap = function () { + return _ymap; + }; + + /** + * Type of node + * @type {string} + * @private + */ + var _type = type; + + /** + * Label of edge + * @type {canvas_widget.SingleValueAttribute} + * @private + */ + var _label = new SingleValueAttribute(id + "[label]", "Label", this, y); + + /** + * Appearance information of edge + * @type {{left: number, top: number, width: number, height: number}} + * @private + */ + var _appearance = { + left: left, + top: top, + width: width, + height: height, + containment: containment, + }; + + /** + * Position of node on z-axis + * @type {number} + * @private + */ + var _zIndex = zIndex; + + /** + * Type of node + * @containment {boolean} + * @private + */ + var _containment = containment; + + /** + * Canvas the node is drawn on + * @type {canvas_widget.AbstractCanvas} + * @private + */ + var _canvas = null; + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(abstractNodeHtml$1)({ id: id })); + this._$node = _$node; + const resizeHandle = $( + `
                  ` + ); + resizeHandle.css({ + position: "absolute", + bottom: "-15px", + right: "-15px", + cursor: "nwse-resize", + zIndex: 100000, + }); + + // append to node + _$node.append(resizeHandle); + resizeHandle.on("mouseover", () => { + this.disableDraggable(); + }); + resizeHandle.on("mouseout", () => { + this.enableDraggable(); + }); + + this.nodeSelector = getQuerySelectorFromNode(this._$node[0]); + + // this is the node's awareness trace. + // If I understand correctly, it is showing the activity of other users on the node. + var _$awarenessTrace = $( + lodash.template(awarenessTraceHtml)({ id: id + "_awareness" }) + ); + + var _awarenessTimer = setInterval(function () { + var opacity = _$awarenessTrace.css("opacity"); + opacity -= 0.1; + if (opacity < 0) opacity = 0; + _$awarenessTrace.css({ + opacity: opacity, + }); + }, 3000); + + this._$node.on("mousedown", function () { + _canvas.select(that); + _canvas.unbindMoveToolEvents(); + }); + + this._$node.on("mouseup", function () { + _canvas.bindMoveToolEvents(); + }); + + /** + * Attributes of node + * @type {Object} + * @private + */ + var _attributes = {}; + + /** + * Callback to generate list of context menu items + * @type {function} + */ + var _contextMenuItemCallback = function () { + return {}; + }; + + /** + * Set of ingoing edges + * @type {Object} + * @private + */ + var _ingoingEdges = {}; + + /** + * Set of outgoing edges + * @type {Object} + * @private + */ + var _outgoingEdges = {}; + + /** + * Set of nodes with an edge to the node + * @type {Object} + * @private + */ + var _ingoingNeighbors = {}; + + /** + * Set of nodes with an edge from the node + * @type {Object} + * @private + */ + var _outgoingNeighbors = {}; + + var _relatedGhostEdges = []; + + /** + * Apply a Node Move Operation + * @param {operations.ot.NodeMoveOperation} operation + */ + var processNodeMoveOperation = function (operation) { + _canvas.hideGuidanceBox(); + that.move(operation.getOffsetX(), operation.getOffsetY(), 0); + _canvas.showGuidanceBox(); + }; + + /** + * Apply a Node Move Z Operation + * @param {operations.ot.NodeMoveZOperation} operation + */ + var processNodeMoveZOperation = function (operation) { + that.move(0, 0, operation.getOffsetZ()); + }; + + /** + * Propagate a Node Move Operation to the remote users and the local widgets + * @param {operations.ot.NodeMoveOperation} operation + */ + this.propagateNodeMoveOperation = function (operation) { + operation.setJabberId(_iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]); + processNodeMoveOperation(operation); + HistoryManagerInstance.add(operation); + EntityManagerInstance.storeDataYjs(); + + hideTraceAwareness(); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.ATTRIBUTE, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.HEATMAP, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.getOTOperation() + ); + const activityMap = y.getMap("activity"); + activityMap.set( + ActivityOperation.TYPE, + new ActivityOperation( + "NodeMoveActivity", + operation.getEntityId(), + operation.getJabberId(), + NodeMoveOperation.getOperationDescription( + that.getType(), + that.getLabel().getValue().getValue() + ), + { nodeType: that.getType() } + ).toJSON() + ); + + if (_ymap) { + _ymap.set(NodeMoveOperation.TYPE, operation.toJSON()); + } + }; + + /** + * Propagate a Node Move Z Operation to the remote users and the local widgets + * @param {operations.ot.NodeMoveZOperation} operation + */ + this.propagateNodeMoveZOperation = function (operation) { + var jabberId = _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]; + operation.setJabberId(jabberId); + processNodeMoveZOperation(operation); + HistoryManagerInstance.add(operation); + hideTraceAwareness(); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.ATTRIBUTE, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.getOTOperation() + ); + const activityMap = y.getMap("activity"); + activityMap.set( + ActivityOperation.TYPE, + new ActivityOperation( + "NodeMoveActivity", + operation.getEntityId(), + jabberId, + NodeMoveOperation.getOperationDescription( + that.getType(), + that.getLabel().getValue().getValue() + ), + { nodeType: that.getType() } + ).toJSON() + ); + + if (_ymap) _ymap.set(NodeMoveZOperation.TYPE, operation.toJSON()); + }; + + /** + * Apply a Node Resize Operation + * @param {operations.ot.NodeResizeOperation} operation + */ + var processNodeResizeOperation = function (operation) { + _canvas.hideGuidanceBox(); + that.resize(operation.getOffsetX(), operation.getOffsetY()); + _canvas.showGuidanceBox(); + }; + + /** + * Propagate a Node Resize Operation to the remote users and the local widgets + * @param {operations.ot.NodeResizeOperation} operation + */ + this.propagateNodeResizeOperation = function (operation) { + operation.setJabberId(_iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]); + processNodeResizeOperation(operation); + HistoryManagerInstance.add(operation); + EntityManagerInstance.storeDataYjs(); + hideTraceAwareness(); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.ATTRIBUTE, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.HEATMAP, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.getOTOperation() + ); + const activityMap = y.getMap("activity"); + activityMap.set( + ActivityOperation.TYPE, + new ActivityOperation( + "NodeResizeActivity", + operation.getEntityId(), + operation.getJabberId(), + NodeResizeOperation.getOperationDescription( + that.getType(), + that.getLabel().getValue().getValue() + ), + { nodeType: that.getType() } + ).toJSON() + ); + + if (_ymap) _ymap.set("NodeResizeOperation", operation.toJSON()); + }; + + /** + * Apply a Node Delete Operation + * @param {operations.ot.NodeDeleteOperation} operation + */ + var processNodeDeleteOperation = function () { + var edges = that.getEdges(), + edgeId, + edge; + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + edge.remove(); + } + } + + for (var i = 0; i < _relatedGhostEdges.length; i++) { + if (typeof _relatedGhostEdges[i].remove == "function") + _relatedGhostEdges[i].remove(); + } + if (_ymap) { + _ymap = null; + } + that.remove(); + }; + + /** + * Propagate a Node Delete Operation to the remote users and the local widgets + * @param {operations.ot.NodeDeleteOperation} operation + */ + var propagateNodeDeleteOperation = function (operation) { + processNodeDeleteOperation(); + EntityManagerInstance.storeDataYjs(); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.ATTRIBUTE, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.HEATMAP, + operation.getOTOperation() + ); + const activityMap = y.getMap("activity"); + activityMap.set( + ActivityOperation.TYPE, + new ActivityOperation( + "NodeDeleteActivity", + operation.getEntityId(), + _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], + NodeDeleteOperation.getOperationDescription( + that.getType(), + that.getLabel().getValue().getValue() + ), + {} + ).toJSON() + ); + }; + + var refreshTraceAwareness = function (color) { + _$awarenessTrace.css({ + opacity: 1, + fill: color, + }); + }; + + var hideTraceAwareness = function () { + _$awarenessTrace.css({ + opacity: 0, + }); + }; + + /** + * Callback for a remote Node Move Operation + * @param {operations.ot.NodeMoveOperation} operation + */ + var remoteNodeMoveCallback = function (operation) { + if ( + operation instanceof NodeMoveOperation && + operation.getEntityId() === that.getEntityId() + ) { + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.ATTRIBUTE, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.HEATMAP, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.getOTOperation() + ); + const userMap = y.getMap("users"); + if (userMap.get(y.clientID) !== operation.getJabberId()) { + const userList = y.getMap("userList"); + var color = Util.getColor( + userList.get(operation.getJabberId()).globalId + ); + refreshTraceAwareness(color); + } + + processNodeMoveOperation(operation); + } + }; + + /** + * Callback for a remote Node Move Z Operation + * @param {operations.ot.NodeMoveZOperation} operation + */ + var remoteNodeMoveZCallback = function (operation) { + if ( + operation instanceof NodeMoveZOperation && + operation.getEntityId() === that.getEntityId() + ) { + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.ATTRIBUTE, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.getOTOperation() + ); + const userMap = y.getMap("users"); + if (userMap.get(y.clientID) !== operation.getJabberId()) { + const userList = y.getMap("userList"); + var color = Util.getColor( + userList.get(operation.getJabberId()).globalId + ); + refreshTraceAwareness(color); + } + processNodeMoveZOperation(operation); + } + }; + + /** + * Callback for a remote Node Resize Operation + * @param {operations.ot.NodeResizeOperation} operation + */ + var remoteNodeResizeCallback = function (operation) { + if ( + operation instanceof NodeResizeOperation && + operation.getEntityId() === that.getEntityId() + ) { + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.ATTRIBUTE, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.HEATMAP, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.getOTOperation() + ); + const userMap = y.getMap("users"); + if (userMap.get(y.clientID) !== operation.getJabberId()) { + const userList = y.getMap("userList"); + var color = Util.getColor( + userList.get(operation.getJabberId()).globalId + ); + refreshTraceAwareness(color); + } + processNodeResizeOperation(operation); + } + }; + + /** + * Callback for a remote Node Delete Operation + * @param {operations.ot.NodeDeleteOperation} operation + */ + this.remoteNodeDeleteCallback = function (operation) { + if ( + operation instanceof NodeDeleteOperation && + operation.getEntityId() === that.getEntityId() + ) { + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.ATTRIBUTE, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.HEATMAP, + operation.getOTOperation() + ); + processNodeDeleteOperation(); + HistoryManagerInstance.clean(operation.getEntityId()); + } + }; + + this.init = function () { + //Define Node Rightclick Menu + $.contextMenu({ + selector: "#" + id, + zIndex: AbstractEntity.CONTEXT_MENU_Z_INDEX, + build: function ($trigger, e) { + var menuItems; + var EntityManager = EntityManagerInstance; + + $(e.target).offset(); + that.getCanvas().get$node().offset(); + + if ( + _canvas.getSelectedEntity() === null || + _canvas.getSelectedEntity() === that + ) { + menuItems = lodash.extend(_contextMenuItemCallback(), { + connectTo: EntityManager.generateConnectToMenu(that), + sepMove: "---------", + moveToForeground: { + name: "Move to Foreground", + callback: function (/*key, opt*/) { + that.propagateNodeMoveZOperation( + new NodeMoveZOperation( + that.getEntityId(), + ++AbstractEntity.maxZIndex - _zIndex + ) + ); + }, + }, + moveToBackground: { + name: "Move to Background", + callback: function (/*key, opt*/) { + that.propagateNodeMoveZOperation( + new NodeMoveZOperation( + that.getEntityId(), + --AbstractEntity.minZIndex - _zIndex + ) + ); + }, + }, + sepDelete: "---------", + delete: { + name: "Delete", + callback: function (/*key, opt*/) { + that.triggerDeletion(); + }, + }, + quit: { + name: " ", + disabled: true, + }, + }); + + return { + items: menuItems, + events: { + show: function (/*opt*/) { + _canvas.select(that); + }, + }, + }; + } else { + _canvas.select(null); + return false; + } + }, + }); + }; + + /** + * Triggers jsPlumb's repaint function and adjusts the angle of the edge labels + */ + + /** + * Anchor options for new connections + * @type {object} + */ + var _anchorOptions = AnchorLocations.AutoDefault; + + /** + * Get options for new connections + * @returns {Object} + */ + this.getAnchorOptions = function () { + return _anchorOptions; + }; + + /** + * Send NodeDeleteOperation for node + */ + this.triggerDeletion = function (historyFlag) { + var edgeId, + edges = this.getEdges(), + edge; + _canvas.select(null); + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + edge.triggerDeletion(); + } + } + var operation = new NodeDeleteOperation( + id, + that.getType(), + _appearance.left, + _appearance.top, + _appearance.width, + _appearance.height, + _zIndex, + _appearance.containment, + that.toJSON() + ); + if (_ymap) { + propagateNodeDeleteOperation(operation); + const nodesMap = y.getMap("nodes"); + nodesMap.delete(that.getEntityId()); + } else { + propagateNodeDeleteOperation(operation); + } + if (!historyFlag) HistoryManagerInstance.add(operation); + }; + + //noinspection JSUnusedGlobalSymbols + /** + * Get callback to generate list of context menu items + * @returns {object} + */ + this.getContextMenuItemCallback = function () { + return _contextMenuItemCallback; + }; + + /** + * Set callback to generate list of context menu items + * @param {function} contextMenuItemCallback + */ + this.setContextMenuItemCallback = function (contextMenuItemCallback) { + if (typeof contextMenuItemCallback === "function") { + _contextMenuItemCallback = contextMenuItemCallback; + } + }; + + /** + * Get node appearance + * @returns {{left: number, top: number, width: number, height: number}} + */ + this.getAppearance = function () { + return _appearance; + }; + + /** + * Get position of node on z-axis + * @return {number} + */ + this.getZIndex = function () { + return _zIndex; + }; + + this.refreshTraceAwareness = function (color) { + refreshTraceAwareness(color); + }; + + /** + * Adds node to canvas + * @param {canvas_widget.AbstractCanvas} canvas + */ + this.addToCanvas = function (canvas) { + if (!canvas) throw new Error("Canvas is null"); + _canvas = canvas; + canvas.get$canvas().append(_$awarenessTrace); + canvas.get$canvas().append(this._$node); + }; + + /** + * Get associated canvas + * @returns {canvas_widget.AbstractCanvas} + */ + this.getCanvas = function () { + return _canvas; + }; + + /** + * Removes node from canvas + */ + this.removeFromCanvas = function () { + this._$node.remove(); + //destroy the context menu + $.contextMenu("destroy", "#" + that.getEntityId()); + _canvas = null; + _$awarenessTrace.remove(); + if (this.hasOwnProperty("unregisterCallbacks")) + this.unregisterCallbacks(); + }; + + /** + * Add attribute to node + * @param {canvas_widget.AbstractAttribute} attribute + */ + this.addAttribute = function (attribute) { + var id = attribute.getEntityId(); + if (!_attributes.hasOwnProperty(id)) { + _attributes[id] = attribute; + } + }; + + /** + * Get attribute by id + * @param {String} id Attribute's entity id + * @returns {canvas_widget.AbstractAttribute} + */ + this.getAttribute = function (id) { + if (_attributes.hasOwnProperty(id)) { + return _attributes[id]; + } + return null; + }; + + /** + * Delete attribute by id + * @param {String} id Attribute's entity id + */ + this.deleteAttribute = function (id) { + if (_attributes.hasOwnProperty(id)) { + delete _attributes[id]; + } + }; + + /** + * Set node's attributes + * @param {Object} attributes + */ + this.setAttributes = function (attributes) { + _attributes = attributes; + }; + + /** + * Get node's attributes + * @returns {Object} + */ + this.getAttributes = function () { + return _attributes; + }; + + /** + * Set edge label + * @param {canvas_widget.SingleValueAttribute} label + */ + this.setLabel = function (label) { + _label = label; + }; + + /** + * Get edge label + * @returns {canvas_widget.SingleValueAttribute} + */ + this.getLabel = function () { + return _label; + }; + + /** + * Get edge type + * @returns {string} + */ + this.getType = function () { + return _type; + }; + + /** + * Get edge type + * @returns {boolean} + */ + this.getContainment = function () { + return _containment; + }; + + /** + * Get jQuery object of DOM node representing the node + * @returns {jQuery} + * @private + */ + this._get$node = function () { + return this._$node; + }; + + /** + * Apply position and dimension attributes to the node + * @private + */ + this._draw = function () { + //noinspection JSAccessibilityCheck + _$awarenessTrace.css({ + left: _appearance.left + _appearance.width / 2, + top: _appearance.top + _appearance.height / 2, + width: _appearance.width * 1.2, + height: _appearance.height * 1.2, + zIndex: _zIndex - 1, + }); + this._$node.css({ + left: _appearance.left, + top: _appearance.top, + width: _appearance.width, + height: _appearance.height, + zIndex: _zIndex, + }); + }; + + /** + * Move the node + * @param {number} offsetX Offset in x-direction + * @param {number} offsetY Offset in y-direction + * @param {number} offsetZ Offset in z-direction + */ + this.move = function (offsetX, offsetY) { + const x = _appearance.left + offsetX; + const y = _appearance.top + offsetY; + if ( + x < 0 || + y < 0 || + x > _canvas.width - _appearance.width || + y > _canvas.height - _appearance.height + ) { + // reset the position + _$node.css({ + left: _appearance.left, + top: _appearance.top, + }); + console.error("Node cannot be moved outside of canvas"); + if (_ymap) { + window.y.transact(() => { + _ymap.set("left", _appearance.left); + _ymap.set("top", _appearance.top); + _ymap.set("zIndex", _zIndex); + }); + } + } else { + if (_ymap) { + window.y.transact(() => { + _ymap.set("left", (_appearance.left += offsetX)); + _ymap.set("top", (_appearance.top += offsetY)); + _ymap.set("zIndex", _zIndex); + }); + } + } + this._draw(); + this.repaint(); + }; + + this.moveAbs = function (left, top, zIndex) { + if (left < 0 || top < 0) { + console.error("Node cannot be moved outside of canvas"); + } + if ( + left > _canvas.width - _appearance.width || + top > _canvas.height - _appearance.height + ) { + console.error("Node cannot be moved outside of canvas"); + } + _appearance.left = left; + _appearance.top = top; + + if (zIndex) _zIndex = zIndex; + + if (_ymap) { + y.transact(() => { + _ymap.set("left", _appearance.left); + _ymap.set("top", _appearance.top); + if (zIndex) _ymap.set("zIndex", _zIndex); + }); + } + this._draw(); + this.repaint(); + }; + + /** + * Resize the node + * @param {number} offsetX Offset in x-direction + * @param {number} offsetY Offset in y-direction + */ + this.resize = function (offsetX, offsetY) { + _appearance.width += offsetX; + _appearance.height += offsetY; + if (_ymap) { + y.transact(() => { + _ymap.set("width", _appearance.width); + _ymap.set("height", _appearance.height); + }); + } + this._draw(); + this.repaint(); + }; + + /** + * Add ingoing edge + * @param {canvas_widget.AbstractEdge} edge + */ + this.addIngoingEdge = function (edge) { + var id = edge.getEntityId(); + var source = edge.getSource(); + var sourceEntityId = source.getEntityId(); + if (!_ingoingEdges.hasOwnProperty(id)) { + _ingoingEdges[id] = edge; + if (!_ingoingNeighbors.hasOwnProperty(sourceEntityId)) { + _ingoingNeighbors[sourceEntityId] = source; + } + } + }; + + /** + * Add outgoing edge + * @param {canvas_widget.AbstractEdge} edge + */ + this.addOutgoingEdge = function (edge) { + var id = edge.getEntityId(); + var target = edge.getTarget(); + var targetEntityId = target?.getEntityId(); + if (!_outgoingEdges.hasOwnProperty(id)) { + _outgoingEdges[id] = edge; + if (!_outgoingNeighbors.hasOwnProperty(targetEntityId)) { + _outgoingNeighbors[targetEntityId] = target; + } + } + }; + + /** + * Delete ingoing edge + * @param {canvas_widget.AbstractEdge} edge + */ + this.deleteIngoingEdge = function (edge) { + var id = edge.getEntityId(); + var source = edge.getSource(); + var sourceEntityId = source.getEntityId(); + var isMultiEdge = false; + if (_ingoingEdges.hasOwnProperty(id)) { + delete _ingoingEdges[id]; + for (var edgeId in _ingoingEdges) { + if ( + _ingoingEdges.hasOwnProperty(edgeId) && + _ingoingEdges[edgeId].getSource().getEntityId() === sourceEntityId + ) { + isMultiEdge = true; + } + } + if (!isMultiEdge) { + delete _ingoingNeighbors[sourceEntityId]; + } + } + }; + + /** + * Delete outgoing edge + * @param {canvas_widget.AbstractEdge} edge + */ + this.deleteOutgoingEdge = function (edge) { + var id = edge.getEntityId(); + var target = edge.getTarget(); + var targetEntityId = target?.getEntityId(); + var isMultiEdge = false; + if (_outgoingEdges.hasOwnProperty(id)) { + delete _outgoingEdges[id]; + for (var edgeId in _outgoingEdges) { + if ( + _outgoingEdges.hasOwnProperty(edgeId) && + _outgoingEdges[edgeId].getTarget().getEntityId() === targetEntityId + ) { + isMultiEdge = true; + } + } + if (!isMultiEdge) { + delete _outgoingNeighbors[targetEntityId]; + } + } + }; + + //noinspection JSUnusedGlobalSymbols + /** + * Get ingoing edges + * @returns {Object} + */ + this.getIngoingEdges = function () { + return _ingoingEdges; + }; + + /** + * Get outgoing edges + * @returns {Object} + */ + this.getOutgoingEdges = function () { + return _outgoingEdges; + }; + + /** + * Get all ingoing and outgoing edges + * @returns {Array} + */ + this.getEdges = function () { + return Util.union(_ingoingEdges, _outgoingEdges); + }; + + //noinspection JSUnusedGlobalSymbols + /** + * Get neighbors with an edge to the node + * @returns {Object} + */ + this.getIngoingNeighbors = function () { + return _ingoingNeighbors; + }; + + //noinspection JSUnusedGlobalSymbols + /** + * Get neighbors with an edge from the node + * @returns {Object} + */ + this.getOutgoingNeighbors = function () { + return _outgoingNeighbors; + }; + + //noinspection JSUnusedGlobalSymbols + /** + * Get neighbors with an edge to or from the node + * @returns {Object} + */ + this.getNeighbors = function () { + return Util.union(_ingoingNeighbors, _outgoingNeighbors); + }; + + /** + * Lowlight the node + */ + this.lowlight = function () { + this._$node.addClass("lowlighted"); + }; + + /** + * Unlowlight the node + */ + this.unlowlight = function () { + this._$node.removeClass("lowlighted"); + }; + + /** + * Select the node + */ + this.select = function () { + this.unhighlight(); + this._$node.addClass("selected"); + Util.delay(100).then(function () { + lodash.each(EntityManagerInstance.getEdges(), function (e) { + e.setZIndex(); + }); + }); + }; + + /** + * Unselect the node + */ + this.unselect = function () { + //this.highlight(_highlightColor,_highlightUsername); + this._$node.removeClass("selected"); + //trigger save when unselecting an entity + Util.delay(100).then(function () { + lodash.each(EntityManagerInstance.getEdges(), function (e) { + e.setZIndex(); + }); + }); + }; + + /** + * Highlight the node by assigning it the passed color and label it with the passed username + * @param {String} color + * @param {String} username + */ + this.highlight = function (color, username) { + if (color && username) { + this._$node.css({ border: "2px solid " + color }); + this._$node.append( + $("
                  ") + .addClass("user_highlight") + .css("color", color) + .text(username) + ); + Util.delay(100).then(function () { + lodash.each(EntityManagerInstance.getEdges(), function (e) { + e.setZIndex(); + }); + }); + } + }; + + /** + * Unhighlight the node + */ + this.unhighlight = function () { + this._$node.css({ border: "" }); + this._$node.find(".user_highlight").remove(); + Util.delay(100).then(function () { + lodash.each(EntityManagerInstance.getEdges(), function (e) { + e.setZIndex(); + }); + }); + }; + + /** + * Remove the node + */ + this.remove = function () { + clearInterval(_awarenessTimer); + this.removeFromCanvas(); + jsPlumbInstance.removeAllEndpoints(_$node.get(0)); + jsPlumbInstance.unmanage(_$node.get(0)); + EntityManagerInstance.deleteNode(this.getEntityId()); + }; + + /** + * Get JSON representation of the node + * @returns {Object} + * @private + */ + this._toJSON = function () { + var attr = {}; + lodash.forEach(this.getAttributes(), function (val, key) { + attr[key] = val.toJSON(); + }); + //noinspection JSAccessibilityCheck + return { + label: _label.toJSON(), + left: _appearance.left, + top: _appearance.top, + width: _appearance.width, + height: _appearance.height, + zIndex: _zIndex, + type: _type, + attributes: attr, + }; + }; + + this.addGhostEdge = function (ghostEdge) { + _relatedGhostEdges.push(ghostEdge); + }; + + /** + * Bind events for move tool + */ + this.bindMoveToolEvents = () => { + this.enableDraggable(); + var originalPos = { + left: 0, + top: 0, + }; + + var $sizePreview = $('
                  ').hide(); + + this.makeResizable(that, _canvas, $sizePreview, id); + + this._$node + //Enable Node Rightclick menu + .contextMenu(true) + .find("input") + .prop("disabled", false) + .css("pointerEvents", ""); + + this.jsPlumbManagedElement = jsPlumbInstance.manage(this._$node.get(0)); + + jsPlumbInstance.bind(EVENT_DRAG_START, (params) => { + if (params.el.id !== this._$node.attr("id")) return true; + + originalPos.top = params.el.offsetTop; + originalPos.left = params.el.offsetLeft; + + _canvas.hideGuidanceBox(); + _$node.css({ opacity: 0.5 }); + + return true; + }); + + jsPlumbInstance.bind(EVENT_DRAG_STOP, (params) => { + if (params.el.id !== this._$node.attr("id")) return true; + + _$node.css({ opacity: "" }); + _canvas.bindMoveToolEvents(); + var offsetX = Math.round(params.el.offsetLeft - originalPos.left); + var offsetY = Math.round(params.el.offsetTop - originalPos.top); + // if offset is 0, no need to send the operation + if (offsetX === 0 && offsetY === 0) return; + // if offset bigger than canvas size, no need to send the operation + if ( + params.el.offsetLeft < 0 || + params.el.offsetTop < 0 || + params.el.offsetLeft > _canvas.width || + params.el.offsetTop > _canvas.height + ) { + console.error(" offset bigger than canvas size"); + return; + } + + var operation = new NodeMoveOperation( + that.getEntityId(), + offsetX, + offsetY + ); + that.propagateNodeMoveOperation(operation); + + //Avoid node selection on drag stop + _canvas.showGuidanceBox(); + }); + + // view_only is used by the CAE and allows to show a model in the Canvas which is not editable + // therefore, the nodes should not be draggable and their context menu should be disabled + const widgetConfigMap = y.getMap("widgetConfig"); + var viewOnly = widgetConfigMap.get("view_only"); + if (viewOnly) { + this.disableDraggable(); + _$node.on("click").contextMenu(false); + } + }; + + /** + * Unbind events for move tool + */ + this.unbindMoveToolEvents = () => { + //Disable Node Selection + // called for e.g. if we want to draw an edge + this._$node + .off("click") + .contextMenu(false) + .find("input") + .prop("disabled", true) + .css("pointerEvents", "none"); + + //Disable Node Dragging + this.disableDraggable(); + }; + + /** + * Bind source node events for edge tool + */ + this.makeSource = () => { + _$node.addClass("source"); + this.endPoint = window.jsPlumbInstance.addEndpoint(this._$node.get(0), { + connectorPaintStyle: { fill: "black", strokeWidth: 4 }, + source: true, + endpoint: { + type: "Rectangle", + options: { + width: _$node.width() + 50, + height: _$node.height() + 50, + }, + }, + paintStyle: { fill: "transparent" }, + anchor: AnchorLocations.Center, + deleteOnEmpty: true, + //maxConnections:1, + uniqueEndpoint: false, + deleteEndpointsOnDetach: true, + onMaxConnections: function (info /*, originalEvent*/) { + console.log( + "element is ", + info.element, + "maxConnections is", + info.maxConnections + ); + }, + }); + }; + + /** + * Bind target node events for edge tool + */ + this.makeTarget = () => { + _$node.addClass("target"); + this.endPoint = window.jsPlumbInstance.addEndpoint(this._$node.get(0), { + target: true, + endpoint: { + type: "Rectangle", + options: { + width: _$node.width() + 50, + height: _$node.height() + 50, + }, + }, + paintStyle: { fill: "transparent" }, + anchor: AnchorLocations.Center, + uniqueEndpoint: false, + //maxConnections:1, + deleteOnEmpty: true, + onMaxConnections: function (info /*, originalEvent*/) { + console.log( + "user tried to drop connection", + info.connection, + "on element", + info.element, + "with max connections", + info.maxConnections + ); + }, + }); + }; + + /** + * Unbind events for edge tool + */ + this.unbindEdgeToolEvents = function () { + try { + _$node.removeClass("source target"); + jsPlumbInstance.getEndpoints(_$node.get(0)).forEach((endpoint) => { + // We need to remove the endpoint that was created to enable node connection by dragging + // since we are not using the edge tool anymore + if (endpoint.connections.length === 0) { + jsPlumbInstance.deleteEndpoint(endpoint); + } + }); + } catch (error) { + console.error(error); + } + }; + + that.init(); + + this._registerYMap = function () { + _ymap.observe(function (event) { + const array = Array.from(event.changes.keys.entries()); + array.forEach(([key]) => { + if (event.value && event.value.historyFlag) { + var operation; + var data = event.value; + const userMap = y.getMap("users"); + var jabberId = userMap.get(yUserId); + switch (key) { + case NodeMoveOperation.TYPE: { + operation = new NodeMoveOperation( + data.id, + data.offsetX, + data.offsetY, + jabberId + ); + remoteNodeMoveCallback(operation); + break; + } + case NodeMoveZOperation.TYPE: { + operation = new NodeMoveZOperation( + data.id, + data.offsetZ, + jabberId + ); + remoteNodeMoveZCallback(operation); + break; + } + case NodeResizeOperation.TYPE: { + operation = new NodeResizeOperation( + data.id, + data.offsetX, + data.offsetY, + jabberId + ); + remoteNodeResizeCallback(operation); + break; + } + } + } + }); + }); + }; + + jsPlumbInstance.manage(this._$node.get(0)); + // EntityManagerInstance.storeDataYjs(); + } + nodeSelector; + jsPlumbManagedElement; + endPoint; + + repaint() { + window.jsPlumbInstance.repaint(this._$node.get(0)); + + lodash.each(EntityManagerInstance.getEdges(), function (e) { + e.setZIndex(); + }); + } + + enableDraggable() { + jsPlumbInstance.setDraggable(this._$node.get(0), true); + } + + disableDraggable() { + jsPlumbInstance.setDraggable(this._$node.get(0), false); + } + + makeResizable(that, _canvas, $sizePreview, id) { + const initialSize = { + width: that._$node.width(), + height: that._$node.height(), + }; + interact(that.nodeSelector) + .resizable({ + // resize from all edges and corners + edges: { right: ".bi", bottom: ".bi" }, + square: true, + listeners: { + move(event) { + that.disableDraggable(); + let { x, y } = event.target.dataset; + + x = (parseFloat(x) || 0) + event.deltaRect.left; + y = (parseFloat(y) || 0) + event.deltaRect.top; + + Object.assign(event.target.style, { + width: `${event.rect.width}px`, + height: `${event.rect.height}px`, + transform: `translate(${x}px, ${y}px)`, + }); + + Object.assign(event.target.dataset, { x, y }); + + event.rect.width = Math.max(50, event.rect.width); + event.rect.height = Math.max(50, event.rect.height); + + $sizePreview.text( + Math.round(event.rect.width) + + "\u00D7" + + Math.round(event.rect.height) + ); + // that.repaint(); + }, + }, + modifiers: [ + // keep the edges inside the parent + interact.modifiers.restrictEdges({ + outer: "parent", + }), + // minimum size + interact.modifiers.restrictSize({ + min: { width: 40, height: 40 }, + }), + ], + inertia: { enabled: false }, + }) + .on(["resizestart"], () => { + // add resizing class + that._$node.addClass("resizing"); + that.disableDraggable(); + _canvas.hideGuidanceBox(); + $sizePreview.show(); + that._$node.css({ opacity: 0.5 }); + that._$node.append($sizePreview); + initialSize.width = that._$node.width(); + initialSize.height = that._$node.height(); + _canvas.unbindMoveToolEvents(); + }) + .on(["resizeend"], (event) => { + // remove resizing class + that._$node.removeClass("resizing"); + that.enableDraggable(); + const offsetX = event.rect.width - initialSize.width; + const offsetY = event.rect.height - initialSize.height; + $sizePreview.hide(); + that._$node.css({ opacity: "" }); + that.repaint(); + var operation = new NodeResizeOperation(id, offsetX, offsetY); + that.propagateNodeResizeOperation(operation); + _canvas.bindMoveToolEvents(); + }) + .draggable(); + } + + disableResizable() { + interact(this.nodeSelector).unset(); + } + + /** + * Apply position and dimension attributes to the node + */ + draw() { + return this._draw(); + } + /** + * Get jQuery object of DOM node representing the node + * @returns {jQuery} + */ + get$node() { + return this._get$node(); + } + /** + * Get JSON representation of the node + * @returns {{label: Object, left: number, top: number, width: number, height: number, type: string, attributes: Object}} + */ + toJSON() { + return this._toJSON(); + } + /** + * hide the node and all associated edges + */ + hide() { + this.get$node().hide(); + window.jsPlumbInstance.hide(this.get$node()); + } + /** + * show the node and all associated edges + */ + show() { + this.get$node().show(); + window.jsPlumbInstance.show(this.get$node()[0]); + window.jsPlumbInstance.repaint(this.get$node()[0]); + } + registerYMap() { + this._registerYMap(); + } +} + +/** + * Abstract Class Node + * @class canvas_widget.EnumNode + * @extends canvas_widget.AbstractNode + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {number} zIndex Position of node on z-axis + */ +class EnumNode extends AbstractNode { + static TYPE = "Enumeration"; + static DEFAULT_WIDTH = 150; + static DEFAULT_HEIGHT = 100; + constructor(id, left, top, width, height, zIndex, json) { + super(id, EnumNode.TYPE, left, top, width, height, zIndex, json); + var that = this; + + /** + * jQuery object of node template + * @type {jQuery} + * @private + */ + var _$template = $(lodash.template(enumNodeHtml)({ type: that.getType() })); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = AbstractNode.prototype.get$node + .call(this) + .append(_$template) + .addClass("class"); + + /** + * jQuery object of DOM node representing the attributes + * @type {jQuery} + * @private + */ + var _$attributeNode = _$node.find(".attributes"); + + /** + * Attributes of node + * @type {Object} + * @private + */ + var _attributes = this.getAttributes(); + + /** + * Get JSON representation of the node + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractNode.prototype.toJSON.call(this); + json.type = EnumNode.TYPE; + return json; + }; + var attr = new SingleValueListAttribute("[attributes]", "Attributes", this); + this.addAttribute(attr); + + this.registerYMap = function () { + AbstractNode.prototype.registerYMap.call(this); + that.getLabel().getValue().registerYType(); + attr.registerYMap(); + }; + this.unregisterCallbacks = function () { + that.getAttribute("[attributes]").unregisterCallbacks(); + }; + this.registerYTextAttributes = function (map) { + map.get(that.getLabel().getValue().getEntityId()).then(function (ytext) { + that.getLabel().getValue().registerYType(ytext); + }); + }; + + _$node.find(".label").append(this.getLabel().get$node()); + + for (var attributeKey in _attributes) { + if (_attributes.hasOwnProperty(attributeKey)) { + _$attributeNode.append(_attributes[attributeKey].get$node()); + } + } + } +} + +/** + * Abstract Class Node + * @class canvas_widget.NodeShapeNode + * @extends canvas_widget.AbstractNode + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {number} zIndex Position of node on z-axis + * @param {boolean} containment containment + */ +class NodeShapeNode extends AbstractNode { + static TYPE = "Node Shape"; + static DEFAULT_WIDTH = 150; + static DEFAULT_HEIGHT = 150; + constructor(id, left, top, width, height, zIndex, containment, json) { + super( + id, + "Node Shape", + left, + top, + width, + height, + zIndex, + containment, + json + ); + var that = this; + + /** + * jQuery object of node template + * @type {jQuery} + * @private + */ + var _$template = $(lodash.template(nodeShapeNodeHtml)({ type: that.getType() })); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = AbstractNode.prototype.get$node + .call(this) + .append(_$template) + .addClass("class"); + + /** + * jQuery object of DOM node representing the attributes + * @type {jQuery} + * @private + */ + var _$attributeNode = _$node.find(".attributes"); + + /** + * Attributes of node + * @type {Object} + * @private + */ + var _attributes = this.getAttributes(); + + /** + * Get JSON representation of the node + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractNode.prototype.toJSON.call(this); + json.type = NodeShapeNode.TYPE; + return json; + }; + + var attrShapeSelect = new SingleSelectionAttribute( + this.getEntityId() + "[shape]", + "Shape", + this, + { + circle: "Circle", + diamond: "Diamond", + rectangle: "Rectangle", + rounded_rectangle: "Rounded Rectangle", + triangle: "Triangle", + } + ); + var attrWidth = new IntegerAttribute( + this.getEntityId() + "[defaultWidth]", + "Default Width", + this + ); + var attrHeight = new IntegerAttribute( + this.getEntityId() + "[defaultHeight]", + "Default Height", + this + ); + var attrColor = new SingleColorValueAttribute( + this.getEntityId() + "[color]", + "Color", + this + ); + var attrContaintment = new BooleanAttribute( + this.getEntityId() + "[containment]", + "Containment", + this + ); + var attrCustomShape = new SingleMultiLineValueAttribute( + this.getEntityId() + "[customShape]", + "Custom Shape", + this + ); + var attrAnchors = new SingleValueAttribute( + this.getEntityId() + "[customAnchors]", + "Custom Anchors", + this + ); + + this.addAttribute(attrShapeSelect); + this.addAttribute(attrColor); + this.addAttribute(attrWidth); + this.addAttribute(attrHeight); + this.addAttribute(attrContaintment); + this.addAttribute(attrCustomShape); + this.addAttribute(attrAnchors); + + _$node.find(".label").append(this.getLabel().get$node()); + + for (var attributeKey in _attributes) { + if (_attributes.hasOwnProperty(attributeKey)) { + _$attributeNode.append(_attributes[attributeKey].get$node()); + } + } + + this.registerYMap = function () { + AbstractNode.prototype.registerYMap.call(this); + attrShapeSelect.getValue().registerYType(); + attrWidth.getValue().registerYType(); + attrHeight.getValue().registerYType(); + attrContaintment.getValue().registerYType(); + that.getLabel().getValue().registerYType(); + attrColor.getValue().registerYType(); + attrAnchors.getValue().registerYType(); + attrCustomShape.getValue().registerYType(); + }; + } +} + +/** + * EntityManager + * @class canvas_widget.EntityManager + * @memberof canvas_widget + * @constructor + */ +let EntityManager$1 = class EntityManager { + y = null; + setSharedDocument(y) { + this.y = y; + } + _nodes; + _edges; + + constructor() { + /** + * the view id indicates if the EntityManager should use View types for modeling or node types + * @type {string} + * @private + */ + var _viewId = undefined; + + /** + * Model attributes node + * @type {canvas_widget.ModelAttributesNode} + * @private + */ + var _modelAttributesNode = null; + /** + * Nodes of the graph + * @type {{}} + * @private + */ + var _nodes = {}; + this._nodes = _nodes; + /** + * Edges of the graph + * @type {{}} + * @private + */ + var _edges = {}; + this._edges = _edges; + + var metamodel = null; + + var guidancemodel = null; + + //noinspection JSUnusedGlobalSymbols + return { + /** + * Create a new node + * @memberof canvas_widget.EntityManager# + * @param {string} type Type of node + * @param {string} id Entity identifier of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {number} zIndex Position of node on z-axis + * @param {object} json the json representation + * @param {number} y the yjs map + * @param {boolean} store if the node should be stored in the meta model + * @returns {canvas_widget.AbstractNode} + */ + createNode: function ( + type, + id, + left, + top, + width, + height, + zIndex, + containment, + json, + y, + store = true + ) { + var node; + AbstractEntity.maxZIndex = Math.max(AbstractEntity.maxZIndex, zIndex); + AbstractEntity.minZIndex = Math.min(AbstractEntity.minZIndex, zIndex); + + if (_viewId && viewNodeTypes.hasOwnProperty(type)) { + node = viewNodeTypes[type]( + id, + left, + top, + width, + height, + zIndex, + containment, + json, + y + ); + } else if (nodeTypes.hasOwnProperty(type)) { + node = new nodeTypes[type]( + id, + left, + top, + width, + height, + zIndex, + containment, + json, + y + ); + } + _nodes[id] = node; + if (store) EntityManagerInstance.storeDataYjs(); + return node; + }, + saveState: function () { + // if metamodel + const viewId = ViewManager.getCurrentView(); + if (viewId && !metamodel) { + ViewManager.updateViewContent(viewId); + } else { + EntityManager.storeDataYjs(); + } + }, + findObjectNodeByLabel(searchTerm) { + const re = new RegExp(searchTerm, "gi"); + const { nodes } = EntityManagerInstance.graphToJSON(); + for (const [nodeId, node] of Object.entries(nodes)) { + if (node?.type.match(re)) { + // type matches searchTerm + return EntityManagerInstance.find(nodeId); + } + if (node?.label?.value?.value.match(re)) { + // label matches searchTerm + return EntityManagerInstance.find(nodeId); + } + for (const attr of Object.values(node?.attributes)) { + // search attributes + if (typeof attr?.value?.value !== "string") { + continue; + } + if (attr?.value?.value.match(re)) { + // attribute value matches searchTerm + return EntityManagerInstance.find(nodeId); + } + } + } + return null; + }, + /** + * Create model Attributes node + * @returns {canvas_widget.ModelAttributesNode} + */ + createModelAttributesNode: function (y) { + if (_modelAttributesNode === null) { + if (metamodel) + _modelAttributesNode = new ModelAttributesNode( + "modelAttributes", + metamodel.attributes, + y + ); + else + _modelAttributesNode = new ModelAttributesNode( + "modelAttributes", + null, + y + ); + return _modelAttributesNode; + } + return _modelAttributesNode; + }, + /** + * Find nodeby attr + * @memberof attribute_widget.EntityManager# + * @param {string} name Entity name + * @returns {canvas_widget.AbstractNode} + */ + findNodeByAttribute: function (attr, name) { + for (const key in _nodes) { + const node = _nodes[key]; + if (node.getAttribute(attr) === name) { + return node; + } + } + }, + + /** + * Find node by id + * @memberof canvas_widget.EntityManager# + * @param {string} id Entity id + * @returns {canvas_widget.AbstractNode} + */ + findNode: function (id) { + if (_nodes.hasOwnProperty(id)) { + return _nodes[id]; + } + return null; + }, + /** + * Find node or edge by id + * @memberof attribute_widget.EntityManager# + * @param {string} id Entity id + * @returns {*} + */ + find: function (id) { + return this.findNode(id) || this.findEdge(id); + }, + /** + * Delete node by id + * @memberof canvas_widget.EntityManager# + * @param {string} id Entity id + */ + deleteNode: function (id) { + if (_nodes.hasOwnProperty(id)) { + delete _nodes[id]; + } + EntityManagerInstance.storeDataYjs(); + }, + /** + * Get all nodes + * @memberof canvas_widget.EntityManager# + * @returns {object} + */ + getNodes: function () { + return _nodes; + }, + /** + * Get nodes by type + * @memberof canvas_widget.EntityManager# + * @param {string|string[]} type Entity type + * @returns {object} + */ + getNodesByType: function (type) { + var nodeId, + node, + nodesByType = {}; + + if (typeof type === "string") { + type = [type]; + } + + for (nodeId in _nodes) { + if (_nodes.hasOwnProperty(nodeId)) { + node = _nodes[nodeId]; + if (type.indexOf(node.getType()) !== -1) { + nodesByType[nodeId] = node; + } + } + } + return nodesByType; + }, + /** + * Create a new edge + * @memberof canvas_widget.EntityManager# + * @param {string} type Type of edge + * @param {string} id Entity identifier of edge + * @param {canvas_widget.AbstractNode} source Source node + * @param {canvas_widget.AbstractNode} target Target node + * @returns {canvas_widget.AbstractEdge} + */ + //TODO: switch id and type + createEdge: function (type, id, source, target, store = true) { + var edge; + + if (_viewId && viewEdgeTypes.hasOwnProperty(type)) { + edge = viewEdgeTypes[type](id, source, target); + } else if (edgeTypes.hasOwnProperty(type)) { + edge = new edgeTypes[type](id, source, target); + } else { + return undefined; + } + source.addOutgoingEdge(edge); + target?.addIngoingEdge(edge); + _edges[id] = edge; + if (store) EntityManagerInstance.storeDataYjs(); + return edge; + }, + /** + * Find edge by id + * @memberof canvas_widget.EntityManager# + * @param {string} id Entity id + * @returns {*} + */ + findEdge: function (id) { + if (_edges.hasOwnProperty(id)) { + return _edges[id]; + } + return null; + }, + /** + * Delete edge by id + * @memberof canvas_widget.EntityManager# + * @param {string} id Entity id + */ + deleteEdge: function (id) { + if (_edges.hasOwnProperty(id)) { + delete _edges[id]; + } + EntityManagerInstance.storeDataYjs(); + }, + /** + * Get all edges + * @memberof canvas_widget.EntityManager# + * @returns {object} + */ + getEdges: function () { + return _edges; + }, + /** + * Get edges by type + * @memberof canvas_widget.EntityManager# + * @param {string} type Entity type + * @returns {object} + */ + getEdgesByType: function (type) { + var edgeId, + edge, + edgesByType = {}; + + for (edgeId in _edges) { + if (_edges.hasOwnProperty(edgeId)) { + edge = _edges[edgeId]; + if (edge.getType() === type) { + edgesByType[edgeId] = edge; + } + } + } + return edgesByType; + }, + /** + * Get JSON representation of whole graph + * @memberof canvas_widget.EntityManager# + * @returns {object} + */ + graphToJSON: function () { + var attributesJSON; + var nodesJSON = {}; + var edgesJSON = {}; + attributesJSON = _modelAttributesNode + ? _modelAttributesNode?.toJSON() + : {}; + lodash.forEach(_nodes, function (val, key) { + nodesJSON[key] = val?.toJSON(); + }); + lodash.forEach(_edges, function (val, key) { + edgesJSON[key] = val?.toJSON(); + }); + return { + attributes: attributesJSON, + nodes: nodesJSON, + edges: edgesJSON, + }; + }, + /** + * Create model attributes node by its JSON representation + * @memberof canvas_widget.EntityManager# + * @param {object} json JSON representation + * @returns {canvas_widget.AbstractNode} + */ + createModelAttributesNodeFromJSON: function (json) { + var node = this.createModelAttributesNode(); + if (node) { + node.getLabel().getValue().setValue(json.label.value.value); + for (var attrId in json.attributes) { + if (json.attributes.hasOwnProperty(attrId)) { + var attr = node.getAttribute(attrId); + if (attr) { + attr.setValueFromJSON(json.attributes[attrId]); + } + } + } + } + return node; + }, + /** + * Create a new node by its JSON representation + * @memberof canvas_widget.EntityManager# + * @param {string} type Type of node + * @param {string} id Entity identifier of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {object} json JSON representation + * @param {number} zIndex Position of node on z-axis + * @returns {canvas_widget.AbstractNode} + */ + createNodeFromJSON: function ( + type, + id, + left, + top, + width, + height, + zIndex, + containment, + json, + y + ) { + var node = this.createNode( + type, + id, + left, + top, + width, + height, + zIndex, + containment, + json, + y, + false + ); + if (node) { + node.getLabel().getValue().setValue(json.label.value.value); + for (var attrId in json.attributes) { + if (json.attributes.hasOwnProperty(attrId)) { + var attr = node.getAttribute(attrId); + if (attr) { + attr.setValueFromJSON(json.attributes[attrId]); + } else { + var newId = attrId.replace(/[^\[\]]*/, id); + attr = node.getAttribute(newId); + if (attr) { + attr.setValueFromJSON(json.attributes[attrId]); + } + } + } + } + } + return node; + }, + /** + * Create a new node by its JSON representation + * @memberof canvas_widget.EntityManager# + * @param {string} type Type of edge + * @param {string} id Entity identifier of edge + * @param {canvas_widget.AbstractNode} source Source node entity id + * @param {canvas_widget.AbstractNode} target Target node entity id + * @param {object} json JSON representation + * @returns {canvas_widget.AbstractEdge} + */ + createEdgeFromJSON: function (type, id, source, target, json) { + const sourceNode = this.findNode(source); + const targetNode = this.findNode(target); + var edge = this.createEdge(type, id, sourceNode, targetNode, false); + if (edge) { + edge.getLabel().getValue().setValue(json.label.value.value); + for (var attrId in json.attributes) { + if (json.attributes.hasOwnProperty(attrId)) { + var attr = edge.getAttribute(attrId); + if (attr) { + attr.setValueFromJSON(json.attributes[attrId]); + } + } + } + } + return edge; + }, + /** + * Generate the 'Add node..' context menu options + * @param canvas Canvas to add node to + * @param left Position of node on x-axis + * @param top Position of node on <-axis + * @returns {object} Menu items + */ + generateAddNodeMenu: function (canvas, left, top) { + function makeAddNodeCallback(nodeType, width, height, containment) { + return function () { + canvas.createNode( + nodeType, + left, + top, + width, + height, + 32000, + containment + ); + }; + } + var items = {}, + nodeType, + _nodeTypes; + + if (_viewId && _layer === CONFIG.LAYER.MODEL) { + _nodeTypes = viewNodeTypes; + } else { + _nodeTypes = nodeTypes; + } + + for (nodeType in _nodeTypes) { + if (_nodeTypes.hasOwnProperty(nodeType)) { + if ( + _layer === CONFIG.LAYER.META && + !_viewId && + (nodeType === "ViewObject" || nodeType === "ViewRelationship") + ) + continue; + if ( + _layer === CONFIG.LAYER.META && + _viewId && + (nodeType === "Object" || + nodeType === "Relationship" || + nodeType === "Enumeration" || + nodeType === "Abstract Class") + ) + continue; + + items[nodeType] = { + name: ".." + nodeType, + callback: makeAddNodeCallback( + nodeType, + _nodeTypes[nodeType].DEFAULT_WIDTH, + _nodeTypes[nodeType].DEFAULT_HEIGHT, + _nodeTypes[nodeType].CONTAINMENT + ), + }; + } + } + return items; + }, + /** + * generates the context menu for the show and hide operations on node types + * @returns {object} + */ + generateVisibilityNodeMenu: function (visibility) { + var _applyVisibilityCallback = function (nodeType, vis) { + return function () { + if (vis !== "show" && vis !== "hide") return; + + var nodes; + if (_viewId && _layer === CONFIG.LAYER.MODEL) { + nodes = that.getNodesByViewType(nodeType); + } else { + nodes = that.getNodesByType(nodeType); + } + for (var nKey in nodes) { + if (nodes.hasOwnProperty(nKey)) { + nodes[nKey][vis](); + } + } + if (vis === "hide") { + this.data("show" + nodeType + "Disabled", true); + } else { + this.data("show" + nodeType + "Disabled", false); + } + + return false; + }; + }; + + var that = this; + var items = {}, + nodeType, + _nodeTypes; + + if (_viewId && _layer === CONFIG.LAYER.MODEL) { + _nodeTypes = viewNodeTypes; + } else { + _nodeTypes = nodeTypes; + } + + for (nodeType in _nodeTypes) { + if (_nodeTypes.hasOwnProperty(nodeType)) { + if ( + _layer === CONFIG.LAYER.META && + !_viewId && + (nodeType === "ViewObject" || nodeType === "ViewRelationship") + ) + continue; + if ( + _layer === CONFIG.LAYER.META && + _viewId && + (nodeType === "Object" || + nodeType === "Relationship" || + nodeType === "Enumeration" || + nodeType === "Abstract Class") + ) + continue; + + items[visibility + nodeType] = { + name: ".." + nodeType, + callback: _applyVisibilityCallback(nodeType, visibility), + disabled: (function (nodeType) { + return function () { + if (visibility === "hide") + return this.data(visibility + nodeType + "Disabled"); + else return !this.data(visibility + nodeType + "Disabled"); + }; + })(nodeType), + }; + } + } + return items; + }, + /** + * generates a the context menu for the show and hide operations on edge types + * @returns {object} + */ + generateVisibilityEdgeMenu: function (visibility) { + function _applyVisibilityCallback(edgeType, vis) { + return function () { + if (vis !== "show" && vis !== "hide") return; + var edges; + if (_viewId && _layer === CONFIG.LAYER.MODEL) { + edges = that.getEdgesByViewType(edgeType); + } else { + edges = that.getEdgesByType(edgeType); + } + for (var eKey in edges) { + if (edges.hasOwnProperty(eKey)) { + edges[eKey][vis](); + } + } + if (vis === "hide") { + this.data("show" + edgeType + "Disabled", true); + } else { + this.data("show" + edgeType + "Disabled", false); + } + }; + } + var that = this; + var items = {}, + edgeType, + _edgeTypes; + + if (_viewId && _layer === CONFIG.LAYER.MODEL) { + _edgeTypes = viewEdgeTypes; + } else { + _edgeTypes = edgeTypes; + } + + for (edgeType in _edgeTypes) { + if (_edgeTypes.hasOwnProperty(edgeType)) { + items[visibility + edgeType] = { + name: ".." + edgeType, + callback: _applyVisibilityCallback(edgeType, visibility), + disabled: (function (edgeType) { + return function () { + if (visibility === "hide") + return this.data(visibility + edgeType + "Disabled"); + else return !this.data(visibility + edgeType + "Disabled"); + }; + })(edgeType), + }; + } + } + return items; + }, + /** + * Generate the 'Connect to..' context menu options for the passed node + * @param {canvas_widget.AbstractNode} node + */ + generateConnectToMenu: function (node) { + function makeTargetNodeCallback(connectionType, targetNodeId) { + return function (/*key, opt*/) { + node + .getCanvas() + .createEdge(connectionType, node.getEntityId(), targetNodeId); + }; + } + + var connectionType, + sourceNodeTypes, + targetNodeTypes, + targetNodeType, + connectionItems, + targetNodeTypeItems, + targetNodeItems, + i, + numOfRelations, + j, + numOfTargetTypes, + targetNodes, + targetNodeId, + targetNode, + targetAppearance, + sourceAppearance = node.getAppearance(); + + connectionItems = {}; + for (connectionType in relations) { + if (relations.hasOwnProperty(connectionType)) { + targetNodeTypeItems = {}; + for ( + i = 0, numOfRelations = relations[connectionType].length; + i < numOfRelations; + i++ + ) { + sourceNodeTypes = relations[connectionType][i].sourceTypes; + targetNodeTypes = relations[connectionType][i].targetTypes; + if ( + sourceNodeTypes.indexOf(node.getType()) !== -1 || + (_layer === CONFIG.LAYER.MODEL && + _viewId && + sourceNodeTypes.indexOf(node.getCurrentViewType()) !== -1) + ) { + for ( + j = 0, numOfTargetTypes = targetNodeTypes.length; + j < numOfTargetTypes; + j++ + ) { + targetNodeType = targetNodeTypes[j]; + targetNodeItems = {}; + if (_viewId && _layer === CONFIG.LAYER.MODEL) { + targetNodes = this.getNodesByViewType(targetNodeType); + } else { + targetNodes = this.getNodesByType(targetNodeType); + } + for (targetNodeId in targetNodes) { + if (targetNodes.hasOwnProperty(targetNodeId)) { + targetNode = targetNodes[targetNodeId]; + if (targetNode === node) continue; + if ( + _layer === CONFIG.LAYER.MODEL && + _viewId && + targetNode.getCurrentViewType() === null + ) + continue; + targetAppearance = targetNode.getAppearance(); + if ( + !targetNode + .getNeighbors() + .hasOwnProperty(node.getEntityId()) + ) { + targetNodeItems[ + connectionType + targetNodeType + i + targetNodeId + ] = { + name: + ".." + + (targetNode.getLabel().getValue().getValue() || + targetNode.getType()), + callback: makeTargetNodeCallback( + connectionType, + targetNodeId + ), + distanceSquare: + Math.pow( + targetAppearance.left - sourceAppearance.left, + 2 + ) + + Math.pow( + targetAppearance.top - sourceAppearance.top, + 2 + ), + targetNodeId: + connectionType + targetNodeType + i + targetNodeId, + }; + } + } + } + if (lodash.size(targetNodeItems) > 0) { + var targetNodeItemsTmp = lodash.sortBy( + targetNodeItems, + "distanceSquare" + ); + targetNodeItems = {}; + for ( + var k = 0, numOfItems = targetNodeItemsTmp.length; + k < numOfItems; + k++ + ) { + targetNodeItems[k + targetNodeItemsTmp[k].targetNodeId] = + targetNodeItemsTmp[k]; + } + targetNodeTypeItems[connectionType + targetNodeType + i] = { + name: "..to " + targetNodeType + "..", + items: targetNodeItems, + }; + } + } + } + } + if (lodash.size(targetNodeTypeItems) > 0) { + connectionItems[connectionType] = { + name: "..with " + connectionType + "..", + items: targetNodeTypeItems, + }; + } + } + } + + return { + name: "Connect..", + items: connectionItems, + disabled: (function (connectionItems) { + return lodash.size(connectionItems) === 0; + })(connectionItems), + }; + }, + generateGuidanceMetamodel: function () { + var metamodel = this.generateMetaModel(); + var actionNodeLabels = []; + var createEntityNodeLabels = []; + //Create guidance metamodel + var guidanceMetamodel = { + attributes: {}, + nodes: {}, + edges: {}, + }; + + //Create initial node + var initialNode = { + label: guidancemodel.INITIAL_NODE_LABEL, + shape: { + shape: "", + color: "", + defaultWidth: 200, + defaultHeight: 60, + containment: false, + customShape: startActivityNodeHtml, + customAnchors: "", + }, + attributes: {}, + }; + + //Add a label attribute to the initial node + initialNode.attributes[Util.generateRandomId()] = { + key: "label", + value: "string", + }; + + guidanceMetamodel.nodes[Util.generateRandomId()] = initialNode; + + //Create final node + var finalNode = { + label: guidancemodel.ACTIVITY_FINAL_NODE_LABEL, + shape: { + shape: "circle", + color: "", + defaultWidth: 50, + defaultHeight: 50, + containment: false, + customShape: activityFinalNodeHtml, + customAnchors: ["Perimeter", { shape: "Circle", anchorCount: 60 }], + }, + attributes: {}, + }; + + guidanceMetamodel.nodes[Util.generateRandomId()] = finalNode; + + //Create merge node + var mergeNode = { + label: guidancemodel.MERGE_NODE_LABEL, + shape: { + shape: "diamond", + color: "yellow", + defaultWidth: 0, + defaultHeight: 0, + containment: false, + customShape: "", + customAnchors: "", + }, + attributes: {}, + }; + + guidanceMetamodel.nodes[Util.generateRandomId()] = mergeNode; + + //Create 'call activity node' + var callActivityNode = { + label: guidancemodel.CALL_ACTIVITY_NODE_LABEL, + shape: { + shape: "rounded_rectangle", + color: "", + defaultWidth: 100, + defaultHeight: 50, + containment: false, + customShape: callActivityNodeHtml, + customAnchors: "", + }, + attributes: {}, + }; + + actionNodeLabels.push(guidancemodel.CALL_ACTIVITY_NODE_LABEL); + + //Add a label attribute to the call activity node + callActivityNode.attributes[Util.generateRandomId()] = { + key: "label", + value: "string", + }; + + guidanceMetamodel.nodes[Util.generateRandomId()] = callActivityNode; + + //Create concurrency node + var concurrencyNode = { + label: guidancemodel.CONCURRENCY_NODE_LABEL, + shape: { + shape: "rectangle", + color: "black", + defaultWidth: 10, + defaultHeight: 200, + containment: false, + customShape: "", + customAnchors: "", + }, + attributes: {}, + }; + + guidanceMetamodel.nodes[Util.generateRandomId()] = concurrencyNode; + + var flowEdgeRelations = []; + var dataFlowEdgeRelations = []; + + var nodes = metamodel.nodes; + for (var nodeId in nodes) { + if (nodes.hasOwnProperty(nodeId)) { + var node = nodes[nodeId]; + + var createObjectNodeToEntityNodeRelation = { + sourceTypes: [], + targetTypes: [], + }; + //Generate the 'create object node' + var label = guidancemodel.getCreateObjectNodeLabelForType( + node.label + ); + createObjectNodeToEntityNodeRelation.sourceTypes.push(label); + actionNodeLabels.push(label); + createEntityNodeLabels.push(label); + var id = Util.generateRandomId(); + guidanceMetamodel.nodes[id] = { + label: label, + attributes: {}, + shape: { + shape: "rounded_rectangle", + color: "", + defaultWidth: 100, + defaultHeight: 50, + containment: false, + customShape: lodash.template(actionNodeHtml)({ + label: node.label, + icon: "plus", + }), + customAnchors: "", + }, + }; + + guidanceMetamodel.nodes[id]; + + //Generate the 'entity node' + var entityLabel = guidancemodel.getEntityNodeLabelForType( + node.label + ); + createObjectNodeToEntityNodeRelation.targetTypes.push(label); + id = Util.generateRandomId(); + guidanceMetamodel.nodes[id] = { + label: entityLabel, + attributes: {}, + shape: { + shape: "rectangle", + color: "", + defaultWidth: 100, + defaultHeight: 50, + containment: false, + customShape: lodash.template(entityNodeHtml)({ + icon: "square", + label: node.label, + }), + customAnchors: "", + }, + }; + + //Generate the 'set property node' + setPropertyLabel = guidancemodel.getSetPropertyNodeLabelForType( + node.label + ); + actionNodeLabels.push(setPropertyLabel); + id = Util.generateRandomId(); + guidanceMetamodel.nodes[id] = { + label: setPropertyLabel, + attributes: {}, + shape: { + shape: "", + defaultWidth: 130, + defaultHeight: 50, + containment: false, + customShape: lodash.template(setPropertyNodeHtml)(), + customAnchors: "", + }, + }; + + var options = {}; + for (var attributeId in node.attributes) { + var attribute = node.attributes[attributeId]; + options[attribute.key] = attribute.key; + } + + guidanceMetamodel.nodes[id].attributes[Util.generateRandomId()] = { + key: "Property", + value: "Value", + options: options, + }; + + guidanceMetamodel.nodes[id]; + + //Define the 'create object node' to 'entity node' relation + dataFlowEdgeRelations.push({ + sourceTypes: [label], + targetTypes: [entityLabel], + }); + + //Define the 'entity node' to 'set property node' relation + dataFlowEdgeRelations.push({ + sourceTypes: [entityLabel], + targetTypes: [setPropertyLabel], + }); + + //Define the 'entity node' to 'create relationship node' relation + for (var edgeId in metamodel.edges) { + var edge = metamodel.edges[edgeId]; + for (var relationId in edge.relations) { + var relation = edge.relations[relationId]; + if ( + relation.sourceTypes.indexOf(node.label) > -1 || + relation.targetTypes.indexOf(node.label) > -1 + ) { + dataFlowEdgeRelations.push({ + sourceTypes: [entityLabel], + targetTypes: + guidancemodel.getCreateRelationshipNodeLabelForType( + edge.label + ), + }); + break; + } + } + } + } + } + var edgesByLabel = {}; + + var edges = metamodel.edges; + for (var edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + var edge = edges[edgeId]; + //Generate 'create relationship node' + var label = guidancemodel.getCreateRelationshipNodeLabelForType( + edge.label + ); + actionNodeLabels.push(label); + createEntityNodeLabels.push(label); + edgesByLabel[edge.label] = edge; + + var id = Util.generateRandomId(); + guidanceMetamodel.nodes[id] = { + label: label, + attributes: {}, + shape: { + shape: "rounded_rectangle", + color: "", + defaultWidth: 100, + defaultHeight: 50, + containment: false, + customShape: lodash.template(actionNodeHtml)({ + label: edge.label, + icon: "plus", + }), + customAnchors: "", + }, + }; + + guidanceMetamodel.nodes[id]; + + //Generate 'entity node' + var entityLabel = guidancemodel.getEntityNodeLabelForType( + edge.label + ); + + var id = Util.generateRandomId(); + guidanceMetamodel.nodes[id] = { + label: entityLabel, + attributes: {}, + shape: { + shape: "rectangle", + color: "black", + defaultWidth: 100, + defaultHeight: 50, + containment: false, + customShape: lodash.template(entityNodeHtml)({ + icon: "exchange", + label: edge.label, + }), + customAnchors: "", + }, + }; + + guidanceMetamodel.nodes[id]; + + //Generate the 'set property node' + if (Object.keys(edge.attributes).length > 0) { + var setPropertyLabel = + guidancemodel.getSetPropertyNodeLabelForType(edge.label); + actionNodeLabels.push(setPropertyLabel); + id = Util.generateRandomId(); + guidanceMetamodel.nodes[id] = { + label: setPropertyLabel, + attributes: {}, + shape: { + shape: "", + defaultWidth: 0, + defaultHeight: 0, + containment: false, + customShape: lodash.template(setPropertyNodeHtml)({ + type: setPropertyLabel, + color: "white", + }), + customAnchors: "", + }, + }; + + var options = {}; + for (var attributeId in edge.attributes) { + var attribute = edge.attributes[attributeId]; + options[attribute.key] = attribute.key; + } + + guidanceMetamodel.nodes[id].attributes[Util.generateRandomId()] = + { + key: "Property", + value: "Value", + options: options, + }; + } + + //Define the 'create relationship node' to 'entity node' relation + dataFlowEdgeRelations.push({ + sourceTypes: [label], + targetTypes: [entityLabel], + }); + + //Define the 'entity node' to 'set property node' relation + dataFlowEdgeRelations.push({ + sourceTypes: [entityLabel], + targetTypes: [setPropertyLabel], + }); + } + } + + //Create the flow edge + + //Relations between all action nodes + flowEdgeRelations = flowEdgeRelations.concat({ + sourceTypes: actionNodeLabels, + targetTypes: actionNodeLabels.concat([ + guidancemodel.MERGE_NODE_LABEL, + guidancemodel.ACTIVITY_FINAL_NODE_LABEL, + guidancemodel.CONCURRENCY_NODE_LABEL, + ]), + }); + + //Relations for the initial node + flowEdgeRelations = flowEdgeRelations.concat({ + sourceTypes: [guidancemodel.INITIAL_NODE_LABEL], + targetTypes: [ + guidancemodel.CALL_ACTIVITY_NODE_LABEL, + guidancemodel.MERGE_NODE_LABEL, + guidancemodel.CONCURRENCY_NODE_LABEL, + ].concat(createEntityNodeLabels), + }); + + //Relations for the merge node + flowEdgeRelations = flowEdgeRelations.concat({ + sourceTypes: [guidancemodel.MERGE_NODE_LABEL], + targetTypes: [ + guidancemodel.ACTIVITY_FINAL_NODE_LABEL, + guidancemodel.MERGE_NODE_LABEL, + guidancemodel.CONCURRENCY_NODE_LABEL, + ].concat(actionNodeLabels), + }); + + //Relations for the concurrency node + flowEdgeRelations = flowEdgeRelations.concat({ + sourceTypes: [guidancemodel.CONCURRENCY_NODE_LABEL], + targetTypes: [ + guidancemodel.ACTIVITY_FINAL_NODE_LABEL, + guidancemodel.CONCURRENCY_NODE_LABEL, + guidancemodel.MERGE_NODE_LABEL, + ].concat(actionNodeLabels), + }); + + //Create the action flow edge + guidanceMetamodel.edges[Util.generateRandomId()] = { + label: "Action flow edge", + shape: { + arrow: "unidirassociation", + shape: "curved", + color: "black", + overlay: "", + overlayPosition: "top", + overlayRotate: true, + }, + relations: flowEdgeRelations, + }; + + //Create the data flow edge + var dataFlowEdge = { + label: "Data flow edge", + shape: { + arrow: "unidirassociation", + shape: "curved", + color: "black", + overlay: "", + overlayPosition: "top", + overlayRotate: true, + }, + attributes: {}, + relations: dataFlowEdgeRelations, + }; + + dataFlowEdge.attributes[Util.generateRandomId()] = { + key: "Destination", + value: "Value", + options: { + Source: "Source", + Target: "Target", + }, + }; + guidanceMetamodel.edges[Util.generateRandomId()] = dataFlowEdge; + + //Create the association edge + guidanceMetamodel.edges[Util.generateRandomId()] = { + label: "Association edge", + shape: { + arrow: "unidirassociation", + shape: "curved", + color: "", + dashstyle: "4 2", + overlay: "", + overlayPosition: "hidden", + overlayRotate: true, + }, + relations: [ + { + sourceTypes: [guidancemodel.CALL_ACTIVITY_NODE_LABEL], + targetTypes: [guidancemodel.INITIAL_NODE_LABEL], + }, + ], + }; + + return guidanceMetamodel; + }, + generateLogicalGuidanceRepresentation: function (m) { + const dataMap = y.getMap("data"); + var graph = new graphlib.Graph(); + var model; + if (m) model = m; + else model = dataMap.get("guidancemodel"); + if (!model) return null; + var nodes = model.nodes; + var edges = model.edges; + //Returns successor node which belong to the action flow (everything except entity nodes) + var getFlowSuccessors = function (nodeId) { + var targets = []; + var labels = []; + for (var edgeId in edges) { + var edge = edges[edgeId]; + if (edge.source == nodeId) { + //var targetType = nodes[edge.target].type + if (edge.type == "Action flow edge") { + targets.push(edge.target); + labels.push(edge.label.value.value); + } + } + } + return { + targets: targets, + labels: labels, + }; + }; + + var getEntitySuccessor = function (nodeId) { + for (var edgeId in edges) { + var edge = edges[edgeId]; + if (edge.source == nodeId) { + var targetType = nodes[edge.target].type; + if ((targetType = guidancemodel.isEntityNodeLabel(targetType))) + return edge.target; + } + } + return ""; + }; + + var getEntityPredecessorsForCreateRelationshipAction = function ( + nodeId + ) { + var entities = { + Source: "", + Target: "", + }; + for (var edgeId in edges) { + var edge = edges[edgeId]; + if (edge.target == nodeId) { + var sourceType = nodes[edge.source].type; + if ((sourceType = guidancemodel.isEntityNodeLabel(sourceType))) { + var destination = getAttributeValue(edge, "Destination"); + entities[destination] = edge.source; + } + } + } + return entities; + }; + + var getEntityPredecessorForSetPropertyAction = function (nodeId) { + for (var edgeId in edges) { + var edge = edges[edgeId]; + if (edge.target == nodeId) { + var sourceType = nodes[edge.source].type; + if ((sourceType = guidancemodel.isEntityNodeLabel(sourceType))) { + return edge.source; + } + } + } + return ""; + }; + + var getInitialNodeForCallActivityAction = function (nodeId) { + for (var edgeId in edges) { + var edge = edges[edgeId]; + if (edge.source == nodeId && edge.type == "Association edge") { + return edge.target; + } + } + return ""; + }; + + var getAttributeValue = function (node, attributeName) { + for (var attributeId in node.attributes) { + var attribute = node.attributes[attributeId]; + if (attribute.name == attributeName) return attribute.value.value; + } + return ""; + }; + + for (var nodeId in nodes) { + var node = nodes[nodeId]; + var type = node.type; + var subType = ""; + + if (type == guidancemodel.INITIAL_NODE_LABEL) { + var successors = getFlowSuccessors(nodeId); + graph.setNode(nodeId, { + type: "INITIAL_NODE", + name: getAttributeValue(node, "label"), + }); + for (var i = 0; i < successors.targets.length; i++) { + graph.setEdge( + nodeId, + successors.targets[i], + successors.labels[i] + ); + } + } else if (type == guidancemodel.MERGE_NODE_LABEL) { + var successors = getFlowSuccessors(nodeId); + graph.setNode(nodeId, { + type: "MERGE_NODE", + }); + for (var i = 0; i < successors.targets.length; i++) { + graph.setEdge( + nodeId, + successors.targets[i], + successors.labels[i] + ); + } + } else if (type == guidancemodel.CONCURRENCY_NODE_LABEL) { + var successors = getFlowSuccessors(nodeId); + graph.setNode(nodeId, { + type: "CONCURRENCY_NODE", + }); + for (var i = 0; i < successors.targets.length; i++) { + graph.setEdge( + nodeId, + successors.targets[i], + successors.labels[i] + ); + } + } else if (type == guidancemodel.ACTIVITY_FINAL_NODE_LABEL) { + graph.setNode(nodeId, { + type: "ACTIVITY_FINAL_NODE", + }); + } else if ((subType = guidancemodel.isCreateObjectNodeLabel(type))) { + var successors = getFlowSuccessors(nodeId); + graph.setNode(nodeId, { + type: "CREATE_OBJECT_ACTION", + objectType: subType, + createdObjectId: getEntitySuccessor(nodeId), + }); + for (var i = 0; i < successors.targets.length; i++) { + graph.setEdge( + nodeId, + successors.targets[i], + successors.labels[i] + ); + } + } else if ( + (subType = guidancemodel.isCreateRelationshipNodeLabel(type)) + ) { + var entities = + getEntityPredecessorsForCreateRelationshipAction(nodeId); + var successors = getFlowSuccessors(nodeId); + graph.setNode(nodeId, { + type: "CREATE_RELATIONSHIP_ACTION", + relationshipType: subType, + createdRelationshipId: getEntitySuccessor(nodeId), + sourceObjectId: entities["Source"], + targetObjectId: entities["Target"], + }); + for (var i = 0; i < successors.targets.length; i++) { + graph.setEdge( + nodeId, + successors.targets[i], + successors.labels[i] + ); + } + } else if ((subType = guidancemodel.isSetPropertyNodeLabel(type))) { + var successors = getFlowSuccessors(nodeId); + graph.setNode(nodeId, { + type: "SET_PROPERTY_ACTION", + entityType: subType, + propertyName: getAttributeValue(node, "Property"), + sourceObjectId: getEntityPredecessorForSetPropertyAction(nodeId), + }); + for (var i = 0; i < successors.targets.length; i++) { + graph.setEdge( + nodeId, + successors.targets[i], + successors.labels[i] + ); + } + } else if (type == guidancemodel.CALL_ACTIVITY_NODE_LABEL) { + var successors = getFlowSuccessors(nodeId); + graph.setNode(nodeId, { + type: "CALL_ACTIVITY_ACTION", + initialNodeId: getInitialNodeForCallActivityAction(nodeId), + }); + for (var i = 0; i < successors.targets.length; i++) { + graph.setEdge( + nodeId, + successors.targets[i], + successors.labels[i] + ); + } + } + } + return graphlib.json.write(graph); + }, + generateGuidanceRules: function () { + var guidanceRules = { objectToolRules: [] }; + var nodes = guidancemodel.guidancemodel.nodes; + var edges = guidancemodel.guidancemodel.edges; + for (var nodeId in nodes) { + var node = nodes[nodeId]; + var type = node.type; + + if (guidancemodel.isObjectToolType(type)) { + var srcObjectType = + guidancemodel.getObjectTypeForObjectToolType(type); + var destObjectType = null; + var relationshipType = null; + var relevantEdges = []; + var label = ""; + //Get the label attribute + for (var attributeId in node.attributes) { + if (node.attributes[attributeId].name == "label") + label = node.attributes[attributeId].value.value; + } + var edgeId; + for (edgeId in edges) { + if (edges[edgeId].source == nodeId) + relevantEdges.push(edges[edgeId]); + } + for (var i = 0; i < relevantEdges.length; i++) { + var edge = relevantEdges[i]; + var target = nodes[edge.target]; + if (guidancemodel.isObjectContextType(target.type)) { + destObjectType = + guidancemodel.getObjectTypeForObjectContextType(target.type); + } else if (guidancemodel.isRelationshipContextType(target.type)) { + relationshipType = + guidancemodel.getRelationshipTypeForRelationshipContextType( + target.type + ); + } + } + if (destObjectType !== null && relationshipType !== null) { + var objectToolRule = { + srcObjectType: srcObjectType, + destObjectType: destObjectType, + relationshipType: relationshipType, + label: label, + }; + guidanceRules.objectToolRules.push(objectToolRule); + } + } + } + return guidanceRules; + }, + /** + * Generate the JSON Representation of the meta-model for a new editor instance based on the current graph + * @returns {{nodes: {}, edges: {}}} JSON representation of meta model + */ + generateMetaModel: function () { + /** + * Determine the type of the concrete classes (ObjectNodes) of the class diagram contained in the sub graph rooted by the passed node + * @param node Node to start with + * @param [visitedNodes] List of node that already have been visited + * @returns {object} + */ + function getConcreteObjectNodeTypes(node, visitedNodes) { + var edgeId, + edge, + ingoingEdges, + source, + type, + classTypes = []; + + if (!visitedNodes) visitedNodes = []; + + if (visitedNodes.indexOf(node) !== -1) return []; + + visitedNodes.push(node); + + type = node.getLabel().getValue().getValue(); + if (node instanceof ObjectNode && classTypes.indexOf(type) === -1) { + classTypes.push(type); + } + + ingoingEdges = node.getIngoingEdges(); + for (edgeId in ingoingEdges) { + if (ingoingEdges.hasOwnProperty(edgeId)) { + edge = ingoingEdges[edgeId]; + source = edge.getSource(); + if ( + (edge instanceof GeneralisationEdge && + source instanceof ObjectNode) || + (edge instanceof GeneralisationEdge && + source instanceof AbstractClassNode) + ) { + classTypes = classTypes.concat( + getConcreteObjectNodeTypes(source, visitedNodes) + ); + } + } + } + return classTypes; + } + + /** + * Determine the attributes of the passed node by traversing the underlying class diagram + * @param node Node to start with + * @param [visitedNodes] List of node that already have been visited + * @returns {object} + */ + function getNodeAttributes(node, visitedNodes) { + var nodeAttributes, attributeId, attribute; + var edgeId, edge, edges; + var source, target; + var neighbor, options; + var attributes = {}; + var obj = {}; + + if (!visitedNodes) visitedNodes = []; + + if (visitedNodes.indexOf(node) !== -1) return {}; + + visitedNodes.push(node); + + //Traverse edges to check for inheritance and linked enums + edges = node.getOutgoingEdges(); + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + source = edge.getSource(); + target = edge.getTarget(); + + //Does the node inherit attributes from a parent node? + if ( + (edge instanceof GeneralisationEdge && + target instanceof AbstractClassNode) || + (edge instanceof GeneralisationEdge && + node instanceof ObjectNode && + target instanceof ObjectNode) || + (edge instanceof GeneralisationEdge && + node instanceof RelationshipNode && + target instanceof RelationshipNode) || + (edge instanceof GeneralisationEdge && + node instanceof EnumNode && + target instanceof EnumNode) + ) { + Util.merge(attributes, getNodeAttributes(target, visitedNodes)); + + //Is there an enum linked to the node + } else if ( + (edge instanceof BiDirAssociationEdge && + ((target === node && + (neighbor = source) instanceof EnumNode) || + (source === node && + (neighbor = target) instanceof EnumNode))) || + (edge instanceof UniDirAssociationEdge && + (neighbor = target) instanceof EnumNode) + ) { + options = {}; + nodeAttributes = {}; + Util.merge(nodeAttributes, getNodeAttributes(neighbor, [])); + for (attributeId in nodeAttributes) { + if (nodeAttributes.hasOwnProperty(attributeId)) { + attribute = nodeAttributes[attributeId]; + options[attribute.value] = attribute.value; + } + } + obj = {}; + obj[neighbor.getEntityId()] = { + key: edge.getLabel().getValue().getValue(), + value: neighbor.getLabel().getValue().getValue(), + options: options, + }; + Util.merge(attributes, obj); + } + } + } + //Compute node attributes + nodeAttributes = node.getAttribute("[attributes]").getAttributes(); + for (attributeId in nodeAttributes) { + if (nodeAttributes.hasOwnProperty(attributeId)) { + attribute = nodeAttributes[attributeId]; + if (node instanceof RelationshipNode) { + obj = {}; + obj[attributeId] = { + key: attribute.getKey().getValue(), + value: attribute.getValue().getValue(), + position: attribute.getValue2().getValue(), + }; + Util.merge(attributes, obj); + } else if (node instanceof EnumNode) { + obj = {}; + obj[attributeId] = { + value: attribute.getValue().getValue(), + }; + Util.merge(attributes, obj); + } else { + obj = {}; + obj[attributeId] = { + key: attribute.getKey().getValue(), + value: attribute.getValue().getValue(), + }; + Util.merge(attributes, obj); + } + } + } + return attributes; + } + + var metamodel = { + attributes: {}, + nodes: {}, + edges: {}, + }; + + var nodeId, node; + var attributes; + var edge, edgeId, edges; + var source, target; + var neighbor; + var groupSource, groupTarget; + var groupNeighbor; + var shape; + var sourceTypes, targetTypes, concreteTypes; + var groupSourceTypes, groupTargetTypes, groupConcreteTypes; + var relations; + var groupEdge, groupEdgeId, groupEdges; + + for (nodeId in _nodes) { + if (_nodes.hasOwnProperty(nodeId)) { + node = _nodes[nodeId]; + if (node instanceof ObjectNode) { + if ( + node.getLabel().getValue().getValue() === "Model Attributes" + ) { + attributes = getNodeAttributes(node); + metamodel.attributes = attributes; + } else { + attributes = getNodeAttributes(node); + edges = node.getEdges(); + shape = null; + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + source = edge.getSource(); + target = edge.getTarget(); + if ( + (edge instanceof BiDirAssociationEdge && + ((target === node && + (neighbor = source) instanceof NodeShapeNode) || + (source === node && + (neighbor = target) instanceof NodeShapeNode))) || + (edge instanceof UniDirAssociationEdge && + (neighbor = target) instanceof NodeShapeNode) + ) { + shape = { + shape: neighbor + .getAttribute(neighbor.getEntityId() + "[shape]") + .getValue() + .getValue(), + color: neighbor + .getAttribute(neighbor.getEntityId() + "[color]") + .getValue() + .getValue(), + defaultWidth: parseInt( + neighbor + .getAttribute( + neighbor.getEntityId() + "[defaultWidth]" + ) + .getValue() + .getValue() + ), + defaultHeight: parseInt( + neighbor + .getAttribute( + neighbor.getEntityId() + "[defaultHeight]" + ) + .getValue() + .getValue() + ), + containment: neighbor + .getAttribute( + neighbor.getEntityId() + "[containment]" + ) + .getValue() + .getValue(), + customShape: neighbor + .getAttribute( + neighbor.getEntityId() + "[customShape]" + ) + .getValue() + .getValue(), + customAnchors: neighbor + .getAttribute( + neighbor.getEntityId() + "[customAnchors]" + ) + .getValue() + .getValue(), + }; + } + } + } + metamodel.nodes[nodeId] = { + label: node.getLabel().getValue().getValue(), + attributes: attributes, + shape: shape || { + shape: "rectangle", + color: "white", + containment: false, + customShape: "", + customAnchors: "", + defaultWidth: 0, + defaultHeight: 0, + }, + }; + } + } else if (node instanceof RelationshipNode) { + attributes = getNodeAttributes(node); + edges = node.getEdges(); + sourceTypes = []; + targetTypes = []; + relations = []; + shape = null; + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + source = edge.getSource(); + target = edge.getTarget(); + if ( + edge instanceof BiDirAssociationEdge && + ((target === node && + (neighbor = source) instanceof ObjectNode) || + (source === node && + (neighbor = target) instanceof ObjectNode)) + ) { + concreteTypes = getConcreteObjectNodeTypes(neighbor); + sourceTypes = sourceTypes.concat(concreteTypes); + targetTypes = targetTypes.concat(concreteTypes); + } else if ( + edge instanceof UniDirAssociationEdge && + source === node && + target instanceof ObjectNode + ) { + targetTypes = targetTypes.concat( + getConcreteObjectNodeTypes(target) + ); + } else if ( + edge instanceof UniDirAssociationEdge && + target === node && + source instanceof ObjectNode + ) { + sourceTypes = sourceTypes.concat( + getConcreteObjectNodeTypes(source) + ); + } else if ( + edge instanceof BiDirAssociationEdge && + ((target === node && + (neighbor = source) instanceof AbstractClassNode) || + (source === node && + (neighbor = target) instanceof AbstractClassNode)) + ) { + concreteTypes = getConcreteObjectNodeTypes(neighbor); + sourceTypes = sourceTypes.concat(concreteTypes); + targetTypes = targetTypes.concat(concreteTypes); + } else if ( + edge instanceof UniDirAssociationEdge && + source === node && + target instanceof AbstractClassNode + ) { + targetTypes = targetTypes.concat( + getConcreteObjectNodeTypes(target) + ); + } else if ( + edge instanceof UniDirAssociationEdge && + target === node && + source instanceof AbstractClassNode + ) { + sourceTypes = sourceTypes.concat( + getConcreteObjectNodeTypes(source) + ); + } else if ( + (edge instanceof BiDirAssociationEdge && + ((target === node && + (neighbor = source) instanceof EdgeShapeNode) || + (source === node && + (neighbor = target) instanceof EdgeShapeNode))) || + (edge instanceof UniDirAssociationEdge && + source === node && + (neighbor = target) instanceof EdgeShapeNode) + ) { + shape = { + arrow: neighbor + .getAttribute(neighbor.getEntityId() + "[arrow]") + .getValue() + .getValue(), + shape: neighbor + .getAttribute(neighbor.getEntityId() + "[shape]") + .getValue() + .getValue(), + color: neighbor + .getAttribute(neighbor.getEntityId() + "[color]") + .getValue() + .getValue(), + overlay: neighbor + .getAttribute(neighbor.getEntityId() + "[overlay]") + .getValue() + .getValue(), + overlayPosition: neighbor + .getAttribute( + neighbor.getEntityId() + "[overlayPosition]" + ) + .getValue() + .getValue(), + overlayRotate: neighbor + .getAttribute( + neighbor.getEntityId() + "[overlayRotate]" + ) + .getValue() + .getValue(), + }; + } else if ( + edge instanceof GeneralisationEdge && + target === node && + (neighbor = source) instanceof RelationshipGroupNode + ) { + groupEdges = neighbor.getEdges(); + groupSourceTypes = []; + groupTargetTypes = []; + for (groupEdgeId in groupEdges) { + if (groupEdges.hasOwnProperty(groupEdgeId)) { + groupEdge = groupEdges[groupEdgeId]; + groupSource = groupEdge.getSource(); + groupTarget = groupEdge.getTarget(); + if ( + groupEdge instanceof BiDirAssociationEdge && + ((groupTarget === neighbor && + (groupNeighbor = groupSource) instanceof + ObjectNode) || + (groupSource === neighbor && + (groupNeighbor = groupTarget) instanceof + ObjectNode)) + ) { + groupConcreteTypes = + getConcreteObjectNodeTypes(groupNeighbor); + groupSourceTypes = + groupSourceTypes.concat(groupConcreteTypes); + groupTargetTypes = + groupTargetTypes.concat(groupConcreteTypes); + } else if ( + groupEdge instanceof UniDirAssociationEdge && + groupSource === neighbor && + groupTarget instanceof ObjectNode + ) { + groupTargetTypes = groupTargetTypes.concat( + getConcreteObjectNodeTypes(groupTarget) + ); + } else if ( + groupEdge instanceof UniDirAssociationEdge && + groupTarget === neighbor && + groupSource instanceof ObjectNode + ) { + groupSourceTypes = groupSourceTypes.concat( + getConcreteObjectNodeTypes(groupSource) + ); + } else if ( + groupEdge instanceof BiDirAssociationEdge && + ((groupTarget === neighbor && + (groupNeighbor = groupSource) instanceof + AbstractClassNode) || + (groupSource === neighbor && + (groupNeighbor = groupTarget) instanceof + AbstractClassNode)) + ) { + groupConcreteTypes = + getConcreteObjectNodeTypes(groupNeighbor); + groupSourceTypes = + groupSourceTypes.concat(groupConcreteTypes); + groupTargetTypes = + groupTargetTypes.concat(groupConcreteTypes); + } else if ( + groupEdge instanceof UniDirAssociationEdge && + groupSource === neighbor && + groupTarget instanceof AbstractClassNode + ) { + groupTargetTypes = groupTargetTypes.concat( + getConcreteObjectNodeTypes(groupTarget) + ); + } else if ( + groupEdge instanceof UniDirAssociationEdge && + groupTarget === neighbor && + groupSource instanceof AbstractClassNode + ) { + groupSourceTypes = groupSourceTypes.concat( + getConcreteObjectNodeTypes(groupSource) + ); + } + } + } + + if ( + groupSourceTypes.length > 0 && + groupTargetTypes.length > 0 + ) { + relations.push({ + sourceTypes: groupSourceTypes, + targetTypes: groupTargetTypes, + }); + } + } + } + } + + if (sourceTypes.length > 0 && targetTypes.length > 0) { + relations.push({ + sourceTypes: sourceTypes, + targetTypes: targetTypes, + }); + } + + metamodel.edges[nodeId] = { + label: node.getLabel().getValue().getValue(), + shape: shape || { + arrow: "bidirassociation", + shape: "straight", + color: "black", + overlay: "", + overlayPosition: "top", + overlayRotate: true, + }, + relations: relations, + attributes: attributes, + }; + } + } + } + return metamodel; + }, + /** + * Store current graph representation in the ROLE space + * @returns {Deferred} + */ + storeData: function () { + var resourceSpace = new openapp.oo.Resource(openapp.param.space()); + + var data = this.graphToJSON(); + + var resourcesToSave = []; + var promises = []; + + //In the guidance model editor update the guidance model + if (guidancemodel.isGuidanceEditor()) { + resourcesToSave.push({ + typeName: CONFIG.NS.MY.GUIDANCEMODEL, + representation: data, + }); + } + //In the metamodel editor create the guidance metamodel needed for the guidance editor + else if (!metamodel.hasOwnProperty("nodes")) { + resourcesToSave.push({ + typeName: CONFIG.NS.MY.METAMODELPREVIEW, + representation: this.generateMetaModel(), + }); + resourcesToSave.push({ + typeName: CONFIG.NS.MY.GUIDANCEMETAMODEL, + representation: this.generateGuidanceMetamodel(), + }); + resourcesToSave.push({ + typeName: CONFIG.NS.MY.MODEL, + representation: data, + }); + } + //In the model editor just update the model + else { + resourcesToSave.push({ + typeName: CONFIG.NS.MY.MODEL, + representation: data, + }); + } + + var recreateResource = function (type, representation) { + var deferred = $.Deferred(); + var innerDeferred = $.Deferred(); + //noinspection JSUnusedGlobalSymbols + resourceSpace.getSubResources({ + relation: openapp.ns.role + "data", + type: type, + onEach: function (doc) { + doc.del(); + }, + onAll: function () { + innerDeferred.resolve(); + }, + }); + innerDeferred.then(function () { + resourceSpace.create({ + relation: openapp.ns.role + "data", + type: type, + representation: representation, + callback: function () { + deferred.resolve(); + }, + }); + }); + return deferred.promise(); + }; + + for (var i = 0; i < resourcesToSave.length; i++) { + var item = resourcesToSave[i]; + promises.push(recreateResource(item.typeName, item.representation)); + } + + return $.when.apply($, promises); + }, + storeDataYjs: function () { + var data = this.graphToJSON(); + const dataMap = y.getMap("data"); + window.y.transact(() => { + if (guidancemodel.isGuidanceEditor()) { + dataMap.set("guidancemodel", data); + } else if (!metamodel) { + dataMap.set("metamodelpreview", this.generateMetaModel()); + dataMap.set("guidancemetamodel", this.generateGuidanceMetamodel()); + dataMap.set("model", data); + } else { + dataMap.set("model", data); + } + }); + }, + /** + * Delete the Model Attribute Node + */ + deleteModelAttribute: function () { + _modelAttributesNode = null; + }, + /** + * resets the EntityManager + */ + reset: function () { + _nodes = {}; + _edges = {}; + this.deleteModelAttribute(); + }, + /** + * initializes the node types + * @param vls the vvs + */ + initNodeTypes: function (vls) { + nodeTypes = _initNodeTypes(vls); + }, + /** + * initializes the view edge types + * @param vls the vvs + */ + initEdgeTypes: function (vls) { + var res = _initEdgeTypes(vls); + edgeTypes = res.edgeTypes; + relations = res.relations; + }, + /** + * initializes both the node types- and the edge types Object + * @param vls the vvs + */ + initModelTypes: function (vls) { + this.initNodeTypes(vls); + this.initEdgeTypes(vls); + }, + /** + * Get the node type by its name + * @param type the name of the node type + * @returns {object} + */ + getNodeType: function (type) { + return nodeTypes.hasOwnProperty(type) ? nodeTypes[type] : null; + }, + /** + * Get the edge type bt its name + * @param {string} type the name of the edge type + * @returns {*} + */ + getEdgeType: function (type) { + return edgeTypes.hasOwnProperty(type) ? edgeTypes[type] : null; + }, + /** + * initializes the node types of a view + * @param vvs + */ + initViewNodeTypes: function (vvs) { + //delete the old view type references + for (var nodeTypeName in nodeTypes) { + if (nodeTypes.hasOwnProperty(nodeTypeName)) { + delete nodeTypes[nodeTypeName].VIEWTYPE; + } + } + viewNodeTypes = _initNodeTypes(vvs); + }, + /** + * initializes the edge types of a view + * @param vvs + */ + initViewEdgeTypes: function (vvs) { + //delete the old view type references + for (var edgeTypeName in edgeTypes) { + if (edgeTypes.hasOwnProperty(edgeTypeName)) { + delete edgeTypes[edgeTypeName].VIEWTYPE; + } + } + var res = _initEdgeTypes(vvs); + viewEdgeTypes = res.edgeTypes; + relations = res.relations; + }, + /** + * initializes the node and edge types of view + * @param vvs + */ + initViewTypes: function (vvs) { + this.setViewId(vvs.id); + this.initViewNodeTypes(vvs); + this.initViewEdgeTypes(vvs); + }, + /** + * get a view node type + * @param {string} type the name of the view type + * @returns {*} + */ + getViewNodeType: function (type) { + return viewNodeTypes.hasOwnProperty(type) ? viewNodeTypes[type] : null; + }, + /** + * get a view edge type + * @param {string} type the name of the view edge type + * @returns {*} + */ + getViewEdgeType: function (type) { + return viewEdgeTypes.hasOwnProperty(type) ? viewEdgeTypes[type] : null; + }, + /** + * set the identifier of the view + * @param {string} viewId + */ + setViewId: function (viewId) { + _viewId = viewId; + }, + /** + * get the identifier of the view + * @returns {*} + */ + getViewId: function () { + return _viewId; + }, + /** + * get nodes by view type + * @param {string} type the name of the view type + * @returns {object} a map of objects with key as identifier and value as Node + */ + getNodesByViewType: function (type) { + if (viewNodeTypes.hasOwnProperty(type)) { + return this.getNodesByType( + viewNodeTypes[type].getTargetNodeType().TYPE + ); + } + return null; + }, + /** + * get edges by view type + * @param {string}type the view type + * @returns {*} + */ + getEdgesByViewType: function (type) { + if (viewEdgeTypes.hasOwnProperty(type)) { + return this.getEdgesByType( + viewEdgeTypes[type].getTargetEdgeType().TYPE + ); + } + return null; + }, + /** + * Get the current layer you are operating on + * @returns {string} CONFIG.LAYER.META or CONFIG.LAYER.MODEL + */ + getLayer: function () { + return _layer; + }, + /** + * Get the relations between nodes and edges types + * @returns {{}} + */ + getRelations: function () { + return relations; + }, + setGuidance: function (guidance) { + guidancemodel = guidance; + }, + init: function (mm) { + metamodel = mm; + if (metamodel && metamodel.hasOwnProperty("nodes")) { + nodeTypes = _initNodeTypes(metamodel); + _layer = CONFIG.LAYER.MODEL; + } else { + _layer = CONFIG.LAYER.META; + + nodeTypes[ObjectNode.TYPE] = ObjectNode; + nodeTypes[AbstractClassNode.TYPE] = AbstractClassNode; + nodeTypes[RelationshipNode.TYPE] = RelationshipNode; + nodeTypes[RelationshipGroupNode.TYPE] = RelationshipGroupNode; + nodeTypes[EnumNode.TYPE] = EnumNode; + nodeTypes[NodeShapeNode.TYPE] = NodeShapeNode; + nodeTypes[EdgeShapeNode.TYPE] = EdgeShapeNode; + + //add view types + nodeTypes[ViewObjectNode.TYPE] = ViewObjectNode; + nodeTypes[ViewRelationshipNode$1.TYPE] = ViewRelationshipNode$1; + } + + if (metamodel && metamodel.hasOwnProperty("edges")) { + var res = _initEdgeTypes(metamodel); + edgeTypes = res.edgeTypes; + relations = res.relations; + } else { + edgeTypes[GeneralisationEdge.TYPE] = GeneralisationEdge; + edgeTypes[BiDirAssociationEdge.TYPE] = BiDirAssociationEdge; + edgeTypes[UniDirAssociationEdge.TYPE] = UniDirAssociationEdge; + + relations[BiDirAssociationEdge.TYPE] = BiDirAssociationEdge.RELATIONS; + relations[UniDirAssociationEdge.TYPE] = + UniDirAssociationEdge.RELATIONS; + relations[GeneralisationEdge.TYPE] = GeneralisationEdge.RELATIONS; + } + }, + }; + } +}; + +const EntityManagerInstance = new EntityManager$1(); +Object.freeze(EntityManagerInstance); + +/** + * Node + * @class canvas_widget.makeNode + * @memberof canvas_widget + * @constructor + * @param type Type of node + * @param $shape + * @param anchors + * @param attributes + * @returns {Node} + */ +function makeNode(type, $shape, anchors, attributes) { + /** + * Node + * @class canvas_widget.Node + * @extends canvas_widget.AbstractNode + * @constructor + * @param {string} id Entity identifier of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {number} zIndex Position of node on z-axis + * @param {boolean} containment containment + */ + class Node extends AbstractNode { + constructor(id, left, top, width, height, zIndex, containment) { + super(id, type, left, top, width, height, zIndex, containment); + var that = this; + + var currentViewType = null; + + this.setCurrentViewType = function (type) { + currentViewType = type; + }; + + this.getCurrentViewType = function () { + return currentViewType; + }; + + /** + * jQuery object of node template + * @type {jQuery} + * @private + */ + var _$template = $shape.clone(); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = AbstractNode.prototype.get$node + .call(this) + .append(_$template); + + /** + * Options for new connections + * @type {object} + */ + var _anchorOptions = anchors; + + this.nodeSelector = getQuerySelectorFromNode(_$node); + + var init = function () { + var attribute, attributeId, attrObj; + attrObj = {}; + for (attributeId in attributes) { + if (attributes.hasOwnProperty(attributeId)) { + attribute = attributes[attributeId]; + var key = attribute.key.toLowerCase(); + switch (attribute.value) { + case "boolean": + attrObj[attributeId] = new BooleanAttribute( + id + "[" + attribute.key.toLowerCase() + "]", + attribute.key, + that + ); + break; + case "string": + attrObj[attributeId] = new SingleValueAttribute( + id + "[" + attribute.key.toLowerCase() + "]", + attribute.key, + that + ); + if ( + attribute.key.toLowerCase() === "label" || + attribute.key.toLowerCase() === "title" || + attribute.key.toLowerCase() === "name" + ) { + that.setLabel(attrObj[attributeId]); + } + break; + case "integer": + attrObj[attributeId] = new IntegerAttribute( + id + "[" + attribute.key.toLowerCase() + "]", + attribute.key, + that + ); + break; + case "file": + attrObj[attributeId] = new FileAttribute( + id + "[" + attribute.key.toLowerCase() + "]", + attribute.key, + that + ); + break; + case "quiz": + attrObj[attributeId] = new QuizAttribute( + id + "[" + attribute.key.toLowerCase() + "]", + attribute.key, + that + ); + if ( + attribute.key.toLowerCase() === "label" || + attribute.key.toLowerCase() === "title" || + attribute.key.toLowerCase() === "name" + ) { + that.setLabel(attrObj[attributeId]); + } + default: + if (attribute.options) { + attrObj[attributeId] = new SingleSelectionAttribute( + id + "[" + attribute.key.toLowerCase() + "]", + attribute.key, + that, + attribute.options + ); + } + } + _$node.find("." + key).append(attrObj[attributeId].get$node()); + } + } + that.setAttributes(attrObj); + }; + + /** + * Get anchor options for new connections + * @returns {Object} + */ + this.getAnchorOptions = function () { + return _anchorOptions; + }; + + /** Set anchor options for new connections + * + */ + this.setAnchorOptions = function (anchors) { + _anchorOptions = anchors; + }; + + /** + * Bind source node events for edge tool + */ + this.makeSource = () => { + _$node.addClass("source"); + window.jsPlumbInstance.addEndpoint(_$node.get(0), { + connectorPaintStyle: { fill: "black", strokeWidth: 4 }, + source: true, + endpoint: { + type: "Rectangle", + options: { + width: _$node.width() + 50, + height: _$node.height() + 50, + }, + }, + paintStyle: { fill: "transparent" }, + anchor: AnchorLocations.Center, + deleteOnEmpty: true, + uuid: id + "_eps1", + //maxConnections:1, + uniqueEndpoint: false, + deleteEndpointsOnDetach: true, + onMaxConnections: function (info /*, originalEvent*/) { + console.log( + "element is ", + info.element, + "maxConnections is", + info.maxConnections + ); + }, + }); + }; + + /** + * Bind target node events for edge tool + */ + this.makeTarget = () => { + _$node.addClass("target"); + window.jsPlumbInstance.addEndpoint(_$node.get(0), { + target: true, + endpoint: { + type: "Rectangle", + options: { + width: _$node.width() + 50, + height: _$node.height() + 50, + }, + }, + uuid: id + "_ept1", + paintStyle: { fill: "transparent" }, + anchor: AnchorLocations.Center, + uniqueEndpoint: false, + //maxConnections:1, + deleteOnEmpty: true, + onMaxConnections: function (info /*, originalEvent*/) { + console.log( + "user tried to drop connection", + info.connection, + "on element", + info.element, + "with max connections", + info.maxConnections + ); + }, + }); + + //local user wants to create an edge selected from the pallette + window.jsPlumbInstance.bind("beforeDrop", function (info) { + var allConn = window.jsPlumbInstance.getConnections({ + target: info.targetId, + source: info.sourceId, + }); + var length = allConn.length; + //if true => Detected a duplicated edge + if (length > 0) return false; //don't create the edge + else return true; //no duplicate create the edge + }); + }; + + /** + * Unbind events for edge tool + */ + this.unbindEdgeToolEvents = function () { + try { + _$node.removeClass("source target"); + jsPlumbInstance.getEndpoints(_$node.get(0)).forEach((endpoint) => { + // We need to remove the endpoint that was created to enable node connection by dragging + // since we are not using the edge tool anymore + if (endpoint.connections.length === 0) { + jsPlumbInstance.deleteEndpoint(endpoint); + } + }); + } catch (error) { + console.error(error); + } + }; + + /** + * Get JSON representation of the node + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractNode.prototype.toJSON.call(this); + json.type = type; + return json; + }; + + /** + * set a new shape for the node + * @param $shape + */ + this.set$shape = function ($shape) { + _$template.remove(); + var _$shape = $shape.clone(); + + var attributes = that.getAttributes(); + for (var attrKey in attributes) { + if (attributes.hasOwnProperty(attrKey)) { + var attribute = attributes[attrKey]; + var $tmp = _$shape.find("." + attribute.getName().toLowerCase()); + if ($tmp.length > 0) { + //initialize the value again + if (attribute.getValue().hasOwnProperty("init")) + attribute.getValue().init(); + $tmp.append(attribute.get$node()); + break; + } + } + } + _$template = _$shape; + _$node.append(_$shape); + }; + + this.get$node = function () { + return _$node; + }; + + init(); + + this.registerYMap = function () { + AbstractNode.prototype.registerYMap.call(this); + var labelAttr = that.getLabel(); + if (labelAttr) labelAttr.registerYType(); + var attr = that.getAttributes(); + for (var key in attr) { + if (attr.hasOwnProperty(key)) { + var val = attr[key].getValue(); + if (val.hasOwnProperty("registerYType")) { + val.registerYType(); + } + } + } + }; + } + nodeSelector; + /** + * Get the jquery shape object from the node type + * @static + * @returns {*} + */ + static get$shape() { + return $shape; + } + /** + * Get the anchors of the node type + * @static + * @returns {*} + */ + static getAnchors() { + return anchors; + } + static getAttributes() { + return attributes; + } + } + + return Node; +} + +/** + * AbstractNode + * @class canvas_widget.AbstractNode + * @extends canvas_widget.AbstractEntity + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of node + * @param {string} type Type of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {boolean} containment containment + * @param {number} zIndex Position of node on z-axis + */ + +/** + * ObjectNode + * @class canvas_widget.ObjectNode + * @extends canvas_widget.AbstractNode + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {number} zIndex Position of node on z-axis + */ +class ObjectNode extends AbstractNode { + static TYPE = "Object"; + static DEFAULT_WIDTH = 150; + static DEFAULT_HEIGHT = 100; + constructor(id, left, top, width, height, zIndex, json, y) { + super(id, ObjectNode.TYPE, left, top, width, height, zIndex, json, y); + var that = this; + + /** + * jQuery object of node template + * @type {jQuery} + * @private + */ + var _$template = $(lodash.template(objectNodeHtml)({ type: that.getType() })); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = AbstractNode.prototype.get$node + .call(this) + .append(_$template) + .addClass("object"); + + /** + * jQuery object of DOM node representing the attributes + * @type {jQuery} + * @private + */ + var _$attributeNode = _$node.find(".attributes"); + + /** + * Attributes of node + * @type {Object} + * @private + */ + var _attributes = this.getAttributes(); + + /** + * Get JSON representation of the node + * @returns {Object} + */ + this.toJSON = function () { + return AbstractNode.prototype.toJSON.call(this); + }; + var attr = new KeySelectionValueListAttribute( + "[attributes]", + "Attributes", + this, + { + string: "String", + boolean: "Boolean", + integer: "Integer", + file: "File", + quiz: "Questions", + } + ); + this.addAttribute(attr); + + this.registerYMap = function () { + AbstractNode.prototype.registerYMap.call(this); + that.getLabel().getValue().registerYType(); + attr.registerYMap(); + }; + + _$node.find(".label").append(this.getLabel().get$node()); + + for (var attributeKey in _attributes) { + if (_attributes.hasOwnProperty(attributeKey)) { + _$attributeNode.append(_attributes[attributeKey].get$node()); + } + } + + this.unregisterCallbacks = function () { + that.getAttribute("[attributes]").unregisterCallbacks(); + }; + + this.setContextMenuItemCallback(function () { + return { + addShape: { + name: "Add Node Shape", + callback: function () { + var canvas = that.getCanvas(), + appearance = that.getAppearance(); + + //noinspection JSAccessibilityCheck + const id = canvas.createNode( + NodeShapeNode.TYPE, + appearance.left + appearance.width + 50, + appearance.top, + 150, + 100 + ); + canvas.createEdge( + BiDirAssociationEdge.TYPE, + that.getEntityId(), + id + ); + }, + disabled: function () { + var edges = that.getEdges(), + edge, + edgeId; + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if ( + (edge instanceof BiDirAssociationEdge && + ((edge.getTarget() === that && + edge.getSource() instanceof NodeShapeNode) || + (edge.getSource() === that && + edge.getTarget() instanceof NodeShapeNode))) || + (edge instanceof UniDirAssociationEdge && + edge.getTarget() instanceof NodeShapeNode) + ) { + return true; + } + } + } + return false; + }, + }, + sepConvertTo: "---------", + convertTo: { + name: "Convert to..", + items: { + abstractClassNode: { + name: "..Abstract Class", + callback: function () { + var canvas = that.getCanvas(), + appearance = that.getAppearance(), + nodeId; + + //noinspection JSAccessibilityCheck + nodeId = canvas.createNode( + AbstractClassNode.TYPE, + appearance.left, + appearance.top, + appearance.width, + appearance.height, + that.getZIndex(), + that.toJSON() + ); + var edges = that.getOutgoingEdges(), + edge, + edgeId; + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + canvas.createEdge( + edge.getType(), + nodeId, + edge.getTarget().getEntityId(), + edge.toJSON() + ); + } + } + + edges = that.getIngoingEdges(); + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if (edge.getSource() !== edge.getTarget()) { + canvas.createEdge( + edge.getType(), + edge.getSource().getEntityId(), + nodeId, + edge.toJSON() + ); + } + } + } + + that.triggerDeletion(); + }, + }, + relationshipNode: { + name: "..Relationship", + callback: function () { + var canvas = that.getCanvas(), + appearance = that.getAppearance(), + nodeId; + + //noinspection JSAccessibilityCheck + nodeId = canvas.createNode( + RelationshipNode.TYPE, + appearance.left, + appearance.top, + appearance.width, + appearance.height, + that.getZIndex(), + that.toJSON() + ); + var edges = that.getOutgoingEdges(), + edge, + edgeId; + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + canvas.createEdge( + edge.getType(), + nodeId, + edge.getTarget().getEntityId(), + edge.toJSON() + ); + } + } + + edges = that.getIngoingEdges(); + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if (edge.getSource() !== edge.getTarget()) { + canvas.createEdge( + edge.getType(), + edge.getSource().getEntityId(), + nodeId, + edge.toJSON() + ); + } + } + } + + that.triggerDeletion(); + }, + }, + relationshipGroupNode: { + name: "..Relationship Group", + callback: function () { + var canvas = that.getCanvas(), + appearance = that.getAppearance(), + nodeId; + + //noinspection JSAccessibilityCheck + nodeId = canvas.createNode( + RelationshipGroupNode.TYPE, + appearance.left, + appearance.top, + appearance.width, + appearance.height, + that.getZIndex(), + that.toJSON() + ); + var edges = that.getOutgoingEdges(), + edge, + edgeId; + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + canvas.createEdge( + edge.getType(), + nodeId, + edge.getTarget().getEntityId(), + edge.toJSON() + ); + } + } + + edges = that.getIngoingEdges(); + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if (edge.getSource() !== edge.getTarget()) { + canvas.createEdge( + edge.getType(), + edge.getSource().getEntityId(), + nodeId, + edge.toJSON() + ); + } + } + } + + that.triggerDeletion(); + }, + }, + }, + }, + sep: "---------", + }; + }); + } +} + +/** + * Abstract Class Node + * @class canvas_widget.AbstractClassNode + * @extends canvas_widget.AbstractNode + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {number} zIndex Position of node on z-axis + */ +class AbstractClassNode extends AbstractNode { + static TYPE = "Abstract Class"; + static DEFAULT_WIDTH = 150; + static DEFAULT_HEIGHT = 100; + + constructor(id, left, top, width, height, zIndex, json) { + super(id, AbstractClassNode.TYPE, left, top, width, height, zIndex, json); + + var that = this; + + /** + * jQuery object of node template + * @type {jQuery} + * @private + */ + var _$template = $( + lodash.template(abstractClassNodeHtml)({ type: that.getType() }) + ); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = AbstractNode.prototype.get$node + .call(this) + .append(_$template) + .addClass("class"); + + /** + * jQuery object of DOM node representing the attributes + * @type {jQuery} + * @private + */ + var _$attributeNode = _$node.find(".attributes"); + + /** + * Attributes of node + * @type {Object} + * @private + */ + var _attributes = this.getAttributes(); + + /** + * Get JSON representation of the node + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractNode.prototype.toJSON.call(this); + json.type = AbstractClassNode.TYPE; + return json; + }; + + var attr = new KeySelectionValueListAttribute( + "[attributes]", + "Attributes", + this, + { + string: "String", + boolean: "Boolean", + integer: "Integer", + file: "File", + quiz: "Questions", + } + ); + this.addAttribute(attr); + + this.registerYMap = function () { + AbstractNode.prototype.registerYMap.call(this); + that.getLabel().getValue().registerYType(); + attr.registerYMap(); + }; + + this.unregisterCallbacks = function () { + that.getAttribute("[attributes]").unregisterCallbacks(); + }; + + _$node.find(".label").append(this.getLabel().get$node()); + + for (var attributeKey in _attributes) { + if (_attributes.hasOwnProperty(attributeKey)) { + _$attributeNode.append(_attributes[attributeKey].get$node()); + } + } + + this.setContextMenuItemCallback(function () { + return { + convertTo: { + name: "Convert to..", + items: { + objectNode: { + name: "..Object", + callback: function () { + var canvas = that.getCanvas(), + appearance = that.getAppearance(), + nodeId; + + //noinspection JSAccessibilityCheck + nodeId = canvas.createNode( + ObjectNode.TYPE, + appearance.left, + appearance.top, + appearance.width, + appearance.height, + that.getZIndex(), + that.getContainment(), + that.toJSON() + ); + var edges = that.getOutgoingEdges(), + edge, + edgeId; + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + canvas.createEdge( + edge.getType(), + nodeId, + edge.getTarget().getEntityId(), + edge.toJSON() + ); + } + } + + edges = that.getIngoingEdges(); + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if (edge.getSource() !== edge.getTarget()) { + canvas.createEdge( + edge.getType(), + edge.getSource().getEntityId(), + nodeId, + edge.toJSON() + ); + } + } + } + + that.triggerDeletion(); + }, + }, + relationshipNode: { + name: "..Relationship", + callback: function () { + var canvas = that.getCanvas(), + appearance = that.getAppearance(), + nodeId; + + //noinspection JSAccessibilityCheck + nodeId = canvas.createNode( + RelationshipNode.TYPE, + appearance.left, + appearance.top, + appearance.width, + appearance.height, + that.getZIndex(), + that.getContainment(), + that.toJSON() + ); + var edges = that.getOutgoingEdges(), + edge, + edgeId; + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + canvas.createEdge( + edge.getType(), + nodeId, + edge.getTarget().getEntityId(), + edge.toJSON() + ); + } + } + + edges = that.getIngoingEdges(); + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if (edge.getSource() !== edge.getTarget()) { + canvas.createEdge( + edge.getType(), + edge.getSource().getEntityId(), + nodeId, + edge.toJSON() + ); + } + } + } + + that.triggerDeletion(); + }, + }, + relationshipGroupNode: { + name: "..Relationship Group", + callback: function () { + var canvas = that.getCanvas(), + appearance = that.getAppearance(), + nodeId; + + //noinspection JSAccessibilityCheck + nodeId = canvas.createNode( + RelationshipGroupNode.TYPE, + appearance.left, + appearance.top, + appearance.width, + appearance.height, + that.getZIndex(), + that.getContainment(), + that.toJSON() + ); + var edges = that.getOutgoingEdges(), + edge, + edgeId; + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + canvas.createEdge( + edge.getType(), + nodeId, + edge.getTarget().getEntityId(), + edge.toJSON() + ); + } + } + + edges = that.getIngoingEdges(); + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if (edge.getSource() !== edge.getTarget()) { + canvas.createEdge( + edge.getType(), + edge.getSource().getEntityId(), + nodeId, + edge.toJSON() + ); + } + } + } + + that.triggerDeletion(); + }, + }, + }, + }, + sep: "---------", + }; + }); + } +} + +/** + * RelationshipNode + * @class canvas_widget.RelationshipNode + * @extends canvas_widget.AbstractNode + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {number} zIndex Position of node on z-axis + */ +class RelationshipNode extends AbstractNode { + static TYPE = "Relationship"; + static DEFAULT_WIDTH = 150; + static DEFAULT_HEIGHT = 100; + + constructor(id, left, top, width, height, zIndex, json) { + super(id, "Relationship", left, top, width, height, zIndex, json); + var that = this; + + /** + * jQuery object of node template + * @type {jQuery} + * @private + */ + var _$template = $( + lodash.template(relationshipNodeHtml)({ type: that.getType() }) + ); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var $node = AbstractNode.prototype.get$node + .call(this) + .append(_$template) + .addClass("relation"); + + /** + * jQuery object of DOM node representing the attributes + * @type {jQuery} + * @private + */ + var _$attributeNode = $node.find(".attributes"); + + /** + * Attributes of node + * @type {Object} + * @private + */ + var _attributes = this.getAttributes(); + + /** + * Get JSON representation of the node + * @returns {Object} + */ + this.toJSON = function () { + return AbstractNode.prototype.toJSON.call(this); + }; + + var attr = new KeySelectionValueSelectionValueListAttribute( + "[attributes]", + "Attributes", + this, + { + string: "String", + boolean: "Boolean", + integer: "Integer", + file: "File", + }, + { hidden: "Hide", top: "Top", center: "Center", bottom: "Bottom" } + ); + this.addAttribute(attr); + + this.registerYMap = function () { + AbstractNode.prototype.registerYMap.call(this); + that.getLabel().getValue().registerYType(); + attr.registerYMap(); + }; + + this.unregisterCallbacks = function () { + that.getAttribute("[attributes]").unregisterCallbacks(); + }; + + $node.find(".label").append(this.getLabel().get$node()); + + for (var attributeKey in _attributes) { + if (_attributes.hasOwnProperty(attributeKey)) { + _$attributeNode.append(_attributes[attributeKey].get$node()); + } + } + + this.setContextMenuItemCallback(function () { + return { + addShape: { + name: "Add Edge Shape", + callback: function () { + var canvas = that.getCanvas(), + appearance = that.getAppearance(); + + //noinspection JSAccessibilityCheck + canvas + .createNode( + EdgeShapeNode.TYPE, + appearance.left + appearance.width + 50, + appearance.top, + 150, + 100 + ) + .done(function (nodeId) { + canvas.createEdge( + BiDirAssociationEdge.TYPE, + that.getEntityId(), + nodeId + ); + }); + }, + disabled: function () { + var edges = that.getEdges(), + edge, + edgeId; + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if ( + (edge instanceof BiDirAssociationEdge && + ((edge.getTarget() === that && + edge.getSource() instanceof EdgeShapeNode) || + (edge.getSource() === that && + edge.getTarget() instanceof EdgeShapeNode))) || + (edge instanceof UniDirAssociationEdge && + edge.getTarget() instanceof EdgeShapeNode) + ) { + return true; + } + } + } + return false; + }, + }, + sepConvertTo: "---------", + convertTo: { + name: "Convert to..", + items: { + abstractNode: { + name: "..Abstract Class Node", + callback: function () { + var canvas = that.getCanvas(), + appearance = that.getAppearance(), + nodeId; + + //noinspection JSAccessibilityCheck + nodeId = canvas.createNode( + AbstractClassNode.TYPE, + appearance.left, + appearance.top, + appearance.width, + appearance.height, + that.getZIndex(), + that.toJSON() + ); + var edges = that.getOutgoingEdges(), + edge, + edgeId; + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + canvas.createEdge( + edge.getType(), + nodeId, + edge.getTarget().getEntityId(), + edge.toJSON() + ); + } + } + + edges = that.getIngoingEdges(); + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if (edge.getSource() !== edge.getTarget()) { + canvas.createEdge( + edge.getType(), + edge.getSource().getEntityId(), + nodeId, + edge.toJSON() + ); + } + } + } + + that.triggerDeletion(); + }, + }, + objectNode: { + name: "..Object Node", + callback: function () { + var canvas = that.getCanvas(), + appearance = that.getAppearance(), + nodeId; + + //noinspection JSAccessibilityCheck + nodeId = canvas.createNode( + ObjectNode.TYPE, + appearance.left, + appearance.top, + appearance.width, + appearance.height, + that.getZIndex(), + that.toJSON() + ); + var edges = that.getOutgoingEdges(), + edge, + edgeId; + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + canvas.createEdge( + edge.getType(), + nodeId, + edge.getTarget().getEntityId(), + edge.toJSON() + ); + } + } + + edges = that.getIngoingEdges(); + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if (edge.getSource() !== edge.getTarget()) { + canvas.createEdge( + edge.getType(), + edge.getSource().getEntityId(), + nodeId, + edge.toJSON() + ); + } + } + } + + that.triggerDeletion(); + }, + }, + relationshipGroupNode: { + name: "..Relationship Group", + callback: function () { + var canvas = that.getCanvas(), + appearance = that.getAppearance(), + nodeId; + + //noinspection JSAccessibilityCheck + nodeId = canvas.createNode( + RelationshipGroupNode.TYPE, + appearance.left, + appearance.top, + appearance.width, + appearance.height, + that.getZIndex(), + that.toJSON() + ); + var edges = that.getOutgoingEdges(), + edge, + edgeId; + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + canvas.createEdge( + edge.getType(), + nodeId, + edge.getTarget().getEntityId(), + edge.toJSON() + ); + } + } + + edges = that.getIngoingEdges(); + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if (edge.getSource() !== edge.getTarget()) { + canvas.createEdge( + edge.getType(), + edge.getSource().getEntityId(), + nodeId, + edge.toJSON() + ); + } + } + } + + that.triggerDeletion(); + }, + }, + }, + }, + sep: "---------", + }; + }); + } +} + +/** + * Abstract Class Node + * @class canvas_widget.EdgeShapeNode + * @extends canvas_widget.AbstractNode + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {number} zIndex Position of node on z-axis + */ +class EdgeShapeNode extends AbstractNode { + static TYPE = "Edge Shape"; + static DEFAULT_WIDTH = 150; + static DEFAULT_HEIGHT = 150; + + constructor(id, left, top, width, height, zIndex, json) { + super(id, EdgeShapeNode.TYPE, left, top, width, height, zIndex, json); + var that = this; + + /** + * jQuery object of node template + * @type {jQuery} + * @private + */ + var _$template = $(lodash.template(edgeShapeNodeHtml)({ type: that.getType() })); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = AbstractNode.prototype.get$node + .call(this) + .append(_$template) + .addClass("class"); + + /** + * jQuery object of DOM node representing the attributes + * @type {jQuery} + * @private + */ + var _$attributeNode = _$node.find(".attributes"); + + /** + * Attributes of node + * @type {Object} + * @private + */ + var _attributes = this.getAttributes(); + + /** + * Get JSON representation of the node + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractNode.prototype.toJSON.call(this); + json.type = EdgeShapeNode.TYPE; + return json; + }; + + var attrArrow = new SingleSelectionAttribute( + this.getEntityId() + "[arrow]", + "Arrow", + this, + { + bidirassociation: "---", + unidirassociation: "-->", + generalisation: "--▷", + diamond: "-◁▷", + } + ); + var attrShape = new SingleSelectionAttribute( + this.getEntityId() + "[shape]", + "Shape", + this, + { straight: "Straight", curved: "Curved", segmented: "Segmented" } + ); + var attrColor = new SingleColorValueAttribute( + this.getEntityId() + "[color]", + "Color", + this + ); + var attrOverlay = new SingleValueAttribute( + this.getEntityId() + "[overlay]", + "Overlay Text", + this + ); + var attrOverlayPos = new SingleSelectionAttribute( + this.getEntityId() + "[overlayPosition]", + "Overlay Position", + this, + { hidden: "Hide", top: "Top", center: "Center", bottom: "Bottom" } + ); + var attrOverlayRotate = new BooleanAttribute( + this.getEntityId() + "[overlayRotate]", + "Autoflip Overlay", + this + ); + + this.addAttribute(attrArrow); + this.addAttribute(attrShape); + this.addAttribute(attrColor); + this.addAttribute(attrOverlay); + this.addAttribute(attrOverlayPos); + this.addAttribute(attrOverlayRotate); + + this.registerYMap = function (map) { + AbstractNode.prototype.registerYMap.call(this, map); + attrArrow.getValue().registerYType(); + attrShape.getValue().registerYType(); + attrOverlayPos.getValue().registerYType(); + attrOverlayRotate.getValue().registerYType(); + that.getLabel().getValue().registerYType(); + attrColor.getValue().registerYType(); + attrOverlay.getValue().registerYType(); + }; + + _$node.find(".label").append(this.getLabel().get$node()); + + for (var attributeKey in _attributes) { + if (_attributes.hasOwnProperty(attributeKey)) { + _$attributeNode.append(_attributes[attributeKey].get$node()); + } + } + } +} + +/** + * makeEdge + * @class canvas_widget.makeEdge + * @memberof canvas_widget + * @constructor + * @param {string} type Type of edge + * @param arrowType + * @param shapeType + * @param color + * @param dashstyle + * @param overlay + * @param overlayPosition + * @param overlayRotate + * @param attributes + * @returns {Edge} + */ +function makeEdge( + type, + arrowType, + shapeType, + color, + dashstyle, + overlay, + overlayPosition, + overlayRotate, + attributes +) { + var shape = shapes.hasOwnProperty(shapeType) + ? shapes[shapeType] + : lodash.values(shapes)[0]; + color = color + ? $colorTestElement.css("color", "#000000").css("color", color).css("color") + : "#000000"; + + /** + * Edge + * @class canvas_widget.Edge + * @extends canvas_widget.AbstractEdge + * @constructor + * @param {string} id Entity identifier of edge + * @param {canvas_widget.AbstractNode} source Source node + * @param {canvas_widget.AbstractNode} target Target node + */ + class Edge extends AbstractEdge { + constructor(id, source, target) { + super(id, type, source, target, overlayRotate); + var that = this; + + var currentViewType = null; + + /** + * Set the currently applied view type + * @param {string} type + */ + this.setCurrentViewType = function (type) { + currentViewType = type; + }; + + /** + * Get the currently applied view type + * @returns {string} the view type + */ + this.getCurrentViewType = function () { + return currentViewType; + }; + + /** + * Stores jsPlumb overlays for the edge + * @type {Array} + */ + var overlays = []; + + /** + * make jsPlumb overlay + * @param text + * @returns {Function} + */ + var makeOverlayFunction = function (text) { + return function () { + return $("
                  ").append( + $("
                  ") + .addClass("edge_label fixed") + .css("color", color) + .text(text) + ); + }; + }; + + /** + * make a jsPlumb overlay for a attribute + * @param attribute + * @returns {Function} + */ + var makeAttributeOverlayFunction = function (attribute) { + return function () { + const $node = $("
                  ").append( + $("
                  ").addClass("edge_label").append(attribute.get$node()) + ); + return $node.get(0); + }; + }; + var init = function () { + var attribute, attributeId, attrObj; + + if (Arrows().hasOwnProperty(arrowType)) { + overlays.push(Arrows(color)[arrowType]); + } + + if (overlay) { + switch (overlayPosition) { + case "top": + overlays.push({ + type: "Custom", + options: { + create: makeOverlayFunction(overlay), + location: 0.9, + id: "label", + }, + }); + break; + case "bottom": + overlays.push({ + type: "Custom", + options: { + create: makeOverlayFunction(overlay), + location: 0.1, + id: "label", + }, + }); + break; + default: + case "center": + overlays.push({ + type: "Custom", + options: { + create: makeOverlayFunction(overlay), + location: 0.5, + id: "label", + }, + }); + break; + } + } + + attrObj = {}; + for (attributeId in attributes) { + if (attributes.hasOwnProperty(attributeId)) { + attribute = attributes[attributeId]; + switch (attribute.value) { + case "boolean": + attrObj[attributeId] = new BooleanAttribute( + id + "[" + attribute.key.toLowerCase() + "]", + attribute.key, + that + ); + break; + case "string": + attrObj[attributeId] = new SingleValueAttribute( + id + "[" + attribute.key.toLowerCase() + "]", + attribute.key, + that + ); + break; + case "integer": + attrObj[attributeId] = new IntegerAttribute( + id + "[" + attribute.key.toLowerCase() + "]", + attribute.key, + that + ); + break; + case "file": + attrObj[attributeId] = new FileAttribute( + id + "[" + attribute.key.toLowerCase() + "]", + attribute.key, + that + ); + break; + default: + if (attribute.options) { + attrObj[attributeId] = new SingleSelectionAttribute( + id + "[" + attribute.key.toLowerCase() + "]", + attribute.key, + that, + attribute.options + ); + } + } + + switch (attribute.position) { + case "top": + overlays.push({ + type: "Custom", + options: { + create: makeAttributeOverlayFunction(attrObj[attributeId]), + location: 1, + id: "label " + attributeId, + }, + }); + break; + case "center": + overlays.push({ + type: "Custom", + options: { + create: makeAttributeOverlayFunction(attrObj[attributeId]), + location: 0.5, + id: "label " + attributeId, + }, + }); + break; + case "bottom": + overlays.push({ + type: "Custom", + options: { + create: makeAttributeOverlayFunction(attrObj[attributeId]), + location: 0, + id: "label " + attributeId, + }, + }); + break; + } + } + } + that.setAttributes(attrObj); + + overlays.push({ + type: "Custom", + options: { + create: function () { + that.get$overlay().hide().find(".type").addClass(shapeType); + return that.get$overlay().get(0); + }, + location: 0.5, + id: "label", + }, + }); + + if (overlay) { + that + .get$overlay() + .find("input[name='Label']") + .css("visibility", "hidden"); + } + + that.setDefaultPaintStyle({ + stroke: color, + strokeWidth: 4, + }); + }; + + /** + * Connect source and target node and draw the edge on canvas + */ + this.connect = function () { + var source = this.getSource(); + var target = this.getTarget(); + var connectOptions = { + source: source.get$node().get(0), + target: target.get$node().get(0), + paintStyle: that.getDefaultPaintStyle(), + endpoint: "Dot", + anchors: [source.getAnchorOptions(), target.getAnchorOptions()], + connector: shape, + overlays: overlays, + cssClass: this.getEntityId(), + }; + + if (source === target) { + connectOptions.anchors = ["TopCenter", "LeftMiddle"]; + } + + source.addOutgoingEdge(this); + target.addIngoingEdge(this); + this.setJsPlumbConnection( + window.jsPlumbInstance.connect(connectOptions) + ); + + this.repaintOverlays(); + lodash.each(EntityManagerInstance.getEdges(), function (e) { + e.setZIndex(); + }); + }; + + /** + * Get JSON representation of the edge + * @returns {object} + */ + this.toJSON = function () { + var json = AbstractEdge.prototype.toJSON.call(this); + json.type = type; + return json; + }; + + /** + * restyles the edge + * @param arrowType + * @param color + * @param shapeType + * @param dashstyle + * @param overlay + * @param overlayPosition + * @param overlayRotate + * @param attributes + */ + this.restyle = function ( + arrowType, + color, + shapeType, + dashstyle, + overlay, + overlayPosition, + overlayRotate, + attributes + ) { + overlays = []; + + color = color + ? $colorTestElement + .css("color", "black") + .css("color", color) + .css("color") + : "black"; + + if (Arrows().hasOwnProperty(arrowType)) { + overlays.push(Arrows(color)[arrowType]); + } + + if (overlay) { + switch (overlayPosition) { + case "top": + overlays.push({ + type: "Custom", + options: { + create: makeOverlayFunction(overlay), + location: 0.9, + id: "label", + }, + }); + break; + case "bottom": + overlays.push({ + type: "Custom", + options: { + create: makeOverlayFunction(overlay), + location: 0.1, + id: "label", + }, + }); + break; + default: + case "center": + overlays.push({ + type: "Custom", + options: { + create: makeOverlayFunction(overlay), + location: 0.5, + id: "label", + }, + }); + break; + } + } + + overlays.push({ + type: "Custom", + options: { + create: function () { + that.get$overlay().hide().find(".type").addClass(shapeType); + return that.get$overlay().get(0); + }, + location: 0.5, + id: "label", + }, + }); + + if (overlay) { + that + .get$overlay() + .find("input[name='Label']") + .css("visibility", "hidden"); + } + + for (var attributeId in attributes) { + if (attributes.hasOwnProperty(attributeId)) { + var attribute = attributes[attributeId]; + switch (attribute.position) { + case "top": + overlays.push({ + type: "Custom", + options: { + create: makeAttributeOverlayFunction( + that.getAttribute(attributeId) + ), + location: 1, + id: "label " + attributeId, + }, + }); + break; + case "center": + overlays.push({ + type: "Custom", + options: { + create: makeAttributeOverlayFunction( + that.getAttribute(attributeId) + ), + location: 0.5, + id: "label " + attributeId, + }, + }); + break; + case "bottom": + overlays.push({ + type: "Custom", + options: { + create: makeAttributeOverlayFunction( + that.getAttribute(attributeId) + ), + location: 0, + id: "label " + attributeId, + }, + }); + break; + } + } + } + + var paintStyle = { + strokeStyle: color, + lineWidth: 2, + dashstyle: dashstyle, + }; + + that.setDefaultPaintStyle(paintStyle); + that.setRotateOverlay(overlayRotate); + + if (that.getJsPlumbConnection()) { + //if the edge is drawn on the canvas + that.getJsPlumbConnection().removeAllOverlays(); + for (var i = 0; i < overlays.length; i++) { + that.getJsPlumbConnection().addOverlay(overlays[i]); + } + that.getJsPlumbConnection().setPaintStyle(paintStyle); + that.repaintOverlays(); + } + }; + + this.registerYMap = function () { + AbstractEdge.prototype.registerYMap.call(this); + + var attr = that.getAttributes(); + for (var key in attr) { + if (attr.hasOwnProperty(key)) { + var val = attr[key].getValue(); + if (val.hasOwnProperty("registerYType")) { + val.registerYType(); + } + } + } + }; + + init(); + } + /** + * Get the arrow type of the edge type + * @static + * @returns {*} + */ + static getArrowType() { + return arrowType; + } + /** + * Get the shape type of the edge type + * @static + * @returns {*} + */ + static getShapeType() { + return shapeType; + } + /** + * Get the color of the edge type + * @static + * @returns {*} + */ + static getShape() { + return shape; + } + static getColor() { + return color; + } + /** + * Get the overlay of the edge type + * @static + * @returns {*} + */ + static getOverlay() { + return overlay; + } + /** + * Get the overlay position of the edge type + * @static + * @returns {*} + */ + static getOverlayPosition() { + return overlayPosition; + } + /** + * Get the overlay rotate of the edge type + * @static + * @returns {*} + */ + static getOverlayRotate() { + return overlayRotate; + } + /** + * Get the attribute definition of the edge type + * @static + * @returns {*} + */ + static getAttributes() { + return attributes; + } + static getType() { + return type; + } + static getArrowOverlays() { + var overlays = []; + if (Arrows().hasOwnProperty(arrowType)) { + overlays.push(Arrows(color)[arrowType]); + } + return overlays; + } + } + + return Edge; +} + +/** + * AbstractNode + * @class canvas_widget.AbstractNode + * @extends canvas_widget.AbstractEntity + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of node + * @param {string} type Type of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {boolean} containment containment + * @param {number} zIndex Position of node on z-axis + */ + +/** + * Abstract Class Node + * @class canvas_widget.RelationshipGroupNode + * @extends canvas_widget.AbstractNode + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {number} zIndex Position of node on z-axis + */ +class RelationshipGroupNode extends AbstractNode { + static TYPE = "Relation"; + static DEFAULT_WIDTH = 150; + static DEFAULT_HEIGHT = 100; + constructor(id, left, top, width, height, zIndex) { + super(id, RelationshipGroupNode.TYPE, left, top, width, height, zIndex); + var that = this; + + /** + * jQuery object of node template + * @type {jQuery} + * @private + */ + var _$template = $( + lodash.template(relationshipGroupNodeHtml)({ type: that.getType() }) + ); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = AbstractNode.prototype.get$node + .call(this) + .append(_$template) + .addClass("class"); + + /** + * jQuery object of DOM node representing the attributes + * @type {jQuery} + * @private + */ + var _$attributeNode = _$node.find(".attributes"); + + /** + * Attributes of node + * @type {Object} + * @private + */ + var _attributes = this.getAttributes(); + + /** + * Get JSON representation of the node + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractNode.prototype.toJSON.call(this); + json.type = RelationshipGroupNode.TYPE; + return json; + }; + + this.registerYMap = function () { + AbstractNode.prototype.registerYMap.call(this); + that.getLabel().getValue().registerYType(); + }; + + _$node.find(".label").append(this.getLabel().get$node()); + + for (var attributeKey in _attributes) { + if (_attributes.hasOwnProperty(attributeKey)) { + _$attributeNode.append(_attributes[attributeKey].get$node()); + } + } + } +} + +/** + * SelectionValue + * @class canvas_widget.SelectionValue + * @extends canvas_widget.AbstractValue + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier + * @param {string} name Name of attribute + * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {canvas_widget.AbstractNode|canvas_widget.AbstractEdge} rootSubjectEntity Topmost entity in the chain of entity the attribute is assigned to + * @param {Object} options Selection options + */ +class SelectionValue extends AbstractValue { + constructor( + id, + name, + subjectEntity, + rootSubjectEntity, + options, + useAttributeHtml + ) { + super(id, name, subjectEntity, rootSubjectEntity); + + var that = this; + + useAttributeHtml = + typeof useAttributeHtml !== "undefinded" ? useAttributeHtml : false; + + /** + * Value + * @type {string} + * @private + */ + var _value = lodash.keys(options)[0]; + + if (useAttributeHtml) { + selectionValueHtml = attributeSelectionValueHtml; + } + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = $( + lodash.template(selectionValueHtml)({ + name: name, + options: options, + }) + ); + + if (useAttributeHtml) { + _$node.off(); + } + + /** + * Inter widget communication wrapper + * @type {Object} + * @private + */ + y = y || window.y; + var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); + + /** + * Apply a Value Change Operation + * @param {operations.ot.ValueChangeOperation} operation + */ + var processValueChangeOperation = function (operation) { + that.setValue(operation.getValue()); + }; + + /** + * Set value + * @param {string} value + */ + this.setValue = function (value) { + _value = value; + if (useAttributeHtml) { + _$node.val(value); + if (value == "Quiz") { + Object.values(rootSubjectEntity.getAttributes()).forEach((value) => { + if (value instanceof QuizAttribute) { + value.showTable(); + } + }); + } else + Object.values(rootSubjectEntity.getAttributes()).forEach((value) => { + if (value instanceof QuizAttribute) { + value.hideTable(); + } + }); + } else _$node.text(options[value]); + }; + + /** + * Get value + * @returns {string} + */ + this.getValue = function () { + return _value; + }; + + /** + * Get jQuery object of DOM node representing the value + * @returns {jQuery} + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the edge + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractValue.prototype.toJSON.call(this); + json.value = _value; + return json; + }; + + /** + * Set value by its JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + this.setValue(json.value); + }; + + this.registerYType = function () { + //observer + that + .getRootSubjectEntity() + .getYMap() + .observeDeep(function ([event]) { + const array = Array.from(event.changes.keys.entries()); + array.forEach(([key]) => { + const updated = event.currentTarget.get(key); + if ( + updated?.type !== "update" || + !(updated?.entityId === that.getEntityId()) + ) + return; + var operation = new ValueChangeOperation( + updated.entityId, + updated.value, + updated.type, + updated.position, + updated.jabberId + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.getOTOperation() + ); + processValueChangeOperation(operation); + + //Only the local user Propagates the activity and saves the state of the model + if ( + _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID] === + operation.getJabberId() + ) { + const activityMap = y.getMap("activity"); + + activityMap.set( + ActivityOperation.TYPE, + new ActivityOperation( + "ValueChangeActivity", + that.getEntityId(), + _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], + ValueChangeOperation.getOperationDescription( + that.getSubjectEntity().getName(), + that.getRootSubjectEntity().getType(), + that.getRootSubjectEntity().getLabel().getValue().getValue() + ), + { + value: operation.getValue(), + subjectEntityName: that.getSubjectEntity().getName(), + rootSubjectEntityType: that + .getRootSubjectEntity() + .getType(), + rootSubjectEntityId: that + .getRootSubjectEntity() + .getEntityId(), + } + ).toJSON() + ); + + //its a view type and create a reference to the origin + if (updated.entityId.indexOf("[target]") != -1) { + ViewTypesUtil.createReferenceToOrigin( + that.getRootSubjectEntity() + ); + //CVG + Promise.resolve().then(function () { return ClosedViewGeneration; }).then(function (CVG) { + CVG(rootSubjectEntity); + }); + } + //trigger the save + EntityManagerInstance.storeDataYjs(); + } else { + //the remote users propagtes the change to their local attribute widget + //TODO(PENDING): can be replaced with yjs as well + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.ATTRIBUTE, + operation.getOTOperation() + ); + } + }); + }); + }; + } +} + +/** + * IntegerAttribute + * @class canvas_widget.IntegerAttribute + * @extends canvas_widget.AbstractAttribute + * @memberof canvas_widget + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to + */ +class IntegerAttribute extends AbstractAttribute { + constructor(id, name, subjectEntity, useAttributeHtml) { + super(id, name, subjectEntity); + useAttributeHtml = + typeof useAttributeHtml !== "undefined" ? useAttributeHtml : false; + + /*** + * Value object of value + * @type {canvas_widget.IntegerValue} + * @private + */ + var _value = new IntegerValue( + id, + name, + this, + this.getRootSubjectEntity(), + useAttributeHtml + ); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(integerAttributeHtml)()); + + /** + * Set Value object of value + * @param {canvas_widget.IntegerValue} value + */ + this.setValue = function (value) { + _value = value; + _$node.val(value); + }; + + /** + * Get Value object of value + * @return {canvas_widget.IntegerValue} value + */ + this.getValue = function () { + return _value; + }; + + /** + * jQuery object of DOM node representing the attribute + * @type {jQuery} + * @private + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the attribute + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.value = _value.toJSON(); + return json; + }; + + /** + * Set attribute value by its JSON representation + * @param {Object} json + */ + this.setValueFromJSON = function (json) { + _value.setValueFromJSON(json.value); + }; + + _$node.find(".name").text(this.getName()); + _$node.find(".value").append(_value.get$node()); + } +} + +/** + * SingleSelectionAttribute + * @class canvas_widget.SingleSelectionAttribute + * @extends canvas_widget.AbstractAttribute + * @memberof canvas_widget + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {Object} options Selection options as key value object + */ + +class SingleSelectionAttribute extends AbstractAttribute { + constructor(id, name, subjectEntity, options, useAttributeHtml) { + super(id, name, subjectEntity); + useAttributeHtml = + typeof useAttributeHtml !== "undefinded" ? useAttributeHtml : false; + var that = this; + /*** + * Value object of value + * @type {canvas_widget.SelectionValue} + * @private + */ + var _value = new SelectionValue( + id, + name, + this, + this.getRootSubjectEntity(), + options, + useAttributeHtml + ); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(singleSelectionAttributeHtml)()); + + /** + * Set Value object of value + * @param {canvas_widget.SelectionValue} value + */ + this.setValue = function (value) { + _value = value; + _$node.val(value); + }; + + /** + * Get Value object of value + * @return {canvas_widget.SelectionValue} value + */ + this.getValue = function () { + return _value; + }; + + /** + * jQuery object of DOM node representing the attribute + * @type {jQuery} + * @private + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get the options object for the Attribute + * @returns {Object} + */ + this.getOptionValue = function () { + return options.hasOwnProperty(_value.getValue()) + ? options[_value.getValue()] + : null; + }; + + /** + * Get JSON representation of the attribute + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.value = _value.toJSON(); + json.option = that.getOptionValue(); + return json; + }; + + this.getOptions = function () { + return options; + }; + + /** + * Set attribute value by its JSON representation + * @param {Object} json + */ + this.setValueFromJSON = function (json) { + _value.setValueFromJSON(json.value); + }; + + _$node.find(".name").text(this.getName()); + _$node.find(".value").append(_value.get$node()); + } +} + +/** + * IntegerValue + * @class canvas_widget.IntegerValue + * @extends canvas_widget.AbstractValue + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier + * @param {string} name Name of attribute + * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {canvas_widget.AbstractNode|canvas_widget.AbstractEdge} rootSubjectEntity Topmost entity in the chain of entity the attribute is assigned to + */ +class IntegerValue extends AbstractValue { + constructor(id, name, subjectEntity, rootSubjectEntity, useAttributeHtml) { + super(id, name, subjectEntity, rootSubjectEntity); + var that = this; + + if (useAttributeHtml) integerValueHtml = attributeIntegerValueHtml; + + /** + * Value + * @type {number} + * @private + */ + var _value = 0; + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(integerValueHtml)({ value: _value })); + + /** + * Inter widget communication wrapper + * @type {Object} + * @private + */ + y = y || window.y; + var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); + + /** + * Apply a Value Change Operation + * @param {operations.ot.ValueChangeOperation} operation + */ + var processValueChangeOperation = function (operation) { + that.setValue(operation.getValue()); + }; + + var init = function () { + _$node.off(); + }; + + /** + * Set value + * @param {number} value + */ + this.setValue = function (value) { + _value = value; + if (useAttributeHtml) _$node.val(value); + else _$node.text(value); + }; + + /** + * Get value + * @returns {number} + */ + this.getValue = function () { + return _value; + }; + + /** + * Get jQuery object of DOM node representing the value + * @returns {jQuery} + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the edge + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractValue.prototype.toJSON.call(this); + json.value = _value; + return json; + }; + + /** + * Set value by its JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + this.setValue(json?.value); + }; + + this.registerYType = function () { + //observer + that + .getRootSubjectEntity() + .getYMap() + .observe(function (event) { + const array = Array.from(event.changes.keys.entries()); + array.forEach(([key, change]) => { + if (change.action !== "update") return; + // check if key is the entity id + if (key !== that.getEntityId()) return; + const data = event.target.get(key); + var operation = new ValueChangeOperation( + data.entityId, + data.value, + data.type, + data.position, + data.jabberId + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.getOTOperation() + ); + processValueChangeOperation(operation); + + //Only the local user Propagates the activity + if ( + _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID] === + operation.getJabberId() + ) { + EntityManagerInstance.storeDataYjs(); + const activityMap = y.getMap("activity"); + + activityMap.set( + ActivityOperation.TYPE, + new ActivityOperation( + "ValueChangeActivity", + that.getEntityId(), + _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], + ValueChangeOperation.getOperationDescription( + that.getSubjectEntity().getName(), + that.getRootSubjectEntity().getType(), + that.getRootSubjectEntity().getLabel().getValue().getValue() + ), + { + value: operation.getValue(), + subjectEntityName: that.getSubjectEntity().getName(), + rootSubjectEntityType: that + .getRootSubjectEntity() + .getType(), + rootSubjectEntityId: that + .getRootSubjectEntity() + .getEntityId(), + } + ).toJSON() + ); + } else { + //the remote users propagtes the change to their local attribute widget + //TODO(PENDING): can be replaced with yjs as well + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.ATTRIBUTE, + operation.getOTOperation() + ); + } + }); + }); + }; + + init(); + } +} + +/** + * SingleValueAttribute + * @class canvas_widget.SingleValueAttribute + * @extends canvas_widget.AbstractAttribute + * @memberof canvas_widget + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to + */ +class SingleValueAttribute extends AbstractAttribute { + value; + constructor(id, name, subjectEntity, y) { + y = y || window.y; + if (!y) { + throw new Error("y is undefined"); + } + super(id, name, subjectEntity); + + /*** + * Value object of value + * @type {canvas_widget.Value} + * @private + */ + var _value = new Value(id, name, this, this.getRootSubjectEntity(), y); + this.value = _value; + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(canvasSingleValueAttributeHtml)()); + + /** + * Set Value object of value + * @param {canvas_widget.Value} value + */ + this.setValue = function (value) { + _value = value; + this.value = value; + }; + + /** + * Get Value object of value + * @returns {canvas_widget.Value} + */ + this.getValue = function () { + return _value; + }; + + /** + * jQuery object of DOM node representing the attribute + * @type {jQuery} + * @private + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the attribute + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.value = _value.toJSON(); + return json; + }; + + /** + * Set attribute value by its JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + _value.setValueFromJSON(json.value); + }; + + this.registerYType = function () { + _value.registerYType(); + }; + + _$node.find(".name").text(this.getName()); + _$node.find(".value").append(_value.get$node()); + } +} + +/** + * SingleValueListAttribute + * @class canvas_widget.SingleValueListAttribute + * @extends canvas_widget.AbstractAttribute + * @memberof canvas_widget + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to + */ +class SingleValueListAttribute extends AbstractAttribute { + static TYPE = "SingleValueListAttribute"; + constructor(id, name, subjectEntity) { + super(id, name, subjectEntity); + var that = this; + + /** + * List of attributes + * @type {Object} + * @private + */ + var _list = {}; + + /** + * jQuery object of DOM node representing the attribute + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(singleValueListAttributeHtml)()); + y = y || window.y; + /** + * Inter widget communication wrapper + * @type {Object} + */ + var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); + + /** + * Apply an Attribute Add Operation + * @param {operations.ot.AttributeAddOperation} operation + */ + var processAttributeAddOperation = function (operation) { + var attribute = new SingleValueAttribute( + operation.getEntityId() + "[value]", + "Attribute", + that + ); + attribute.registerYType(); + that.addAttribute(attribute); + _$node.find(".list").append(attribute.get$node()); + }; + + /** + * Apply an Attribute Delete Operation + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var processAttributeDeleteOperation = function (operation) { + var attribute = that.getAttribute(operation.getEntityId()); + if (attribute) { + that.deleteAttribute(attribute.getEntityId()); + attribute.get$node().remove(); + } + }; + /** + * Propagate an Attribute Add Operation to the remote users and the local widgets + * @param {operations.ot.AttributeAddOperation} operation + */ + var propagateAttributeAddOperation = function (operation) { + processAttributeAddOperation(operation); + EntityManagerInstance.storeDataYjs(); + }; + + /** + * Propagate an Attribute Delete Operation to the remote users and the local widgets + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var propagateAttributeDeleteOperation = function (operation) { + processAttributeDeleteOperation(operation); + var ynode = that.getRootSubjectEntity().getYMap(); + ynode.delete(operation.getEntityId()); + EntityManagerInstance.storeDataYjs(); + }; + + /** + * Callback for a remote Attrbute Add Operation + * @param {operations.ot.AttributeAddOperation} operation + */ + var remoteAttributeAddCallback = function (operation) { + if ( + operation instanceof AttributeAddOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + processAttributeAddOperation(operation); + } + }; + + /** + * Callback for a remote Attribute Delete Operation + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var remoteAttributeDeleteCallback = function (operation) { + if ( + operation instanceof AttributeDeleteOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + processAttributeDeleteOperation(operation); + } + }; + + var localAttributeAddCallback = function (operation) { + if ( + operation instanceof AttributeAddOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + propagateAttributeAddOperation(operation); + } + }; + + /** + * Callback for a local Attribute Delete Operation + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var localAttributeDeleteCallback = function (operation) { + if ( + operation instanceof AttributeDeleteOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + propagateAttributeDeleteOperation(operation); + } + }; + + /** + * Add attribute to attribute list + * @param {canvas_widget.AbstractAttribute} attribute + */ + this.addAttribute = function (attribute) { + var id = attribute.getEntityId(); + if (!_list.hasOwnProperty(id)) { + _list[id] = attribute; + } + }; + + /** + * Get attribute of attribute list by its entity id + * @param id + * @returns {canvas_widget.AbstractAttribute} + */ + this.getAttribute = function (id) { + if (_list.hasOwnProperty(id)) { + return _list[id]; + } + return null; + }; + + /** + * Delete attribute from attribute list by its entity id + * @param {string} id + */ + this.deleteAttribute = function (id) { + if (_list.hasOwnProperty(id)) { + delete _list[id]; + } + }; + + /** + * Get attribute list + * @returns {Object} + */ + this.getAttributes = function () { + return _list; + }; + + /** + * Set attribute list + * @param {Object} list + */ + this.setAttributes = function (list) { + _list = list; + }; + + /** + * Get jQuery object of the DOM node representing the attribute (list) + * @returns {jQuery} + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the attribute (list) + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.type = SingleValueListAttribute.TYPE; + var attr = {}; + lodash.forEach(this.getAttributes(), function (val, key) { + attr[key] = val.toJSON(); + }); + json.list = attr; + return json; + }; + + /** + * Set attribute list by its JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + lodash.forEach(json.list, function (val, key) { + var attribute = new SingleValueAttribute(key, key, that, y); + attribute.setValueFromJSON(json.list[key]); + that.addAttribute(attribute); + _$node.find(".list").append(attribute.get$node()); + }); + }; + + /** + * Register inter widget communication callbacks + */ + this.registerCallbacks = function () { + _iwcw.registerOnDataReceivedCallback(localAttributeAddCallback); + _iwcw.registerOnDataReceivedCallback(localAttributeDeleteCallback); + }; + + /** + * Unregister inter widget communication callbacks + */ + this.unregisterCallbacks = function () { + _iwcw.unregisterOnDataReceivedCallback(localAttributeAddCallback); + _iwcw.unregisterOnDataReceivedCallback(localAttributeDeleteCallback); + }; + + _$node.find(".name").text(this.getName()); + + for (var attributeId in _list) { + if (_list.hasOwnProperty(attributeId)) { + _$node.find(".list").append(_list[attributeId].get$node()); + } + } + + if (_iwcw) { + that.registerCallbacks(); + } + this.registerYMap = function () { + var ymap = that.getRootSubjectEntity().getYMap(); + + var attrs = that.getAttributes(); + for (var key in attrs) { + if (attrs.hasOwnProperty(key)) { + var attr = attrs[key]; + attr.getValue().registerYType(); + } + } + + ymap.observe(function (event) { + var operation; + + const array = Array.from(event.changes.keys.entries()); + array.forEach(([key, change]) => { + if (key.indexOf("[value]") != -1) { + switch (change.action) { + case "add": { + if (event.currentTarget.get("modifiedBy") === window.y.clientID) + return; + + operation = new AttributeAddOperation( + key.replace(/\[\w*\]/g, ""), + that.getEntityId(), + that.getRootSubjectEntity().getEntityId(), + that.constructor.name + ); + remoteAttributeAddCallback(operation); + break; + } + case "delete": { + operation = new AttributeDeleteOperation( + key, + that.getEntityId(), + that.getRootSubjectEntity().getEntityId(), + that.constructor.name + ); + remoteAttributeDeleteCallback(operation); + } + } + } + }); + }); + }; + } +} + +/** + * Value + * @class canvas_widget.Value + * @extends canvas_widget.AbstractValue + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier + * @param {string} name Name of attribute + * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {canvas_widget.AbstractNode|canvas_widget.AbstractEdge} rootSubjectEntity Topmost entity in the chain of entity the attribute is assigned to + */ +class Value extends AbstractValue { + value = ""; + constructor(id, name, subjectEntity, rootSubjectEntity, y) { + super(id, name, subjectEntity, rootSubjectEntity); + y = y || window.y; + if (!y) throw new Error("y is undefined"); + var _ytext = null; + + const yMap = rootSubjectEntity.getYMap(); + if (!yMap) { + throw new Error("yMap is undefined"); + } + y.transact(() => { + if (yMap?.has(id)) { + _ytext = rootSubjectEntity.getYMap().get(id); + if (!(_ytext instanceof Text)) { + _ytext = new Text(); + rootSubjectEntity.getYMap().set(id, _ytext); + } + } else { + _ytext = new Text(); + rootSubjectEntity.getYMap().set(id, _ytext); + } + rootSubjectEntity.getYMap().set("modifiedBy", window.y.clientID); + }); + + var that = this; + /** + * Value + * @type {string} + * @private + */ + var _value = ""; + this.value = _value; + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(valueHtml)({ name: name })); + + /** + * Set value + * @param {string} value + */ + this.setValue = function (value) { + _value = value; + _$node.text(value); + + this.value = _ytext.toString(); + }; + + /** + * Get value + * @returns {string} + */ + this.getValue = function () { + return _value; + }; + + /** + * Get jQuery object of DOM node representing the value + * @returns {jQuery} + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the edge + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractValue.prototype.toJSON.call(this); + json.value = _value; + return json; + }; + + /** + * Set value by its JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + this.setValue(json.value); + }; + + this.registerYType = function () { + _ytext.observe( + lodash.debounce(function (event) { + _value = _ytext.toString().replace(/\n/g, ""); + that.setValue(_value); + if (event.currentTarget.get("modifiedBy") === window.y.clientID) { + EntityManagerInstance.storeDataYjs(); + const userMap = y.getMap("users"); + const jabberId = userMap.get(event.currentTarget.doc.clientID); + + const activityMap = y.getMap("activity"); + activityMap.set( + ActivityOperation.TYPE, + new ActivityOperation( + "ValueChangeActivity", + that.getEntityId(), + jabberId, + ValueChangeOperation.getOperationDescription( + that.getSubjectEntity().getName(), + that.getRootSubjectEntity().getType(), + that.getRootSubjectEntity().getLabel().getValue().getValue() + ), + { + value: _value, + subjectEntityName: that.getSubjectEntity().getName(), + rootSubjectEntityType: that.getRootSubjectEntity().getType(), + rootSubjectEntityId: that + .getRootSubjectEntity() + .getEntityId(), + } + ).toJSON() + ); + } + }, 500) + ); + }; + + this.getYText = function () { + return _ytext; + }; + + //automatically determines the size of input + _$node + .autoGrowInput({ + comfortZone: 15, + minWidth: 40, + maxWidth: 1000, + }) + .trigger("blur"); + } +} + +/** + * QuizAttribute + * @class attribute_widget.SingleValueAttribute + * @memberof attribute_widget + * @extends attribute_widget.AbstractAttribute + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {attribute_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to + */ +class QuizAttribute extends AbstractAttribute { + constructor(id, name, subjectEntity) { + super(id, name, subjectEntity); + /*** + * Value object of value + * @type {attribute_widget.Value} + * @private + */ + var _value = new Value(id, name, this, this.getRootSubjectEntity()); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(singleQuizAttributeHtml)({ id: id })); + + /** + * Set Value object of value + * @param {attribute_widget.Value} value + */ + this.setValue = function (value) { + _value = value; + }; + + /** + * Get Value object of value + * @returns {attribute_widget.Value} + */ + this.getValue = function () { + return _value; + }; + + /** + * jQuery object of DOM node representing the attribute + * @type {jQuery} + * @public + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the attribute + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.value = _value.toJSON(); + return json; + }; + + /** + * Set attribute value by its JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + _value.setValueFromJSON(json.value); + }; + + this.registerYType = function () { + _value.registerYType(); + }; + + _$node.find(".name").text(this.getName()); + _$node.find(".value").append(_value.get$node()); + + function addRow() { + var table = _$node.find("#table")[0]; + var rows = table.rows.length; + var row = table.insertRow(table.rows.length); + var cell0 = row.insertCell(0); + var cell1 = row.insertCell(1); + var cell2 = row.insertCell(2); + var cell3 = row.insertCell(3); + var input0 = document.createElement("input"); + var input1 = document.createElement("input"); + var input2 = document.createElement("input"); + var input3 = document.createElement("input"); + input0.id = rows + "0"; + input1.id = rows + "1"; + input2.id = rows + "2"; + input3.id = rows + "3"; + input1.type = "text"; + input2.type = "text"; + input3.type = "text"; + cell0.appendChild(input0); + cell1.appendChild(input1); + cell2.appendChild(input2); + cell3.appendChild(input3); + } + + this.showTable = function () { + _$node.find("#table")[0].style.visibility = "visible"; + _$node.find("#b")[0].style.visibility = "visible"; + _$node.find("#c")[0].style.visibility = "visible"; + _$node.find("#submit")[0].style.visibility = "visible"; + _$node.find("#display")[0].style.visibility = "visible"; + }; + + this.hideTable = function () { + _$node.find("#table")[0].style.visibility = "hidden"; + _$node.find("#b")[0].style.visibility = "hidden"; + _$node.find("#c")[0].style.visibility = "hidden"; + _$node.find("#submit")[0].style.visibility = "hidden"; + _$node.find("#display")[0].style.visibility = "hidden"; + }; + + _$node.find("#b").click(function () { + addRow(); + }); + + // remove rows from table + _$node.find("#c").click(function () { + var table = _$node.find("#table")[0]; + var rows = table.rows.length; + table.deleteRow(rows - 1); + }); + + // write table input into attribute field + _$node.find("#submit").click(function () { + var table = _$node.find("#table")[0]; + var Json = {}; + Json["topic"] = _$node.find("#topic")[0].value; + var Sequence = []; + var Questions = []; + var Intents = []; + var Hints = []; + var row = table.rows.length; + for (var i = 2; i < row; i++) { + if ( + _$node.find("#" + i.toString() + "1")[0].value == "" || + _$node.find("#" + i.toString() + "2")[0].value == "" + ) { + continue; + } + Sequence.push(_$node.find("#" + i.toString() + "0")[0].value); + Questions.push(_$node.find("#" + i.toString() + "1")[0].value); + Intents.push(_$node.find("#" + i.toString() + "2")[0].value); + if (_$node.find("#" + i.toString() + "3")[0].value == "") { + Hints.push("No Hint Available for this Question"); + } else Hints.push(_$node.find("#" + i.toString() + "3")[0].value); + } + Json["Questions"] = Questions; + Json["Sequence"] = Sequence; + Json["Intents"] = Intents; + Json["Hints"] = Hints; + console.log(JSON.stringify(Json)); + _$node.find(".val")[0].value = JSON.stringify(Json); + var field = _$node.find(".val")[0]; + field.dispatchEvent(new Event("input")); + }); + + // take content from attribute field and display as table + _$node.find("#display").click(function () { + var table = _$node.find("#table")[0]; + var Json = _$node.find(".val")[0].value; + console.log(Json); + var content = JSON.parse(Json); + _$node.find("#topic")[0].value = content.topic; + var rowNumb = content.Questions.length; + console.log(rowNumb); + var currRows = table.rows.length - 2; + console.log(currRows); + if (currRows < rowNumb) { + for (currRows; currRows < rowNumb; currRows++) { + addRow(); + } + } + for (var i = 2; i < rowNumb + 2; i++) { + if (_$node.find("#" + i.toString() + "0")[0].value == null) { + break; + } + _$node.find("#" + i.toString() + "0")[0].value = + content.Sequence[i - 2]; + _$node.find("#" + i.toString() + "1")[0].value = + content.Questions[i - 2]; + _$node.find("#" + i.toString() + "2")[0].value = content.Intents[i - 2]; + _$node.find("#" + i.toString() + "3")[0].value = content.Hints[i - 2]; + } + }); + } +} + +/** + * KeySelectionValueAttribute + * @class canvas_widget.KeySelectionValueAttribute + * @extends canvas_widget.AbstractAttribute + * @memberof canvas_widget + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {Object} options Selection options + */ +class KeySelectionValueAttribute extends AbstractAttribute { + constructor(id, name, subjectEntity, options) { + super(id, name, subjectEntity); + + var _ymap = null; + + //noinspection UnnecessaryLocalVariableJS + /** + * Selection options + * @type {Object} + * @private + */ + var _options = options; + + /** + * Value object of key + * @type {canvas_widget.Value} + * @private + */ + var _key = new Value(id + "[key]", "", this, this.getRootSubjectEntity()); + + /*** + * Value object of value + * @type {canvas_widget.Value} + * @private + */ + var _value = new SelectionValue( + id + "[value]", + "", + this, + this.getRootSubjectEntity(), + _options + ); + + /** + * jQuery object of the DOM node representing the attribute + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(keySelectionValueAttributeHtml)({ id: id })); + + //noinspection JSUnusedGlobalSymbols + /** + * Set Value object of key + * @param {canvas_widget.Value} key + */ + this.setKey = function (key) { + _key = key; + }; + + /** + * Get Value object of key + * @returns {canvas_widget.Value} + */ + this.getKey = function () { + return _key; + }; + + /** + * Set Value object of value + * @param {canvas_widget.Value} value + */ + this.setValue = function (value) { + _value = value; + }; + + /** + * Get Value object of value + * @returns {canvas_widget.Value} + */ + this.getValue = function () { + return _value; + }; + + /** + * Get jQuery object of the DOM node representing the attribute + * @returns {jQuery} + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the attribute + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.key = _key.toJSON(); + json.value = _value.toJSON(); + return json; + }; + + /** + * Set value of key and value by their JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + _key.setValueFromJSON(json.key); + _value.setValueFromJSON(json.value); + }; + + this.registerYMap = function () { + _key.registerYType(); + _value.registerYType(); + }; + + this.getYMap = function () { + return _ymap; + }; + + _$node.find(".key").append(_key.get$node()); + _$node.find(".value").append(_value.get$node()); + } +} + +/** + * ConditionListAttribute + * @class canvas_widget.ConditionListAttribute + * @extends canvas_widget.AbstractAttribute + * @memberof canvas_widget + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {Object} options Selection options + * @param {Object} options2 Selection options + */ +class ConditionListAttribute extends AbstractAttribute { + static TYPE = "ConditionListAttribute"; + constructor(id, name, subjectEntity, options, options2, y) { + y = y || window.y; + super(id, name, subjectEntity); + var that = this; + + /** + * Selection options + * @type {Object} + * @private + */ + var _options = options; + + /** + * Selection options + * @type {Object} + * @private + */ + var _options2 = options2; + + /** + * List of attributes + * @type {Object} + * @private + */ + var _list = {}; + + /** + * jQuery object of DOM node representing the attribute + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(listHtml)()); + + /** + * Inter widget communication wrapper + * @type {Object} + */ + var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); + + /** + * Apply an Attribute Add Operation + * @param {operations.ot.AttributeAddOperation} operation + * @param {YText} ytext + */ + var processAttributeAddOperation = function (operation) { + var attribute = new ConditionPredicateAttribute( + operation.getEntityId(), + "Attribute", + that, + _options, + _options2 + ); + attribute.registerYMap(); + that.addAttribute(attribute); + _$node.find(".list").append(attribute.get$node()); + }; + + /** + * Propagate an Attribute Add Operation to the remote users and the local widgets + * @param {operations.ot.AttributeAddOperation} operation + */ + var propagateAttributeAddOperation = function (operation) { + processAttributeAddOperation(operation); + EntityManagerInstance.storeDataYjs(); + }; + + /** + * Apply an Attribute Delete Operation + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var processAttributeDeleteOperation = function (operation) { + var attribute = that.getAttribute(operation.getEntityId()); + if (attribute) { + that.deleteAttribute(attribute.getEntityId()); + attribute.get$node().remove(); + } + EntityManagerInstance.storeDataYjs(); + }; + + /** + * Propagate an Attribute Delete Operation to the remote users and the local widgets + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var propagateAttributeDeleteOperation = function (operation) { + processAttributeDeleteOperation(operation); + var ymap = that.getRootSubjectEntity().getYMap(); + ymap.delete(operation.getEntityId() + "[val]"); + }; + + /** + * Callback for a remote Attrbute Add Operation + * @param {operations.ot.AttributeAddOperation} operation + */ + var remoteAttributeAddCallback = function (operation) { + if ( + operation instanceof AttributeAddOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + processAttributeAddOperation(operation); + } + }; + + /** + * Callback for a remote Attribute Delete Operation + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var remoteAttributeDeleteCallback = function (operation) { + if ( + operation instanceof AttributeDeleteOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + processAttributeDeleteOperation(operation); + } + }; + + /** + * Callback for a local Attribute Add Operation + * @param {operations.ot.AttributeAddOperation} operation + */ + var localAttributeAddCallback = function (operation) { + if ( + operation instanceof AttributeAddOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + propagateAttributeAddOperation(operation); + } + }; + + /** + * Callback for a local Attribute Delete Operation + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var localAttributeDeleteCallback = function (operation) { + if ( + operation instanceof AttributeDeleteOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + propagateAttributeDeleteOperation(operation); + } + }; + + /** + * Add attribute to attribute list + * @param {canvas_widget.AbstractAttribute} attribute + */ + this.addAttribute = function (attribute) { + var id = attribute.getEntityId(); + if (!_list.hasOwnProperty(id)) { + _list[id] = attribute; + } + }; + + /** + * Get attribute of attribute list by its entity id + * @param id + * @returns {canvas_widget.AbstractAttribute} + */ + this.getAttribute = function (id) { + if (_list.hasOwnProperty(id)) { + return _list[id]; + } + return null; + }; + + /** + * Delete attribute from attribute list by its entity id + * @param {string} id + */ + this.deleteAttribute = function (id) { + if (_list.hasOwnProperty(id)) { + delete _list[id]; + } + }; + + /** + * Get attribute list + * @returns {Object} + */ + this.getAttributes = function () { + return _list; + }; + + /** + * Set attribute list + * @param {Object} list + */ + this.setAttributes = function (list) { + _list = list; + }; + + /** + * Get jQuery object of the DOM node representing the attribute (list) + * @returns {jQuery} + */ + this.get$node = function () { + return _$node; + }; + + this.setOptions = function (options) { + _options = options; + }; + + /** + * Get JSON representation of the attribute (list) + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.type = ConditionListAttribute.TYPE; + var attr = {}; + lodash.forEach(this.getAttributes(), function (val, key) { + attr[key] = val.toJSON(); + }); + json.list = attr; + return json; + }; + + /** + * Set attribute list by its JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + lodash.forEach(json.list, function (val, key) { + var attribute = new ConditionPredicateAttribute( + key, + key, + that, + _options, + _options2 + ); + attribute.setValueFromJSON(json.list[key]); + that.addAttribute(attribute); + _$node.find(".list").append(attribute.get$node()); + }); + }; + + /** + * Register inter widget communication callbacks + */ + this.registerCallbacks = function () { + _iwcw.registerOnDataReceivedCallback(localAttributeAddCallback); + _iwcw.registerOnDataReceivedCallback(localAttributeDeleteCallback); + }; + + /** + * Unregister inter widget communication callbacks + */ + this.unregisterCallbacks = function () { + _iwcw.unregisterOnDataReceivedCallback(localAttributeAddCallback); + _iwcw.unregisterOnDataReceivedCallback(localAttributeDeleteCallback); + }; + + _$node.find(".name").text(this.getName()); + + for (var attributeId in _list) { + if (_list.hasOwnProperty(attributeId)) { + _$node.find(".list").append(_list[attributeId].get$node()); + } + } + + this.registerYMap = function () { + var ymap = that.getRootSubjectEntity().getYMap(); + var attrs = that.getAttributes(); + for (var key in attrs) { + if (attrs.hasOwnProperty(key)) { + attrs[key].registerYMap(); + } + } + + ymap.observe(function (event) { + const array = Array.from(event.changes.keys.entries()); + array.forEach(([key, change]) => { + if (key.indexOf("[value]") != -1) { + var operation; + switch (change.action) { + case "add": { + if (eventWasTriggeredByMe(event)) return; + const jabberId = event.currentTarget.get("jabberId"); + if (jabberId === _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]) + return; + operation = new AttributeAddOperation( + key.replace(/\[\w*\]/g, ""), + that.getEntityId(), + that.getRootSubjectEntity().getEntityId(), + that.constructor.name + ); + remoteAttributeAddCallback(operation); + + break; + } + case "delete": { + operation = new AttributeDeleteOperation( + key.replace(/\[\w*\]/g, ""), + that.getEntityId(), + that.getRootSubjectEntity().getEntityId(), + that.constructor.name + ); + remoteAttributeDeleteCallback(operation); + break; + } + } + } else if (key.indexOf("updateConditionOption") != -1) { + that.setOptions(event.value); + } + }); + }); + }; + + if (_iwcw) { + that.registerCallbacks(); + } + } +} + +/** + * RenamingAttribute + * @class canvas_widget.ConditionPredicateAttribute + * @memberof canvas_widget + * @extends canvas_widget.AbstractAttribute + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {Object} options Selection options + * @constructor + */ +class RenamingAttribute extends AbstractAttribute { + static TYPE = "RenamingAttribute"; + constructor(id, name, subjectEntity, options) { + super(id, name, subjectEntity); + + //noinspection UnnecessaryLocalVariableJS + /** + * Selection options + * @type {Object} + * @private + */ + var _options = options; + + /** + * Value object of key + * @type {canvas_widget.Value} + * @private + */ + var _key = new Value( + id + "[val]", + "Attribute Name", + this, + this.getRootSubjectEntity() + ); + + /*** + * Value object of ref + * @type {canvas_widget.Value} + * @private + */ + var _ref = new Value( + id + "[ref]", + "Attribute Reference", + this, + this.getRootSubjectEntity() + ); + + /*** + * Value object of vis + * @type {canvas_widget.Value} + * @private + */ + var _vis = new SelectionValue( + id + "[vis]", + "Attribute Visibility", + this, + this.getRootSubjectEntity(), + _options + ); + + /** + * jQuery object of the DOM node representing the attribute + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(renamingAttrHTML)()); + + //noinspection JSUnusedGlobalSymbols + /** + * Set Value object of key + * @param {canvas_widget.Value} key + */ + this.setKey = function (key) { + _key = key; + }; + + /** + * Get Value object of key + * @returns {canvas_widget.Value} + */ + this.getKey = function () { + return _key; + }; + + /** + * Get Value object of value + * @returns {canvas_widget.Value} + */ + this.getRef = function () { + return _ref; + }; + + /** + * Get Visibility object of value + * @returns {canvas_widget.Value} + */ + this.getVis = function () { + return _vis; + }; + + //noinspection JSUnusedGlobalSymbols + /** + * Set Value object of value + * @param {canvas_widget.Value} value + */ + this.setVis = function (value) { + _vis = value; + }; + + /** + * Get jQuery object of the DOM node representing the attribute + * @returns {jQuery} + */ + this.get$node = function () { + return _$node; + }; + + /** + * Set value of key and value by their JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + _key.setValueFromJSON(json.val); + _ref.setValueFromJSON(json.ref); + _vis.setValueFromJSON(json.vis || { value: "" }); + }; + + /** + * Get JSON representation of the attribute + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.val = _key.toJSON(); + json.ref = _ref.toJSON(); + json.vis = _vis.toJSON(); + return json; + }; + _$node.find(".val").append(_key.get$node()); + _$node.find(".ref").append(_ref.get$node()).hide(); + _$node.find(".vis").append(_vis.get$node()); + + this.registerYMap = function () { + _key.registerYType(); + _ref.registerYType(); + _vis.registerYType(); + }; + } +} + +/** + * KeySelectionValueSelectionValueListAttribute + * @class canvas_widget.KeySelectionValueSelectionValueListAttribute + * @extends canvas_widget.AbstractAttribute + * @memberof canvas_widget + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {Object} options Selection options + * @param {Object} options2 Selection options + */ +class KeySelectionValueSelectionValueListAttribute extends AbstractAttribute { + static TYPE = "KeySelectionValueSelectionValueListAttribute"; + + constructor(id, name, subjectEntity, options, options2) { + super(id, name, subjectEntity); + var that = this; + + /** + * Selection options + * @type {Object} + * @private + */ + var _options = options; + + /** + * Selection options + * @type {Object} + * @private + */ + var _options2 = options2; + + /** + * List of attributes + * @type {Object} + * @private + */ + var _list = {}; + + /** + * jQuery object of DOM node representing the attribute + * @type {jQuery} + * @private + */ + var _$node = $( + lodash.template(keySelectionValueSelectionValueListAttributeHtml)() + ); + + /** + * Inter widget communication wrapper + * @type {Object} + */ + y = y || window.y; + var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); + + /** + * Apply an Attribute Add Operation + * @param {operations.ot.AttributeAddOperation} operation + */ + var processAttributeAddOperation = function (operation) { + var attribute = new KeySelectionValueSelectionValueAttribute( + operation.getEntityId(), + "Attribute", + that, + _options, + _options2 + ); + attribute.registerYType(); + that.addAttribute(attribute); + if (_$node.find(".list").find("#" + attribute.getEntityId()).length == 0) + _$node.find(".list").append(attribute.get$node()); + EntityManagerInstance.storeDataYjs(); + }; + + /** + * Apply an Attribute Delete Operation + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var processAttributeDeleteOperation = function (operation) { + var attribute = that.getAttribute(operation.getEntityId()); + if (attribute) { + that.deleteAttribute(attribute.getEntityId()); + attribute.get$node().remove(); + } + EntityManagerInstance.storeDataYjs(); + }; + + /** + * Propagate an Attribute Add Operation to the remote users and the local widgets + * @param {operations.ot.AttributeAddOperation} operation + */ + var propagateAttributeAddOperation = function (operation) { + processAttributeAddOperation(operation); + }; + + /** + * Propagate an Attribute Delete Operation to the remote users and the local widgets + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var propagateAttributeDeleteOperation = function (operation) { + processAttributeDeleteOperation(operation); + var ynode = that.getRootSubjectEntity().getYMap(); + ynode.delete(operation.getEntityId() + "[key]"); + }; + + /** + * Callback for a remote Attrbute Add Operation + * @param {operations.ot.AttributeAddOperation} operation + */ + var remoteAttributeAddCallback = function (operation) { + if ( + operation instanceof AttributeAddOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + processAttributeAddOperation(operation); + } + }; + + /** + * Callback for a remote Attribute Delete Operation + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var remoteAttributeDeleteCallback = function (operation) { + if ( + operation instanceof AttributeDeleteOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.ATTRIBUTE, + operation.getOTOperation() + ); + processAttributeDeleteOperation(operation); + } + }; + + var localAttributeAddCallback = function (operation) { + if ( + operation instanceof AttributeAddOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + propagateAttributeAddOperation(operation); + } + }; + + /** + * Callback for a local Attribute Delete Operation + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var localAttributeDeleteCallback = function (operation) { + if ( + operation instanceof AttributeDeleteOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + propagateAttributeDeleteOperation(operation); + } + }; + + /** + * Add attribute to attribute list + * @param {canvas_widget.AbstractAttribute} attribute + */ + this.addAttribute = function (attribute) { + var id = attribute.getEntityId(); + if (!_list.hasOwnProperty(id)) { + _list[id] = attribute; + } + }; + + /** + * Get attribute of attribute list by its entity id + * @param id + * @returns {canvas_widget.AbstractAttribute} + */ + this.getAttribute = function (id) { + if (_list.hasOwnProperty(id)) { + return _list[id]; + } + return null; + }; + + /** + * Delete attribute from attribute list by its entity id + * @param {string} id + */ + this.deleteAttribute = function (id) { + if (_list.hasOwnProperty(id)) { + delete _list[id]; + } + }; + + /** + * Get attribute list + * @returns {Object} + */ + this.getAttributes = function () { + return _list; + }; + + /** + * Set attribute list + * @param {Object} list + */ + this.setAttributes = function (list) { + _list = list; + }; + + /** + * Get jQuery object of the DOM node representing the attribute (list) + * @returns {jQuery} + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the attribute (list) + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.type = KeySelectionValueSelectionValueListAttribute.TYPE; + var attr = {}; + lodash.forEach(this.getAttributes(), function (val, key) { + attr[key] = val.toJSON(); + }); + json.list = attr; + return json; + }; + + /** + * Set attribute list by its JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + lodash.forEach(json.list, function (val, key) { + var attribute = new KeySelectionValueSelectionValueAttribute( + key, + key, + that, + _options, + _options2 + ); + attribute.setValueFromJSON(json.list[key]); + that.addAttribute(attribute); + if ( + _$node.find(".list").find("#" + attribute.getEntityId()).length == 0 + ) + _$node.find(".list").append(attribute.get$node()); + }); + }; + + /** + * Register inter widget communication callbacks + */ + this.registerCallbacks = function () { + _iwcw.registerOnDataReceivedCallback(localAttributeAddCallback); + _iwcw.registerOnDataReceivedCallback(localAttributeDeleteCallback); + }; + + /** + * Unregister inter widget communication callbacks + */ + this.unregisterCallbacks = function () { + _iwcw.unregisterOnDataReceivedCallback(localAttributeAddCallback); + _iwcw.unregisterOnDataReceivedCallback(localAttributeDeleteCallback); + }; + + _$node.find(".name").text(this.getName()); + + for (var attributeId in _list) { + if (_list.hasOwnProperty(attributeId)) { + _$node.find(".list").append(_list[attributeId].get$node()); + } + } + + if (_iwcw) { + that.registerCallbacks(); + } + + this.registerYMap = function () { + var ymap = that.getRootSubjectEntity().getYMap(); + var attrs = that.getAttributes(); + for (var key in attrs) { + if (attrs.hasOwnProperty(key)) { + var attr = attrs[key]; + attr.registerYType(); + } + } + + ymap.observe(function (event) { + const array = Array.from(event.changes.keys.entries()); + array.forEach(([key, change]) => { + if (key.indexOf("[key]") != -1) { + var operation; + switch (change.action) { + case "add": { + const jabberId = event.currentTarget.get("jabberId"); + if (jabberId === _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]) + return; + operation = new AttributeAddOperation( + key.replace(/\[\w*\]/g, ""), + that.getEntityId(), + that.getRootSubjectEntity().getEntityId(), + that.constructor.name + ); + remoteAttributeAddCallback(operation); + break; + } + case "delete": { + operation = new AttributeDeleteOperation( + key.replace(/\[\w*\]/g, ""), + that.getEntityId(), + that.getRootSubjectEntity().getEntityId(), + that.constructor.name + ); + remoteAttributeDeleteCallback(operation); + break; + } + } + } + }); + }); + }; + } +} + +/** + * RenamingListAttribute + * @class canvas_widget.RenamingListAttribute + * @extends canvas_widget.AbstractAttribute + * @memberof canvas_widget + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {Object} options Selection options + */ +class RenamingListAttribute extends AbstractAttribute { + static TYPE = "RenamingListAttribute"; + constructor(id, name, subjectEntity, options, y) { + y = y || window.y; + super(id, name, subjectEntity); + var that = this; + + /** + * Selection options + * @type {Object} + * @private + */ + var _options = options; + + /** + * List of attributes + * @type {Object} + * @private + */ + var _list = {}; + + /** + * jQuery object of DOM node representing the attribute + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(listHtml)()); + + /** + * Inter widget communication wrapper + * @type {Object} + */ + var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); + + /** + * Apply an Attribute Add Operation + * @param {operations.ot.AttributeAddOperation} operation + * @param { YText} ytext + */ + var processAttributeAddOperation = function (operation) { + var attribute = new RenamingAttribute( + operation.getEntityId(), + "Attribute", + that, + _options + ); + that.addAttribute(attribute); + attribute.registerYMap(); + _$node.find(".list").append(attribute.get$node()); + EntityManagerInstance.storeDataYjs(); + return attribute; + }; + + /** + * Propagate an Attribute Add Operation to the remote users and the local widgets + * @param {operations.ot.AttributeAddOperation} operation + */ + this.propagateAttributeAddOperation = function (operation) { + return processAttributeAddOperation(operation); + }; + + /** + * Apply an Attribute Delete Operation + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var processAttributeDeleteOperation = function (operation) { + var attribute = that.getAttribute(operation.getEntityId()); + if (attribute) { + that.deleteAttribute(attribute.getEntityId()); + attribute.get$node().remove(); + } + }; + + /** + * Propagate an Attribute Delete Operation to the remote users and the local widgets + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var propagateAttributeDeleteOperation = function (operation) { + processAttributeDeleteOperation(operation); + var ymap = that.getRootSubjectEntity().getYMap(); + ymap.delete(operation.getEntityId() + "[val]"); + EntityManagerInstance.storeDataYjs(); + }; + + /** + * Callback for a remote Attrbute Add Operation + * @param {operations.ot.AttributeAddOperation} operation + */ + var remoteAttributeAddCallback = function (operation) { + if ( + operation instanceof AttributeAddOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + processAttributeAddOperation(operation); + subjectEntity.showAttributes(); + } + }; + + /** + * Callback for a remote Attribute Delete Operation + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var remoteAttributeDeleteCallback = function (operation) { + if ( + operation instanceof AttributeDeleteOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + processAttributeDeleteOperation(operation); + } + }; + + /** + * Callback for a local Attribute Add Operation + * @param {operations.ot.AttributeAddOperation} operation + */ + var localAttributeAddCallback = function (operation) { + if ( + operation instanceof AttributeAddOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + propagateAttributeAddOperation(operation); + } + }; + + /** + * Callback for a local Attribute Delete Operation + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var localAttributeDeleteCallback = function (operation) { + if ( + operation instanceof AttributeDeleteOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + propagateAttributeDeleteOperation(operation); + } + }; + + /** + * Add attribute to attribute list + * @param {canvas_widget.AbstractAttribute} attribute + */ + this.addAttribute = function (attribute) { + var id = attribute.getEntityId(); + if (!_list.hasOwnProperty(id)) { + _list[id] = attribute; + } + }; + + /** + * Get attribute of attribute list by its entity id + * @param id + * @returns {canvas_widget.AbstractAttribute} + */ + this.getAttribute = function (id) { + if (_list.hasOwnProperty(id)) { + return _list[id]; + } + return null; + }; + + /** + * Delete attribute from attribute list by its entity id + * @param {string} id + */ + this.deleteAttribute = function (id) { + if (_list.hasOwnProperty(id)) { + delete _list[id]; + } + }; + + /** + * Get attribute list + * @returns {Object} + */ + this.getAttributes = function () { + return _list; + }; + + /** + * Set attribute list + * @param {Object} list + */ + this.setAttributes = function (list) { + _list = list; + }; + + /** + * Get jQuery object of the DOM node representing the attribute (list) + * @returns {jQuery} + */ + this.get$node = function () { + return _$node; + }; + + this.setOptions = function (options) { + _options = options; + }; + + /** + * Get JSON representation of the attribute (list) + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.type = RenamingListAttribute.TYPE; + var attr = {}; + lodash.forEach(this.getAttributes(), function (val, key) { + attr[key] = val.toJSON(); + }); + json.list = attr; + return json; + }; + + /** + * Set attribute list by its JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + lodash.forEach(json.list, function (val, key) { + var attribute = new RenamingAttribute(key, key, that, _options); + attribute.setValueFromJSON(json.list[key]); + that.addAttribute(attribute); + _$node.find(".list").append(attribute.get$node()); + }); + }; + + /** + * Register inter widget communication callbacks + */ + this.registerCallbacks = function () { + _iwcw.registerOnDataReceivedCallback(localAttributeAddCallback); + _iwcw.registerOnDataReceivedCallback(localAttributeDeleteCallback); + }; + + /** + * Unregister inter widget communication callbacks + */ + this.unregisterCallbacks = function () { + _iwcw.unregisterOnDataReceivedCallback(localAttributeAddCallback); + _iwcw.unregisterOnDataReceivedCallback(localAttributeDeleteCallback); + }; + + _$node.find(".name").text(this.getName()); + + for (var attributeId in _list) { + if (_list.hasOwnProperty(attributeId)) { + _$node.find(".list").append(_list[attributeId].get$node()); + } + } + + if (_iwcw) { + that.registerCallbacks(); + } + this.registerYMap = function () { + var ymap = that.getRootSubjectEntity().getYMap(); + var attrs = that.getAttributes(); + for (var key in attrs) { + if (attrs.hasOwnProperty(key)) { + var attr = attrs[key]; + attr.registerYMap(); + } + } + + ymap.observe(function (event) { + const array = Array.from(event.changes.keys.entries()); + array.forEach(([key, change]) => { + if (key.indexOf("[val]") != -1) { + switch (change.action) { + case "add": { + // var yUserId = event.object.map[key][0]; + // if (yUserId === y.clientID) return; + const operation = new AttributeAddOperation( + key.replace(/\[\w*\]/g, ""), + that.getEntityId(), + that.getRootSubjectEntity().getEntityId(), + that.constructor.name + ); + remoteAttributeAddCallback(operation); + + break; + } + case "delete": { + const operation = new AttributeDeleteOperation( + key.replace(/\[\w*\]/g, ""), + that.getEntityId(), + that.getRootSubjectEntity().getEntityId(), + that.constructor.name + ); + remoteAttributeDeleteCallback(operation); + break; + } + } + } + }); + }); + }; + } +} + +/** + * ConditionPredicateAttribute + * @class attribute_widget.ConditionPredicateAttribute + * @memberof attribute_widget + * @extends attribute_widget.AbstractAttribute + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {Object} options Selection options + * @param {Object} options2 Selection options + * @constructor + */ +class ConditionPredicateAttribute extends AbstractAttribute { + static TYPE = "ConditionPredicateAttribute"; + constructor(id, name, subjectEntity, options, options2) { + super(id, name, subjectEntity); + + //noinspection UnnecessaryLocalVariableJS + /** + * Selection options + * @type {Object} + * @private + */ + var _options = options; + + //noinspection UnnecessaryLocalVariableJS + /** + * Selection options + * @type {Object} + * @private + */ + var _options2 = options2; + + //var _options3 = options3; + /** + * Value object of key + * @type {attribute_widget.Value} + * @private + */ + var _key = new Value( + id + "[value]", + "Attribute Value", + this, + this.getRootSubjectEntity() + ); + + /*** + * Value object of value + * @type {attribute_widget.Value} + * @private + */ + var _value = new SelectionValue( + id + "[property]", + "Attribute Name", + this, + this.getRootSubjectEntity(), + _options + ); + + /*** + * Value object of value + * @type {attribute_widget.Value} + * @private + */ + var _value2 = new SelectionValue( + id + "[operator]", + "Logical Operator", + this, + this.getRootSubjectEntity(), + _options2 + ); + + /** + * jQuery object of the DOM node representing the attribute + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(condition_predicateHtml)()); + + //noinspection JSUnusedGlobalSymbols + /** + * Set Value object of key + * @param {attribute_widget.Value} key + */ + this.setKey = function (key) { + _key = key; + }; + + /** + * Get Value object of key + * @returns {attribute_widget.Value} + */ + this.getKey = function () { + return _key; + }; + + /** + * Set Value object of value + * @param {attribute_widget.Value} value + */ + this.setValue = function (value) { + _value = value; + }; + + /** + * Get Value object of value + * @returns {attribute_widget.Value} + */ + this.getValue = function () { + return _value; + }; + + //noinspection JSUnusedGlobalSymbols + /** + * Set Value object of value + * @param {attribute_widget.Value} value + */ + this.setValue2 = function (value) { + _value2 = value; + }; + + /** + * Get Value object of value + * @returns {attribute_widget.Value} + */ + this.getValue2 = function () { + return _value2; + }; + + /** + * Get jQuery object of the DOM node representing the attribute + * @returns {jQuery} + */ + this.get$node = function () { + return _$node; + }; + + /** + * Set value of key and value by their JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + _key.setValueFromJSON(json.val); + _value.setValueFromJSON(json.property); + _value2.setValueFromJSON(json.operator || { value: "" }); + }; + /** + * Get JSON representation of the attribute + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.val = _key.toJSON(); + json.property = _value.toJSON(); + json.operator = _value2.toJSON(); + return json; + }; + _$node.find(".val").append(_key.get$node()); + _$node.find(".property").append(_value.get$node()); + _$node.find(".operator").append(_value2.get$node()); + //_$node.find(".operator2").append(_value3.get$node()); + this.registerYMap = function () { + _key.registerYType(); + _value.registerYType(); + _value2.registerYType(); + }; + } +} + +/** + * SingleColorValueAttribute + * @class canvas_widget.SingleColorValueAttribute + * @extends canvas_widget.AbstractAttribute + * @memberof canvas_widget + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to + */ +class SingleColorValueAttribute extends AbstractAttribute { + constructor(id, name, subjectEntity) { + super(id, name, subjectEntity); + + /*** + * Value object of value + * @type {canvas_widget.Value} + * @private + */ + var _value = new Value(id, name, this, this.getRootSubjectEntity()); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(singleColorValueAttributeHtml)()); + + /** + * Set Value object of value + * @param {canvas_widget.Value} value + */ + this.setValue = function (value) { + _value = value; + }; + + /** + * Get Value object of value + * @returns {canvas_widget.Value} + */ + this.getValue = function () { + return _value; + }; + + /** + * jQuery object of DOM node representing the attribute + * @type {jQuery} + * @private + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the attribute + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.value = _value.toJSON(); + return json; + }; + + /** + * Set attribute value by its JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + _value.setValueFromJSON(json.value); + }; + + _$node.find(".name").text(this.getName()); + _$node.find(".value").append(_value.get$node()); + } +} + +/** + * KeySelectionValueSelectionValueAttribute + * @class canvas_widget.KeySelectionValueSelectionValueAttribute + * @extends canvas_widget.AbstractAttribute + * @memberof canvas_widget + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {Object} options Selection options + * @param {Object} options2 Selection options + */ +class KeySelectionValueSelectionValueAttribute extends AbstractAttribute { + constructor(id, name, subjectEntity, options, options2) { + super(id, name, subjectEntity); + + //noinspection UnnecessaryLocalVariableJS + /** + * Selection options + * @type {Object} + * @private + */ + var _options = options; + + //noinspection UnnecessaryLocalVariableJS + /** + * Selection options + * @type {Object} + * @private + */ + var _options2 = options2; + + /** + * Value object of key + * @type {canvas_widget.Value} + * @private + */ + var _key = new Value(id + "[key]", "", this, this.getRootSubjectEntity()); + + /*** + * Value object of value + * @type {canvas_widget.Value} + * @private + */ + var _value = new SelectionValue( + id + "[value]", + "", + this, + this.getRootSubjectEntity(), + _options + ); + + /*** + * Value object of value + * @type {canvas_widget.Value} + * @private + */ + var _value2 = new SelectionValue( + id + "[value2]", + "", + this, + this.getRootSubjectEntity(), + _options2 + ); + + /** + * jQuery object of the DOM node representing the attribute + * @type {jQuery} + * @private + */ + var _$node = $( + lodash.template(keySelectionValueSelectionValueAttributeHtml)({ id: id }) + ); + + //noinspection JSUnusedGlobalSymbols + /** + * Set Value object of key + * @param {canvas_widget.Value} key + */ + this.setKey = function (key) { + _key = key; + }; + + /** + * Get Value object of key + * @returns {canvas_widget.Value} + */ + this.getKey = function () { + return _key; + }; + + /** + * Set Value object of value + * @param {canvas_widget.Value} value + */ + this.setValue = function (value) { + _value = value; + }; + + /** + * Get Value object of value + * @returns {canvas_widget.Value} + */ + this.getValue = function () { + return _value; + }; + + /** + * Set Value object of value + * @param {canvas_widget.Value} value + */ + this.setValue2 = function (value) { + _value2 = value; + }; + + /** + * Get Value object of value + * @returns {canvas_widget.Value} + */ + this.getValue2 = function () { + return _value2; + }; + + /** + * Get jQuery object of the DOM node representing the attribute + * @returns {jQuery} + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the attribute + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.key = _key.toJSON(); + json.value = _value.toJSON(); + json.value2 = _value2.toJSON(); + return json; + }; + + /** + * Set value of key and value by their JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + _key.setValueFromJSON(json.key); + _value.setValueFromJSON(json.value); + _value2.setValueFromJSON(json.value2 || { value: "" }); + }; + + this.registerYType = function () { + _key.registerYType(); + _value.registerYType(); + _value2.registerYType(); + }; + + _$node.find(".key").append(_key.get$node()); + _$node.find(".value").append(_value.get$node()); + } +} + +/** + * KeySelectionValueListAttribute + * @class canvas_widget.KeySelectionValueListAttribute + * @extends canvas_widget.AbstractAttribute + * @memberof canvas_widget + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {Object} options Selection options + */ +class KeySelectionValueListAttribute extends AbstractAttribute { + static TYPE = "KeySelectionValueListAttribute"; + constructor(id, name, subjectEntity, options) { + super(id, name, subjectEntity); + var that = this; + + /** + * Selection options + * @type {Object} + * @private + */ + var _options = options; + + /** + * List of attributes + * @type {Object} + * @private + */ + var _list = {}; + + /** + * jQuery object of DOM node representing the attribute + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(keySelectionValueListAttributeHtml)()); + + /** + * Inter widget communication wrapper + * @type {Object} + */ + y = y || window.y; + var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); + + /** + * Apply an Attribute Add Operation + * @param {operations.ot.AttributeAddOperation} operation + */ + var processAttributeAddOperation = function (operation) { + var attribute = new KeySelectionValueAttribute( + operation.getEntityId(), + "Attribute", + that, + _options + ); + attribute.registerYMap(); + that.addAttribute(attribute); + if (_$node.find(".list").find("#" + attribute.getEntityId()).length == 0) + _$node.find(".list").append(attribute.get$node()); + }; + + /** + * Apply an Attribute Delete Operation + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var processAttributeDeleteOperation = function (operation) { + var attribute = that.getAttribute(operation.getEntityId()); + if (attribute) { + that.deleteAttribute(attribute.getEntityId()); + attribute.get$node().remove(); + } + }; + + /** + * Propagate an Attribute Add Operation to the remote users and the local widgets + * @param {operations.ot.AttributeAddOperation} operation + */ + var propagateAttributeAddOperation = function (operation) { + processAttributeAddOperation(operation); + EntityManagerInstance.storeDataYjs(); + }; + + /** + * Propagate an Attribute Delete Operation to the remote users and the local widgets + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var propagateAttributeDeleteOperation = function (operation) { + processAttributeDeleteOperation(operation); + var ymap = that.getRootSubjectEntity().getYMap(); + ymap.delete(operation.getEntityId() + "[key]"); + EntityManagerInstance.storeDataYjs(); + }; + + /** + * Callback for a remote Attrbute Add Operation + * @param {operations.ot.AttributeAddOperation} operation + */ + var remoteAttributeAddCallback = function (operation) { + if ( + operation instanceof AttributeAddOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + processAttributeAddOperation(operation); + } + }; + + /** + * Callback for a remote Attribute Delete Operation + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var remoteAttributeDeleteCallback = function (operation) { + if ( + operation instanceof AttributeDeleteOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + processAttributeDeleteOperation(operation); + } + }; + + var localAttributeAddCallback = function (operation) { + if ( + operation instanceof AttributeAddOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + propagateAttributeAddOperation(operation); + } + }; + /** + * Callback for a local Attribute Delete Operation + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var localAttributeDeleteCallback = function (operation) { + if ( + operation instanceof AttributeDeleteOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + propagateAttributeDeleteOperation(operation); + } + }; + + /** + * Add attribute to attribute list + * @param {canvas_widget.AbstractAttribute} attribute + */ + this.addAttribute = function (attribute) { + var id = attribute.getEntityId(); + if (!_list.hasOwnProperty(id)) { + _list[id] = attribute; + } + }; + + /** + * Get attribute of attribute list by its entity id + * @param id + * @returns {canvas_widget.AbstractAttribute} + */ + this.getAttribute = function (id) { + if (_list.hasOwnProperty(id)) { + return _list[id]; + } + return null; + }; + + /** + * Delete attribute from attribute list by its entity id + * @param {string} id + */ + this.deleteAttribute = function (id) { + if (_list.hasOwnProperty(id)) { + delete _list[id]; + } + }; + + /** + * Get attribute list + * @returns {Object} + */ + this.getAttributes = function () { + return _list; + }; + + /** + * Set attribute list + * @param {Object} list + */ + this.setAttributes = function (list) { + _list = list; + }; + + /** + * Get jQuery object of the DOM node representing the attribute (list) + * @returns {jQuery} + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the attribute (list) + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.type = KeySelectionValueListAttribute.TYPE; + var attr = {}; + lodash.forEach(this.getAttributes(), function (val, key) { + attr[key] = val.toJSON(); + }); + json.list = attr; + return json; + }; + + /** + * Set attribute list by its JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + lodash.forEach(json.list, function (val, key) { + var attribute = new KeySelectionValueAttribute( + key, + key, + that, + _options + ); + attribute.setValueFromJSON(json.list[key]); + that.addAttribute(attribute); + if ( + _$node.find(".list").find("#" + attribute.getEntityId()).length == 0 + ) + _$node.find(".list").append(attribute.get$node()); + }); + }; + + /** + * Register inter widget communication callbacks + */ + this.registerCallbacks = function () { + _iwcw.registerOnDataReceivedCallback(localAttributeAddCallback); + _iwcw.registerOnDataReceivedCallback(localAttributeDeleteCallback); + }; + + /** + * Unregister inter widget communication callbacks + */ + this.unregisterCallbacks = function () { + _iwcw.unregisterOnDataReceivedCallback(localAttributeAddCallback); + _iwcw.unregisterOnDataReceivedCallback(localAttributeDeleteCallback); + }; + + _$node.find(".name").text(this.getName()); + + for (var attributeId in _list) { + if (_list.hasOwnProperty(attributeId)) { + _$node.find(".list").append(_list[attributeId].get$node()); + } + } + + if (_iwcw) { + that.registerCallbacks(); + } + + this.registerYMap = function () { + var ymap = that.getRootSubjectEntity().getYMap(); + var attrs = that.getAttributes(); + for (var key in attrs) { + if (attrs.hasOwnProperty(key)) { + var attr = attrs[key]; + attr.getKey().registerYType(); + attr.getValue().registerYType(); + } + } + + ymap.observe(function (event) { + const array = Array.from(event.changes.keys.entries()); + array.forEach(([key, change]) => { + if (key.indexOf("[key]") != -1) { + var operation; + switch (change.action) { + case "add": { + // var yUserId = event.object.map[key][0]; + // if (yUserId === y.clientID) return; + operation = new AttributeAddOperation( + key.replace(/\[\w*\]/g, ""), + that.getEntityId(), + that.getRootSubjectEntity().getEntityId(), + that.constructor.name + ); + remoteAttributeAddCallback(operation); + + break; + } + case "delete": { + operation = new AttributeDeleteOperation( + key.replace(/\[\w*\]/g, ""), + that.getEntityId(), + that.getRootSubjectEntity().getEntityId(), + that.constructor.name + ); + remoteAttributeDeleteCallback(operation); + break; + } + } + } + }); + }); + }; + } +} + +/** + * Abstract Class Node + * @class canvas_widget.ModelAttributesNode + * @extends canvas_widget.AbstractNode + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of node + * @param {object} [attr] model attributes + */ +class ModelAttributesNode extends AbstractNode { + static TYPE = "ModelAttributesNode"; + + constructor(id, attr, y) { + super(id, ModelAttributesNode.TYPE, 0, 0, 0, 0, 0, null, null, y); + y = y || window.y; + if (!y) { + throw new Error("y is not defined"); + } + + /** + * jQuery object of node template + * @type {jQuery} + * @private + */ + var _$template = $(lodash.template(modelAttributesNodeHtml)()); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = AbstractNode.prototype.get$node + .call(this) + .append(_$template) + .addClass("class"); + + /** + * jQuery object of DOM node representing the attributes + * @type {jQuery} + * @private + */ + var _$attributeNode = _$node.find(".attributes"); + + /** + * Attributes of node + * @type {Object} + * @private + */ + var _attributes = this.getAttributes(); + + /** + * Get JSON representation of the node + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractNode.prototype.toJSON.call(this); + json.type = ModelAttributesNode.TYPE; + return json; + }; + + if (attr) { + for (var attrKey in attr) { + if (attr.hasOwnProperty(attrKey)) { + switch (attr[attrKey].value) { + case "boolean": + this.addAttribute( + new BooleanAttribute( + this.getEntityId() + + "[" + + attr[attrKey].key.toLowerCase() + + "]", + attr[attrKey].key, + this + ) + ); + break; + case "string": + this.addAttribute( + new SingleValueAttribute( + this.getEntityId() + + "[" + + attr[attrKey].key.toLowerCase() + + "]", + attr[attrKey].key, + this + ) + ); + break; + case "integer": + this.addAttribute( + new IntegerAttribute( + this.getEntityId() + + "[" + + attr[attrKey].key.toLowerCase() + + "]", + attr[attrKey].key, + this + ) + ); + break; + case "file": + this.addAttribute( + new FileAttribute( + this.getEntityId() + + "[" + + attr[attrKey].key.toLowerCase() + + "]", + attr[attrKey].key, + this + ) + ); + break; + default: + if (attr[attrKey].options) { + this.addAttribute( + new SingleSelectionAttribute( + this.getEntityId() + + "[" + + attr[attrKey].key.toLowerCase() + + "]", + attr[attrKey].key, + this, + attr[attrKey].options + ) + ); + } + break; + } + } + } + } else { + this.addAttribute( + new SingleValueAttribute(this.getEntityId() + "[name]", "Name", this, y) + ); + this.addAttribute( + new SingleMultiLineValueAttribute( + this.getEntityId() + "[description]", + "Description", + this, + y + ) + ); + } + + this.getLabel().getValue().setValue("Model Attributes"); + + _$node.find(".label").text("Model Attributes"); + _$node.hide(); + + for (var attributeKey in _attributes) { + if (_attributes.hasOwnProperty(attributeKey)) { + _$attributeNode.append(_attributes[attributeKey].get$node()); + } + } + + this.registerYMap = function () { + AbstractNode.prototype.registerYMap.call(this); + var attrs = this.getAttributes(); + for (var key in attrs) { + if (attrs.hasOwnProperty(key)) { + var attr = attrs[key]; + if ( + attr instanceof SingleValueAttribute || + attr instanceof SingleMultiLineValueAttribute + ) { + attr.getValue().registerYType(); + } else if ( + !(attr instanceof FileAttribute) && + !(attr instanceof SingleValueAttribute) && + !(attr instanceof SingleMultiLineValueAttribute) + ) { + attr.getValue().registerYType(); + } + } + } + }; + } +} + +/** + * ViewObjectNode + * @class canvas_widget.ViewObjectNode + * @extends canvas_widget.AbstractNode + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {number} zIndex Position of node on z-axis + * @param {object} jsonFromResource the ViewObjectNode is created from a json + */ +class ViewObjectNode extends AbstractNode { + static TYPE = "ViewObject"; + static DEFAULT_WIDTH = 150; + static DEFAULT_HEIGHT = 100; + constructor(id, left, top, width, height, zIndex, json) { + var that = this; + + super(id, "ViewObject", left, top, width, height, zIndex, json); + + /** + * jQuery object of node template + * @type {jQuery} + * @private + */ + var _$template = $( + lodash.template(viewobjectNodeHtml)({ type: that.getType() }) + ); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = AbstractNode.prototype.get$node + .call(this) + .append(_$template) + .addClass("viewobject"); + + /** + * jQuery object of DOM node representing the attributes + * @type {jQuery} + * @private + */ + var _$attributeNode = _$node.find(".attributes"); + + /** + * Get JSON representation of the node + * @returns {Object} + */ + this.toJSON = function () { + return AbstractNode.prototype.toJSON.call(this); + }; + + this.createConditionListAttribute = function (refAttrs) { + var targetAttrList = {}; + if (refAttrs && refAttrs.constructor.name === "RenamingListAttribute") { + var attrs = refAttrs.getAttributes(); + for (var key in attrs) { + if (attrs.hasOwnProperty(key)) { + targetAttrList[key] = attrs[key].getKey().getValue(); + } + } + } else { + for (var key in refAttrs) { + if (refAttrs.hasOwnProperty(key)) { + targetAttrList[key] = refAttrs[key].val.value; + } + } + } + var conditionListAttr = new ConditionListAttribute( + "[condition]", + "Conditions", + that, + targetAttrList, + LogicalOperator + ); + that.addAttribute(conditionListAttr); + _$attributeNode.append(conditionListAttr.get$node()); + conditionListAttr.get$node().hide(); + return conditionListAttr; + }; + + this.registerYMap = function () { + AbstractNode.prototype.registerYMap.call(this); + that.getLabel().getValue().registerYType(); + renamingList.registerYMap(); + if (cla) cla.registerYMap(); + targetAttribute.getValue().registerYType(); + conjSelection.getValue().registerYType(); + }; + + this.showAttributes = function () { + if (renamingList.get$node().is(":hidden")) renamingList.get$node().show(); + if (conjSelection.get$node().is(":hidden")) + conjSelection.get$node().show(); + if (cla.get$node().is(":hidden")) cla.get$node().show(); + if (!targetAttribute.get$node().is(":hidden")) + targetAttribute.get$node().hide(); + }; + + var targetAttribute, renamingList, conjSelection, cla; + _$node.find(".label").append(this.getLabel().get$node()); + if (window.hasOwnProperty("y")) { + const dataMap = y.getMap("data"); + var model = dataMap.get("model"); + if (model) { + var selectionValues = + ViewTypesUtil.GetAllNodesOfBaseModelAsSelectionList2(model.nodes, [ + "Object", + ]); + targetAttribute = new SingleSelectionAttribute( + id + "[target]", + "Target", + that, + selectionValues + ); + that.addAttribute(targetAttribute); + _$attributeNode.prepend(targetAttribute.get$node()); + } + if (json) + cla = that.createConditionListAttribute( + json.attributes["[attributes]"].list + ); + else cla = that.createConditionListAttribute(); + } + + renamingList = new RenamingListAttribute( + "[attributes]", + "Attributes", + that, + { + show: "Visible", + hide: "Hidden", + } + ); + that.addAttribute(renamingList); + _$attributeNode.append(renamingList.get$node()); + renamingList.get$node().hide(); + + conjSelection = new SingleSelectionAttribute( + id + "[conjunction]", + "Conjunction", + that, + LogicalConjunctions + ); + that.addAttribute(conjSelection); + _$attributeNode.append(conjSelection.get$node()); + conjSelection.get$node().hide(); + + if (json && conjSelection && cla && renamingList && targetAttribute) + that.showAttributes(); + + this.setContextMenuItemCallback(function () { + var viewId = $("#lblCurrentView").text(); + return { + addShape: { + name: "Add Node Shape", + callback: function () { + var canvas = that.getCanvas(), + appearance = that.getAppearance(); + + //noinspection JSAccessibilityCheck + canvas + .createNode( + NodeShapeNode.TYPE, + appearance.left + appearance.width + 50, + appearance.top, + 150, + 100 + ) + .done(function (nodeId) { + canvas.createEdge( + BiDirAssociationEdge.TYPE, + that.getEntityId(), + nodeId, + null, + null, + viewId + ); + }); + }, + disabled: function () { + var edges = that.getEdges(), + edge, + edgeId; + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if ( + (edge instanceof BiDirAssociationEdge && + ((edge.getTarget() === that && + edge.getSource() instanceof NodeShapeNode) || + (edge.getSource() === that && + edge.getTarget() instanceof NodeShapeNode))) || + (edge instanceof UniDirAssociationEdge && + edge.getTarget() instanceof NodeShapeNode) + ) { + return true; + } + } + } + return false; + }, + }, + sep: "---------", + }; + }); + } +} + +/** + * ViewRelationshipNode + * @class canvas_widget.ViewRelationshipNode + * @extends canvas_widget.AbstractNode + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {number} zIndex Position of node on z-axis + * @param {object} json indicates if the ViewObjectNode is created from a json + + */ +let ViewRelationshipNode$1 = class ViewRelationshipNode extends AbstractNode { + static TYPE = "ViewRelationship"; + static DEFAULT_WIDTH = 150; + static DEFAULT_HEIGHT = 100; + constructor(id, left, top, width, height, zIndex, json) { + super(id, "ViewRelationship", left, top, width, height, zIndex, json); + var that = this; + + /** + * jQuery object of node template + * @type {jQuery} + * @private + */ + var _$template = $( + lodash.template(viewrelationshipNodeHtml$1)({ + type: that.getType(), + }) + ); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = AbstractNode.prototype.get$node + .call(this) + .append(_$template) + .addClass("viewrelationship"); + + /** + * jQuery object of DOM node representing the attributes + * @type {jQuery} + * @private + */ + var _$attributeNode = _$node.find(".attributes"); + + /** + * Get JSON representation of the node + * @returns {Object} + */ + this.toJSON = function () { + return AbstractNode.prototype.toJSON.call(this); + }; + + this.registerYMap = function () { + AbstractNode.prototype.registerYMap.call(this); + that.getLabel().getValue().registerYType(); + attributeList.registerYMap(); + if (cla) cla.registerYMap(); + attribute.getValue().registerYType(); + conjSelection.getValue().registerYType(); + }; + + this.showAttributes = function () { + if (renamingList.get$node().is(":hidden")) renamingList.get$node().show(); + if (conjSelection.get$node().is(":hidden")) + conjSelection.get$node().show(); + if (cla.get$node().is(":hidden")) cla.get$node().show(); + if (!targetAttribute.get$node().is(":hidden")) + targetAttribute.get$node().hide(); + }; + + this.createConditionListAttribute = function (refAttrs) { + var targetAttrList = {}; + if (refAttrs && refAttrs.constructor.name === "RenamingListAttribute") { + var attrs = refAttrs.getAttributes(); + for (var key in attrs) { + if (attrs.hasOwnProperty(key)) { + targetAttrList[key] = attrs[key].getKey().getValue(); + } + } + } else { + for (var key in refAttrs) { + if (refAttrs.hasOwnProperty(key)) { + targetAttrList[key] = refAttrs[key].val.value; + } + } + } + var conditionListAttr = new ConditionListAttribute( + "[condition]", + "Conditions", + that, + targetAttrList, + LogicalOperator + ); + that.addAttribute(conditionListAttr); + _$attributeNode.append(conditionListAttr.get$node()); + conditionListAttr.get$node().hide(); + return conditionListAttr; + }; + + this.registerYMap = function () { + AbstractNode.prototype.registerYMap.call(this); + that.getLabel().getValue().registerYType(); + renamingList.registerYMap(); + if (cla) cla.registerYMap(); + targetAttribute.getValue().registerYType(); + conjSelection.getValue().registerYType(); + }; + + var targetAttribute, renamingList, conjSelection, cla; + _$node.find(".label").append(this.getLabel().get$node()); + if (window.hasOwnProperty("y")) { + const dataMap = y.getMap("data"); + var model = dataMap.get("model"); + if (model) { + var selectionValues = + ViewTypesUtil.GetAllNodesOfBaseModelAsSelectionList2(model.nodes, [ + "Relationship", + ]); + targetAttribute = new SingleSelectionAttribute( + id + "[target]", + "Reference", + that, + selectionValues + ); + that.addAttribute(targetAttribute); + _$attributeNode.prepend(targetAttribute.get$node()); + + if (json) + cla = that.createConditionListAttribute( + json.attributes["[attributes]"].list + ); + else cla = that.createConditionListAttribute(); + } + } + + renamingList = new RenamingListAttribute( + "[attributes]", + "Attributes", + that, + { + hidden: "Show", + top: "Show Top", + center: "Show Center", + bottom: "Show Bottom", + hide: "Hide", + } + ); + that.addAttribute(renamingList); + _$attributeNode.append(renamingList.get$node()); + renamingList.get$node().hide(); + + conjSelection = new SingleSelectionAttribute( + id + "[conjunction]", + "Conjunction", + that, + LogicalConjunctions + ); + that.addAttribute(conjSelection); + _$attributeNode.append(conjSelection.get$node()); + conjSelection.get$node().hide(); + + if (json && conjSelection && cla && renamingList && targetAttribute) + that.showAttributes(); + + this.setContextMenuItemCallback(function () { + var viewId = $("#lblCurrentView").text(); + return { + addShape: { + name: "Add Edge Shape", + callback: function () { + var canvas = that.getCanvas(), + appearance = that.getAppearance(), + nodeId; + + canvas.createNode( + EdgeShapeNode.TYPE, + appearance.left + appearance.width + 50, + appearance.top, + 150, + 100 + ); + canvas.createEdge( + BiDirAssociationEdge.TYPE, + that.getEntityId(), + nodeId, + null, + null, + viewId + ); + }, + disabled: function () { + var edges = that.getEdges(), + edge, + edgeId; + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if ( + (edge instanceof BiDirAssociationEdge && + ((edge.getTarget() === that && + edge.getSource() instanceof EdgeShapeNode) || + (edge.getSource() === that && + edge.getTarget() instanceof EdgeShapeNode))) || + (edge instanceof UniDirAssociationEdge && + edge.getTarget() instanceof EdgeShapeNode) + ) { + return true; + } + } + } + return false; + }, + }, + sep: "---------", + }; + }); + } +}; + +/** + * BiDirAssociationEdge + * @class canvas_widget.BiDirAssociationEdge + * @extends canvas_widget.AbstractEdge + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of edge + * @param {canvas_widget.AbstractNode} source Source node + * @param {canvas_widget.AbstractNode} target Target node + */ + +/** + * GeneralisationEdge + * @class GeneralisationEdge + * @extends AbstractEdge + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of edge + * @param {canvas_widget.AbstractNode} source Source node + * @param {canvas_widget.AbstractNode} target Target node + */ +class GeneralisationEdge extends AbstractEdge { + static TYPE = "Generalisation"; + static RELATIONS = [ + { + sourceTypes: [ObjectNode.TYPE], + targetTypes: [ObjectNode.TYPE, AbstractClassNode.TYPE], + }, + { + sourceTypes: [RelationshipNode.TYPE], + targetTypes: [RelationshipNode.TYPE, AbstractClassNode.TYPE], + }, + { + sourceTypes: [RelationshipGroupNode.TYPE], + targetTypes: [RelationshipNode.TYPE, ViewRelationshipNode$1.TYPE], + }, + { + sourceTypes: [AbstractClassNode.TYPE], + targetTypes: [AbstractClassNode.TYPE], + }, + { + sourceTypes: [EnumNode.TYPE], + targetTypes: [EnumNode.TYPE], + }, + ]; + + constructor(id, source, target) { + super(id, GeneralisationEdge.TYPE, source, target); + var that = this; + + /** + * Connect source and target node and draw the edge on canvas + */ + this.connect = function () { + var source = this.getSource(); + var target = this.getTarget(); + var connectOptions = { + source: source.get$node().get(0), + target: target.get$node().get(0), + paintStyle: { + stroke: "black", + strokeWidth: 4, + }, + endpoint: "Dot", + anchors: [source.getAnchorOptions(), target.getAnchorOptions()], + connector: { + type: StraightConnector.type, + options: { gap: 0 }, + }, + overlays: [ + { + type: "Arrow", + options: { + width: 20, + length: 25, + location: 1, + foldback: 1, + paintStyle: { + fill: "#ffffff", + outlineWidth: 2, + dashstyle: "black", + }, + }, + }, + { + type: "Custom", + options: { + create: function () { + return that.get$overlay().get(0); + }, + location: 0.5, + id: "label", + }, + }, + ], + cssClass: this.getEntityId(), + }; + + if (source === target) { + connectOptions.anchor = ["TopCenter", "LeftMiddle"]; + } + + source.addOutgoingEdge(this); + target.addIngoingEdge(this); + this.setJsPlumbConnection(window.jsPlumbInstance.connect(connectOptions)); + + this.repaintOverlays(); + lodash.each(EntityManagerInstance.getEdges(), function (e) { + e.setZIndex(); + }); + }; + + this.get$overlay().find(".type").addClass("segmented"); + } +} + +/** + * UniDirAssociationEdge + * @class canvas_widget.UniDirAssociationEdge + * @extends canvas_widget.AbstractEdge + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of edge + * @param {canvas_widget.AbstractNode} source Source node + * @param {canvas_widget.AbstractNode} target Target node + */ +class UniDirAssociationEdge extends AbstractEdge { + static TYPE = "Uni-Dir-Association"; + static RELATIONS = [ + { + sourceTypes: [ObjectNode.TYPE], + targetTypes: [ + EnumNode.TYPE, + NodeShapeNode.TYPE, + RelationshipNode.TYPE, + RelationshipGroupNode.TYPE, + ViewRelationshipNode$1.TYPE, + ], + }, + { + sourceTypes: [RelationshipNode.TYPE], + targetTypes: [ + EnumNode.TYPE, + EdgeShapeNode.TYPE, + ObjectNode.TYPE, + AbstractClassNode.TYPE, + ViewObjectNode.TYPE, + ], + }, + { + sourceTypes: [RelationshipGroupNode.TYPE], + targetTypes: [ObjectNode.TYPE, AbstractClassNode.TYPE], + }, + { + sourceTypes: [AbstractClassNode.TYPE], + targetTypes: [ + EnumNode.TYPE, + RelationshipNode.TYPE, + RelationshipGroupNode.TYPE, + ], + }, + { + sourceTypes: [ViewObjectNode.TYPE], + targetTypes: [ + EnumNode.TYPE, + NodeShapeNode.TYPE, + RelationshipNode.TYPE, + RelationshipGroupNode.TYPE, + ViewRelationshipNode$1.TYPE, + ], + }, + { + sourceTypes: [ViewRelationshipNode$1.TYPE], + targetTypes: [ + EnumNode.TYPE, + EdgeShapeNode.TYPE, + ObjectNode.TYPE, + AbstractClassNode.TYPE, + ViewObjectNode.TYPE, + ], + }, + ]; + + constructor(id, source, target) { + super(id, UniDirAssociationEdge.TYPE, source, target); + var that = this; + + /** + * Connect source and target node and draw the edge on canvas + */ + this.connect = function () { + var source = this.getSource(); + var target = this.getTarget(); + var connectOptions = { + source: source.get$node().get(0), + target: target.get$node().get(0), + paintStyle: { + stroke: "black", + strokeWidth: 4, + }, + endpoint: "Dot", + anchors: [source.getAnchorOptions(), target.getAnchorOptions()], + connector: { + type: StraightConnector.type, + options: { gap: 0 }, + }, + overlays: [ + { + type: "Arrow", + options: { + width: 20, + length: 30, + location: 1, + foldback: 0.5, + paintStyle: { + fill: "#ffffff", + outlineWidth: 2, + outlineStroke: "black", + }, + }, + }, + { + type: "Custom", + options: { + create: function () { + return that.get$overlay().get(0); + }, + location: 0.5, + id: "label", + }, + }, + ], + cssClass: this.getEntityId(), + }; + + if (source === target) { + connectOptions.anchors = ["TopCenter", "LeftMiddle"]; + } + + source.addOutgoingEdge(this); + target.addIngoingEdge(this); + this.setJsPlumbConnection(window.jsPlumbInstance.connect(connectOptions)); + + this.repaintOverlays(); + lodash.each(EntityManagerInstance.getEdges(), function (e) { + e.setZIndex(); + }); + }; + + this.get$overlay().find(".type").addClass("segmented"); + + /*this.setContextMenuItems({ + sep0: "---------", + convertToBiDirAssociationEdge: { + name: "Convert to Bi-Dir. Assoc. Edge", + callback: function(){ + var canvas = that.getCanvas(); + + //noinspection JSAccessibilityCheck + canvas.createEdge(require('canvas_widget/BiDirAssociationEdge').TYPE,that.getSource().getEntityId(),that.getTarget().getEntityId(),that.toJSON()); + + that.triggerDeletion(); + + } + } + });*/ + } +} + +class BiDirAssociationEdge extends AbstractEdge { + static TYPE = "Bi-Dir-Association"; + static RELATIONS = [ + { + sourceTypes: [ObjectNode.TYPE], + targetTypes: [ + EnumNode.TYPE, + NodeShapeNode.TYPE, + RelationshipNode.TYPE, + RelationshipGroupNode.TYPE, + ViewRelationshipNode$1.TYPE, + ], + }, + { + sourceTypes: [RelationshipNode.TYPE], + targetTypes: [ + EnumNode.TYPE, + EdgeShapeNode.TYPE, + ObjectNode.TYPE, + AbstractClassNode.TYPE, + ViewObjectNode.TYPE, + ], + }, + { + sourceTypes: [RelationshipGroupNode.TYPE], + targetTypes: [ObjectNode.TYPE, AbstractClassNode.TYPE], + }, + { + sourceTypes: [AbstractClassNode.TYPE], + targetTypes: [ + EnumNode.TYPE, + RelationshipNode.TYPE, + RelationshipGroupNode.TYPE, + ], + }, + { + sourceTypes: [EnumNode.TYPE], + targetTypes: [ + ObjectNode.TYPE, + RelationshipNode.TYPE, + AbstractClassNode.TYPE, + ], + }, + { + sourceTypes: [NodeShapeNode.TYPE], + targetTypes: [ObjectNode.TYPE], + }, + { + sourceTypes: [EdgeShapeNode.TYPE], + targetTypes: [RelationshipNode.TYPE], + }, + { + sourceTypes: [ViewObjectNode.TYPE], + targetTypes: [ + EnumNode.TYPE, + NodeShapeNode.TYPE, + RelationshipNode.TYPE, + RelationshipGroupNode.TYPE, + ViewRelationshipNode$1.TYPE, + ], + }, + { + sourceTypes: [ViewRelationshipNode$1.TYPE], + targetTypes: [ + EnumNode.TYPE, + EdgeShapeNode.TYPE, + ObjectNode.TYPE, + AbstractClassNode.TYPE, + ViewObjectNode.TYPE, + ], + }, + ]; + constructor(id, source, target) { + super(id, BiDirAssociationEdge.TYPE, source, target); + var that = this; + + /** + * Connect source and target node and draw the edge on canvas + */ + this.connect = function () { + var source = this.getSource(); + var target = this.getTarget(); + var connectOptions = { + source: source.get$node().get(0), + target: target.get$node().get(0), + paintStyle: { + stroke: "black", + strokeWidth: 4, + }, + endpoint: "Dot", + anchors: [source.getAnchorOptions(), target.getAnchorOptions()], + connector: { + type: StraightConnector.type, + options: { gap: 0 }, + }, + overlays: [ + { + type: "Custom", + options: { + create: function () { + return that.get$overlay().get(0); + }, + location: 0.5, + id: "label", + }, + }, + ], + cssClass: this.getEntityId(), + }; + + if (source === target) { + connectOptions.anchors = ["TopCenter", "LeftMiddle"]; + } + + source.addOutgoingEdge(this); + target.addIngoingEdge(this); + this.setJsPlumbConnection(window.jsPlumbInstance.connect(connectOptions)); + + this.repaintOverlays(); + lodash.each(EntityManagerInstance.getEdges(), function (e) { + e.setZIndex(); + }); + }; + + this.get$overlay().find(".type").addClass("segmented"); + } +} + +//noinspection JSUnusedGlobalSymbols + /** + * AbstractCanvasTool + * @class canvas_widget.AbstractCanvasTool + * @memberof canvas_widget + * @constructor + * @param {string} [name] Name of tool + * @param {string} [className] Class name assigned to canvas node when tool is mounted + * @param {string} [description] Description of tool + */ + class AbstractCanvasTool { + constructor(name, className, description) { + /** + * Canvas that the tool is added to + * @type {canvas_widget.AbstractCanvas} + * @private + */ + var _canvas = null; + + /** + * Name of tool + * @type {string} + * @private + */ + var _name = name || "AbstractTool"; + + /** + * Class name assigned to canvas node when tool is mounted + * @type {string} + * @private + */ + var _className = className || "tool-abstract"; + + /** + * Description of tool + * @type {string} + * @private + */ + var _description = description || "An abstract canvas tool"; + + /** + * Set canvas that the tool is added to + * @param {canvas_widget.AbstractCanvas} canvas + */ + this.setCanvas = function (canvas) { + if (!canvas) throw new Error("Canvas is null"); + _canvas = canvas; + }; + + /** + * Get canvas that the tool is added to + * @returns {canvas_widget.AbstractCanvas} + */ + this.getCanvas = function () { + return _canvas; + }; + + /** + * Get name of tool + * @returns {string} + */ + this.getName = function () { + return _name; + }; + + //noinspection JSUnusedGlobalSymbols + /** + * Get class name assigned to canvas node when tool is mounted + * @returns {string} + */ + this.getClassName = function () { + return _className; + }; + + /** + * Get description of tool + * @returns {string} + */ + this.getDescription = function () { + return _description; + }; + + /** + * Mount the tool on canvas + * @private + */ + this._mount = function () { + _canvas.get$canvas().addClass(_className); + }; + + /** + * Unmount the tool from canvas + * @private + */ + this._unmount = function () { + _canvas.get$canvas().removeClass(_className); + }; + } + /** + * Mount the tool on canvas + */ + mount() { + this._mount(); + } + /** + * Unmount the tool from canvas + */ + unmount() { + this._unmount(); + } + } + +/** + * NodeTool + * @class canvas_widget.NodeTool + * @extends canvas_widget.AbstractCanvasTool + * @memberof canvas_widget + * @constructor + */ +class NodeTool extends AbstractCanvasTool { + constructor( + name, + className, + description, + containment, + defaultWidth, + defaultHeight + ) { + super(name, className || "tool-node", description || "Add a node"); + + var _defaultWidth = defaultWidth || 100, + _defaultHeight = defaultHeight || 50; + + /** + * Mount the tool on canvas + */ + this.mount = function (defaultLabel, defaultAttributeValues) { + var $canvas = this.getCanvas().get$canvas(); + var that = this; + AbstractCanvasTool.prototype.mount.call(this); + + //Enable Node Addition + $canvas.on("mouseup.nodeadd", function (ev) { + var offsetCanvas; + + if (ev.which != 1) return; + + offsetCanvas = $canvas.offset(); // current offset of the canvas relative to the document + var zoom = that.getCanvas().getZoom(); + var nodeX = (ev.pageX - offsetCanvas.left) / zoom - _defaultWidth / 2; // center position of the node + var nodeY = (ev.pageY - offsetCanvas.top) / zoom - _defaultHeight / 2; // center position of the node + + that + .getCanvas() + .createNode( + that.getName(), + nodeX, + nodeY, + _defaultWidth, + _defaultHeight, + null, + containment, + null, + null, + null, + defaultLabel, + defaultAttributeValues + ); + that.getCanvas().resetTool(); + }); + + $canvas.bind("contextmenu", function (ev) { + if (ev.target == this) { + ev.preventDefault(); + that.getCanvas().resetTool(); + return false; + } + return true; + }); + + $canvas.find(".node").bind("contextmenu", function (ev) { + ev.preventDefault(); + that.getCanvas().resetTool(); + that.getCanvas().select(EntityManagerInstance.findNode($(this).attr("id"))); + return false; + }); + }; + + /** + * Unmount the tool from canvas + */ + this.unmount = function () { + var $canvas = this.getCanvas().get$canvas(); + AbstractCanvasTool.prototype.unmount.call(this); + + //Disable Node Addition + $canvas.off("mouseup.nodeadd"); + + $canvas.unbind("contextmenu"); + $canvas.find(".node").unbind("contextmenu"); + }; + } +} + +/** + * AbstractClassNodeTool + * @class canvas_widget.ClassNodeTool + * @extends canvas_widget.NodeTool + * @memberof canvas_widget + * @constructor + */ +class AbstractClassNodeTool extends NodeTool{ + constructor() { + super( + AbstractClassNode.TYPE, + null, + null, + null, + AbstractClassNode.DEFAULT_WIDTH, + AbstractClassNode.DEFAULT_HEIGHT + ); + } +} + +/** + * EdgeTool + * @class canvas_widget.EdgeTool + * @extends canvas_widget.AbstractCanvasTool + * @memberof canvas_widget + * @constructor + * @param {string} name Name of tool + * @param {string[]} relations Array of valid relations of node types the edge can connect + * @param {string} [className] Class name assigned to canvas node when tool is mounted + * @param {string} [description] Description of tool + */ +class EdgeTool extends AbstractCanvasTool { + constructor(name, relations, className, description) { + super(name, className || "tool-edge", description || "Add an edge"); + const jsPlumbInstance = window.jsPlumbInstance; + + var _relations = relations; + + /** + * Mount the tool on canvas + */ + this.mount = function () { + AbstractCanvasTool.prototype.mount.call(this); + function makeNeighborhoodFilter(nodeId) { + return function (n) { + return ( + n.getEntityId() !== nodeId && + !n.getNeighbors().hasOwnProperty(nodeId) + ); + }; + } + + function makeMakeTargetCallback() { + return function (node) { + node.makeTarget(); + node.unlowlight(); + }; + } + + var that = this; + + var $canvas = this.getCanvas().get$canvas(); + + //Bind Node Events + var nodes = EntityManagerInstance.getNodes(); + var nodeId, node, nodeType, strGetNodesByType; + var i, numOfRelations; + + for (nodeId in nodes) { + if (nodes.hasOwnProperty(nodeId)) { + node = nodes[nodeId]; + node.lowlight(); + if ( + EntityManagerInstance.getViewId() === undefined || + EntityManagerInstance.getLayer() === CONFIG.LAYER.META + ) { + nodeType = node.getType(); + strGetNodesByType = "getNodesByType"; + } else { + nodeType = node.getCurrentViewType(); + strGetNodesByType = "getNodesByViewType"; + } + for ( + i = 0, numOfRelations = _relations.length; + i < numOfRelations; + i++ + ) { + if (relations[i].sourceTypes.indexOf(nodeType) !== -1) { + if ( + lodash.size( + lodash.filter( + EntityManagerInstance[strGetNodesByType](relations[i].targetTypes), + makeNeighborhoodFilter(node.getEntityId()) + ) + ) > 0 + ) { + node.makeSource(); + node.unbindMoveToolEvents(); + node.unlowlight(); + break; + } + } + } + } + } + + jsPlumbInstance.bind("beforeDrag", function (info) { + var sourceNode = EntityManagerInstance.findNode(info.sourceId), + sourceType, + i, + numOfRelations, + strGetNodesByType; + if (sourceNode) { + if ( + EntityManagerInstance.getViewId() === undefined || + EntityManagerInstance.getLayer() === CONFIG.LAYER.META + ) { + sourceType = sourceNode.getType(); + strGetNodesByType = "getNodesByType"; + } else { + sourceType = sourceNode.getCurrentViewType(); + strGetNodesByType = "getNodesByViewType"; + } + + for ( + i = 0, numOfRelations = _relations.length; + i < numOfRelations; + i++ + ) { + if (relations[i].sourceTypes.indexOf(sourceType) !== -1) { + lodash.each( + lodash.filter( + EntityManagerInstance[strGetNodesByType](relations[i].targetTypes), + makeNeighborhoodFilter(sourceNode.getEntityId()) + ), + makeMakeTargetCallback() + ); + } + } + } + $(info.source).addClass("current"); + $canvas.addClass("dragging"); + return true; + }); + jsPlumbInstance.bind("beforeDrop", function () { + $canvas.removeClass("dragging"); + $(".node.current").removeClass("current"); + return true; + }); + jsPlumbInstance.bind("beforeDetach", function (info) { + if (info.connection?.pending) { + $(".node.current").removeClass("current"); + $canvas.removeClass("dragging"); + } + return true; + }); + + jsPlumbInstance.bind("connection", function (info, originalEvent) { + if (typeof originalEvent !== "undefined") { + //Was the connection established using Drag'n Drop? + // If so we delete the connection and form it manually again + if (info.connection) { + jsPlumbInstance.deleteConnection(info.connection, { + fireEvent: false, + }); + } + + that + .getCanvas() + .createEdge(that.getName(), info.sourceId, info.targetId); + } + return true; + }); + + $canvas.bind("contextmenu", function (ev) { + if (ev.target == this) { + ev.preventDefault(); + that.getCanvas().resetTool(); + return false; + } + return true; + }); + + $canvas.find(".node").bind("contextmenu", function (ev) { + ev.preventDefault(); + that.getCanvas().resetTool(); + that.getCanvas().select(EntityManagerInstance.findNode($(this).attr("id"))); + return false; + }); + }; + + /** + * Unmount the tool from canvas + */ + this.unmount = function () { + AbstractCanvasTool.prototype.unmount.call(this, arguments); + + var $canvas = this.getCanvas().get$canvas(); + + //Unbind Node Events + //TODO Not very nicely implemented. Iterates over all nodes again like it was in MoveTool + var nodes = EntityManagerInstance.getNodes(); + var nodeId, node; + for (nodeId in nodes) { + if (nodes.hasOwnProperty(nodeId)) { + node = nodes[nodeId]; + node.unlowlight(); + node.unbindEdgeToolEvents(); + node.bindMoveToolEvents(); + } + } + + //Disable Edge Dragging + // $canvas.find(".node").each(function () { + // var $this = $(this); + // try { + // const nodeSelector = getQuerySelectorFromNode($this); + // jsPlumbInstance.removeSourceSelector(nodeSelector); + // jsPlumbInstance.removeTargetSelector(nodeSelector); + // } catch (error) { + // console.error(error); + // } + // }); + jsPlumbInstance.unbind("connectionDrag"); + jsPlumbInstance.unbind("beforeDrop"); + jsPlumbInstance.unbind("connection"); + + $canvas.unbind("contextmenu"); + $canvas.find(".node").unbind("contextmenu"); + }; + } +} + +/** + * BiDirAssociationEdgeTool + * @class canvas_widget.BiDirAssociationEdgeTool + * @extends canvas_widget.EdgeTool + * @memberof canvas_widget + * @constructor + */ +class BiDirAssociationEdgeTool extends EdgeTool { + constructor() { + super(BiDirAssociationEdge.TYPE, BiDirAssociationEdge.RELATIONS); + } +} + +function DagreLayout() { + return { + apply: function () { + var node, edge, e, appearance, relX, relY, x, y; + var g = new dagre.graphlib.Graph(); + g.setGraph({}); + g.setDefaultEdgeLabel(function () { + return {}; + }); + var nodes = EntityManagerInstance.getNodes(); + + for (var nodeId in nodes) { + if (nodes.hasOwnProperty(nodeId)) { + node = nodes[nodeId]; + appearance = node.getAppearance(); + g.setNode(nodeId, { + width: appearance.width, + height: appearance.height, + }); + } + } + var edges = EntityManagerInstance.getEdges(); + for (var edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + g.setEdge( + edge.getSource().getEntityId(), + edge.getTarget().getEntityId() + ); + } + } + dagre.layout(g, { + rankdir: "BT", + align: "UL", + ranker: "tight-tree", + marginx: 9000, + marginy: 9000, + }); + + relX = 4500 - g.graph().width / 2; + relY = 4500 - g.graph().height / 2; + g.nodes().forEach(function (v) { + e = EntityManagerInstance.findNode(v); + if (e) { + appearance = e.getAppearance(); + node = g.node(v); + x = relX + node.x; + y = relY + node.y; + if (appearance.top !== x || appearance.top !== y) e.moveAbs(x, y); + } + }); + }, + }; +} var DagreLayout$1 = DagreLayout(); -const selectToolGuidanceHtml$1 = ""; // replaced by importmap.plugin.js -class CollaborationGuidance { - constructor(id, label, activityId, objectId, canvas, y) { - y = y || window.y; - var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); - var _canvas = canvas; - var _$node = $( - lodash.template(selectToolGuidanceHtml$1)({ text: label, icon: "users" }) - ); - - _$node.click(function () { - var operation = new CollaborateInActivityOperation(activityId); - _iwcw.sendLocalNonOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.toNonOTOperation() - ); - _canvas.hideGuidanceBox(); - _canvas.scrollNodeIntoView(objectId); - }); - - this.get$node = function () { - return _$node; - }; - } +const selectToolGuidanceHtml$1 = ""; // replaced by importmap.plugin.js +class CollaborationGuidance { + constructor(id, label, activityId, objectId, canvas, y) { + y = y || window.y; + var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); + var _canvas = canvas; + var _$node = $( + lodash.template(selectToolGuidanceHtml$1)({ text: label, icon: "users" }) + ); + + _$node.click(function () { + var operation = new CollaborateInActivityOperation(activityId); + _iwcw.sendLocalNonOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.toNonOTOperation() + ); + _canvas.hideGuidanceBox(); + _canvas.scrollNodeIntoView(objectId); + }); + + this.get$node = function () { + return _$node; + }; + } +} + +class GhostEdge { + constructor(canvas, edgeFunction, source, target) { + var _jsPlumbConnection = null; + var _label = edgeFunction.getType(); + + source.addGhostEdge(this); + target.addGhostEdge(this); + + this.getLabel = function () { + return _label; + }; + + this.connect = function (button) { + if (_jsPlumbConnection) return; + var overlays = edgeFunction.getArrowOverlays(); + overlays.push([ + "Custom", + { + create: function (component) { + return $("
                  ").append(button); + }, + location: 0.5, + id: "customOverlay", + cssClass: "ghost-edge-overlay", + }, + ]); + var connectOptions = { + source: source.get$node(), + target: target.get$node(), + paintStyle: { + stroke: edgeFunction.getColor(), + strokeWidth: 4, + dashstyle: "", + }, + endpoint: "Dot", + anchors: [source.getAnchorOptions(), target.getAnchorOptions()], + connector: edgeFunction.getShape(), + overlays: overlays, + cssClass: "ghost-edge", + }; + + if (source === target) { + connectOptions.anchors = ["TopCenter", "LeftMiddle"]; + } + + _jsPlumbConnection = window.JsPlumbInstance.connect(connectOptions); + lodash.each(EntityManagerInstance.getEdges(), function (e) { + e.setZIndex(); + }); + }; + + this.remove = function () { + if (_jsPlumbConnection) + window.JsPlumbInstance.destroyConnector(_jsPlumbConnection); + _jsPlumbConnection = null; + }; + + this.getEdgeFunction = function () { + return edgeFunction; + }; + + this.getSource = function () { + return source; + }; + + this.getTarget = function () { + return target; + }; + } +} + +const ghostEdgeHtml = "\n\n
                  \n \n \n
                    \n
                  \n
                  "; // replaced by importmap.plugin.js +// import "bootstrap"; +function GhostEdgeGuidance(canvas, node1, node2) { + var _button = $(ghostEdgeHtml); + var _dropdown = _button.find(".bs-dropdown-toggle"); + _dropdown.detach(); + var _dropdownList = _button.find(".edge-list"); + _dropdownList.detach(); + var _canvas = canvas; + var that = this; + var _edges = []; + var _node1 = node1; + var _node2 = node2; + var _currentEdge = null; + + _node1.addGhostEdge(this); + _node2.addGhostEdge(this); + + _button.hover( + function () { + $(this).css({ opacity: 1 }); + }, + function () { + $(this).css({ opacity: 0.4 }); + } + ); + this.show = function () { + _currentEdge.connect(_button); + }; + + this.addEdge = function (edgeFunction, source, target) { + var edge = new GhostEdge(_canvas, edgeFunction, source, target); + _edges.push(edge); + var listItem = $("
                • "); + listItem.click(function () { + that.remove(); + that.setCurrentEdge(edge); + that.show(); + }); + listItem.find("a").text(edge.getLabel()); + _dropdownList.append(listItem); + + if (_edges.length == 1) { + this.setCurrentEdge(edge); + } + if (_edges.length == 2) { + _button.append(_dropdown); + _button.append(_dropdownList); + } + }; + + this.remove = function () { + _button.detach(); + if (_currentEdge) _currentEdge.remove(); + }; + + this.getNode1 = function () { + return _node1; + }; + + this.getNode2 = function () { + return _node2; + }; + + this.setCurrentEdge = function (edge) { + if (_currentEdge) _currentEdge.remove(); + _currentEdge = edge; + _button.find(".label").text(_currentEdge.getLabel()); + + var createEdgeButton = _button.find(".create-edge-button"); + createEdgeButton.off("click"); + createEdgeButton.click(function (event) { + event.stopPropagation(); + that.remove(); + //if(EntityManager.getViewId() !== null && EntityManager.getLayer() === CONFIG.LAYER.MODEL){ + // _canvas.createEdge(_currentEdge.getEdgeFunction().VIEWTYPE, _currentEdge.getSource().getEntityId(), _currentEdge.getTarget().getEntityId()); + //} + //else { + _canvas.createEdge( + _currentEdge.getEdgeFunction().getType(), + _currentEdge.getSource().getEntityId(), + _currentEdge.getTarget().getEntityId() + ); + //} + //guidanceFollowed does not exists, seems to be unnecessary and obsolete + //_canvas.guidanceFollowed(); + }); + }; +} + +const abstractNodeHtml = "
                  \" class=\"node\">\n
                  "; // replaced by importmap.plugin.js +const guidanceBoxNodeHtml = "
                  \n
                  \n \t\t
                  \n\t\t
                  \n
                  \n
                  \n \t

                  Guidance

                  \n
                  \n
                  "; // replaced by importmap.plugin.js +function GuidanceBox(id, label, left, top) { + var _$node = $(lodash.template(abstractNodeHtml)({ id: id })).append( + guidanceBoxNodeHtml + ); + + _$node.find(".guidance-box").hover( + function () { + $(this).css({ opacity: 1 }); + }, + function () { + $(this).css({ opacity: 0.5 }); + } + ); + + var _appearance = { + left: left, + top: top, + }; + + this.get$node = function () { + return _$node; + }; + + this.addGuidance = function (guidance) { + + _$node.find(".buttons").append(guidance.get$node()); + }; + + this.draw = function () { + var width = _$node.width(); + _$node.css({ + left: _appearance.left - width / 2, + top: _appearance.top, + zIndex: 30000, + }); + }; + + this.addToCanvas = function (canvas) { + canvas.get$canvas().append(_$node); + }; + + this.remove = function () { + _$node.remove(); + }; +} + +const selectToolGuidanceHtml = ""; // replaced by importmap.plugin.js +function SelectToolGuidance(id, label, tool, canvas, icon) { + //var _id = id; + //var _label = label; + //var _tool = tool; + var _canvas = canvas; + var _$node = $( + lodash.template(selectToolGuidanceHtml)({ + text: label, + icon: icon || "plus-circle", + }) + ); + + _$node.click(function () { + if ( + EntityManagerInstance.getViewId() !== undefined && + EntityManagerInstance.getLayer() === CONFIG.LAYER.MODEL + ) { + if (EntityManagerInstance.getNodeType(tool) !== null) { + _canvas.mountTool(EntityManagerInstance.getNodeType(tool).VIEWTYPE); + } else { + _canvas.mountTool(tool); + } + } else _canvas.mountTool(tool); + + _canvas.hideGuidanceBox(); + //guidanceFollowed does not exists, seems to be unnecessary and obsolete + // _canvas.guidanceFollowed(); + }); + + this.get$node = function () { + return _$node; + }; +} + +const setPropertyGuidanceHtml = "
                  \n\n
                    \n\t
                  • \n
                  \n
                  "; // replaced by importmap.plugin.js +// import "bootstrap"; +function SetPropertyGuidance(id, label, entity, propertyName, canvas) { + var _entityId = entity.getEntityId(); + var _canvas = canvas; + var _entityAttribute = null; + var _$node = $( + lodash.template(setPropertyGuidanceHtml)({ text: label, icon: "edit" }) + ); + var _propertyInput; + + var entityAttributes = entity.getAttributes(); + + for (var attribId in entityAttributes) { + var attrib = entityAttributes[attribId]; + if ( + attrib.getEntityId() == + entity.getEntityId() + "[" + propertyName.toLowerCase() + "]" + ) + _entityAttribute = attrib; + } + + if (_entityAttribute instanceof SingleValueAttribute) { + _propertyInput = new SingleValueAttribute( + entity.getEntityId() + "[" + propertyName.toLowerCase() + "]", + propertyName, + entity + ); + // @ts-ignore + _propertyInput.getValue().setValue(_entityAttribute.getValue().getValue()); + // @ts-ignore + + if (_entityAttribute.getRootSubjectEntity().constructor.name === "Edge") { + const edgeMap = y.getMap("edges"); + var ymap = edgeMap.get(entity.getEntityId()); + var ytext = ymap.get( + entity.getEntityId() + "[" + propertyName.toLowerCase() + "]" + ); + ytext.bind(_propertyInput.getValue().get$node()[0]); + } else { + const nodesMap = y.getMap("nodes"); + var ymap = nodesMap.get(entity.getEntityId()); + var ytext = ymap.get( + entity.getEntityId() + "[" + propertyName.toLowerCase() + "]" + ); + ytext.bind(_propertyInput.getValue().get$node()[0]); + } + + /* _entityAttribute.get$node().find(".val").bind("input", function(){ + // @ts-ignore +_propertyInput.getValue().setValue(_entityAttribute.getValue().getValue()); +// @ts-ignore + }); + + _propertyInput.get$node().find(".val").bind("input", function(){ + _entityAttribute.getValue().setValue(_propertyInput.getValue().getValue()); + });*/ + + _$node + .find(".property-input") + .append(_propertyInput.get$node().find(".val").prop("disabled", false)); + } else if (_entityAttribute instanceof SingleSelectionAttribute) { + // @ts-ignore + var options = _entityAttribute.getOptions(); + _propertyInput = new SingleSelectionAttribute( + entity.getEntityId() + "[" + propertyName.toLowerCase() + "]", + propertyName, + entity, + options, + true + ); + // @ts-ignore + _propertyInput.getValue().setValue(_entityAttribute.getValue().getValue()); + // @ts-ignore + _propertyInput + .getValue() + .get$node() + .bind("change", function (ev) { + _entityAttribute + .getValue() + .setValue(_propertyInput.getValue().getValue()); + }); + + _$node.find(".property-input").append(_propertyInput.getValue().get$node()); + _$node.find(".property-input").click(function (ev) { + ev.stopPropagation(); + }); + } else if (_entityAttribute instanceof IntegerAttribute) { + _propertyInput = new IntegerAttribute( + entity.getEntityId() + "[" + propertyName.toLowerCase() + "]", + propertyName, + entity, + true + ); + // @ts-ignore + _propertyInput.getValue().setValue(_entityAttribute.getValue().getValue()); + // @ts-ignore + + _entityAttribute + // @ts-ignore + .get$node() + .find(".val") + .bind("change", function () { + _propertyInput + .getValue() + .setValue(_entityAttribute.getValue().getValue()); + }); + + _propertyInput + .get$node() + .find(".val") + .bind("change", function (ev) { + _entityAttribute + .getValue() + .setValue(_propertyInput.getValue().getValue()); + }); + + _$node + .find(".property-input") + .append(_propertyInput.get$node().find(".val").prop("disabled", false)); + _$node.find(".property-input").click(function (ev) { + ev.stopPropagation(); + }); + } else if (_entityAttribute instanceof BooleanAttribute) { + _propertyInput = new BooleanAttribute( + entity.getEntityId() + "[" + propertyName.toLowerCase() + "]", + propertyName, + entity, + true + ); + // @ts-ignore + _propertyInput.getValue().setValue(_entityAttribute.getValue().getValue()); + // @ts-ignore + + _entityAttribute + // @ts-ignore + .get$node() + .find(".val") + .bind("change", function () { + _propertyInput + .getValue() + .setValue(_entityAttribute.getValue().getValue()); + }); + + _propertyInput + .get$node() + .find(".val") + .bind("change", function (ev) { + _entityAttribute + .getValue() + .setValue(_propertyInput.getValue().getValue()); + }); + + _$node + .find(".property-input") + .append(_propertyInput.get$node().find(".val")); + _$node.find(".property-input").click(function (ev) { + ev.stopPropagation(); + }); + } else if (_entityAttribute instanceof FileAttribute) { + _propertyInput = new FileAttribute( + entity.getEntityId() + "[" + propertyName.toLowerCase() + "]", + propertyName, + entity, + true + ); + //@ts-ignore + _propertyInput.getValue().setValue(_entityAttribute.getValue().getValue()); + // @ts-ignore + + // _entityAttribute.get$node().find(".val").bind("change", function(){ + // // @ts-ignore + _propertyInput.getValue().setValue(_entityAttribute.getValue().getValue()); + // @ts-ignore + // }); + + // _propertyInput.get$node().find(".val").bind("change", function(ev){ + // _entityAttribute.getValue().setValue(_propertyInput.getValue().getValue()); + // }); + + _$node.find(".property-input").append(_propertyInput.getValue().get$node()); + _$node.find(".property-input").click(function (ev) { + ev.stopPropagation(); + }); + } + if (_propertyInput) + _propertyInput + .get$node() + .find(".val") + .keypress(function (ev) { + //The event is never triggered + if (ev.which == 13) { + _$node.find(".bs-dropdown-toggle").dropdown("toggle"); + } + }); + + //guidanceFollowed does not exists, seems to be unnecessary and obsolete + /*_$node.on('show.bs.dropdown', function () { + _canvas.guidanceFollowed(); + });*/ + + _$node.hover( + function () { + if (_entityId) _canvas.highlightEntity(_entityId); + }, + function () { + if (_entityId) _canvas.unhighlightEntity(_entityId); + } + ); + + this.get$node = function () { + return _$node; + }; +} + +/** + * MoveTool + * @class canvas_widget.MoveTool + * @extends canvas_widget.AbstractCanvasTool + * @memberof canvas_widget + * @constructor + */ +class MoveTool extends AbstractCanvasTool { + static TYPE = "MoveTool"; + mount + unmount + constructor() { + super(MoveTool.TYPE, "tool-move", "Move Nodes and Edges"); + + /** + * Mount the tool on canvas + */ + this.mount = function () { + + AbstractCanvasTool.prototype.mount.call(this); + //WTF??? + //Bind Node and Edge Events + /*var nodes = EntityManager.getNodes(); + var nodeId, node; + for(nodeId in nodes){ + if(nodes.hasOwnProperty(nodeId)){ + node = nodes[nodeId]; + node.bindMoveToolEvents(); + } + } + + var edges = EntityManager.getEdges(); + var edgeId, edge; + for(edgeId in edges){ + if(edges.hasOwnProperty(edgeId)){ + edge = edges[edgeId]; + edge.bindMoveToolEvents(); + } + }*/ + this.getCanvas().bindMoveToolEvents(); + }; + + /** + * Unmount the tool from canvas + */ + this.unmount = function () { + AbstractCanvasTool.prototype.unmount.call(this); + //WTF?? + /*var nodes = EntityManager.getNodes(); + var nodeId, node; + for(nodeId in nodes){ + if(nodes.hasOwnProperty(nodeId)){ + node = nodes[nodeId]; + node.unbindMoveToolEvents(); + } + } + + var edges = EntityManager.getEdges(); + var edgeId, edge; + for(edgeId in edges){ + if(edges.hasOwnProperty(edgeId)){ + edge = edges[edgeId]; + edge.unbindMoveToolEvents(); + } + }*/ + this.getCanvas().unbindMoveToolEvents(); + }; + } +} + +/** + * AbstractCanvas + * @class canvas_widget.AbstractCanvas + * @memberof canvas_widget + * @constructor + * @param {jQuery} $node jQuery selector of canvas node + */ +class AbstractCanvas { + constructor($node) { + var that = this; + + /** + * Tools added to canvas + * @type {Object} + * @private + */ + var _tools = {}; + + /** + * Name of tool currently mounted + * @type {string} + * @private + */ + var _currentToolName = null; + + /** + * jQuery object of DOM node representing the canvas + * @type {jQuery} + * @private + */ + var _$node = $node; + + /** + * Get jQuery object of DOM node representing the canvas + * @returns {jQuery} jQuery object of DOM node representing the canvas + */ + this.get$canvas = function () { + return _$node; + }; + + /** + * Add tool to canvas + * @param {string} name Name of tool + * @param {canvas_widget.AbstractCanvasTool} tool Canvas tool + */ + this.addTool = function (name, tool) { + if ( + !_tools.hasOwnProperty(name) && + typeof tool.mount === "function" && + typeof tool.unmount === "function" && + typeof tool.setCanvas === "function" + ) { + tool.setCanvas(this); + _tools[name] = tool; + } + }; + + //noinspection JSUnusedGlobalSymbols + /** + * Get tool added to canvas by its name + * @param {string} name Name of tool + * @returns {canvas_widget.AbstractCanvasTool} Canvas tool + */ + this.getTool = function (name) { + if (_tools.hasOwnProperty(name)) { + return _tools[name]; + } + return null; + }; + + /** + * Mount a canvas tool previously added to the canvas + * @param {string} name Name of tool + * @param defaultLabel + * @param defaultAttributeValues May be used to set default values for node attributes. + */ + this.mountTool = function (name, defaultLabel, defaultAttributeValues) { + if (_currentToolName && _tools[_currentToolName]) + _tools[_currentToolName].unmount(); + if (_tools.hasOwnProperty(name)) { + _tools[name].mount(defaultLabel, defaultAttributeValues); + } else { + if (name !== "MoveTool") { + throw new Error("Tool " + name + " not found"); + } + _tools["MoveTool"].mount(); + } + _currentToolName = name; + }; + + /** + * Unmount and mount currenty mounted tool again + */ + this.remountCurrentTool = function () { + that.mountTool(_currentToolName); + }; + + //noinspection JSUnusedGlobalSymbols + /** + * Get name of tool currently mounted + * @returns {string} + */ + this.getCurrentToolName = function () { + return _currentToolName; + }; + + this.removeTools = function () { + _tools = {}; + }; + } +} + +/** + * Canvas + * @class canvas_widget.Canvas + * @extends canvas_widget.AbstractCanvas + * @memberof canvas_widget + * @constructor + * @param {jQuery} $node jquery Selector of canvas node + */ +class Canvas extends AbstractCanvas { + constructor($node, y = window.y) { + super($node); + var that = this; + + /** + * jQuery object of DOM node representing the canvas + * @type {jQuery} + * @private + */ + var _$node = $node; + + /** + * Current zoom level + * @type {number} + * @private + */ + var _zoom = 1; + + /** + * Default canvas width + * @type {number} + * @private + */ + var _canvasWidth = 9000; + this.width = _canvasWidth; + + /** + * Default canvas height + * @type {number} + * @private + */ + var _canvasHeight = 9000; + this.height = _canvasHeight; + + /** + * Model attributes + * @type {canvas_widget.ModelAttributesNode} + * @private + */ + var _modelAttributesNode = null; + + /** + * Inter widget communication wrapper + * @type {Object} + */ + var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); + + /** + * Entity currently selected + * @type {canvas_widget.AbstractNode|canvas_widget/AbstractEdge} + * @private + */ + var _selectedEntity = null; + + /** + * Offset of the DOM node representating the canvas + * @type {{left: number, top: number, right: number, bottom: number}} + */ + var canvasOffset = _$node.offset(); + + var _guidanceBox = null; + var _guidanceBoxLabel = ""; + var _guidanceDefinition = null; + var _ghostEdges = []; + var _guidanceBoxEntityId = null; + + const jsPlumbInstance = newInstance({ + container: _$node.get(0), + elementsDraggable: true, + connectionsDetachable: false, + dragOptions: { + filter: ".resizing", + containment: "parentEnclosed", + }, + }); + + window.jsPlumbInstance = jsPlumbInstance; + + $(window).resize(function () { + sendViewChangeOperation(); + }); + + /** + * Apply a Tool Select Operation + * @param {operations.non_ot.ToolSelectOperation} operation + */ + var processToolSelectOperation = function (operation) { + that.mountTool( + operation.getSelectedToolName(), + operation.getDefaultLabel(), + operation.getDefaultAttributeValues() + ); + }; + + /** + * Apply a Node Add Operation + * @param {operations.ot.NodeAddOperation} operation + * @param {YMap} ymap + */ + var processNodeAddOperation = function (operation) { + var node; + if (operation.getJSON()) { + node = EntityManagerInstance.createNodeFromJSON( + operation.getType(), + operation.getEntityId(), + operation.getLeft(), + operation.getTop(), + operation.getWidth(), + operation.getHeight(), + operation.getZIndex(), + operation.getContainment(), + operation.getJSON() + ); + } else { + node = EntityManagerInstance.createNode( + operation.getType(), + operation.getEntityId(), + operation.getLeft(), + operation.getTop(), + operation.getWidth(), + operation.getHeight(), + operation.getZIndex(), + operation.getContainment() + ); + } + + if (operation.getDefaultLabel()) { + node.getLabel().getValue().setValue(operation.getDefaultLabel()); + } + + if (operation.getDefaultAttributeValues()) { + for (const [key, value] of Object.entries( + operation.getDefaultAttributeValues() + )) { + node.getAttribute(key).getValue().setValue(value); + } + } + const userMap = y.getMap("users"); + if (userMap.get(y.clientID) !== operation.getJabberId()) { + const userList = y.getMap("userList"); + var color = Util.getColor( + userList.get(operation.getJabberId()).globalId + ); + node.refreshTraceAwareness(color); + } + if (y) node.registerYMap(); + + node.draw(); + node.addToCanvas(that); + node.bindMoveToolEvents(); + that.remountCurrentTool(); + }; + + /** + * Propagate a Node Add Operation to the remote users and the local widgets + * @param {operations.ot.NodeAddOperation} operation + */ + var propagateNodeAddOperation = function (operation) { + processNodeAddOperation(operation); + //_iwcw.sendLocalOTOperation(CONFIG.WIDGET.NAME.ATTRIBUTE, operation.getOTOperation()); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.HEATMAP, + operation.getOTOperation() + ); + const activityMap = y.getMap("activity"); + activityMap.set( + ActivityOperation.TYPE, + new ActivityOperation( + "NodeAddActivity", + operation.getEntityId(), + _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], + NodeAddOperation.getOperationDescription(operation.getType()), + { + nodeType: operation.getType(), + } + ).toJSON() + ); + }; + + /** + * Apply an Edge Add Operation + * @param {operations.ot.EdgeAddOperation} operation + * @param {YMap} ymap + */ + var processEdgeAddOperation = function (operation) { + var edge; + + if (operation.getJSON()) { + edge = EntityManagerInstance.createEdgeFromJSON( + operation.getType(), + operation.getEntityId(), + operation.getSource(), + operation.getTarget(), + operation.getJSON() + ); + } else { + edge = EntityManagerInstance.createEdge( + operation.getType(), + operation.getEntityId(), + EntityManagerInstance.findNode(operation.getSource()), + EntityManagerInstance.findNode(operation.getTarget()) + ); + } + + if (window.hasOwnProperty("y")) edge.registerYMap(); + + edge.connect(); + edge.addToCanvas(that); + edge.bindMoveToolEvents(); + that.remountCurrentTool(); + }; + /** + * Propagate an Edge Add Operation to the remote users and the local widgets + * @param {operations.ot.EdgeAddOperation} operation + */ + var propagateEdgeAddOperation = function (operation) { + var sourceNode = EntityManagerInstance.findNode(operation.getSource()); + var targetNode = EntityManagerInstance.findNode(operation.getTarget()); + + processEdgeAddOperation(operation); + EntityManagerInstance.saveState(); + + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.getOTOperation() + ); + const activityMap = y.getMap("activity"); + activityMap.set( + ActivityOperation.TYPE, + new ActivityOperation( + "EdgeAddActivity", + operation.getEntityId(), + _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], + EdgeAddOperation.getOperationDescription( + operation.getType(), + "", + sourceNode.getLabel().getValue().getValue(), + sourceNode.getType(), + targetNode.getType(), + targetNode.getLabel().getValue().getValue() + ), + { + nodeType: operation.getType(), + sourceNodeId: operation.getSource(), + sourceNodeLabel: sourceNode.getLabel().getValue().getValue(), + sourceNodeType: sourceNode.getType(), + targetNodeId: operation.getTarget(), + targetNodeLabel: targetNode.getLabel().getValue().getValue(), + targetNodeType: targetNode.getType(), + } + ).toJSON() + ); + }; + + /** + * Callback for a remote Node Add Operation + * @param {operations.ot.NodeAddOperation} operation + */ + var remoteNodeAddCallback = function (operation) { + if (operation instanceof NodeAddOperation) { + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.HEATMAP, + operation.getOTOperation() + ); + if ( + operation.getViewId() === EntityManagerInstance.getViewId() && + EntityManagerInstance.getLayer() === CONFIG.LAYER.META + ) { + processNodeAddOperation(operation); + } else if (EntityManagerInstance.getLayer() === CONFIG.LAYER.MODEL) { + var type, node, viewType; + + if (!operation.getViewId()) { + type = operation.getType(); + } else { + type = operation.getOriginType(); + } + + if (EntityManagerInstance.getViewId()) { + viewType = EntityManagerInstance.getNodeType(type).VIEWTYPE; + if (viewType) { + type = viewType; + } + } + + //processNodeAddOperation + if (operation.getJSON()) { + node = EntityManagerInstance.createNodeFromJSON( + type, + operation.getEntityId(), + operation.getLeft(), + operation.getTop(), + operation.getWidth(), + operation.getHeight(), + operation.getZIndex(), + operation.getContainment(), + operation.getJSON() + ); + } else { + node = EntityManagerInstance.createNode( + type, + operation.getEntityId(), + operation.getLeft(), + operation.getTop(), + operation.getWidth(), + operation.getHeight(), + operation.getZIndex(), + operation.getContainment() + ); + } + + if (operation.getDefaultLabel()) { + node.getLabel().getValue().setValue(operation.getDefaultLabel()); + } + + if (operation.getDefaultAttributeValues()) { + for (const [key, value] of Object.entries( + operation.getDefaultAttributeValues() + )) { + node.getAttribute(key).getValue().setValue(value); + } + } + + node.registerYMap(); + node.draw(); + node.addToCanvas(that); + node.bindMoveToolEvents(); + + //if we are in a view but the view type got no mapping in this view -> hide the element + if (!viewType && EntityManagerInstance.getViewId()) { + node.hide(); + } else { + const userMap = y.getMap("users"); + if ( + userMap.get(y.clientID) !== operation.getJabberId() && + operation.getJabberId() != null + ) { + const userList = y.getMap("userList"); + var color = Util.getColor( + userList.get(operation.getJabberId()).globalId + ); + node.refreshTraceAwareness(color); + } + } + that.remountCurrentTool(); + } + } + }; + + var sendViewChangeOperation = function () { + var canvasFrame = $("#canvas-frame"); + var operation = new CanvasViewChangeOperation( + _$node.position().left, + _$node.position().top, + canvasFrame.width(), + canvasFrame.height(), + _zoom + ); + _iwcw.sendLocalNonOTOperation( + CONFIG.WIDGET.NAME.HEATMAP, + operation.toNonOTOperation() + ); + }; + + /** + * Callback for a remote Edge Add Operation + * @param {operations.ot.EdgeAddOperation} operation + */ + var remoteEdgeAddCallback = function (operation) { + if (operation instanceof EdgeAddOperation) { + EntityManagerInstance.findNode(operation.getSource()); + EntityManagerInstance.findNode(operation.getTarget()); + + if ( + operation.getViewId() === EntityManagerInstance.getViewId() || + EntityManagerInstance.getLayer() === CONFIG.LAYER.META + ) { + processEdgeAddOperation(operation); + } else if (EntityManagerInstance.getLayer() === CONFIG.LAYER.MODEL) { + var type, edge, viewType; + + if (!operation.getViewId()) { + type = operation.getType(); + } else { + type = operation.getOriginType(); + } + + if (EntityManagerInstance.getViewId()) { + viewType = EntityManagerInstance.getEdgeType(type).VIEWTYPE; + if (viewType) { + type = viewType; + } + } + + if (operation.getJSON()) { + edge = EntityManagerInstance.createEdgeFromJSON( + type, + operation.getEntityId(), + operation.getSource(), + operation.getTarget(), + operation.getJSON() + ); + } else { + edge = EntityManagerInstance.createEdge( + type, + operation.getEntityId(), + EntityManagerInstance.findNode(operation.getSource()), + EntityManagerInstance.findNode(operation.getTarget()) + ); + } + + edge.registerYMap(); + edge.connect(); + edge.addToCanvas(that); + + //if we are in a view but the view type got no mapping in this view -> hide the element + if (!viewType && EntityManagerInstance.getViewId()) { + edge.hide(); + } + + that.remountCurrentTool(); + } + } + }; + + /** + * Callback for a local Tool Select Operation + * @param {operations.non_ot.ToolSelectOperation.non_ot.ToolSelectOperation} operation + */ + var localToolSelectCallback = function (operation) { + if (operation instanceof ToolSelectOperation) { + processToolSelectOperation(operation); + } + }; + + var localShowGuidanceBoxCallback = function (operation) { + if (operation instanceof ShowGuidanceBoxOperation) { + processShowGuidanceBoxOperation(operation); + } + }; + + var processShowGuidanceBoxOperation = function (operation) { + _guidanceDefinition = operation.getGuidance(); + _guidanceBoxLabel = operation.getLabel(); + that.showGuidanceBox(operation.getEntityId()); + }; + + /** + * Callback for a local Export Data Operation + * @param {operations.non_ot.ExportMetaModelOperation} operation + */ + var localExportMetaModelCallback = function (operation) { + if (operation instanceof ExportMetaModelOperation) { + if (operation.getData() === null) { + operation.setData(EntityManagerInstance.generateMetaModel()); + _iwcw.sendLocalNonOTOperation( + operation.getRequestingComponent(), + operation.toNonOTOperation() + ); + } else { + var data = operation.getData(); + var op = new ActivityOperation( + "EditorGenerateActivity", + "-1", + _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], + '..generated new Editor ' + + data.spaceTitle + + "", + {} + ); + const activityMap = y.getMap("activity"); + activityMap.set("EditorGenerateActivity", op.toJSON()); + } + } + }; + + var localMoveCanvasOperation = function (operation) { + if (operation instanceof MoveCanvasOperation) { + that.scrollEntityIntoView(operation.getObjectId()); + } + }; + + var localExportLogicalGuidanceRepresentationCallback = function ( + operation + ) { + if (operation instanceof ExportLogicalGuidanceRepresentationOperation) { + if (operation.getData() === null) { + operation.setData( + EntityManagerInstance.generateLogicalGuidanceRepresentation() + ); + _iwcw.sendLocalNonOTOperation( + operation.getRequestingComponent(), + operation.toNonOTOperation() + ); + } + } + }; + + var localGuidanceStrategyOperationCallback = function (operation) { + const canvasMap = y.getMap("canvas"); + if (operation instanceof GuidanceStrategyOperation) { + //Just forward the message to remote users + canvasMap.set(GuidanceStrategyOperation.TYPE, operation.toJSON()); + } + }; + + var localRevokeSharedActivityOperationCallback = function (operation) { + if (operation instanceof RevokeSharedActivityOperation) { + const canvasMap = y.getMap("canvas"); + //Just forward the message to remote users + canvasMap.set(RevokeSharedActivityOperation.TYPE, operation.toJSON()); + } + }; + + var remoteGuidanceStrategyOperation = function (operation) { + if (operation instanceof GuidanceStrategyOperation) { + //Just forward the message to the local guidance widget + _iwcw.sendLocalNonOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.toNonOTOperation() + ); + } + }; + + var remoteRevokeSharedActivityOperationCallback = function (operation) { + if (operation instanceof RevokeSharedActivityOperation) { + //Just forward the message to the local guidance widget + _iwcw.sendLocalNonOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.toNonOTOperation() + ); + } + }; + + /** + * Callback for a local Export Data Operation + * @param {operations.non_ot.ExportImageOperation} operation + */ + var localExportImageCallback = function (operation) { + if (operation instanceof ExportImageOperation) { + that.toPNG().then(function (url) { + operation.setData(url); + _iwcw.sendLocalNonOTOperation( + operation.getRequestingComponent(), + operation.toNonOTOperation() + ); + }); + } + }; + + /** + * Callback for an undone resp. redone Node Add Operation + * @param {operations.ot.NodeAddOperation} operation + */ + var init = function () { + var $canvasFrame = _$node.parent(); + + that.addTool(MoveTool.TYPE, new MoveTool()); + + _$node.css({ + width: _canvasWidth, + height: _canvasHeight, + left: (-_canvasWidth + $canvasFrame.width()) / 2, + top: (-_canvasHeight + $canvasFrame.height()) / 2, + }); + + _$node.draggable({ + stop: function () { + sendViewChangeOperation(); + }, + }); + + if (_$node.transformable != null) { + // since recently, this method doesnt exist anymore. BUGFIX + _$node.transformable({ + rotatable: false, + skewable: false, + scalable: false, + }); + } + _$node.mousewheel(function (event) { + that.setZoom(that.getZoom() + 0.1 * event.deltaY); + event.preventDefault(); + }); + }; + + /** + * Get jQuery object of DOM node representing the canvas + * @returns {jQuery} + */ + this.get$node = function () { + return _$node; + }; + + this.showGuidanceBox = function (entityId) { + this.hideGuidanceBox(); + var entity; + if (typeof entityId == "undefined") { + entityId = _guidanceBoxEntityId; + } else { + _guidanceBoxEntityId = entityId; + } + if (_guidanceDefinition === null) return; + if (_guidanceDefinition.length == 0) return; + if (!entityId) entityId = _selectedEntity.getEntityId(); + + entity = EntityManagerInstance.findNode(entityId); + if (!entity) return; + var entityAppearance = entity.getAppearance(); + var appearance = { + top: entityAppearance.top, + left: entityAppearance.left, + width: entityAppearance.width, + height: entityAppearance.height, + }; + appearance.top += entityAppearance.height + 10; + appearance.left += entityAppearance.width / 2; + _guidanceBox = new GuidanceBox( + Util.generateRandomId(), + _guidanceBoxLabel, + appearance.left, + appearance.top + ); + var inView = false; + if ( + EntityManagerInstance.getViewId() != null && + EntityManagerInstance.getLayer() === CONFIG.LAYER.MODEL + ) { + inView = true; + } + for (var i = 0; i < _guidanceDefinition.length; i++) { + var guidanceItem = null; + switch (_guidanceDefinition[i].type) { + case "SELECT_TOOL_GUIDANCE": + var tool; + if ( + inView && + EntityManagerInstance.getNodeType(_guidanceDefinition[i].tool) + .VIEWTYPE === null + ) + continue; + else if (inView) + tool = EntityManagerInstance.getNodeType( + _guidanceDefinition[i].tool + ).VIEWTYPE; + else tool = _guidanceDefinition[i].tool; + + guidanceItem = new SelectToolGuidance( + _guidanceDefinition[i].id, + _guidanceDefinition[i].label, + tool, + that, + _guidanceDefinition[i].icon + ); + break; + case "SET_PROPERTY_GUIDANCE": + var entity = EntityManagerInstance.findNode( + _guidanceDefinition[i].entityId + ); + if (!entity) + entity = EntityManagerInstance.findEdge(_guidanceDefinition[i].entityId); + guidanceItem = new SetPropertyGuidance( + _guidanceDefinition[i].id, + _guidanceDefinition[i].label, + entity, + _guidanceDefinition[i].propertyName, + that + ); + break; + case "COLLABORATION_GUIDANCE": + guidanceItem = new CollaborationGuidance( + "", + _guidanceDefinition[i].label, + _guidanceDefinition[i].activityId, + _guidanceDefinition[i].objectId, + that + ); + break; + case "GHOST_EDGE_GUIDANCE": + var relationshipType; + if ( + inView && + EntityManagerInstance.getEdgeType(_guidanceDefinition[i].relationshipType) + .VIEWTYPE === undefined + ) + continue; + else if (inView) { + relationshipType = EntityManagerInstance.getEdgeType( + _guidanceDefinition[i].relationshipType + ).VIEWTYPE; + } else { + relationshipType = _guidanceDefinition[i].relationshipType; + } + that.showGhostEdge( + _guidanceDefinition[i].sourceId, + _guidanceDefinition[i].targetId, + relationshipType + ); + break; + } + if (guidanceItem) _guidanceBox.addGuidance(guidanceItem); + } + + _guidanceBox.addToCanvas(that); + _guidanceBox.draw(); + }; + + this.hideGuidanceBox = function () { + if (_guidanceBox !== null) _guidanceBox.remove(); + _guidanceBox = null; + for (var i = 0; i < _ghostEdges.length; i++) { + _ghostEdges[i].remove(); + } + _ghostEdges = []; + }; + + /** + * Set model attributes + * @param {canvas_widget.ModelAttributesNode} node + */ + this.setModelAttributesNode = function (node) { + _modelAttributesNode = node; + }; + + /** + * Get model attributes + * @returns {canvas_widget.ModelAttributesNode} + */ + this.getModelAttributesNode = function () { + return _modelAttributesNode; + }; + + /** + * Bind events for move tool + */ + this.bindMoveToolEvents = function () { + //Enable Canvas Dragging + _$node.draggable("enable"); + + // view_only is used by the CAE and allows to show a model in the Canvas which is not editable + // therefore, the context menu in the Canvas must be disabled + const widgetConfigMap = y.getMap("widgetConfig"); + var viewOnly = widgetConfigMap.get("view_only"); + + //Define Node Rightclick Menu + if (viewOnly) { + // view only mode is activated, no context menu should be shown + $.contextMenu({ + selector: "#" + _$node.attr("id"), + build: function ($trigger, e) { + return false; + }, + }); + return; + } + // otherwise show normal context menu + $.contextMenu({ + selector: "#" + _$node.attr("id"), + zIndex: AbstractEntity.CONTEXT_MENU_Z_INDEX, + build: function ($trigger, e) { + if (_selectedEntity === null) { + return { + items: { + addNode: { + name: "Add node..", + items: EntityManagerInstance.generateAddNodeMenu( + that, + e.originalEvent.offsetX, + e.originalEvent.offsetY + ), + }, + hide: { + name: "Hide entities..", + items: { + nodes: { + name: "nodes..", + items: EntityManagerInstance.generateVisibilityNodeMenu("hide"), + }, + edges: { + name: "edges..", + items: EntityManagerInstance.generateVisibilityEdgeMenu("hide"), + }, + }, + }, + show: { + name: "Show entities..", + items: { + nodes: { + name: "nodes..", + items: EntityManagerInstance.generateVisibilityNodeMenu("show"), + }, + edges: { + name: "edges..", + items: EntityManagerInstance.generateVisibilityEdgeMenu("show"), + }, + }, + }, + }, + }; + } else { + that.select(null); + return false; + } + }, + }); + }; + + /** + * Bind events for move tool + */ + this.unbindMoveToolEvents = function () { + //Disable Canvas Dragging + _$node.draggable("disable"); + + if (_$node.transformable != null) { + _$node.transformable("destroy"); + } + + //Unbind Node and Edge Events + //this.select(null); + //Disable Canvas Rightclick Menu + _$node.unbind("contextmenu"); + }; + + /** + * Select an entity + * @param {canvas_widget.AbstractNode|canvas_widget.AbstractEdge} entity + */ + this.select = function (entity) { + if (_selectedEntity != entity) { + if (_selectedEntity) _selectedEntity.unselect(); + if (entity) entity.select(); + } + + var operation = new EntitySelectOperation( + entity ? entity.getEntityId() : null, + entity ? entity.getType() : null, + _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID] + ); + + _iwcw.sendLocalNonOTOperation( + CONFIG.WIDGET.NAME.ATTRIBUTE, + operation.toNonOTOperation() + ); + _iwcw.sendLocalNonOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.toNonOTOperation() + ); + _iwcw.sendLocalNonOTOperation( + CONFIG.WIDGET.NAME.METADATA, + operation.toNonOTOperation() + ); + _iwcw.sendLocalNonOTOperation( + CONFIG.WIDGET.NAME.OPENAPI, + operation.toNonOTOperation() + ); + const selectionMap = y.getMap("select"); + const userMap = y.getMap("users"); + if (entity === null) { + selectionMap.set(userMap.get(y.clientID), null); + } else { + selectionMap.set(userMap.get(y.clientID), entity.getEntityId()); + } + _selectedEntity = entity; + }; + + /** + * Get entity currently selected + * @return {canvas_widget.AbstractNode|canvas_widget/AbstractEdge} + */ + this.getSelectedEntity = function () { + return _selectedEntity; + }; + + /** + * Set zoom level (between 0.5 and 2, default is 1) + * @param {number} zoom + */ + this.setZoom = function (zoom) { + if (zoom < 0.1 || zoom > 2) { + return; + } + _zoom = zoom; + + _$node.css("transform", `scaleX(${zoom}) scaleY(${zoom})`); + _$node.animate({ + transform: `scaleX(${zoom}) scaleY(${zoom})`, + }); + + window.jsPlumbInstance.setZoom(zoom); + sendViewChangeOperation(); + }; + + this.showGhostEdge = function (sourceId, targetId, relationshipType) { + var source = EntityManagerInstance.findNode(sourceId); + var target = EntityManagerInstance.findNode(targetId); + if (!source || !target) { + //console.error('GhostEdge guidance not possible. Bad params: src' + source + ' target: ' + target + ' type: ' + relationshipType); + return; + } + var ghostEdgeGuidance = null; + //Check if there already is a ghost edge between the two nodes + for (var i = 0; i < _ghostEdges.length; i++) { + var ghostEdge = _ghostEdges[i]; + var node1 = ghostEdge.getNode1(); + var node2 = ghostEdge.getNode2(); + if ( + (source == node1 && target == node2) || + (source == node2 && target == node1) + ) { + ghostEdgeGuidance = ghostEdge; + break; + } + } + if (!ghostEdgeGuidance) { + ghostEdgeGuidance = new GhostEdgeGuidance(that, source, target); + _ghostEdges.push(ghostEdgeGuidance); + } + if ( + EntityManagerInstance.getViewId() && + EntityManagerInstance.getLayer() === CONFIG.LAYER.MODEL + ) { + ghostEdgeGuidance.addEdge( + EntityManagerInstance.getViewEdgeType(relationshipType), + source, + target + ); + } else { + ghostEdgeGuidance.addEdge( + EntityManagerInstance.getEdgeType(relationshipType), + source, + target + ); + } + for (var j = 0; j < _ghostEdges.length; j++) { + _ghostEdges[j].show(); + } + }; + + this.highlightEntity = function (entityId) { + var entity = EntityManagerInstance.findNode(entityId); + + if (entity) entity.highlight("blue", "Set property"); + else { + entity = EntityManagerInstance.findEdge(entityId); + entity.highlight("blue"); + } + }; + + this.unhighlightEntity = function (entityId) { + var entity = EntityManagerInstance.findNode(entityId); + + if (!entity) entity = EntityManagerInstance.findEdge(entityId); + + entity.unhighlight(); + }; + + /** + * Get zoom level + * @returns {number} + */ + this.getZoom = function () { + return _zoom; + }; + + /** + * Reset the currently mounted tool back to the Move Tool + */ + this.resetTool = function () { + var operation = new ToolSelectOperation(MoveTool.TYPE); + + _iwcw.sendLocalNonOTOperation( + CONFIG.WIDGET.NAME.PALETTE, + operation.toNonOTOperation() + ); + this.mountTool(MoveTool.TYPE); + //this.callListeners(CONFIG.CANVAS.LISTENERS.RESET); + }; + + /** + * Create a new node and draw it on the canvas + * @param {string} type Type of node + * @param {Number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {number} [zIndex] Position of node on z-axis + * @param {boolean} containment containment + * @param {object} [json] representation of node + * @param {string} identifier the identifier of the node, if null a new id is generated + * @param defaultAttributeValues May be used to set default values for node attributes. + * @return {number} id of new node + */ + this.createNode = function ( + type, + left, + top, + width, + height, + zIndex, + containment, + json, + identifier, + historyFlag, + defaultLabel, + defaultAttributeValues + ) { + var id, + oType = null; + if (identifier) id = identifier; + else id = Util.generateRandomId(24); + zIndex = zIndex || AbstractEntity.maxZIndex + 1; + + if ( + EntityManagerInstance.getViewId() !== undefined && + EntityManagerInstance.getLayer() === CONFIG.LAYER.MODEL + ) { + oType = EntityManagerInstance.getViewNodeType(type).getTargetNodeType().TYPE; + } + + var operation = new NodeAddOperation( + id, + type, + left, + top, + width, + height, + zIndex, + containment, + json || null, + EntityManagerInstance.getViewId(), + oType, + _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], + defaultLabel, + defaultAttributeValues + ); + try { + propagateNodeAddOperation(operation); + } catch (error) { + console.error(error); + } + if (y) { + const canvasMap = y.getMap("canvas"); + canvasMap.set(NodeAddOperation.TYPE, operation.toJSON()); + } + if (!historyFlag) HistoryManagerInstance.add(operation); + return id; + }; + + /** + * Create a new edge and draw it on the canvas + * @param {string} type Type of edge + * @param {canvas_widget.AbstractNode} source Source node entity id + * @param {canvas_widget.AbstractNode} target Target node entity id + * @param {object} [json] representation of edge + * @param {string} identifier the identifier of the edge + * @return {number} id of new edge + */ + this.createEdge = function ( + type, + source, + target, + json, + identifier, + historyFlag + ) { + var id = null, + oType = null; + + if (identifier) id = identifier; + else id = Util.generateRandomId(24); + if ( + EntityManagerInstance.getViewId() !== undefined && + EntityManagerInstance.getLayer() === CONFIG.LAYER.MODEL + ) { + oType = EntityManagerInstance.getViewEdgeType(type).getTargetEdgeType().TYPE; + } + var operation = new EdgeAddOperation( + id, + type, + source, + target, + json || null, + EntityManagerInstance.getViewId(), + oType, + _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID] + ); + propagateEdgeAddOperation(operation); + + if (window.hasOwnProperty("y")) { + const canvasMap = y.getMap("canvas"); + canvasMap.set(EdgeAddOperation.TYPE, operation.toJSON()); + } + + if (!historyFlag) HistoryManagerInstance.add(operation); + return id; + }; + + this.scrollNodeIntoView = function (node) { + if (!node) return; + + var frameOffset = $("#canvas-frame").offset(); + var frameWidth = $("#canvas-frame").width(); + var frameHeight = $("#canvas-frame").height(); + + var nodeOffset = node.get$node().offset(); + var nodeWidth = node.get$node().width(); + var nodeHeight = node.get$node().height(); + + var scrollX = nodeOffset.left - frameOffset.left; + var scrollY = nodeOffset.top - frameOffset.top; + _$node.position().top; + _$node.position().left; + + _$node.animate( + { + top: "+=" + (frameHeight / 2 - scrollY - nodeHeight / 2), + left: "+=" + (frameWidth / 2 - scrollX - nodeWidth / 2), + }, + 1000 + ); + }; + + this.scrollEdgeIntoView = function (edge) { + if (!edge) return; + var frameOffset = $("#canvas-frame").offset(); + var frameWidth = $("#canvas-frame").width(); + var frameHeight = $("#canvas-frame").height(); + + var srcNode = edge.getSource(); + var targetNode = edge.getTarget(); + + var srcNodeOffset = srcNode.get$node().offset(); + var srcNodeWidth = srcNode.get$node().width(); + var srcNodeHeight = srcNode.get$node().height(); + + var targetNodeOffset = targetNode.get$node().offset(); + var targetNodeWidth = targetNode.get$node().width(); + var targetNodeHeight = targetNode.get$node().height(); + + var scrollX = + (srcNodeOffset.left + targetNodeOffset.left) / 2 - frameOffset.left; + var scrollY = + (srcNodeOffset.top + targetNodeOffset.top) / 2 - frameOffset.top; + _$node.position().top; + _$node.position().left; + + _$node.animate( + { + top: + "+=" + + (frameHeight / 2 - + scrollY - + Math.max(srcNodeHeight, targetNodeHeight) / 2), + left: + "+=" + + (frameWidth / 2 - + scrollX - + Math.max(srcNodeWidth, targetNodeWidth) / 2), + }, + 1000 + ); + }; + + this.scrollEntityIntoView = function (entityId) { + if (!entityId) return null; + if (entityId.indexOf("[") != -1 && entityId.indexOf("]") != -1) + entityId = entityId.replace(/\[\w*\]/g, ""); + var entity = EntityManagerInstance.findNode(entityId); + if (!entity) { + entity = EntityManagerInstance.findEdge(entityId); + if (!entity) return null; + else that.scrollEdgeIntoView(entity); + } else that.scrollNodeIntoView(entity); + return true; + }; + + /** + * Convert current canvas content to PNG image file + * @return {string} Data-URI of generated PNG image + */ + this.toPNG = function () { + var $renderedCanvas = $("") + .insertAfter(_$node) + .attr("width", _$node.width()) + .attr("height", _$node.height()), + ctx = $renderedCanvas[0].getContext("2d"), + deferred = $.Deferred(), + promises = [], + oldZoom = this.getZoom(); + + $("#loading").show(); + + this.setZoom(1); + + canvasOffset = _$node.offset(); + + ctx.beginPath(); + ctx.rect(0, 0, _canvasWidth, _canvasHeight); + ctx.fillStyle = _$node.css("backgroundColor"); + ctx.fill(); + + lodash.each( + lodash.sortBy($.makeArray(_$node.children()), function (e) { + return $(e).css("zIndex"); + }), + function (e) { + var $this = $(e); + if ( + typeof $this.attr("id") === "undefined" || + (!$this.attr("id").startsWith("modelAttributes") && + !$this.attr("id").endsWith("awareness")) + ) { + promises.push(convertNodeTreeToCanvas($this, ctx)); + } + } + ); + + $.when.apply($, promises).then(function () { + var tempCanvas = document.createElement("canvas"), + tCtx = tempCanvas.getContext("2d"), + minLeft = _canvasWidth, + minTop = _canvasHeight, + maxRight = 0, + maxBottom = 0, + nodes = EntityManagerInstance.getNodes(), + nodeId, + appearance, + width, + height, + padding = 20, + nodeExists = false; + + for (nodeId in nodes) { + if (nodes.hasOwnProperty(nodeId)) { + nodeExists = true; + appearance = nodes[nodeId].getAppearance(); + //noinspection JSAccessibilityCheck + minLeft = Math.min(minLeft, appearance.left); + minTop = Math.min(minTop, appearance.top); + //noinspection JSAccessibilityCheck + maxRight = Math.max(maxRight, appearance.left + appearance.width); + maxBottom = Math.max(maxBottom, appearance.top + appearance.height); + } + } + + if (!nodeExists) { + minLeft = _canvasWidth / 2; + minTop = _canvasHeight / 2; + maxRight = _canvasWidth / 2; + maxBottom = _canvasHeight / 2; + } + + minLeft -= padding; + minTop -= padding; + maxRight += padding; + maxBottom += padding; + + width = maxRight - minLeft; + height = maxBottom - minTop; + + tempCanvas.width = width; + tempCanvas.height = height; + + tCtx.drawImage( + $renderedCanvas[0], + minLeft, + minTop, + width, + height, + 0, + 0, + width, + height + ); + + that.setZoom(oldZoom); + $("#loading").hide(); + deferred.resolve(tempCanvas.toDataURL()); + }); + + return deferred.promise(); + }; + + /** + * Draw DOM node onto canvas + * @param $node jquery object of node + * @param ctx Canvas context + * @returns {promise} + */ + var convertNodeTreeToCanvas = function ($node, ctx) { + function drawSVGOnCanvas(ctx, svgMarkup, x, y) { + var svg = new Blob([svgMarkup], { + type: "image/svg+xml;charset=utf-8", + }), + DOMURL = self.URL || self.webkitURL || self, + url = DOMURL.createObjectURL(svg), + img = new Image(), + deferred = $.Deferred(); + + img.onload = function () { + ctx.drawImage(img, x, y); + DOMURL.revokeObjectURL(url); + deferred.resolve(); + }; + img.src = url; + setTimeout(function () { + deferred.resolve(); + }, 500); + return deferred.promise(); + } + + function convertNodeToSVG($node) { + if ($node[0].nodeType === Node.TEXT_NODE) { + if ($.trim($node.text()) === "") { + return $.Deferred().resolve().promise(); + } else { + $node = $node.wrap($("")).parent(); + } + } + + if (!$node.is(":visible")) { + return $.Deferred().resolve().promise(); + } + + var height = $node.height(), + width = $node.width(), + padding = { + left: parseInt($node.css("paddingLeft"), 10), + top: parseInt($node.css("paddingTop"), 10), + right: parseInt($node.css("paddingRight"), 10), + bottom: parseInt($node.css("paddingBottom"), 10), + }, + border = { + width: parseInt($node.css("borderWidth")), + color: $node.css("borderColor"), + left: { + width: parseInt($node.css("borderLeftWidth")), + color: $node.css("borderLeftColor"), + }, + top: { + width: parseInt($node.css("borderTopWidth")), + color: $node.css("borderTopColor"), + }, + right: { + width: parseInt($node.css("borderRightWidth")), + color: $node.css("borderRightColor"), + }, + bottom: { + width: parseInt($node.css("borderBottomWidth")), + color: $node.css("borderBottomColor"), + }, + }, + borderMarkup = [], + backgroundColor = $node.css("backgroundColor"), + color = $node.css("color"), + font = $node.css("font"), + fontSize = parseInt($node.css("fontSize"), 10), + textDecoration = $node.css("textDecoration").split(" ")[0], + offset = $node.offset(), + value, + textX, + textY = height, + textAnchor, + contents = $node.contents(); + + if ($node[0].nodeName.toLowerCase() === "svg") { + $node.attr("width", width); + $node.attr("height", height); + + return drawSVGOnCanvas( + ctx, + $node[0].outerHTML + .replace(/style="[^"]*"/, "") + .replace( + /http:\/\/www\.w3\.org\/1999\/xhtml/g, + "http://www.w3.org/2000/svg" + ), + offset.left - canvasOffset.left, + offset.top - canvasOffset.top + ); + } + + if (contents.length === 1 && contents[0].nodeType === Node.TEXT_NODE) { + value = $node.text(); + } else { + value = $node.val(); + } + + var tagsToReplace = { + "&": "&", + "<": "<", + ">": ">", + }; + + value = $.trim(value).replace(/[&<>]/g, function (tag) { + return tagsToReplace[tag] || tag; + }); + + switch ($node.css("textAlign")) { + case "right": + textX = width; + textAnchor = "right"; + break; + case "center": + textX = width / 2; + textAnchor = "middle"; + break; + default: + case "left": + textX = 0; + textAnchor = "left"; + break; + } + + textX += padding.left; + textY += + padding.top + border.width - Math.ceil((height - fontSize) / 2) - 1; + height += padding.top + padding.bottom + 2 * border.width; + width += padding.left + padding.right + 2 * border.width; + + if ( + border.color.split(" ").length !== 1 || + border.width.split(" ").length !== 1 + ) { + border.width = 0; + if (border.left.width > 0) { + borderMarkup.push( + '' + ); + } + if (border.top.width > 0) { + borderMarkup.push( + '' + ); + } + if (border.right.width > 0) { + borderMarkup.push( + '' + ); + } + if (border.bottom.width > 0) { + borderMarkup.push( + '' + ); + } + } + + return drawSVGOnCanvas( + ctx, + '' + + '' + + borderMarkup.join("\n") + + '' + + value + + "" + + "", + offset.left - canvasOffset.left, + offset.top - canvasOffset.top + ); + } + + var contents = $node.contents(); + + return convertNodeToSVG($node).then(function () { + var promises = []; + if (contents.length !== 1 || contents[0].nodeType !== Node.TEXT_NODE) { + contents.each(function () { + var $this = $(this); + if ($node[0].nodeName.toLowerCase() !== "svg") { + promises.push(convertNodeTreeToCanvas($this, ctx)); + } + }); + } + return $.when.apply($, promises).then(function () { + return true; + }); + }); + }; + + /** + * Register inter widget communication callbacks + */ + this.registerCallbacks = function () { + _iwcw.registerOnDataReceivedCallback(localToolSelectCallback); + _iwcw.registerOnDataReceivedCallback(localExportMetaModelCallback); + _iwcw.registerOnDataReceivedCallback( + localExportLogicalGuidanceRepresentationCallback + ); + _iwcw.registerOnDataReceivedCallback(localExportImageCallback); + _iwcw.registerOnDataReceivedCallback(localShowGuidanceBoxCallback); + _iwcw.registerOnDataReceivedCallback( + localRevokeSharedActivityOperationCallback + ); + _iwcw.registerOnDataReceivedCallback(localMoveCanvasOperation); + _iwcw.registerOnDataReceivedCallback( + localGuidanceStrategyOperationCallback + ); + }; + + /** + * Unregister inter widget communication callbacks + */ + this.unregisterCallbacks = function () { + _iwcw.unregisterOnDataReceivedCallback(localToolSelectCallback); + _iwcw.unregisterOnDataReceivedCallback(localExportMetaModelCallback); + _iwcw.unregisterOnDataReceivedCallback( + localExportLogicalGuidanceRepresentationCallback + ); + _iwcw.unregisterOnDataReceivedCallback(localExportImageCallback); + _iwcw.unregisterOnDataReceivedCallback(localShowGuidanceBoxCallback); + _iwcw.unregisterOnLocalDataReceivedCallback( + localRevokeSharedActivityOperationCallback + ); + _iwcw.unregisterOnLocalDataReceivedCallback(localMoveCanvasOperation); + _iwcw.unregisterOnLocalDataReceivedCallback( + localGuidanceStrategyOperationCallback + ); + }; + + init(); + + if (window.hasOwnProperty("y")) { + const canvasMap = y.getMap("canvas"); + canvasMap.observe(function (event) { + var yUserId = event.currentTarget.doc.clientID; + + event.keysChanged.forEach(function (key) { + const data = event.currentTarget.get(key); + const eventTriggeredLocally = window.y.clientID === data?.triggeredBy; + if (!eventTriggeredLocally || data.historyFlagSet) { + const userMap = y.getMap("users"); + var jabberId = userMap.get(yUserId); + var operation; + + switch (key) { + case NodeAddOperation.TYPE: { + operation = new NodeAddOperation( + data.id, + data.type, + data.left, + data.top, + data.width, + data.height, + data.zIndex, + data.containment, + data.json, + data.viewId, + data.oType, + jabberId || data.jabberId, + data.defaultLabel, + data.defaultAttributeValues + ); + remoteNodeAddCallback(operation); + break; + } + case EdgeAddOperation.TYPE: { + operation = new EdgeAddOperation( + data.id, + data.type, + data.source, + data.target, + data.json, + data.viewId, + data.oType, + jabberId || data.jabberId + ); + remoteEdgeAddCallback(operation); + break; + } + case RevokeSharedActivityOperation.TYPE: { + operation = new RevokeSharedActivityOperation(data.id); + remoteRevokeSharedActivityOperationCallback(operation); + break; + } + case GuidanceStrategyOperation.TYPE: { + operation = new GuidanceStrategyOperation(data.data); + remoteGuidanceStrategyOperation(operation); + break; + } + case "ViewApplyActivity": { + var activityOperation = new ActivityOperation( + "ViewApplyActivity", + event.value.viewId, + event.value.jabberId + ); + const activityMap = y.getMap("activity"); + + activityMap.set( + ActivityOperation.TYPE, + activityOperation.toJSON() + ); + break; + } + case "triggerSave": { + if (data.value === _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]) + EntityManagerInstance.saveState(); + break; + } + case "applyLayout": { + //remote user + DagreLayout$1.apply(); + jsPlumbInstance.repaintEverything(); + break; + } + //used by the syncmeta-plugin only + case "highlight": { + var userId = _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]; + if (!event.value.remote && userId !== event.value.userId) + return; + + // when an entity (or multiple entities) get highlighted, then + // one of them can be selected where the canvas should move to + if (event.value.moveCanvasToEntity) { + var entityId = event.value.moveCanvasToEntity; + var entity = EntityManagerInstance.find(entityId); + + // move canvas to entity + that.scrollEntityIntoView(entityId); + + // select the entity (note: this needs to be done before the highlighting, + // because otherwise the "select" overwrites the highlighting) + that.select(entity); + } + + // highlight entity/entities + for (var i = 0; i < event.value.entities.length; i++) { + var entityId = event.value.entities[i]; + var entity = EntityManagerInstance.find(entityId); + if (entity) { + entity.highlight(event.value.color, event.value.label); + } + } + + break; + } + //used by the syncmeta-plugin only + case "unhighlight": { + var userId = _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]; + if (!event.value.remote && userId !== event.value.userId) + return; + for (var i = 0; i < event.value.entities.length; i++) { + var entityId = event.value.entities[i]; + var entity = EntityManagerInstance.find(entityId); + if (entity) { + entity.unhighlight(); + } + } + break; + } + //used by the syncmeta-plugin only + case NodeDeleteOperation.TYPE: { + var userId = _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]; + const nodesMap = y.getMap("nodes"); + if (event.value.jabberId === userId) + nodesMap.delete(event.value.entityId); + setTimeout(function () { + EntityManagerInstance.saveState(); + }, 300); + break; + } + //used by the syncmeta-plugin only + case EdgeDeleteOperation.TYPE: { + break; + } + } + //local user. todo ugly coding style + } else if (key === "applyLayout") { + DagreLayout$1.apply(); + EntityManagerInstance.saveState(); + } + }); + }); + const selectionMap = y.getMap("select"); + selectionMap.observe(function (event) { + const array = Array.from(event.changes.keys.entries()); + array.forEach(([key, change]) => { + const userMap = y.getMap("users"); + if (key !== userMap.get(y.clientID)) { + const userList = y.getMap("userList"); + var userInfo = userList.get(key); + if (event.oldValue != null) { + var unselectedEntity = EntityManagerInstance.find(event.oldValue); + if (unselectedEntity) unselectedEntity.unhighlight(); + } + + if (event.value != null) { + var selectedEntity = EntityManagerInstance.find(event.value); + if (selectedEntity) + selectedEntity.highlight( + Util.getColor(userInfo.globalId), + userInfo[CONFIG.NS.PERSON.TITLE] + ); + } + } + }); + }); + const nodesMap = y.getMap("nodes"); + nodesMap.observe(function (event) { + const array = Array.from(event.changes.keys.entries()); + array.forEach(([key, change]) => { + switch (change.action) { + case "delete": { + var node = EntityManagerInstance.findNode(key); + if (node) + node.remoteNodeDeleteCallback(new NodeDeleteOperation(key)); + break; + } + } + }); + }); + const edgeMap = y.getMap("edges"); + edgeMap.observe(function (event) { + const array = Array.from(event.changes.keys.entries()); + array.forEach(([key, change]) => { + switch (change.action) { + case "delete": { + var edge = EntityManagerInstance.findEdge(key); + if (edge) + edge.remoteEdgeDeleteCallback(new EdgeDeleteOperation(key)); + break; + } + } + }); + }); + } + if (_iwcw) { + that.registerCallbacks(); + } + } + width; + height; +} + +/** + * EdgeShapeNodeTool + * @class canvas_widget.ClassNodeTool + * @extends canvas_widget.NodeTool + * @memberof canvas_widget + * @constructor + */ +class EdgeShapeNodeTool extends NodeTool { + constructor() { + super( + EdgeShapeNode.TYPE, + null, + null, + null, + EdgeShapeNode.DEFAULT_WIDTH, + EdgeShapeNode.DEFAULT_HEIGHT + ); + } +} + +/** + * EnumNodeTool + * @class canvas_widget.ClassNodeTool + * @extends canvas_widget.NodeTool + * @memberof canvas_widget + * @constructor + */ +class EnumNodeTool extends NodeTool { + constructor() { + super( + EnumNode.TYPE, + null, + null, + null, + EnumNode.DEFAULT_WIDTH, + EnumNode.DEFAULT_HEIGHT + ); + } +} + +/** + * GeneralisationEdgeTool + * @class canvas_widget.GeneralisationEdgeTool + * @extends canvas_widget.EdgeTool + * @memberof canvas_widget + * @constructor + */ +class GeneralisationEdgeTool extends EdgeTool { + constructor() { + super(GeneralisationEdge.TYPE, GeneralisationEdge.RELATIONS); + } +} + +const viewrelationshipNodeHtml = "
                  \n
                  <%= type %>
                  \n
                  <<ViewRelationship>>
                  \n
                  \n
                  "; // replaced by importmap.plugin.js + +/** + * ViewRelationshipNode + * @class canvas_widget.ViewRelationshipNode + * @extends canvas_widget.AbstractNode + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {number} zIndex Position of node on z-axis + * @param {object} json indicates if the ViewObjectNode is created from a json + + */ +class ViewRelationshipNode extends AbstractNode { + static TYPE = "ViewRelationship"; + static DEFAULT_WIDTH = 150; + static DEFAULT_HEIGHT = 100; + constructor(id, left, top, width, height, zIndex, json) { + super(id, "ViewRelationship", left, top, width, height, zIndex, json); + var that = this; + + /** + * jQuery object of node template + * @type {jQuery} + * @private + */ + var _$template = $( + lodash.template(viewrelationshipNodeHtml)({ + type: that.getType(), + }) + ); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = AbstractNode.prototype.get$node + .call(this) + .append(_$template) + .addClass("viewrelationship"); + + /** + * jQuery object of DOM node representing the attributes + * @type {jQuery} + * @private + */ + var _$attributeNode = _$node.find(".attributes"); + + /** + * Attributes of node + * @type {Object} + * @private + */ + this.getAttributes(); + + /** + * Get JSON representation of the node + * @returns {Object} + */ + this.toJSON = function () { + return AbstractNode.prototype.toJSON.call(this); + }; + + this.registerYMap = function () { + AbstractNode.prototype.registerYMap.call(this); + that.getLabel().getValue().registerYType(); + attributeList.registerYMap(); + if (cla) cla.registerYMap(); + attribute.getValue().registerYType(); + conjSelection.getValue().registerYType(); + }; + + this.showAttributes = function () { + if (renamingList.get$node().is(":hidden")) renamingList.get$node().show(); + if (conjSelection.get$node().is(":hidden")) + conjSelection.get$node().show(); + if (cla.get$node().is(":hidden")) cla.get$node().show(); + if (!targetAttribute.get$node().is(":hidden")) + targetAttribute.get$node().hide(); + }; + + this.createConditionListAttribute = function (refAttrs) { + var targetAttrList = {}; + if (refAttrs && refAttrs.constructor.name === "RenamingListAttribute") { + var attrs = refAttrs.getAttributes(); + for (var key in attrs) { + if (attrs.hasOwnProperty(key)) { + targetAttrList[key] = attrs[key].getKey().getValue(); + } + } + } else { + for (var key in refAttrs) { + if (refAttrs.hasOwnProperty(key)) { + targetAttrList[key] = refAttrs[key].val.value; + } + } + } + var conditionListAttr = new ConditionListAttribute( + "[condition]", + "Conditions", + that, + targetAttrList, + LogicalOperator + ); + that.addAttribute(conditionListAttr); + _$attributeNode.append(conditionListAttr.get$node()); + conditionListAttr.get$node().hide(); + return conditionListAttr; + }; + + this.registerYMap = function () { + AbstractNode.prototype.registerYMap.call(this); + that.getLabel().getValue().registerYType(); + renamingList.registerYMap(); + if (cla) cla.registerYMap(); + targetAttribute.getValue().registerYType(); + conjSelection.getValue().registerYType(); + }; + + var targetAttribute, renamingList, conjSelection, cla; + _$node.find(".label").append(this.getLabel().get$node()); + if (window.hasOwnProperty("y")) { + const dataMap = y.getMap("data"); + var model = dataMap.get("model"); + if (model) { + var selectionValues = + ViewTypesUtil.GetAllNodesOfBaseModelAsSelectionList2(model.nodes, [ + "Relationship", + ]); + targetAttribute = new SingleSelectionAttribute( + id + "[target]", + "Reference", + that, + selectionValues + ); + that.addAttribute(targetAttribute); + _$attributeNode.prepend(targetAttribute.get$node()); + + if (json) + cla = that.createConditionListAttribute( + json.attributes["[attributes]"].list + ); + else cla = that.createConditionListAttribute(); + } + } + + renamingList = new RenamingListAttribute( + "[attributes]", + "Attributes", + that, + { + hidden: "Show", + top: "Show Top", + center: "Show Center", + bottom: "Show Bottom", + hide: "Hide", + } + ); + that.addAttribute(renamingList); + _$attributeNode.append(renamingList.get$node()); + renamingList.get$node().hide(); + + conjSelection = new SingleSelectionAttribute( + id + "[conjunction]", + "Conjunction", + that, + LogicalConjunctions + ); + that.addAttribute(conjSelection); + _$attributeNode.append(conjSelection.get$node()); + conjSelection.get$node().hide(); + + if (json && conjSelection && cla && renamingList && targetAttribute) + that.showAttributes(); + + this.setContextMenuItemCallback(function () { + var viewId = $("#lblCurrentView").text(); + return { + addShape: { + name: "Add Edge Shape", + callback: function () { + var canvas = that.getCanvas(), + appearance = that.getAppearance(), + nodeId; + + canvas.createNode( + EdgeShapeNode.TYPE, + appearance.left + appearance.width + 50, + appearance.top, + 150, + 100 + ); + canvas.createEdge( + BiDirAssociationEdge.TYPE, + that.getEntityId(), + nodeId, + null, + null, + viewId + ); + }, + disabled: function () { + var edges = that.getEdges(), + edge, + edgeId; + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if ( + (edge instanceof BiDirAssociationEdge && + ((edge.getTarget() === that && + edge.getSource() instanceof EdgeShapeNode) || + (edge.getSource() === that && + edge.getTarget() instanceof EdgeShapeNode))) || + (edge instanceof UniDirAssociationEdge && + edge.getTarget() instanceof EdgeShapeNode) + ) { + return true; + } + } + } + return false; + }, + }, + sep: "---------", + }; + }); + } +} + +function GenerateViewpointModel(viewpointModel, y) { + EntityManagerInstance.init(); + + for (var node_key in viewpointModel.nodes) { + if (viewpointModel.nodes.hasOwnProperty(node_key)) { + var vpNode = viewpointModel.nodes[node_key]; + const width = vpNode.width || vpNode.containment.width; + const height = vpNode.height || vpNode.containment.height; + const left = vpNode.left || vpNode.containment.left; + const top = vpNode.top || vpNode.containment.top; + const zIndex = vpNode.zIndex || vpNode.containment.zIndex; + EntityManagerInstance.createNodeFromJSON( + vpNode.type, + node_key, + left, + top, + width, + height, + zIndex, + vpNode.containment, + vpNode, + y + ); + } + } + + for (var edge_key in viewpointModel.edges) { + if (viewpointModel.edges.hasOwnProperty(edge_key)) { + var vpEdge = viewpointModel.edges[edge_key]; + EntityManagerInstance.createEdgeFromJSON( + vpEdge.type, + edge_key, + vpEdge.source, + vpEdge.target, + vpEdge + ); + } + } + + /** + * Determine the type of the concrete classes (ObjectNodes) of the class diagram contained in the sub graph rooted by the passed node + * @param node Node to start with + * @param [visitedNodes] List of node that already have been visited + * @returns {object} + */ + function getConcreteObjectNodeTypes(node, visitedNodes) { + var edgeId, + edge, + ingoingEdges, + source, + type, + classTypes = []; + + if (!visitedNodes) visitedNodes = []; + + if (visitedNodes.indexOf(node) !== -1) return []; + + visitedNodes.push(node); + + type = node.getLabel().getValue().getValue(); + if ( + (node instanceof ObjectNode || node instanceof ViewObjectNode) && + classTypes.indexOf(type) === -1 + ) { + classTypes.push(type); + } + + ingoingEdges = node.getIngoingEdges(); + for (edgeId in ingoingEdges) { + if (ingoingEdges.hasOwnProperty(edgeId)) { + edge = ingoingEdges[edgeId]; + source = edge.getSource(); + if ( + (edge instanceof GeneralisationEdge && + source instanceof ObjectNode) || + (edge instanceof GeneralisationEdge && + source instanceof AbstractClassNode) || + (edge instanceof GeneralisationEdge && + source instanceof ViewObjectNode) + ) { + classTypes = classTypes.concat( + getConcreteObjectNodeTypes(source, visitedNodes) + ); + } + } + } + return classTypes; + } + + /** + * Determine the attributes of the passed node by traversing the underlying class diagram + * @param node Node to start with + * @param [visitedNodes] List of node that already have been visited + * @returns {object} + */ + function getNodeAttributes(node, visitedNodes) { + var nodeAttributes, attributeId, attribute; + var edgeId, edge, outgoingEdges; + var source, target; + var neighbor, options; + var attributes = {}; + var obj = {}; + + if (!visitedNodes) visitedNodes = []; + + if (visitedNodes.indexOf(node) !== -1) return {}; + + visitedNodes.push(node); + + //Traverse outgoing edges to check for inheritance and linked enums + outgoingEdges = node.getOutgoingEdges(); + for (edgeId in outgoingEdges) { + if (outgoingEdges.hasOwnProperty(edgeId)) { + edge = outgoingEdges[edgeId]; + source = edge.getSource(); + target = edge.getTarget(); + + //Does the node inherit attributes from a parent node? + if ( + (edge instanceof GeneralisationEdge && + target instanceof AbstractClassNode) || + (edge instanceof GeneralisationEdge && + node instanceof ObjectNode && + target instanceof ObjectNode) || + (edge instanceof GeneralisationEdge && + node instanceof RelationshipNode && + target instanceof RelationshipNode) || + (edge instanceof GeneralisationEdge && + node instanceof EnumNode && + target instanceof EnumNode) + ) { + Util.merge(attributes, getNodeAttributes(target, visitedNodes)); + + //Is there an enum linked to the node + } else if ( + (edge instanceof BiDirAssociationEdge && + ((target === node && (neighbor = source) instanceof EnumNode) || + (source === node && (neighbor = target) instanceof EnumNode))) || + (edge instanceof UniDirAssociationEdge && + (neighbor = target) instanceof EnumNode) + ) { + options = {}; + nodeAttributes = {}; + Util.merge(nodeAttributes, getNodeAttributes(neighbor, [])); + for (attributeId in nodeAttributes) { + if (nodeAttributes.hasOwnProperty(attributeId)) { + attribute = nodeAttributes[attributeId]; + options[attribute.value] = attribute.value; + } + } + obj = {}; + obj[neighbor.getEntityId()] = { + key: edge.getLabel().getValue().getValue(), + value: neighbor.getLabel().getValue().getValue(), + options: options, + }; + Util.merge(attributes, obj); + } + } + } + //Compute node attributes + nodeAttributes = node.getAttribute("[attributes]").getAttributes(); + for (attributeId in nodeAttributes) { + if (nodeAttributes.hasOwnProperty(attributeId)) { + attribute = nodeAttributes[attributeId]; + if (node instanceof RelationshipNode) { + obj = {}; + obj[attributeId] = { + key: attribute.getKey().getValue(), + value: attribute.getValue().getValue(), + position: attribute.getValue2().getValue(), + }; + Util.merge(attributes, obj); + } else if (node instanceof ViewRelationshipNode) { + obj = {}; + obj[attributeId] = { + key: attribute.getKey().getValue(), + ref: attribute.getRef().getValue(), + position: attribute.getVis().getValue(), + }; + Util.merge(attributes, obj); + } else if (node instanceof EnumNode) { + obj = {}; + obj[attributeId] = { + value: attribute.getValue().getValue(), + }; + Util.merge(attributes, obj); + } else if (node instanceof ViewObjectNode) { + obj = {}; + obj[attributeId] = { + key: attribute.getKey().getValue(), + ref: attribute.getRef().getValue(), + visibility: attribute.getVis().getValue(), + }; + Util.merge(attributes, obj); + } else { + obj = {}; + obj[attributeId] = { + key: attribute.getKey().getValue(), + value: attribute.getValue().getValue(), + }; + Util.merge(attributes, obj); + } + } + } + return attributes; + } + + function getViewTypeAttributes(node) { + var target, targetName; + var conjunction; + var conditions = {}; + var nodeid = node.getEntityId(); + if (viewpointModel.nodes.hasOwnProperty(nodeid)) { + if ( + viewpointModel.nodes[nodeid].attributes.hasOwnProperty( + nodeid + "[target]" + ) + ) { + var attr = viewpointModel.nodes[nodeid].attributes[nodeid + "[target]"]; + target = attr.value.value; + targetName = attr.hasOwnProperty("option") ? attr.option : null; + } + if ( + viewpointModel.nodes[nodeid].attributes.hasOwnProperty("[condition]") + ) { + var conditionsList = + viewpointModel.nodes[nodeid].attributes["[condition]"].list; + for (var condId in conditionsList) { + if (conditionsList.hasOwnProperty(condId)) { + conditions[condId] = { + property: conditionsList[condId].property.value, + operator: conditionsList[condId].operator.value, + value: conditionsList[condId].val.value, + //conjunction: conditionsList[condId].operator2.value + }; + } + } + } + if ( + viewpointModel.nodes[nodeid].attributes.hasOwnProperty( + nodeid + "[conjunction]" + ) + ) { + conjunction = + viewpointModel.nodes[nodeid].attributes[nodeid + "[conjunction]"] + .value.value; + } + } + return { + target: target, + targetName: targetName, + conditions: conditions, + conjunction: conjunction, + }; + } + + var metamodel = { + attributes: {}, + nodes: {}, + edges: {}, + }; + + var nodeId, node; + var attributes; + var edge, edgeId, edges; + var source, target; + var neighbor; + var groupSource, groupTarget; + var groupNeighbor; + var shape; + var sourceTypes, targetTypes, concreteTypes; + var groupSourceTypes, groupTargetTypes, groupConcreteTypes; + var relations; + var groupEdge, groupEdgeId, groupEdges; + var viewtypeAttrs; + + var _nodes = EntityManagerInstance.getNodes(); + for (nodeId in _nodes) { + if (_nodes.hasOwnProperty(nodeId)) { + node = _nodes[nodeId]; + if (node instanceof ObjectNode || node instanceof ViewObjectNode) { + if (node.getLabel().getValue().getValue() === "Model Attributes") { + attributes = getNodeAttributes(node); + metamodel.attributes = attributes; + } else { + attributes = getNodeAttributes(node); + edges = node.getEdges(); + shape = null; + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + source = edge.getSource(); + target = edge.getTarget(); + if ( + (edge instanceof BiDirAssociationEdge && + ((target === node && + (neighbor = source) instanceof NodeShapeNode) || + (source === node && + (neighbor = target) instanceof NodeShapeNode))) || + (edge instanceof UniDirAssociationEdge && + (neighbor = target) instanceof NodeShapeNode) + ) { + shape = { + shape: neighbor + .getAttribute(neighbor.getEntityId() + "[shape]") + .getValue() + .getValue(), + color: neighbor + .getAttribute(neighbor.getEntityId() + "[color]") + .getValue() + .getValue(), + defaultWidth: parseInt( + neighbor + .getAttribute(neighbor.getEntityId() + "[defaultWidth]") + .getValue() + .getValue() + ), + defaultHeight: parseInt( + neighbor + .getAttribute(neighbor.getEntityId() + "[defaultHeight]") + .getValue() + .getValue() + ), + containment: neighbor + .getAttribute(neighbor.getEntityId() + "[containment]") + .getValue() + .getValue(), + customShape: neighbor + .getAttribute(neighbor.getEntityId() + "[customShape]") + .getValue() + .getValue(), + customAnchors: neighbor + .getAttribute(neighbor.getEntityId() + "[customAnchors]") + .getValue() + .getValue(), + }; + } + } + } + + metamodel.nodes[nodeId] = { + label: node.getLabel().getValue().getValue(), + attributes: attributes, + shape: shape || { + shape: "rectangle", + color: "white", + containment: false, + customShape: "", + customAnchors: "", + defaultWidth: 0, + defaultHeight: 0, + }, + }; + if (node instanceof ViewObjectNode) { + viewtypeAttrs = getViewTypeAttributes(node); + Util.merge(metamodel.nodes[nodeId], viewtypeAttrs); + } + } + } else if ( + node instanceof RelationshipNode || + node instanceof ViewRelationshipNode + ) { + attributes = getNodeAttributes(node); + edges = node.getEdges(); + sourceTypes = []; + targetTypes = []; + relations = []; + shape = null; + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + source = edge.getSource(); + target = edge.getTarget(); + if ( + edge instanceof BiDirAssociationEdge && + ((target === node && (neighbor = source) instanceof ObjectNode) || + (target === node && + (neighbor = source) instanceof ViewObjectNode) || + (source === node && + (neighbor = target) instanceof ObjectNode) || + (source === node && + (neighbor = target) instanceof ViewObjectNode)) + ) { + concreteTypes = getConcreteObjectNodeTypes(neighbor); + sourceTypes = sourceTypes.concat(concreteTypes); + targetTypes = targetTypes.concat(concreteTypes); + } else if ( + edge instanceof UniDirAssociationEdge && + source === node && + (target instanceof ObjectNode || target instanceof ViewObjectNode) + ) { + targetTypes = targetTypes.concat( + getConcreteObjectNodeTypes(target) + ); + } else if ( + edge instanceof UniDirAssociationEdge && + target === node && + (source instanceof ObjectNode || source instanceof ViewObjectNode) + ) { + sourceTypes = sourceTypes.concat( + getConcreteObjectNodeTypes(source) + ); + } else if ( + edge instanceof BiDirAssociationEdge && + ((target === node && + (neighbor = source) instanceof AbstractClassNode) || + (source === node && + (neighbor = target) instanceof AbstractClassNode)) + ) { + concreteTypes = getConcreteObjectNodeTypes(neighbor); + sourceTypes = sourceTypes.concat(concreteTypes); + targetTypes = targetTypes.concat(concreteTypes); + } else if ( + edge instanceof UniDirAssociationEdge && + source === node && + target instanceof AbstractClassNode + ) { + targetTypes = targetTypes.concat( + getConcreteObjectNodeTypes(target) + ); + } else if ( + edge instanceof UniDirAssociationEdge && + target === node && + source instanceof AbstractClassNode + ) { + sourceTypes = sourceTypes.concat( + getConcreteObjectNodeTypes(source) + ); + } else if ( + (edge instanceof BiDirAssociationEdge && + ((target === node && + (neighbor = source) instanceof EdgeShapeNode) || + (source === node && + (neighbor = target) instanceof EdgeShapeNode))) || + (edge instanceof UniDirAssociationEdge && + source === node && + (neighbor = target) instanceof EdgeShapeNode) + ) { + shape = { + arrow: neighbor + .getAttribute(neighbor.getEntityId() + "[arrow]") + .getValue() + .getValue(), + shape: neighbor + .getAttribute(neighbor.getEntityId() + "[shape]") + .getValue() + .getValue(), + color: neighbor + .getAttribute(neighbor.getEntityId() + "[color]") + .getValue() + .getValue(), + overlay: neighbor + .getAttribute(neighbor.getEntityId() + "[overlay]") + .getValue() + .getValue(), + overlayPosition: neighbor + .getAttribute(neighbor.getEntityId() + "[overlayPosition]") + .getValue() + .getValue(), + overlayRotate: neighbor + .getAttribute(neighbor.getEntityId() + "[overlayRotate]") + .getValue() + .getValue(), + }; + } else if ( + edge instanceof GeneralisationEdge && + target === node && + (neighbor = source) instanceof RelationshipGroupNode + ) { + groupEdges = neighbor.getEdges(); + groupSourceTypes = []; + groupTargetTypes = []; + for (groupEdgeId in groupEdges) { + if (groupEdges.hasOwnProperty(groupEdgeId)) { + groupEdge = groupEdges[groupEdgeId]; + groupSource = groupEdge.getSource(); + groupTarget = groupEdge.getTarget(); + if ( + groupEdge instanceof BiDirAssociationEdge && + ((groupTarget === neighbor && + (groupNeighbor = groupSource) instanceof ObjectNode) || + (groupSource === neighbor && + (groupNeighbor = groupTarget) instanceof ObjectNode) || + (groupTarget === neighbor && + (groupNeighbor = groupSource) instanceof + ViewObjectNode) || + (groupSource === neighbor && + (groupNeighbor = groupTarget) instanceof + ViewObjectNode)) + ) { + groupConcreteTypes = + getConcreteObjectNodeTypes(groupNeighbor); + groupSourceTypes = + groupSourceTypes.concat(groupConcreteTypes); + groupTargetTypes = + groupTargetTypes.concat(groupConcreteTypes); + } else if ( + groupEdge instanceof UniDirAssociationEdge && + groupSource === neighbor && + (groupTarget instanceof ObjectNode || + groupTarget instanceof ViewObjectNode) + ) { + groupTargetTypes = groupTargetTypes.concat( + getConcreteObjectNodeTypes(groupTarget) + ); + } else if ( + groupEdge instanceof UniDirAssociationEdge && + groupTarget === neighbor && + (groupSource instanceof ObjectNode || + groupSource instanceof ViewObjectNode) + ) { + groupSourceTypes = groupSourceTypes.concat( + getConcreteObjectNodeTypes(groupSource) + ); + } else if ( + groupEdge instanceof BiDirAssociationEdge && + ((groupTarget === neighbor && + (groupNeighbor = groupSource) instanceof + AbstractClassNode) || + (groupSource === neighbor && + (groupNeighbor = groupTarget) instanceof + AbstractClassNode)) + ) { + groupConcreteTypes = + getConcreteObjectNodeTypes(groupNeighbor); + groupSourceTypes = + groupSourceTypes.concat(groupConcreteTypes); + groupTargetTypes = + groupTargetTypes.concat(groupConcreteTypes); + } else if ( + groupEdge instanceof UniDirAssociationEdge && + groupSource === neighbor && + groupTarget instanceof AbstractClassNode + ) { + groupTargetTypes = groupTargetTypes.concat( + getConcreteObjectNodeTypes(groupTarget) + ); + } else if ( + groupEdge instanceof UniDirAssociationEdge && + groupTarget === neighbor && + groupSource instanceof AbstractClassNode + ) { + groupSourceTypes = groupSourceTypes.concat( + getConcreteObjectNodeTypes(groupSource) + ); + } + } + } + + if (groupSourceTypes.length > 0 && groupTargetTypes.length > 0) { + relations.push({ + sourceTypes: groupSourceTypes, + targetTypes: groupTargetTypes, + }); + } + } + } + } + + if (sourceTypes.length > 0 && targetTypes.length > 0) { + relations.push({ + sourceTypes: sourceTypes, + targetTypes: targetTypes, + }); + } + + metamodel.edges[nodeId] = { + label: node.getLabel().getValue().getValue(), + shape: shape || { + arrow: "bidirassociation", + shape: "straight", + color: "black", + overlay: "", + overlayPosition: "top", + overlayRotate: true, + }, + relations: relations, + attributes: attributes, + }; + if (node instanceof ViewRelationshipNode) { + viewtypeAttrs = getViewTypeAttributes(node); + Util.merge(metamodel.edges[nodeId], viewtypeAttrs); + } + } + } + } + metamodel["id"] = viewpointModel.id; + EntityManagerInstance.reset(); + return metamodel; +} + +function JSONtoGraph (json, canvas) { + if (!canvas) return new Error("No canvas object defined!"); + + //cleanUpYSpace('nodes'); + //cleanUpYSpace('edges'); + + $.Deferred(); + var numberOfNodes = lodash.keys(json.nodes).length; + var numberOfEdges = lodash.keys(json.edges).length; + var createdNodes = 0; + var createdEdges = 0; + var report = { + widget: "CANVAS", + createdYText: 0, + modelAttributes: { attributes: {} }, + nodes: {}, + edges: {}, + }; + + if (!lodash.isEmpty(json.attributes)) { + var modelAttributesNode = EntityManagerInstance.createModelAttributesNodeFromJSON( + json.attributes + ); + modelAttributesNode.registerYMap(); + canvas.setModelAttributesNode(modelAttributesNode); + modelAttributesNode.addToCanvas(canvas); + } + + function createNode(nodeId, jsonNode) { + const nodesMap = y.getMap("nodes"); + var map = nodesMap.get(nodeId); + + var node = null; + if (map) { + node = EntityManagerInstance.createNodeFromJSON( + jsonNode.type, + nodeId, + map.get("left") ? map.get("left") : jsonNode.left, + map.get("top") ? map.get("top") : jsonNode.top, + map.get("width") ? map.get("width") : jsonNode.width, + map.get("height") ? map.get("height") : jsonNode.height, + map.get("zIndex") ? map.get("zIndex") : jsonNode.zIndex, + map.get("containment") ? map.get("containment") : jsonNode.containment, + jsonNode + ); + } else { + node = EntityManagerInstance.createNodeFromJSON( + jsonNode.type, + nodeId, + jsonNode.left, + jsonNode.top, + jsonNode.width, + jsonNode.height, + jsonNode.zIndex, + jsonNode.containment, + jsonNode + ); + } + + if (node === undefined) { + console.error( + "SYNCMETA: Node undefined. Check if " + + jsonNode.type + + " type is defined in the VLS" + ); + var $errorMsg = $("#errorMsg"); + $("#loading").hide(); + $("#canvas-frame").hide(); + $errorMsg.parent().css("display", "inline-table"); + $errorMsg.text( + "SYNCMETA: Model is not compatible to the current Metamodel! Delete the current model or change the metamodel." + ); + return; + } + + node.registerYMap(); + node.addToCanvas(canvas); + node.bindMoveToolEvents(); + node.draw(); + } + + function createNodes(nodes) { + for (var nodeId in nodes) { + if (nodes.hasOwnProperty(nodeId)) { + createNode(nodeId, nodes[nodeId]); + createdNodes++; + } + } + } + + function createEdges(edges) { + for (const edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + //create edge + var edge = EntityManagerInstance.createEdgeFromJSON( + edges[edgeId].type, + edgeId, + edges[edgeId].source, + edges[edgeId].target, + edges[edgeId] + ); + + if (edge === undefined) { + console.error( + "SYNCMETA: Edge undefined. Check if " + + edges[edgeId].type + + " type is defined in the VLS" + ); + var $errorMsg = $("#errorMsg"); + $errorMsg.parent().show(); + $("#canvas-frame").hide(); + $("#loading").hide(); + $errorMsg.parent().css("display", "inline-table"); + $errorMsg.text( + "SYNCMETA: Model is not compatible to the current Metamodel! Delete the current model or change the metamodel." + ); + continue; + } + + //register it to Yjs and draw it to the canvas + edge.registerYMap(); + edge.addToCanvas(canvas); + edge.connect(); + edge.bindMoveToolEvents(); + createdEdges++; + } + } + } + + if (numberOfNodes > 0) { + createNodes(json.nodes); + if (createdNodes === numberOfNodes) { + if (numberOfEdges > 0) { + createEdges(json.edges); + if (createdEdges === numberOfEdges) { + canvas.resetTool(); + report.createdNodes = createdNodes; + report.createdEdges = createdEdges; + } + } else { + report.createdNodes = createdNodes; + report.createdEdges = 0; + } + } + } + return report; +} + +/** + * NodeShapeNodeTool + * @class canvas_widget.ClassNodeTool + * @extends canvas_widget.NodeTool + * @memberof canvas_widget + * @constructor + */ +class NodeShapeNodeTool extends NodeTool { + constructor() { + super( + NodeShapeNode.TYPE, + null, + null, + null, + NodeShapeNode.DEFAULT_WIDTH, + NodeShapeNode.DEFAULT_HEIGHT + ); + } +} + +/** + * ObjectNodeTool + * @class canvas_widget.ObjectNodeTool + * @memberof canvas_widget + * @constructor + */ +class ObjectNodeTool extends NodeTool { + constructor() { + super( + ObjectNode.TYPE, + null, + null, + null, + ObjectNode.DEFAULT_WIDTH, + ObjectNode.DEFAULT_HEIGHT + ); + } +} + +/** + * RelationshipGroupNodeTool + * @class canvas_widget.ClassNodeTool + * @extends canvas_widget.NodeTool + * @memberof canvas_widget + * @constructor + */ +class RelationshipGroupNodeTool extends NodeTool { + constructor() { + super( + RelationshipGroupNode.TYPE, + null, + null, + null, + RelationshipGroupNode.DEFAULT_WIDTH, + RelationshipGroupNode.DEFAULT_HEIGHT + ); + } +} + +/** + * RelationshipNodeTool + * @class canvas_widget.RelationshipNodeTool + * @extends canvas_widget.NodeTool + * @memberof canvas_widget + * @constructor + */ +class RelationshipNodeTool extends NodeTool { + constructor() { + super( + RelationshipNode.TYPE, + null, + null, + null, + RelationshipNode.DEFAULT_WIDTH, + RelationshipNode.DEFAULT_HEIGHT + ); + } +} + +/** + * BiDirAssociationEdgeTool + * @class canvas_widget.UniDirAssociationEdgeTool + * @extends canvas_widget.EdgeTool + * @memberof canvas_widget + * @constructor + */ +class UniDirAssociationEdgeTool extends EdgeTool { + constructor() { + super(UniDirAssociationEdge.TYPE, UniDirAssociationEdge.RELATIONS); + } +} + +/** + * Generates the Views + * @constructor + */ +function ViewGenerator() {} + +/** + * Applies a node type to a node + * @param {object} nodeType the node type object. Be found in the EntityManager via getNodeType(typeName) + * @param {canvas_widget.Node} node the node + */ +function applyNodeTypeToNode(nodeType, node) { + if (checkConditions(nodeType, node)) { + node.set$shape(nodeType.get$shape()); + node.setAnchorOptions(nodeType.getAnchors()); + node.setCurrentViewType(nodeType.TYPE); + node.show(); + } else { + node.setCurrentViewType(null); + node.hide(); + } +} + +/** + * check the condition for node + * @param type + * @param entity + * @returns {boolean} + */ +function checkConditions(type, entity) { + if (type.name === "Edge" || type.name === "Node") { + return true; + } + + var cond, + conj = type.getConditionConj(), + conditions = type.getConditions(); + + for (var cKey in conditions) { + if (conditions.hasOwnProperty(cKey)) { + cond = conditions[cKey]; + var attr = entity.getAttribute(cond.property); + if (attr) { + var res = resolveCondition( + attr.getValue().getValue(), + cond.operator, + cond.value + ); + if (conj === "AND" && !res) { + return false; + } else if (conj === "OR" && res) { + return true; + } + } + } + } + if (conj === "AND") { + return true; + } else if (conj === "OR") { + return false; + } +} + +/** + * resolves a condition + * @param attrValue the attribute value from the instance of a view type + * @param {string} operator the operator defined in the view type definition + * @param {string} value the value defined in the view type definition + * @returns {boolean} true if the condition is true else false + */ +function resolveCondition(attrValue, operator, value) { + var val = null; + try { + if (typeof val === "boolean") val = value; + else val = parseInt(value); + if (isNaN(val)) val = value; + } catch (e) { + val = value; + } + switch (operator) { + case "greater": + return attrValue > val; + case "smaller": + return attrValue < val; + case "equal": + return attrValue === val; + case "greater_eq": + return attrValue >= val; + case "smaller_eq": + return attrValue <= val; + case "nequal": + return attrValue != val; + } +} + +/** + * Applies a node type to a set of nodes + * @param {object} nodeType the node type object. Be found in the EntityManager via getNodeType(typeName) + * @param {object} nodes nodes as key value store + */ +function applyNodeTypeToNodes(nodeType, nodes) { + for (var nodeKey in nodes) { + if (nodes.hasOwnProperty(nodeKey)) { + applyNodeTypeToNode(nodeType, nodes[nodeKey]); + } + } +} + +/** + * Applies a edge type to a edge + * @param {object} edgeType the edge type object can be found in the EntityManager via getEdgeType(typeName) + * @param {canvas_widget.Edge} edge the edge to transform + */ +function applyEdgeTypeToEdge(edgeType, edge) { + if (checkConditions(edgeType, edge)) { + edge.restyle( + edgeType.getArrowType(), + edgeType.getColor(), + edgeType.getShapeType(), + null, + edgeType.getOverlay(), + edgeType.getOverlayPosition(), + edgeType.getOverlayRotate(), + edgeType.getAttributes() + ); + edge.setCurrentViewType(edgeType.TYPE); + } else { + edge.hide(); + } +} + +/** + * Applies a edge type to a set of nodes + * @param {object} edgeType the edge type object can be found in the EntityManager via getEdgeType(typeName) + * @param {object} edges the edges as key value store + */ +function applyEdgeTypeToEdges(edgeType, edges) { + for (var edgeKey in edges) { + if (edges.hasOwnProperty(edgeKey)) { + applyEdgeTypeToEdge(edgeType, edges[edgeKey]); + } + } +} + +/** + * Transforms a the nodes and edges of a model using a particular VLS to another VLS + * Currently only works if the vls is the meta-model (the initial VLS) but this should work in all directions as well as with vvs to vvs + * @param vls the current VLS + * @param vvs the target VLS the model should be transformed to + */ +ViewGenerator.generate = function (vls, vvs) { + var _processed = {}; + + //transform the view types + var viewpointNodes = vvs.nodes; + for (var vpNodeKey in viewpointNodes) { + if (viewpointNodes.hasOwnProperty(vpNodeKey)) { + var nodeViewType = viewpointNodes[vpNodeKey]; + if (nodeViewType.hasOwnProperty("target")) { + _processed[nodeViewType.target] = true; + var viewNodeTypeObject = EntityManagerInstance.getViewNodeType( + nodeViewType.label + ); + applyNodeTypeToNodes( + viewNodeTypeObject, + EntityManagerInstance.getNodesByType( + viewNodeTypeObject.getTargetNodeType().TYPE + ) + ); + } + } + } + + //Hide the other types + var nodeTypes = vls.nodes; + for (var nodeTypeKey in nodeTypes) { + if ( + nodeTypes.hasOwnProperty(nodeTypeKey) && + !_processed.hasOwnProperty(nodeTypeKey) + ) { + var nodes = EntityManagerInstance.getNodesByType(nodeTypes[nodeTypeKey].label); + for (var nodeKey in nodes) { + if (nodes.hasOwnProperty(nodeKey)) { + nodes[nodeKey].hide(); + } + } + } + } + + //transform edges + var viewpointEdges = vvs.edges; + for (var vpEdgeKey in viewpointEdges) { + if (viewpointEdges.hasOwnProperty(vpEdgeKey)) { + var edgeViewType = viewpointEdges[vpEdgeKey]; + if (edgeViewType.hasOwnProperty("target")) { + _processed[edgeViewType.target] = true; + var viewEdgeTypeObject = EntityManagerInstance.getViewEdgeType( + edgeViewType.label + ); + applyEdgeTypeToEdges( + viewEdgeTypeObject, + EntityManagerInstance.getEdgesByType( + viewEdgeTypeObject.getTargetEdgeType().TYPE + ) + ); + } + } + } + + //Hide the other types + var edgeTypes = vls.edges; + for (var edgeTypeKey in edgeTypes) { + if ( + edgeTypes.hasOwnProperty(edgeTypeKey) && + !_processed.hasOwnProperty(edgeTypeKey) + ) { + var edges = EntityManagerInstance.getEdgesByType(edgeTypes[edgeTypeKey].label); + for (var edgeKey in edges) { + if (edges.hasOwnProperty(edgeKey)) { + edges[edgeKey].hide(); + } + } + } + } + + //Repaint all jsPlumb connections + window.jsPlumbInstance.repaintEverything(); + _.each(EntityManagerInstance.getEdges(), function (e) { + e.setZIndex(); + }); +}; + +/** + * resets the view generator + * @param vls + */ +ViewGenerator.reset = function (vls) { + var typeName; + var nodes = vls.nodes; + for (var nodeKey in nodes) { + if (nodes.hasOwnProperty(nodeKey)) { + typeName = nodes[nodeKey].label; + applyNodeTypeToNodes( + EntityManagerInstance.getNodeType(typeName), + EntityManagerInstance.getNodesByType(typeName) + ); + } + } + + var edges = vls.edges; + for (var edgeKey in edges) { + if (edges.hasOwnProperty(edgeKey)) { + typeName = edges[edgeKey].label; + applyEdgeTypeToEdges( + EntityManagerInstance.getEdgeType(typeName), + EntityManagerInstance.getEdgesByType(typeName) + ); + } + } + + //Repaint all jsPlumb connections + window.jsPlumbInstance.repaintEverything(); + _.each(EntityManagerInstance.getEdges(), function (e) { + e.setZIndex(); + }); +}; + +const optionHtml = ""; // replaced by importmap.plugin.js + +/** + * the view manager manges a arbitrary number of views + * @returns {{GetViewpointList: Function, existsView: Function, getViewIdOfSelected: Function, getViewUri: Function, getViewpointUri: Function, getSelected$node: Function, getResource: Function, addView: Function, deleteView: Function, initViewList: Function}} + * @constructor + */ +let ViewManager$1 = class ViewManager { + constructor() { + let currentView = null; + /** + * represent a reference to the view selection html element + * @type {jQuery} + * @private + */ + var _$selection = $("#ddmViewSelection"); + + /** + * html option element template + * @type {function} + */ + var optionTpl = lodash.template(optionHtml); + + return { + setCurrentView: function (viewId) { + currentView = viewId; + }, + + getCurrentView: function () { + return currentView; + }, + /** + * initialize the viewpoint selection list of the generic editor instance + */ + GetViewpointList: function () { + y = window.y; + const viewsMap = y.getMap("views"); + _$selection.empty(); + var viewpointList = viewsMap.keys(); + for (var i = 0; i < viewpointList.length; i++) { + var viewpoint = viewsMap.get(viewpointList[i]); + if (viewpoint) { + _$selection.append( + $( + optionTpl({ + id: viewpointList[i], + }) + ) + ); + } else viewsMap.delete(viewpointList[i]); + } + }, + /** + * checks if a view exists + * @param viewId the viewId of the vie + * @returns {boolean} true if the view already exits false if not + */ + existsView: function (viewId) { + const viewsMap = y.getMap("views"); + return viewsMap.has(viewId); + }, + /** + * returns the view identifier of currently selected html selection element + * @returns {string} the identifier of the view + */ + getViewIdOfSelected: function () { + return this.getSelected$node().attr("id"); + }, + /** + * returns the currently selected option node of the html selection element + * @returns {object} jquery object + */ + getSelected$node: function () { + return _$selection.find("option:selected"); + }, + /** + * adds a view to the ViewManager + * @param {string} viewId the view identifier + */ + addView: function (viewId) { + const viewsMap = y.getMap("views"); + if (viewsMap.has(viewId)) { + viewsMap.set(viewId, { + viewId: viewId, + attributes: {}, + nodes: {}, + edges: {}, + }); + return true; + } else return false; + }, + /** + * deletes a view from the view manager + * @param {string} viewId the identifier of the view + */ + deleteView: function (viewId) { + const viewsMap = y.getMap("views"); + viewsMap.delete(viewId); + _$selection.find("#" + viewId).remove(); + }, + /** + * Update a view representation in the ROLE Space + * @param {string} viewId The view identifier + * @param {string} viewId The Identifier of the view + * @param {object} resource openapp.oo.resource of the the view + * @returns {object} jquery promise + */ + updateViewContent: function (viewId) { + const viewsMap = y.getMap("views"); + var data = this.viewToJSON(viewId); + viewsMap.set(viewId, data); + }, + /** + * generates the json representation of a view + * @param viewId the unique name of the view + * @returns {Object} + */ + viewToJSON: function (viewId) { + var vls = EntityManagerInstance.graphToJSON(); + vls["id"] = viewId; + return vls; + }, + }; + } +}; +var ViewManager$2 = new ViewManager$1(); + +/** + * ViewObjectNodeTool + * @class canvas_widget.ViewObjectNodeTool + * @memberof canvas_widget + * @constructor + */ +class ViewObjectNodeTool extends NodeTool { + constructor() { + super( + ViewObjectNode.TYPE, + null, + null, + null, + ViewObjectNode.DEFAULT_WIDTH, + ViewObjectNode.DEFAULT_HEIGHT + ); + } +} + +/** + * ViewRelationshipNodeTool + * @class canvas_widget.ViewRelationshipNodeTool + * @extends canvas_widget.NodeTool + * @memberof canvas_widget + * @constructor + */ +class ViewRelationshipNodeTool extends NodeTool { + constructor() { + super( + ViewRelationshipNode.TYPE, + null, + null, + null, + ViewRelationshipNode.DEFAULT_WIDTH, + ViewRelationshipNode.DEFAULT_HEIGHT + ); + } +} + +function getGuidanceModeling() { + var guidancemodeling = {}; + + var activityName = $(".activityEntry.activitySel", parent.document) + .find(".activity-title") + .text(); + + // console.info( + // "Guidance promise by " + undefined + " Activity:" + activityName + // ); + guidancemodeling.INITIAL_NODE_LABEL = "Initial node"; + guidancemodeling.MERGE_NODE_LABEL = "Decision node"; + guidancemodeling.CALL_ACTIVITY_NODE_LABEL = "Call activity node"; + guidancemodeling.ACTIVITY_FINAL_NODE_LABEL = "Activity final node"; + guidancemodeling.CONCURRENCY_NODE_LABEL = "Fork node"; + + guidancemodeling.isGuidanceEditor = function () { + return activityName == "Guidance modeling"; + }; + + guidancemodeling.getCreateObjectNodeLabelForType = function (type) { + return "Create " + type + " object"; + }; + + guidancemodeling.isCreateObjectNodeLabel = function (label) { + var match = /Create (.*?) object/.exec(label); + if (match) return match[1]; + else return ""; + }; + + guidancemodeling.getCreateRelationshipNodeLabelForType = function (type) { + return "Create " + type + " relationship"; + }; + + guidancemodeling.isCreateRelationshipNodeLabel = function (label) { + var match = /Create (.*?) relationship/.exec(label); + if (match) return match[1]; + else return ""; + }; + + guidancemodeling.getSetPropertyNodeLabelForType = function (type) { + return "Set property for " + type; + }; + + guidancemodeling.isSetPropertyNodeLabel = function (label) { + var match = /Set property for (.*)/.exec(label); + if (match) return match[1]; + else return ""; + }; + + guidancemodeling.getEntityNodeLabelForType = function (type) { + return type + " entity"; + }; + + guidancemodeling.isEntityNodeLabel = function (label) { + var match = /(.*?) entity/.exec(label); + if (match) return match[1]; + else return ""; + }; + + guidancemodeling.getObjectContextLabelForType = function (type) { + return type + " Object Context"; + }; + + guidancemodeling.getObjectTypeForObjectContextType = function (type) { + var i = type.lastIndexOf(" Object Context"); + return type.substring(0, i); + }; + + guidancemodeling.isObjectContextType = function (type) { + return ( + type.indexOf( + " Object Context", + type.length - " Object Context".length + ) !== -1 + ); + }; + + guidancemodeling.getRelationshipContextLabelForType = function (type) { + return type + " Relationship Context"; + }; + + guidancemodeling.getRelationshipTypeForRelationshipContextType = function ( + type + ) { + var i = type.lastIndexOf(" Relationship Context"); + return type.substring(0, i); + }; + + guidancemodeling.isRelationshipContextType = function (type) { + return ( + type.indexOf( + " Relationship Context", + type.length - " Relationship Context".length + ) !== -1 + ); + }; + + guidancemodeling.getObjectToolLabelForType = function (type) { + return type + " Tool"; + }; + + guidancemodeling.getObjectTypeForObjectToolType = function (type) { + var i = type.lastIndexOf(" Tool"); + return type.substring(0, i); + }; + + guidancemodeling.isObjectToolType = function (type) { + return type.indexOf(" Tool", type.length - " Tool".length) !== -1; + }; + + return guidancemodeling; } -class GhostEdge { - constructor(canvas, edgeFunction, source, target) { - var _jsPlumbConnection = null; - var _label = edgeFunction.getType(); - - source.addGhostEdge(this); - target.addGhostEdge(this); - - this.getLabel = function () { - return _label; - }; - - this.connect = function (button) { - if (_jsPlumbConnection) return; - var overlays = edgeFunction.getArrowOverlays(); - overlays.push([ - "Custom", - { - create: function (component) { - return $("
                  ").append(button); - }, - location: 0.5, - id: "customOverlay", - cssClass: "ghost-edge-overlay", - }, - ]); - var connectOptions = { - source: source.get$node(), - target: target.get$node(), - paintStyle: { - stroke: edgeFunction.getColor(), - strokeWidth: 4, - dashstyle: "", - }, - endpoint: "Dot", - anchors: [source.getAnchorOptions(), target.getAnchorOptions()], - connector: edgeFunction.getShape(), - overlays: overlays, - cssClass: "ghost-edge", - }; - - if (source === target) { - connectOptions.anchors = ["TopCenter", "LeftMiddle"]; - } - - _jsPlumbConnection = window.JsPlumbInstance.connect(connectOptions); - lodash.each(EntityManagerInstance.getEdges(), function (e) { - e.setZIndex(); - }); - }; - - this.remove = function () { - if (_jsPlumbConnection) - window.JsPlumbInstance.destroyConnector(_jsPlumbConnection); - _jsPlumbConnection = null; - }; - - this.getEdgeFunction = function () { - return edgeFunction; - }; - - this.getSource = function () { - return source; - }; - - this.getTarget = function () { - return target; - }; - } -} - -const ghostEdgeHtml = "\r\n\r\n
                  \r\n \r\n \r\n
                    \r\n
                  \r\n
                  "; // replaced by importmap.plugin.js -// import "bootstrap"; -function GhostEdgeGuidance(canvas, node1, node2) { - var _button = $(ghostEdgeHtml); - var _dropdown = _button.find(".bs-dropdown-toggle"); - _dropdown.detach(); - var _dropdownList = _button.find(".edge-list"); - _dropdownList.detach(); - var _canvas = canvas; - var that = this; - var _edges = []; - var _node1 = node1; - var _node2 = node2; - var _currentEdge = null; - - _node1.addGhostEdge(this); - _node2.addGhostEdge(this); - - _button.hover( - function () { - $(this).css({ opacity: 1 }); - }, - function () { - $(this).css({ opacity: 0.4 }); - } - ); - this.show = function () { - _currentEdge.connect(_button); - }; - - this.addEdge = function (edgeFunction, source, target) { - var edge = new GhostEdge(_canvas, edgeFunction, source, target); - _edges.push(edge); - var listItem = $("
                • "); - listItem.click(function () { - that.remove(); - that.setCurrentEdge(edge); - that.show(); - }); - listItem.find("a").text(edge.getLabel()); - _dropdownList.append(listItem); - - if (_edges.length == 1) { - this.setCurrentEdge(edge); - } - if (_edges.length == 2) { - _button.append(_dropdown); - _button.append(_dropdownList); - } - }; - - this.remove = function () { - _button.detach(); - if (_currentEdge) _currentEdge.remove(); - }; - - this.getNode1 = function () { - return _node1; - }; - - this.getNode2 = function () { - return _node2; - }; - - this.setCurrentEdge = function (edge) { - if (_currentEdge) _currentEdge.remove(); - _currentEdge = edge; - _button.find(".label").text(_currentEdge.getLabel()); - - var createEdgeButton = _button.find(".create-edge-button"); - createEdgeButton.off("click"); - createEdgeButton.click(function (event) { - event.stopPropagation(); - that.remove(); - //if(EntityManager.getViewId() !== null && EntityManager.getLayer() === CONFIG.LAYER.MODEL){ - // _canvas.createEdge(_currentEdge.getEdgeFunction().VIEWTYPE, _currentEdge.getSource().getEntityId(), _currentEdge.getTarget().getEntityId()); - //} - //else { - _canvas.createEdge( - _currentEdge.getEdgeFunction().getType(), - _currentEdge.getSource().getEntityId(), - _currentEdge.getTarget().getEntityId() - ); - //} - //guidanceFollowed does not exists, seems to be unnecessary and obsolete - //_canvas.guidanceFollowed(); - }); - }; -} - -const abstractNodeHtml = "
                  \" class=\"node\">\r\n
                  "; // replaced by importmap.plugin.js -const guidanceBoxNodeHtml = "
                  \r\n
                  \r\n \t\t
                  \r\n\t\t
                  \r\n
                  \r\n
                  \r\n \t

                  Guidance

                  \r\n
                  \r\n
                  "; // replaced by importmap.plugin.js -function GuidanceBox(id, label, left, top) { - var _$node = $(lodash.template(abstractNodeHtml)({ id: id })).append( - guidanceBoxNodeHtml - ); - - _$node.find(".guidance-box").hover( - function () { - $(this).css({ opacity: 1 }); - }, - function () { - $(this).css({ opacity: 0.5 }); - } - ); - - var _appearance = { - left: left, - top: top, - }; - - this.get$node = function () { - return _$node; - }; - - this.addGuidance = function (guidance) { - - _$node.find(".buttons").append(guidance.get$node()); - }; - - this.draw = function () { - var width = _$node.width(); - _$node.css({ - left: _appearance.left - width / 2, - top: _appearance.top, - zIndex: 30000, - }); - }; - - this.addToCanvas = function (canvas) { - canvas.get$canvas().append(_$node); - }; - - this.remove = function () { - _$node.remove(); - }; -} - -const selectToolGuidanceHtml = ""; // replaced by importmap.plugin.js -function SelectToolGuidance(id, label, tool, canvas, icon) { - //var _id = id; - //var _label = label; - //var _tool = tool; - var _canvas = canvas; - var _$node = $( - lodash.template(selectToolGuidanceHtml)({ - text: label, - icon: icon || "plus-circle", - }) - ); - - _$node.click(function () { - if ( - EntityManagerInstance.getViewId() !== undefined && - EntityManagerInstance.getLayer() === CONFIG.LAYER.MODEL - ) { - if (EntityManagerInstance.getNodeType(tool) !== null) { - _canvas.mountTool(EntityManagerInstance.getNodeType(tool).VIEWTYPE); - } else { - _canvas.mountTool(tool); - } - } else _canvas.mountTool(tool); - - _canvas.hideGuidanceBox(); - //guidanceFollowed does not exists, seems to be unnecessary and obsolete - // _canvas.guidanceFollowed(); - }); - - this.get$node = function () { - return _$node; - }; -} - -const setPropertyGuidanceHtml = "
                  \r\n\r\n
                    \r\n\t
                  • \r\n
                  \r\n
                  "; // replaced by importmap.plugin.js -// import "bootstrap"; -function SetPropertyGuidance(id, label, entity, propertyName, canvas) { - var _entityId = entity.getEntityId(); - var _canvas = canvas; - var _entityAttribute = null; - var _$node = $( - lodash.template(setPropertyGuidanceHtml)({ text: label, icon: "edit" }) - ); - var _propertyInput; - - var entityAttributes = entity.getAttributes(); - - for (var attribId in entityAttributes) { - var attrib = entityAttributes[attribId]; - if ( - attrib.getEntityId() == - entity.getEntityId() + "[" + propertyName.toLowerCase() + "]" - ) - _entityAttribute = attrib; - } - - if (_entityAttribute instanceof SingleValueAttribute) { - _propertyInput = new SingleValueAttribute( - entity.getEntityId() + "[" + propertyName.toLowerCase() + "]", - propertyName, - entity - ); - // @ts-ignore - _propertyInput.getValue().setValue(_entityAttribute.getValue().getValue()); - // @ts-ignore - - if (_entityAttribute.getRootSubjectEntity().constructor.name === "Edge") { - const edgeMap = y.getMap("edges"); - var ymap = edgeMap.get(entity.getEntityId()); - var ytext = ymap.get( - entity.getEntityId() + "[" + propertyName.toLowerCase() + "]" - ); - ytext.bind(_propertyInput.getValue().get$node()[0]); - } else { - const nodesMap = y.getMap("nodes"); - var ymap = nodesMap.get(entity.getEntityId()); - var ytext = ymap.get( - entity.getEntityId() + "[" + propertyName.toLowerCase() + "]" - ); - ytext.bind(_propertyInput.getValue().get$node()[0]); - } - - /* _entityAttribute.get$node().find(".val").bind("input", function(){ - // @ts-ignore -_propertyInput.getValue().setValue(_entityAttribute.getValue().getValue()); -// @ts-ignore - }); - - _propertyInput.get$node().find(".val").bind("input", function(){ - _entityAttribute.getValue().setValue(_propertyInput.getValue().getValue()); - });*/ - - _$node - .find(".property-input") - .append(_propertyInput.get$node().find(".val").prop("disabled", false)); - } else if (_entityAttribute instanceof SingleSelectionAttribute) { - // @ts-ignore - var options = _entityAttribute.getOptions(); - _propertyInput = new SingleSelectionAttribute( - entity.getEntityId() + "[" + propertyName.toLowerCase() + "]", - propertyName, - entity, - options, - true - ); - // @ts-ignore - _propertyInput.getValue().setValue(_entityAttribute.getValue().getValue()); - // @ts-ignore - _propertyInput - .getValue() - .get$node() - .bind("change", function (ev) { - _entityAttribute - .getValue() - .setValue(_propertyInput.getValue().getValue()); - }); - - _$node.find(".property-input").append(_propertyInput.getValue().get$node()); - _$node.find(".property-input").click(function (ev) { - ev.stopPropagation(); - }); - } else if (_entityAttribute instanceof IntegerAttribute) { - _propertyInput = new IntegerAttribute( - entity.getEntityId() + "[" + propertyName.toLowerCase() + "]", - propertyName, - entity, - true - ); - // @ts-ignore - _propertyInput.getValue().setValue(_entityAttribute.getValue().getValue()); - // @ts-ignore - - _entityAttribute - // @ts-ignore - .get$node() - .find(".val") - .bind("change", function () { - _propertyInput - .getValue() - .setValue(_entityAttribute.getValue().getValue()); - }); - - _propertyInput - .get$node() - .find(".val") - .bind("change", function (ev) { - _entityAttribute - .getValue() - .setValue(_propertyInput.getValue().getValue()); - }); - - _$node - .find(".property-input") - .append(_propertyInput.get$node().find(".val").prop("disabled", false)); - _$node.find(".property-input").click(function (ev) { - ev.stopPropagation(); - }); - } else if (_entityAttribute instanceof BooleanAttribute) { - _propertyInput = new BooleanAttribute( - entity.getEntityId() + "[" + propertyName.toLowerCase() + "]", - propertyName, - entity, - true - ); - // @ts-ignore - _propertyInput.getValue().setValue(_entityAttribute.getValue().getValue()); - // @ts-ignore - - _entityAttribute - // @ts-ignore - .get$node() - .find(".val") - .bind("change", function () { - _propertyInput - .getValue() - .setValue(_entityAttribute.getValue().getValue()); - }); - - _propertyInput - .get$node() - .find(".val") - .bind("change", function (ev) { - _entityAttribute - .getValue() - .setValue(_propertyInput.getValue().getValue()); - }); - - _$node - .find(".property-input") - .append(_propertyInput.get$node().find(".val")); - _$node.find(".property-input").click(function (ev) { - ev.stopPropagation(); - }); - } else if (_entityAttribute instanceof FileAttribute) { - _propertyInput = new FileAttribute( - entity.getEntityId() + "[" + propertyName.toLowerCase() + "]", - propertyName, - entity, - true - ); - //@ts-ignore - _propertyInput.getValue().setValue(_entityAttribute.getValue().getValue()); - // @ts-ignore - - // _entityAttribute.get$node().find(".val").bind("change", function(){ - // // @ts-ignore - _propertyInput.getValue().setValue(_entityAttribute.getValue().getValue()); - // @ts-ignore - // }); - - // _propertyInput.get$node().find(".val").bind("change", function(ev){ - // _entityAttribute.getValue().setValue(_propertyInput.getValue().getValue()); - // }); - - _$node.find(".property-input").append(_propertyInput.getValue().get$node()); - _$node.find(".property-input").click(function (ev) { - ev.stopPropagation(); - }); - } - if (_propertyInput) - _propertyInput - .get$node() - .find(".val") - .keypress(function (ev) { - //The event is never triggered - if (ev.which == 13) { - _$node.find(".bs-dropdown-toggle").dropdown("toggle"); - } - }); - - //guidanceFollowed does not exists, seems to be unnecessary and obsolete - /*_$node.on('show.bs.dropdown', function () { - _canvas.guidanceFollowed(); - });*/ - - _$node.hover( - function () { - if (_entityId) _canvas.highlightEntity(_entityId); - }, - function () { - if (_entityId) _canvas.unhighlightEntity(_entityId); - } - ); - - this.get$node = function () { - return _$node; - }; -} - -/** - * MoveTool - * @class canvas_widget.MoveTool - * @extends canvas_widget.AbstractCanvasTool - * @memberof canvas_widget - * @constructor - */ -class MoveTool extends AbstractCanvasTool { - static TYPE = "MoveTool"; - mount - unmount - constructor() { - super(MoveTool.TYPE, "tool-move", "Move Nodes and Edges"); - - /** - * Mount the tool on canvas - */ - this.mount = function () { - - AbstractCanvasTool.prototype.mount.call(this); - //WTF??? - //Bind Node and Edge Events - /*var nodes = EntityManager.getNodes(); - var nodeId, node; - for(nodeId in nodes){ - if(nodes.hasOwnProperty(nodeId)){ - node = nodes[nodeId]; - node.bindMoveToolEvents(); - } - } - - var edges = EntityManager.getEdges(); - var edgeId, edge; - for(edgeId in edges){ - if(edges.hasOwnProperty(edgeId)){ - edge = edges[edgeId]; - edge.bindMoveToolEvents(); - } - }*/ - this.getCanvas().bindMoveToolEvents(); - }; - - /** - * Unmount the tool from canvas - */ - this.unmount = function () { - AbstractCanvasTool.prototype.unmount.call(this); - //WTF?? - /*var nodes = EntityManager.getNodes(); - var nodeId, node; - for(nodeId in nodes){ - if(nodes.hasOwnProperty(nodeId)){ - node = nodes[nodeId]; - node.unbindMoveToolEvents(); - } - } - - var edges = EntityManager.getEdges(); - var edgeId, edge; - for(edgeId in edges){ - if(edges.hasOwnProperty(edgeId)){ - edge = edges[edgeId]; - edge.unbindMoveToolEvents(); - } - }*/ - this.getCanvas().unbindMoveToolEvents(); - }; - } -} - -/** - * AbstractCanvas - * @class canvas_widget.AbstractCanvas - * @memberof canvas_widget - * @constructor - * @param {jQuery} $node jQuery selector of canvas node - */ -class AbstractCanvas { - constructor($node) { - var that = this; - - /** - * Tools added to canvas - * @type {Object} - * @private - */ - var _tools = {}; - - /** - * Name of tool currently mounted - * @type {string} - * @private - */ - var _currentToolName = null; - - /** - * jQuery object of DOM node representing the canvas - * @type {jQuery} - * @private - */ - var _$node = $node; - - /** - * Get jQuery object of DOM node representing the canvas - * @returns {jQuery} jQuery object of DOM node representing the canvas - */ - this.get$canvas = function () { - return _$node; - }; - - /** - * Add tool to canvas - * @param {string} name Name of tool - * @param {canvas_widget.AbstractCanvasTool} tool Canvas tool - */ - this.addTool = function (name, tool) { - if ( - !_tools.hasOwnProperty(name) && - typeof tool.mount === "function" && - typeof tool.unmount === "function" && - typeof tool.setCanvas === "function" - ) { - tool.setCanvas(this); - _tools[name] = tool; - } - }; - - //noinspection JSUnusedGlobalSymbols - /** - * Get tool added to canvas by its name - * @param {string} name Name of tool - * @returns {canvas_widget.AbstractCanvasTool} Canvas tool - */ - this.getTool = function (name) { - if (_tools.hasOwnProperty(name)) { - return _tools[name]; - } - return null; - }; - - /** - * Mount a canvas tool previously added to the canvas - * @param {string} name Name of tool - * @param defaultLabel - * @param defaultAttributeValues May be used to set default values for node attributes. - */ - this.mountTool = function (name, defaultLabel, defaultAttributeValues) { - if (_currentToolName && _tools[_currentToolName]) - _tools[_currentToolName].unmount(); - if (_tools.hasOwnProperty(name)) { - _tools[name].mount(defaultLabel, defaultAttributeValues); - } else { - if (name !== "MoveTool") { - throw new Error("Tool " + name + " not found"); - } - _tools["MoveTool"].mount(); - } - _currentToolName = name; - }; - - /** - * Unmount and mount currenty mounted tool again - */ - this.remountCurrentTool = function () { - that.mountTool(_currentToolName); - }; - - //noinspection JSUnusedGlobalSymbols - /** - * Get name of tool currently mounted - * @returns {string} - */ - this.getCurrentToolName = function () { - return _currentToolName; - }; - - this.removeTools = function () { - _tools = {}; - }; - } -} - -/** - * Canvas - * @class canvas_widget.Canvas - * @extends canvas_widget.AbstractCanvas - * @memberof canvas_widget - * @constructor - * @param {jQuery} $node jquery Selector of canvas node - */ -class Canvas extends AbstractCanvas { - constructor($node, y = window.y) { - super($node); - var that = this; - - /** - * jQuery object of DOM node representing the canvas - * @type {jQuery} - * @private - */ - var _$node = $node; - - /** - * Current zoom level - * @type {number} - * @private - */ - var _zoom = 1; - - /** - * Default canvas width - * @type {number} - * @private - */ - var _canvasWidth = 9000; - this.width = _canvasWidth; - - /** - * Default canvas height - * @type {number} - * @private - */ - var _canvasHeight = 9000; - this.height = _canvasHeight; - - /** - * Model attributes - * @type {canvas_widget.ModelAttributesNode} - * @private - */ - var _modelAttributesNode = null; - - /** - * Inter widget communication wrapper - * @type {Object} - */ - var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); - - /** - * Entity currently selected - * @type {canvas_widget.AbstractNode|canvas_widget/AbstractEdge} - * @private - */ - var _selectedEntity = null; - - /** - * Offset of the DOM node representating the canvas - * @type {{left: number, top: number, right: number, bottom: number}} - */ - var canvasOffset = _$node.offset(); - - var _guidanceBox = null; - var _guidanceBoxLabel = ""; - var _guidanceDefinition = null; - var _ghostEdges = []; - var _guidanceBoxEntityId = null; - - const jsPlumbInstance = newInstance({ - container: _$node.get(0), - elementsDraggable: true, - connectionsDetachable: false, - dragOptions: { - filter: ".resizing", - containment: "parentEnclosed", - }, - }); - - window.jsPlumbInstance = jsPlumbInstance; - - $(window).resize(function () { - sendViewChangeOperation(); - }); - - /** - * Apply a Tool Select Operation - * @param {operations.non_ot.ToolSelectOperation} operation - */ - var processToolSelectOperation = function (operation) { - that.mountTool( - operation.getSelectedToolName(), - operation.getDefaultLabel(), - operation.getDefaultAttributeValues() - ); - }; - - /** - * Apply a Node Add Operation - * @param {operations.ot.NodeAddOperation} operation - * @param {YMap} ymap - */ - var processNodeAddOperation = function (operation) { - var node; - if (operation.getJSON()) { - node = EntityManagerInstance.createNodeFromJSON( - operation.getType(), - operation.getEntityId(), - operation.getLeft(), - operation.getTop(), - operation.getWidth(), - operation.getHeight(), - operation.getZIndex(), - operation.getContainment(), - operation.getJSON() - ); - } else { - node = EntityManagerInstance.createNode( - operation.getType(), - operation.getEntityId(), - operation.getLeft(), - operation.getTop(), - operation.getWidth(), - operation.getHeight(), - operation.getZIndex(), - operation.getContainment() - ); - } - - if (operation.getDefaultLabel()) { - node.getLabel().getValue().setValue(operation.getDefaultLabel()); - } - - if (operation.getDefaultAttributeValues()) { - for (const [key, value] of Object.entries( - operation.getDefaultAttributeValues() - )) { - node.getAttribute(key).getValue().setValue(value); - } - } - const userMap = y.getMap("users"); - if (userMap.get(y.clientID) !== operation.getJabberId()) { - const userList = y.getMap("userList"); - var color = Util.getColor( - userList.get(operation.getJabberId()).globalId - ); - node.refreshTraceAwareness(color); - } - if (y) node.registerYMap(); - - node.draw(); - node.addToCanvas(that); - node.bindMoveToolEvents(); - that.remountCurrentTool(); - }; - - /** - * Propagate a Node Add Operation to the remote users and the local widgets - * @param {operations.ot.NodeAddOperation} operation - */ - var propagateNodeAddOperation = function (operation) { - processNodeAddOperation(operation); - //_iwcw.sendLocalOTOperation(CONFIG.WIDGET.NAME.ATTRIBUTE, operation.getOTOperation()); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.HEATMAP, - operation.getOTOperation() - ); - const activityMap = y.getMap("activity"); - activityMap.set( - ActivityOperation.TYPE, - new ActivityOperation( - "NodeAddActivity", - operation.getEntityId(), - _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], - NodeAddOperation.getOperationDescription(operation.getType()), - { - nodeType: operation.getType(), - } - ).toJSON() - ); - }; - - /** - * Apply an Edge Add Operation - * @param {operations.ot.EdgeAddOperation} operation - * @param {YMap} ymap - */ - var processEdgeAddOperation = function (operation) { - var edge; - - if (operation.getJSON()) { - edge = EntityManagerInstance.createEdgeFromJSON( - operation.getType(), - operation.getEntityId(), - operation.getSource(), - operation.getTarget(), - operation.getJSON() - ); - } else { - edge = EntityManagerInstance.createEdge( - operation.getType(), - operation.getEntityId(), - EntityManagerInstance.findNode(operation.getSource()), - EntityManagerInstance.findNode(operation.getTarget()) - ); - } - - if (window.hasOwnProperty("y")) edge.registerYMap(); - - edge.connect(); - edge.addToCanvas(that); - edge.bindMoveToolEvents(); - that.remountCurrentTool(); - }; - /** - * Propagate an Edge Add Operation to the remote users and the local widgets - * @param {operations.ot.EdgeAddOperation} operation - */ - var propagateEdgeAddOperation = function (operation) { - var sourceNode = EntityManagerInstance.findNode(operation.getSource()); - var targetNode = EntityManagerInstance.findNode(operation.getTarget()); - - processEdgeAddOperation(operation); - EntityManagerInstance.storeDataYjs(); - - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.getOTOperation() - ); - const activityMap = y.getMap("activity"); - activityMap.set( - ActivityOperation.TYPE, - new ActivityOperation( - "EdgeAddActivity", - operation.getEntityId(), - _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], - EdgeAddOperation.getOperationDescription( - operation.getType(), - "", - sourceNode.getLabel().getValue().getValue(), - sourceNode.getType(), - targetNode.getType(), - targetNode.getLabel().getValue().getValue() - ), - { - nodeType: operation.getType(), - sourceNodeId: operation.getSource(), - sourceNodeLabel: sourceNode.getLabel().getValue().getValue(), - sourceNodeType: sourceNode.getType(), - targetNodeId: operation.getTarget(), - targetNodeLabel: targetNode.getLabel().getValue().getValue(), - targetNodeType: targetNode.getType(), - } - ).toJSON() - ); - }; - - /** - * Callback for a remote Node Add Operation - * @param {operations.ot.NodeAddOperation} operation - */ - var remoteNodeAddCallback = function (operation) { - if (operation instanceof NodeAddOperation) { - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.HEATMAP, - operation.getOTOperation() - ); - if ( - operation.getViewId() === EntityManagerInstance.getViewId() && - EntityManagerInstance.getLayer() === CONFIG.LAYER.META - ) { - processNodeAddOperation(operation); - } else if (EntityManagerInstance.getLayer() === CONFIG.LAYER.MODEL) { - var type, node, viewType; - - if (!operation.getViewId()) { - type = operation.getType(); - } else { - type = operation.getOriginType(); - } - - if (EntityManagerInstance.getViewId()) { - viewType = EntityManagerInstance.getNodeType(type).VIEWTYPE; - if (viewType) { - type = viewType; - } - } - - //processNodeAddOperation - if (operation.getJSON()) { - node = EntityManagerInstance.createNodeFromJSON( - type, - operation.getEntityId(), - operation.getLeft(), - operation.getTop(), - operation.getWidth(), - operation.getHeight(), - operation.getZIndex(), - operation.getContainment(), - operation.getJSON() - ); - } else { - node = EntityManagerInstance.createNode( - type, - operation.getEntityId(), - operation.getLeft(), - operation.getTop(), - operation.getWidth(), - operation.getHeight(), - operation.getZIndex(), - operation.getContainment() - ); - } - - if (operation.getDefaultLabel()) { - node.getLabel().getValue().setValue(operation.getDefaultLabel()); - } - - if (operation.getDefaultAttributeValues()) { - for (const [key, value] of Object.entries( - operation.getDefaultAttributeValues() - )) { - node.getAttribute(key).getValue().setValue(value); - } - } - - node.registerYMap(); - node.draw(); - node.addToCanvas(that); - node.bindMoveToolEvents(); - - //if we are in a view but the view type got no mapping in this view -> hide the element - if (!viewType && EntityManagerInstance.getViewId()) { - node.hide(); - } else { - const userMap = y.getMap("users"); - if ( - userMap.get(y.clientID) !== operation.getJabberId() && - operation.getJabberId() != null - ) { - const userList = y.getMap("userList"); - var color = Util.getColor( - userList.get(operation.getJabberId()).globalId - ); - node.refreshTraceAwareness(color); - } - } - that.remountCurrentTool(); - } - } - }; - - var sendViewChangeOperation = function () { - var canvasFrame = $("#canvas-frame"); - var operation = new CanvasViewChangeOperation( - _$node.position().left, - _$node.position().top, - canvasFrame.width(), - canvasFrame.height(), - _zoom - ); - _iwcw.sendLocalNonOTOperation( - CONFIG.WIDGET.NAME.HEATMAP, - operation.toNonOTOperation() - ); - }; - - /** - * Callback for a remote Edge Add Operation - * @param {operations.ot.EdgeAddOperation} operation - */ - var remoteEdgeAddCallback = function (operation) { - if (operation instanceof EdgeAddOperation) { - EntityManagerInstance.findNode(operation.getSource()); - EntityManagerInstance.findNode(operation.getTarget()); - - if ( - operation.getViewId() === EntityManagerInstance.getViewId() || - EntityManagerInstance.getLayer() === CONFIG.LAYER.META - ) { - processEdgeAddOperation(operation); - } else if (EntityManagerInstance.getLayer() === CONFIG.LAYER.MODEL) { - var type, edge, viewType; - - if (!operation.getViewId()) { - type = operation.getType(); - } else { - type = operation.getOriginType(); - } - - if (EntityManagerInstance.getViewId()) { - viewType = EntityManagerInstance.getEdgeType(type).VIEWTYPE; - if (viewType) { - type = viewType; - } - } - - if (operation.getJSON()) { - edge = EntityManagerInstance.createEdgeFromJSON( - type, - operation.getEntityId(), - operation.getSource(), - operation.getTarget(), - operation.getJSON() - ); - } else { - edge = EntityManagerInstance.createEdge( - type, - operation.getEntityId(), - EntityManagerInstance.findNode(operation.getSource()), - EntityManagerInstance.findNode(operation.getTarget()) - ); - } - - edge.registerYMap(); - edge.connect(); - edge.addToCanvas(that); - - //if we are in a view but the view type got no mapping in this view -> hide the element - if (!viewType && EntityManagerInstance.getViewId()) { - edge.hide(); - } - - that.remountCurrentTool(); - } - } - }; - - /** - * Callback for a local Tool Select Operation - * @param {operations.non_ot.ToolSelectOperation.non_ot.ToolSelectOperation} operation - */ - var localToolSelectCallback = function (operation) { - if (operation instanceof ToolSelectOperation) { - processToolSelectOperation(operation); - } - }; - - var localShowGuidanceBoxCallback = function (operation) { - if (operation instanceof ShowGuidanceBoxOperation) { - processShowGuidanceBoxOperation(operation); - } - }; - - var processShowGuidanceBoxOperation = function (operation) { - _guidanceDefinition = operation.getGuidance(); - _guidanceBoxLabel = operation.getLabel(); - that.showGuidanceBox(operation.getEntityId()); - }; - - /** - * Callback for a local Export Data Operation - * @param {operations.non_ot.ExportMetaModelOperation} operation - */ - var localExportMetaModelCallback = function (operation) { - if (operation instanceof ExportMetaModelOperation) { - if (operation.getData() === null) { - operation.setData(EntityManagerInstance.generateMetaModel()); - _iwcw.sendLocalNonOTOperation( - operation.getRequestingComponent(), - operation.toNonOTOperation() - ); - } else { - var data = operation.getData(); - var op = new ActivityOperation( - "EditorGenerateActivity", - "-1", - _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], - '..generated new Editor ' + - data.spaceTitle + - "", - {} - ); - const activityMap = y.getMap("activity"); - activityMap.set("EditorGenerateActivity", op.toJSON()); - } - } - }; - - var localMoveCanvasOperation = function (operation) { - if (operation instanceof MoveCanvasOperation) { - that.scrollEntityIntoView(operation.getObjectId()); - } - }; - - var localExportLogicalGuidanceRepresentationCallback = function ( - operation - ) { - if (operation instanceof ExportLogicalGuidanceRepresentationOperation) { - if (operation.getData() === null) { - operation.setData( - EntityManagerInstance.generateLogicalGuidanceRepresentation() - ); - _iwcw.sendLocalNonOTOperation( - operation.getRequestingComponent(), - operation.toNonOTOperation() - ); - } - } - }; - - var localGuidanceStrategyOperationCallback = function (operation) { - const canvasMap = y.getMap("canvas"); - if (operation instanceof GuidanceStrategyOperation) { - //Just forward the message to remote users - canvasMap.set(GuidanceStrategyOperation.TYPE, operation.toJSON()); - } - }; - - var localRevokeSharedActivityOperationCallback = function (operation) { - if (operation instanceof RevokeSharedActivityOperation) { - const canvasMap = y.getMap("canvas"); - //Just forward the message to remote users - canvasMap.set(RevokeSharedActivityOperation.TYPE, operation.toJSON()); - } - }; - - var remoteGuidanceStrategyOperation = function (operation) { - if (operation instanceof GuidanceStrategyOperation) { - //Just forward the message to the local guidance widget - _iwcw.sendLocalNonOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.toNonOTOperation() - ); - } - }; - - var remoteRevokeSharedActivityOperationCallback = function (operation) { - if (operation instanceof RevokeSharedActivityOperation) { - //Just forward the message to the local guidance widget - _iwcw.sendLocalNonOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.toNonOTOperation() - ); - } - }; - - /** - * Callback for a local Export Data Operation - * @param {operations.non_ot.ExportImageOperation} operation - */ - var localExportImageCallback = function (operation) { - if (operation instanceof ExportImageOperation) { - that.toPNG().then(function (url) { - operation.setData(url); - _iwcw.sendLocalNonOTOperation( - operation.getRequestingComponent(), - operation.toNonOTOperation() - ); - }); - } - }; - - /** - * Callback for an undone resp. redone Node Add Operation - * @param {operations.ot.NodeAddOperation} operation - */ - var init = function () { - var $canvasFrame = _$node.parent(); - - that.addTool(MoveTool.TYPE, new MoveTool()); - - _$node.css({ - width: _canvasWidth, - height: _canvasHeight, - left: (-_canvasWidth + $canvasFrame.width()) / 2, - top: (-_canvasHeight + $canvasFrame.height()) / 2, - }); - - _$node.draggable({ - stop: function () { - sendViewChangeOperation(); - }, - }); - - if (_$node.transformable != null) { - // since recently, this method doesnt exist anymore. BUGFIX - _$node.transformable({ - rotatable: false, - skewable: false, - scalable: false, - }); - } - _$node.mousewheel(function (event) { - that.setZoom(that.getZoom() + 0.1 * event.deltaY); - event.preventDefault(); - }); - }; - - /** - * Get jQuery object of DOM node representing the canvas - * @returns {jQuery} - */ - this.get$node = function () { - return _$node; - }; - - this.showGuidanceBox = function (entityId) { - this.hideGuidanceBox(); - var entity; - if (typeof entityId == "undefined") { - entityId = _guidanceBoxEntityId; - } else { - _guidanceBoxEntityId = entityId; - } - if (_guidanceDefinition === null) return; - if (_guidanceDefinition.length == 0) return; - if (!entityId) entityId = _selectedEntity.getEntityId(); - - entity = EntityManagerInstance.findNode(entityId); - if (!entity) return; - var entityAppearance = entity.getAppearance(); - var appearance = { - top: entityAppearance.top, - left: entityAppearance.left, - width: entityAppearance.width, - height: entityAppearance.height, - }; - appearance.top += entityAppearance.height + 10; - appearance.left += entityAppearance.width / 2; - _guidanceBox = new GuidanceBox( - Util.generateRandomId(), - _guidanceBoxLabel, - appearance.left, - appearance.top - ); - var inView = false; - if ( - EntityManagerInstance.getViewId() != null && - EntityManagerInstance.getLayer() === CONFIG.LAYER.MODEL - ) { - inView = true; - } - for (var i = 0; i < _guidanceDefinition.length; i++) { - var guidanceItem = null; - switch (_guidanceDefinition[i].type) { - case "SELECT_TOOL_GUIDANCE": - var tool; - if ( - inView && - EntityManagerInstance.getNodeType(_guidanceDefinition[i].tool) - .VIEWTYPE === null - ) - continue; - else if (inView) - tool = EntityManagerInstance.getNodeType( - _guidanceDefinition[i].tool - ).VIEWTYPE; - else tool = _guidanceDefinition[i].tool; - - guidanceItem = new SelectToolGuidance( - _guidanceDefinition[i].id, - _guidanceDefinition[i].label, - tool, - that, - _guidanceDefinition[i].icon - ); - break; - case "SET_PROPERTY_GUIDANCE": - var entity = EntityManagerInstance.findNode( - _guidanceDefinition[i].entityId - ); - if (!entity) - entity = EntityManagerInstance.findEdge(_guidanceDefinition[i].entityId); - guidanceItem = new SetPropertyGuidance( - _guidanceDefinition[i].id, - _guidanceDefinition[i].label, - entity, - _guidanceDefinition[i].propertyName, - that - ); - break; - case "COLLABORATION_GUIDANCE": - guidanceItem = new CollaborationGuidance( - "", - _guidanceDefinition[i].label, - _guidanceDefinition[i].activityId, - _guidanceDefinition[i].objectId, - that - ); - break; - case "GHOST_EDGE_GUIDANCE": - var relationshipType; - if ( - inView && - EntityManagerInstance.getEdgeType(_guidanceDefinition[i].relationshipType) - .VIEWTYPE === undefined - ) - continue; - else if (inView) { - relationshipType = EntityManagerInstance.getEdgeType( - _guidanceDefinition[i].relationshipType - ).VIEWTYPE; - } else { - relationshipType = _guidanceDefinition[i].relationshipType; - } - that.showGhostEdge( - _guidanceDefinition[i].sourceId, - _guidanceDefinition[i].targetId, - relationshipType - ); - break; - } - if (guidanceItem) _guidanceBox.addGuidance(guidanceItem); - } - - _guidanceBox.addToCanvas(that); - _guidanceBox.draw(); - }; - - this.hideGuidanceBox = function () { - if (_guidanceBox !== null) _guidanceBox.remove(); - _guidanceBox = null; - for (var i = 0; i < _ghostEdges.length; i++) { - _ghostEdges[i].remove(); - } - _ghostEdges = []; - }; - - /** - * Set model attributes - * @param {canvas_widget.ModelAttributesNode} node - */ - this.setModelAttributesNode = function (node) { - _modelAttributesNode = node; - }; - - /** - * Get model attributes - * @returns {canvas_widget.ModelAttributesNode} - */ - this.getModelAttributesNode = function () { - return _modelAttributesNode; - }; - - /** - * Bind events for move tool - */ - this.bindMoveToolEvents = function () { - //Enable Canvas Dragging - _$node.draggable("enable"); - - // view_only is used by the CAE and allows to show a model in the Canvas which is not editable - // therefore, the context menu in the Canvas must be disabled - const widgetConfigMap = y.getMap("widgetConfig"); - var viewOnly = widgetConfigMap.get("view_only"); - - //Define Node Rightclick Menu - if (viewOnly) { - // view only mode is activated, no context menu should be shown - $.contextMenu({ - selector: "#" + _$node.attr("id"), - build: function ($trigger, e) { - return false; - }, - }); - return; - } - // otherwise show normal context menu - $.contextMenu({ - selector: "#" + _$node.attr("id"), - zIndex: AbstractEntity.CONTEXT_MENU_Z_INDEX, - build: function ($trigger, e) { - if (_selectedEntity === null) { - return { - items: { - addNode: { - name: "Add node..", - items: EntityManagerInstance.generateAddNodeMenu( - that, - e.originalEvent.offsetX, - e.originalEvent.offsetY - ), - }, - hide: { - name: "Hide entities..", - items: { - nodes: { - name: "nodes..", - items: EntityManagerInstance.generateVisibilityNodeMenu("hide"), - }, - edges: { - name: "edges..", - items: EntityManagerInstance.generateVisibilityEdgeMenu("hide"), - }, - }, - }, - show: { - name: "Show entities..", - items: { - nodes: { - name: "nodes..", - items: EntityManagerInstance.generateVisibilityNodeMenu("show"), - }, - edges: { - name: "edges..", - items: EntityManagerInstance.generateVisibilityEdgeMenu("show"), - }, - }, - }, - }, - }; - } else { - that.select(null); - return false; - } - }, - }); - }; - - /** - * Bind events for move tool - */ - this.unbindMoveToolEvents = function () { - //Disable Canvas Dragging - _$node.draggable("disable"); - - if (_$node.transformable != null) { - _$node.transformable("destroy"); - } - - //Unbind Node and Edge Events - //this.select(null); - //Disable Canvas Rightclick Menu - _$node.unbind("contextmenu"); - }; - - /** - * Select an entity - * @param {canvas_widget.AbstractNode|canvas_widget.AbstractEdge} entity - */ - this.select = function (entity) { - if (_selectedEntity != entity) { - if (_selectedEntity) _selectedEntity.unselect(); - if (entity) entity.select(); - } - - var operation = new EntitySelectOperation( - entity ? entity.getEntityId() : null, - entity ? entity.getType() : null, - _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID] - ); - - _iwcw.sendLocalNonOTOperation( - CONFIG.WIDGET.NAME.ATTRIBUTE, - operation.toNonOTOperation() - ); - _iwcw.sendLocalNonOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.toNonOTOperation() - ); - _iwcw.sendLocalNonOTOperation( - CONFIG.WIDGET.NAME.METADATA, - operation.toNonOTOperation() - ); - _iwcw.sendLocalNonOTOperation( - CONFIG.WIDGET.NAME.OPENAPI, - operation.toNonOTOperation() - ); - const selectionMap = y.getMap("select"); - const userMap = y.getMap("users"); - if (entity === null) { - selectionMap.set(userMap.get(y.clientID), null); - } else { - selectionMap.set(userMap.get(y.clientID), entity.getEntityId()); - } - _selectedEntity = entity; - }; - - /** - * Get entity currently selected - * @return {canvas_widget.AbstractNode|canvas_widget/AbstractEdge} - */ - this.getSelectedEntity = function () { - return _selectedEntity; - }; - - /** - * Set zoom level (between 0.5 and 2, default is 1) - * @param {number} zoom - */ - this.setZoom = function (zoom) { - if (zoom < 0.1 || zoom > 2) { - return; - } - _zoom = zoom; - - _$node.css("transform", `scaleX(${zoom}) scaleY(${zoom})`); - _$node.animate({ - transform: `scaleX(${zoom}) scaleY(${zoom})`, - }); - - window.jsPlumbInstance.setZoom(zoom); - sendViewChangeOperation(); - }; - - this.showGhostEdge = function (sourceId, targetId, relationshipType) { - var source = EntityManagerInstance.findNode(sourceId); - var target = EntityManagerInstance.findNode(targetId); - if (!source || !target) { - //console.error('GhostEdge guidance not possible. Bad params: src' + source + ' target: ' + target + ' type: ' + relationshipType); - return; - } - var ghostEdgeGuidance = null; - //Check if there already is a ghost edge between the two nodes - for (var i = 0; i < _ghostEdges.length; i++) { - var ghostEdge = _ghostEdges[i]; - var node1 = ghostEdge.getNode1(); - var node2 = ghostEdge.getNode2(); - if ( - (source == node1 && target == node2) || - (source == node2 && target == node1) - ) { - ghostEdgeGuidance = ghostEdge; - break; - } - } - if (!ghostEdgeGuidance) { - ghostEdgeGuidance = new GhostEdgeGuidance(that, source, target); - _ghostEdges.push(ghostEdgeGuidance); - } - if ( - EntityManagerInstance.getViewId() && - EntityManagerInstance.getLayer() === CONFIG.LAYER.MODEL - ) { - ghostEdgeGuidance.addEdge( - EntityManagerInstance.getViewEdgeType(relationshipType), - source, - target - ); - } else { - ghostEdgeGuidance.addEdge( - EntityManagerInstance.getEdgeType(relationshipType), - source, - target - ); - } - for (var j = 0; j < _ghostEdges.length; j++) { - _ghostEdges[j].show(); - } - }; - - this.highlightEntity = function (entityId) { - var entity = EntityManagerInstance.findNode(entityId); - - if (entity) entity.highlight("blue", "Set property"); - else { - entity = EntityManagerInstance.findEdge(entityId); - entity.highlight("blue"); - } - }; - - this.unhighlightEntity = function (entityId) { - var entity = EntityManagerInstance.findNode(entityId); - - if (!entity) entity = EntityManagerInstance.findEdge(entityId); - - entity.unhighlight(); - }; - - /** - * Get zoom level - * @returns {number} - */ - this.getZoom = function () { - return _zoom; - }; - - /** - * Reset the currently mounted tool back to the Move Tool - */ - this.resetTool = function () { - var operation = new ToolSelectOperation(MoveTool.TYPE); - - _iwcw.sendLocalNonOTOperation( - CONFIG.WIDGET.NAME.PALETTE, - operation.toNonOTOperation() - ); - this.mountTool(MoveTool.TYPE); - //this.callListeners(CONFIG.CANVAS.LISTENERS.RESET); - }; - - /** - * Create a new node and draw it on the canvas - * @param {string} type Type of node - * @param {Number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {number} [zIndex] Position of node on z-axis - * @param {boolean} containment containment - * @param {object} [json] representation of node - * @param {string} identifier the identifier of the node, if null a new id is generated - * @param defaultAttributeValues May be used to set default values for node attributes. - * @return {number} id of new node - */ - this.createNode = function ( - type, - left, - top, - width, - height, - zIndex, - containment, - json, - identifier, - historyFlag, - defaultLabel, - defaultAttributeValues - ) { - var id, - oType = null; - if (identifier) id = identifier; - else id = Util.generateRandomId(24); - zIndex = zIndex || AbstractEntity.maxZIndex + 1; - - if ( - EntityManagerInstance.getViewId() !== undefined && - EntityManagerInstance.getLayer() === CONFIG.LAYER.MODEL - ) { - oType = EntityManagerInstance.getViewNodeType(type).getTargetNodeType().TYPE; - } - - var operation = new NodeAddOperation( - id, - type, - left, - top, - width, - height, - zIndex, - containment, - json || null, - EntityManagerInstance.getViewId(), - oType, - _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], - defaultLabel, - defaultAttributeValues - ); - try { - propagateNodeAddOperation(operation); - } catch (error) { - console.error(error); - } - if (y) { - const canvasMap = y.getMap("canvas"); - canvasMap.set(NodeAddOperation.TYPE, operation.toJSON()); - } - if (!historyFlag) HistoryManagerInstance.add(operation); - return id; - }; - - /** - * Create a new edge and draw it on the canvas - * @param {string} type Type of edge - * @param {canvas_widget.AbstractNode} source Source node entity id - * @param {canvas_widget.AbstractNode} target Target node entity id - * @param {object} [json] representation of edge - * @param {string} identifier the identifier of the edge - * @return {number} id of new edge - */ - this.createEdge = function ( - type, - source, - target, - json, - identifier, - historyFlag - ) { - var id = null, - oType = null; - - if (identifier) id = identifier; - else id = Util.generateRandomId(24); - if ( - EntityManagerInstance.getViewId() !== undefined && - EntityManagerInstance.getLayer() === CONFIG.LAYER.MODEL - ) { - oType = EntityManagerInstance.getViewEdgeType(type).getTargetEdgeType().TYPE; - } - var operation = new EdgeAddOperation( - id, - type, - source, - target, - json || null, - EntityManagerInstance.getViewId(), - oType, - _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID] - ); - propagateEdgeAddOperation(operation); - - if (window.hasOwnProperty("y")) { - const canvasMap = y.getMap("canvas"); - canvasMap.set(EdgeAddOperation.TYPE, operation.toJSON()); - } - - if (!historyFlag) HistoryManagerInstance.add(operation); - return id; - }; - - this.scrollNodeIntoView = function (node) { - if (!node) return; - - var frameOffset = $("#canvas-frame").offset(); - var frameWidth = $("#canvas-frame").width(); - var frameHeight = $("#canvas-frame").height(); - - var nodeOffset = node.get$node().offset(); - var nodeWidth = node.get$node().width(); - var nodeHeight = node.get$node().height(); - - var scrollX = nodeOffset.left - frameOffset.left; - var scrollY = nodeOffset.top - frameOffset.top; - _$node.position().top; - _$node.position().left; - - _$node.animate( - { - top: "+=" + (frameHeight / 2 - scrollY - nodeHeight / 2), - left: "+=" + (frameWidth / 2 - scrollX - nodeWidth / 2), - }, - 1000 - ); - }; - - this.scrollEdgeIntoView = function (edge) { - if (!edge) return; - var frameOffset = $("#canvas-frame").offset(); - var frameWidth = $("#canvas-frame").width(); - var frameHeight = $("#canvas-frame").height(); - - var srcNode = edge.getSource(); - var targetNode = edge.getTarget(); - - var srcNodeOffset = srcNode.get$node().offset(); - var srcNodeWidth = srcNode.get$node().width(); - var srcNodeHeight = srcNode.get$node().height(); - - var targetNodeOffset = targetNode.get$node().offset(); - var targetNodeWidth = targetNode.get$node().width(); - var targetNodeHeight = targetNode.get$node().height(); - - var scrollX = - (srcNodeOffset.left + targetNodeOffset.left) / 2 - frameOffset.left; - var scrollY = - (srcNodeOffset.top + targetNodeOffset.top) / 2 - frameOffset.top; - _$node.position().top; - _$node.position().left; - - _$node.animate( - { - top: - "+=" + - (frameHeight / 2 - - scrollY - - Math.max(srcNodeHeight, targetNodeHeight) / 2), - left: - "+=" + - (frameWidth / 2 - - scrollX - - Math.max(srcNodeWidth, targetNodeWidth) / 2), - }, - 1000 - ); - }; - - this.scrollEntityIntoView = function (entityId) { - if (!entityId) return null; - if (entityId.indexOf("[") != -1 && entityId.indexOf("]") != -1) - entityId = entityId.replace(/\[\w*\]/g, ""); - var entity = EntityManagerInstance.findNode(entityId); - if (!entity) { - entity = EntityManagerInstance.findEdge(entityId); - if (!entity) return null; - else that.scrollEdgeIntoView(entity); - } else that.scrollNodeIntoView(entity); - return true; - }; - - /** - * Convert current canvas content to PNG image file - * @return {string} Data-URI of generated PNG image - */ - this.toPNG = function () { - var $renderedCanvas = $("") - .insertAfter(_$node) - .attr("width", _$node.width()) - .attr("height", _$node.height()), - ctx = $renderedCanvas[0].getContext("2d"), - deferred = $.Deferred(), - promises = [], - oldZoom = this.getZoom(); - - $("#loading").show(); - - this.setZoom(1); - - canvasOffset = _$node.offset(); - - ctx.beginPath(); - ctx.rect(0, 0, _canvasWidth, _canvasHeight); - ctx.fillStyle = _$node.css("backgroundColor"); - ctx.fill(); - - _.each( - _.sortBy($.makeArray(_$node.children()), function (e) { - return $(e).css("zIndex"); - }), - function (e) { - var $this = $(e); - if ( - typeof $this.attr("id") === "undefined" || - (!$this.attr("id").startsWith("modelAttributes") && - !$this.attr("id").endsWith("awareness")) - ) { - promises.push(convertNodeTreeToCanvas($this, ctx)); - } - } - ); - - $.when.apply($, promises).then(function () { - var tempCanvas = document.createElement("canvas"), - tCtx = tempCanvas.getContext("2d"), - minLeft = _canvasWidth, - minTop = _canvasHeight, - maxRight = 0, - maxBottom = 0, - nodes = EntityManagerInstance.getNodes(), - nodeId, - appearance, - width, - height, - padding = 20, - nodeExists = false; - - for (nodeId in nodes) { - if (nodes.hasOwnProperty(nodeId)) { - nodeExists = true; - appearance = nodes[nodeId].getAppearance(); - //noinspection JSAccessibilityCheck - minLeft = Math.min(minLeft, appearance.left); - minTop = Math.min(minTop, appearance.top); - //noinspection JSAccessibilityCheck - maxRight = Math.max(maxRight, appearance.left + appearance.width); - maxBottom = Math.max(maxBottom, appearance.top + appearance.height); - } - } - - if (!nodeExists) { - minLeft = _canvasWidth / 2; - minTop = _canvasHeight / 2; - maxRight = _canvasWidth / 2; - maxBottom = _canvasHeight / 2; - } - - minLeft -= padding; - minTop -= padding; - maxRight += padding; - maxBottom += padding; - - width = maxRight - minLeft; - height = maxBottom - minTop; - - tempCanvas.width = width; - tempCanvas.height = height; - - tCtx.drawImage( - $renderedCanvas[0], - minLeft, - minTop, - width, - height, - 0, - 0, - width, - height - ); - - that.setZoom(oldZoom); - $("#loading").hide(); - deferred.resolve(tempCanvas.toDataURL()); - }); - - return deferred.promise(); - }; - - /** - * Draw DOM node onto canvas - * @param $node jquery object of node - * @param ctx Canvas context - * @returns {promise} - */ - var convertNodeTreeToCanvas = function ($node, ctx) { - function drawSVGOnCanvas(ctx, svgMarkup, x, y) { - var svg = new Blob([svgMarkup], { - type: "image/svg+xml;charset=utf-8", - }), - DOMURL = self.URL || self.webkitURL || self, - url = DOMURL.createObjectURL(svg), - img = new Image(), - deferred = $.Deferred(); - - img.onload = function () { - ctx.drawImage(img, x, y); - DOMURL.revokeObjectURL(url); - deferred.resolve(); - }; - img.src = url; - setTimeout(function () { - deferred.resolve(); - }, 500); - return deferred.promise(); - } - - function convertNodeToSVG($node) { - if ($node[0].nodeType === Node.TEXT_NODE) { - if ($.trim($node.text()) === "") { - return $.Deferred().resolve().promise(); - } else { - $node = $node.wrap($("")).parent(); - } - } - - if (!$node.is(":visible")) { - return $.Deferred().resolve().promise(); - } - - var height = $node.height(), - width = $node.width(), - padding = { - left: parseInt($node.css("paddingLeft"), 10), - top: parseInt($node.css("paddingTop"), 10), - right: parseInt($node.css("paddingRight"), 10), - bottom: parseInt($node.css("paddingBottom"), 10), - }, - border = { - width: parseInt($node.css("borderWidth")), - color: $node.css("borderColor"), - left: { - width: parseInt($node.css("borderLeftWidth")), - color: $node.css("borderLeftColor"), - }, - top: { - width: parseInt($node.css("borderTopWidth")), - color: $node.css("borderTopColor"), - }, - right: { - width: parseInt($node.css("borderRightWidth")), - color: $node.css("borderRightColor"), - }, - bottom: { - width: parseInt($node.css("borderBottomWidth")), - color: $node.css("borderBottomColor"), - }, - }, - borderMarkup = [], - backgroundColor = $node.css("backgroundColor"), - color = $node.css("color"), - font = $node.css("font"), - fontSize = parseInt($node.css("fontSize"), 10), - textDecoration = $node.css("textDecoration").split(" ")[0], - offset = $node.offset(), - value, - textX, - textY = height, - textAnchor, - contents = $node.contents(); - - if ($node[0].nodeName.toLowerCase() === "svg") { - $node.attr("width", width); - $node.attr("height", height); - - return drawSVGOnCanvas( - ctx, - $node[0].outerHTML - .replace(/style="[^"]*"/, "") - .replace( - /http:\/\/www\.w3\.org\/1999\/xhtml/g, - "http://www.w3.org/2000/svg" - ), - offset.left - canvasOffset.left, - offset.top - canvasOffset.top - ); - } - - if (contents.length === 1 && contents[0].nodeType === Node.TEXT_NODE) { - value = $node.text(); - } else { - value = $node.val(); - } - - var tagsToReplace = { - "&": "&", - "<": "<", - ">": ">", - }; - - value = $.trim(value).replace(/[&<>]/g, function (tag) { - return tagsToReplace[tag] || tag; - }); - - switch ($node.css("textAlign")) { - case "right": - textX = width; - textAnchor = "right"; - break; - case "center": - textX = width / 2; - textAnchor = "middle"; - break; - default: - case "left": - textX = 0; - textAnchor = "left"; - break; - } - - textX += padding.left; - textY += - padding.top + border.width - Math.ceil((height - fontSize) / 2) - 1; - height += padding.top + padding.bottom + 2 * border.width; - width += padding.left + padding.right + 2 * border.width; - - if ( - border.color.split(" ").length !== 1 || - border.width.split(" ").length !== 1 - ) { - border.width = 0; - if (border.left.width > 0) { - borderMarkup.push( - '' - ); - } - if (border.top.width > 0) { - borderMarkup.push( - '' - ); - } - if (border.right.width > 0) { - borderMarkup.push( - '' - ); - } - if (border.bottom.width > 0) { - borderMarkup.push( - '' - ); - } - } - - return drawSVGOnCanvas( - ctx, - '' + - '' + - borderMarkup.join("\n") + - '' + - value + - "" + - "", - offset.left - canvasOffset.left, - offset.top - canvasOffset.top - ); - } - - var contents = $node.contents(); - - return convertNodeToSVG($node).then(function () { - var promises = []; - if (contents.length !== 1 || contents[0].nodeType !== Node.TEXT_NODE) { - contents.each(function () { - var $this = $(this); - if ($node[0].nodeName.toLowerCase() !== "svg") { - promises.push(convertNodeTreeToCanvas($this, ctx)); - } - }); - } - return $.when.apply($, promises).then(function () { - return true; - }); - }); - }; - - /** - * Register inter widget communication callbacks - */ - this.registerCallbacks = function () { - _iwcw.registerOnDataReceivedCallback(localToolSelectCallback); - _iwcw.registerOnDataReceivedCallback(localExportMetaModelCallback); - _iwcw.registerOnDataReceivedCallback( - localExportLogicalGuidanceRepresentationCallback - ); - _iwcw.registerOnDataReceivedCallback(localExportImageCallback); - _iwcw.registerOnDataReceivedCallback(localShowGuidanceBoxCallback); - _iwcw.registerOnDataReceivedCallback( - localRevokeSharedActivityOperationCallback - ); - _iwcw.registerOnDataReceivedCallback(localMoveCanvasOperation); - _iwcw.registerOnDataReceivedCallback( - localGuidanceStrategyOperationCallback - ); - }; - - /** - * Unregister inter widget communication callbacks - */ - this.unregisterCallbacks = function () { - _iwcw.unregisterOnDataReceivedCallback(localToolSelectCallback); - _iwcw.unregisterOnDataReceivedCallback(localExportMetaModelCallback); - _iwcw.unregisterOnDataReceivedCallback( - localExportLogicalGuidanceRepresentationCallback - ); - _iwcw.unregisterOnDataReceivedCallback(localExportImageCallback); - _iwcw.unregisterOnDataReceivedCallback(localShowGuidanceBoxCallback); - _iwcw.unregisterOnLocalDataReceivedCallback( - localRevokeSharedActivityOperationCallback - ); - _iwcw.unregisterOnLocalDataReceivedCallback(localMoveCanvasOperation); - _iwcw.unregisterOnLocalDataReceivedCallback( - localGuidanceStrategyOperationCallback - ); - }; - - init(); - - if (window.hasOwnProperty("y")) { - const canvasMap = y.getMap("canvas"); - canvasMap.observe(function (event) { - var yUserId = event.currentTarget.doc.clientID; - - event.keysChanged.forEach(function (key) { - const data = event.currentTarget.get(key); - const eventTriggeredLocally = window.y.clientID === data.triggeredBy; - if (!eventTriggeredLocally || data.historyFlagSet) { - const userMap = y.getMap("users"); - var jabberId = userMap.get(yUserId); - var operation; - - switch (key) { - case NodeAddOperation.TYPE: { - operation = new NodeAddOperation( - data.id, - data.type, - data.left, - data.top, - data.width, - data.height, - data.zIndex, - data.containment, - data.json, - data.viewId, - data.oType, - jabberId || data.jabberId, - data.defaultLabel, - data.defaultAttributeValues - ); - remoteNodeAddCallback(operation); - break; - } - case EdgeAddOperation.TYPE: { - operation = new EdgeAddOperation( - data.id, - data.type, - data.source, - data.target, - data.json, - data.viewId, - data.oType, - jabberId || data.jabberId - ); - remoteEdgeAddCallback(operation); - break; - } - case RevokeSharedActivityOperation.TYPE: { - operation = new RevokeSharedActivityOperation(data.id); - remoteRevokeSharedActivityOperationCallback(operation); - break; - } - case GuidanceStrategyOperation.TYPE: { - operation = new GuidanceStrategyOperation(data.data); - remoteGuidanceStrategyOperation(operation); - break; - } - case "ViewApplyActivity": { - var activityOperation = new ActivityOperation( - "ViewApplyActivity", - event.value.viewId, - event.value.jabberId - ); - const activityMap = y.getMap("activity"); - - activityMap.set( - ActivityOperation.TYPE, - activityOperation.toJSON() - ); - break; - } - case "triggerSave": { - if (data.value === _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]) - EntityManagerInstance.storeDataYjs(); - - break; - } - case "applyLayout": { - //remote user - DagreLayout$1.apply(); - jsPlumbInstance.repaintEverything(); - break; - } - //used by the syncmeta-plugin only - case "highlight": { - var userId = _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]; - if (!event.value.remote && userId !== event.value.userId) - return; - - // when an entity (or multiple entities) get highlighted, then - // one of them can be selected where the canvas should move to - if (event.value.moveCanvasToEntity) { - var entityId = event.value.moveCanvasToEntity; - var entity = EntityManagerInstance.find(entityId); - - // move canvas to entity - that.scrollEntityIntoView(entityId); - - // select the entity (note: this needs to be done before the highlighting, - // because otherwise the "select" overwrites the highlighting) - that.select(entity); - } - - // highlight entity/entities - for (var i = 0; i < event.value.entities.length; i++) { - var entityId = event.value.entities[i]; - var entity = EntityManagerInstance.find(entityId); - if (entity) { - entity.highlight(event.value.color, event.value.label); - } - } - - break; - } - //used by the syncmeta-plugin only - case "unhighlight": { - var userId = _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]; - if (!event.value.remote && userId !== event.value.userId) - return; - for (var i = 0; i < event.value.entities.length; i++) { - var entityId = event.value.entities[i]; - var entity = EntityManagerInstance.find(entityId); - if (entity) { - entity.unhighlight(); - } - } - break; - } - //used by the syncmeta-plugin only - case NodeDeleteOperation.TYPE: { - var userId = _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]; - const nodesMap = y.getMap("nodes"); - if (event.value.jabberId === userId) - nodesMap.delete(event.value.entityId); - setTimeout(function () { - EntityManagerInstance.storeDataYjs(); - }, 300); - break; - } - //used by the syncmeta-plugin only - case EdgeDeleteOperation.TYPE: { - break; - } - } - //local user. todo ugly coding style - } else if (key === "applyLayout") { - DagreLayout$1.apply(); - EntityManagerInstance.storeDataYjs(); - } - }); - }); - const selectionMap = y.getMap("select"); - selectionMap.observe(function (event) { - const array = Array.from(event.changes.keys.entries()); - array.forEach(([key, change]) => { - const userMap = y.getMap("users"); - if (key !== userMap.get(y.clientID)) { - const userList = y.getMap("userList"); - var userInfo = userList.get(key); - if (event.oldValue != null) { - var unselectedEntity = EntityManagerInstance.find(event.oldValue); - if (unselectedEntity) unselectedEntity.unhighlight(); - } - - if (event.value != null) { - var selectedEntity = EntityManagerInstance.find(event.value); - if (selectedEntity) - selectedEntity.highlight( - Util.getColor(userInfo.globalId), - userInfo[CONFIG.NS.PERSON.TITLE] - ); - } - } - }); - }); - const nodesMap = y.getMap("nodes"); - nodesMap.observe(function (event) { - const array = Array.from(event.changes.keys.entries()); - array.forEach(([key, change]) => { - switch (change.action) { - case "delete": { - var node = EntityManagerInstance.findNode(key); - if (node) - node.remoteNodeDeleteCallback(new NodeDeleteOperation(key)); - break; - } - } - }); - }); - const edgeMap = y.getMap("edges"); - edgeMap.observe(function (event) { - const array = Array.from(event.changes.keys.entries()); - array.forEach(([key, change]) => { - switch (change.action) { - case "delete": { - var edge = EntityManagerInstance.findEdge(key); - if (edge) - edge.remoteEdgeDeleteCallback(new EdgeDeleteOperation(key)); - break; - } - } - }); - }); - } - if (_iwcw) { - that.registerCallbacks(); - } - } - width; - height; -} - -/** - * EdgeShapeNodeTool - * @class canvas_widget.ClassNodeTool - * @extends canvas_widget.NodeTool - * @memberof canvas_widget - * @constructor - */ -class EdgeShapeNodeTool extends NodeTool { - constructor() { - super( - EdgeShapeNode.TYPE, - null, - null, - null, - EdgeShapeNode.DEFAULT_WIDTH, - EdgeShapeNode.DEFAULT_HEIGHT - ); - } -} - -/** - * EnumNodeTool - * @class canvas_widget.ClassNodeTool - * @extends canvas_widget.NodeTool - * @memberof canvas_widget - * @constructor - */ -class EnumNodeTool extends NodeTool { - constructor() { - super( - EnumNode.TYPE, - null, - null, - null, - EnumNode.DEFAULT_WIDTH, - EnumNode.DEFAULT_HEIGHT - ); - } -} - -/** - * GeneralisationEdgeTool - * @class canvas_widget.GeneralisationEdgeTool - * @extends canvas_widget.EdgeTool - * @memberof canvas_widget - * @constructor - */ -class GeneralisationEdgeTool extends EdgeTool { - constructor() { - super(GeneralisationEdge.TYPE, GeneralisationEdge.RELATIONS); - } -} - -const viewrelationshipNodeHtml = "
                  \r\n
                  <%= type %>
                  \r\n
                  <<ViewRelationship>>
                  \r\n
                  \r\n
                  "; // replaced by importmap.plugin.js - -/** - * ViewRelationshipNode - * @class canvas_widget.ViewRelationshipNode - * @extends canvas_widget.AbstractNode - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {number} zIndex Position of node on z-axis - * @param {object} json indicates if the ViewObjectNode is created from a json - - */ -class ViewRelationshipNode extends AbstractNode { - static TYPE = "ViewRelationship"; - static DEFAULT_WIDTH = 150; - static DEFAULT_HEIGHT = 100; - constructor(id, left, top, width, height, zIndex, json) { - super(id, "ViewRelationship", left, top, width, height, zIndex, json); - var that = this; - - /** - * jQuery object of node template - * @type {jQuery} - * @private - */ - var _$template = $( - lodash.template(viewrelationshipNodeHtml)({ - type: that.getType(), - }) - ); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = AbstractNode.prototype.get$node - .call(this) - .append(_$template) - .addClass("viewrelationship"); - - /** - * jQuery object of DOM node representing the attributes - * @type {jQuery} - * @private - */ - var _$attributeNode = _$node.find(".attributes"); - - /** - * Attributes of node - * @type {Object} - * @private - */ - this.getAttributes(); - - /** - * Get JSON representation of the node - * @returns {Object} - */ - this.toJSON = function () { - return AbstractNode.prototype.toJSON.call(this); - }; - - this.registerYMap = function () { - AbstractNode.prototype.registerYMap.call(this); - that.getLabel().getValue().registerYType(); - attributeList.registerYMap(); - if (cla) cla.registerYMap(); - attribute.getValue().registerYType(); - conjSelection.getValue().registerYType(); - }; - - this.showAttributes = function () { - if (renamingList.get$node().is(":hidden")) renamingList.get$node().show(); - if (conjSelection.get$node().is(":hidden")) - conjSelection.get$node().show(); - if (cla.get$node().is(":hidden")) cla.get$node().show(); - if (!targetAttribute.get$node().is(":hidden")) - targetAttribute.get$node().hide(); - }; - - this.createConditionListAttribute = function (refAttrs) { - var targetAttrList = {}; - if (refAttrs && refAttrs.constructor.name === "RenamingListAttribute") { - var attrs = refAttrs.getAttributes(); - for (var key in attrs) { - if (attrs.hasOwnProperty(key)) { - targetAttrList[key] = attrs[key].getKey().getValue(); - } - } - } else { - for (var key in refAttrs) { - if (refAttrs.hasOwnProperty(key)) { - targetAttrList[key] = refAttrs[key].val.value; - } - } - } - var conditionListAttr = new ConditionListAttribute( - "[condition]", - "Conditions", - that, - targetAttrList, - LogicalOperator - ); - that.addAttribute(conditionListAttr); - _$attributeNode.append(conditionListAttr.get$node()); - conditionListAttr.get$node().hide(); - return conditionListAttr; - }; - - this.registerYMap = function () { - AbstractNode.prototype.registerYMap.call(this); - that.getLabel().getValue().registerYType(); - renamingList.registerYMap(); - if (cla) cla.registerYMap(); - targetAttribute.getValue().registerYType(); - conjSelection.getValue().registerYType(); - }; - - var targetAttribute, renamingList, conjSelection, cla; - _$node.find(".label").append(this.getLabel().get$node()); - if (window.hasOwnProperty("y")) { - const dataMap = y.getMap("data"); - var model = dataMap.get("model"); - if (model) { - var selectionValues = - ViewTypesUtil.GetAllNodesOfBaseModelAsSelectionList2(model.nodes, [ - "Relationship", - ]); - targetAttribute = new SingleSelectionAttribute( - id + "[target]", - "Reference", - that, - selectionValues - ); - that.addAttribute(targetAttribute); - _$attributeNode.prepend(targetAttribute.get$node()); - - if (json) - cla = that.createConditionListAttribute( - json.attributes["[attributes]"].list - ); - else cla = that.createConditionListAttribute(); - } - } - - renamingList = new RenamingListAttribute( - "[attributes]", - "Attributes", - that, - { - hidden: "Show", - top: "Show Top", - center: "Show Center", - bottom: "Show Bottom", - hide: "Hide", - } - ); - that.addAttribute(renamingList); - _$attributeNode.append(renamingList.get$node()); - renamingList.get$node().hide(); - - conjSelection = new SingleSelectionAttribute( - id + "[conjunction]", - "Conjunction", - that, - LogicalConjunctions - ); - that.addAttribute(conjSelection); - _$attributeNode.append(conjSelection.get$node()); - conjSelection.get$node().hide(); - - if (json && conjSelection && cla && renamingList && targetAttribute) - that.showAttributes(); - - this.setContextMenuItemCallback(function () { - var viewId = $("#lblCurrentView").text(); - return { - addShape: { - name: "Add Edge Shape", - callback: function () { - var canvas = that.getCanvas(), - appearance = that.getAppearance(), - nodeId; - - canvas.createNode( - EdgeShapeNode.TYPE, - appearance.left + appearance.width + 50, - appearance.top, - 150, - 100 - ); - canvas.createEdge( - BiDirAssociationEdge.TYPE, - that.getEntityId(), - nodeId, - null, - null, - viewId - ); - }, - disabled: function () { - var edges = that.getEdges(), - edge, - edgeId; - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if ( - (edge instanceof BiDirAssociationEdge && - ((edge.getTarget() === that && - edge.getSource() instanceof EdgeShapeNode) || - (edge.getSource() === that && - edge.getTarget() instanceof EdgeShapeNode))) || - (edge instanceof UniDirAssociationEdge && - edge.getTarget() instanceof EdgeShapeNode) - ) { - return true; - } - } - } - return false; - }, - }, - sep: "---------", - }; - }); - } -} - -function GenerateViewpointModel(viewpointModel, y) { - EntityManagerInstance.init(); - - for (var node_key in viewpointModel.nodes) { - if (viewpointModel.nodes.hasOwnProperty(node_key)) { - var vpNode = viewpointModel.nodes[node_key]; - const width = vpNode.width || vpNode.containment.width; - const height = vpNode.height || vpNode.containment.height; - const left = vpNode.left || vpNode.containment.left; - const top = vpNode.top || vpNode.containment.top; - const zIndex = vpNode.zIndex || vpNode.containment.zIndex; - EntityManagerInstance.createNodeFromJSON( - vpNode.type, - node_key, - left, - top, - width, - height, - zIndex, - vpNode.containment, - vpNode, - y - ); - } - } - - for (var edge_key in viewpointModel.edges) { - if (viewpointModel.edges.hasOwnProperty(edge_key)) { - var vpEdge = viewpointModel.edges[edge_key]; - EntityManagerInstance.createEdgeFromJSON( - vpEdge.type, - edge_key, - vpEdge.source, - vpEdge.target, - vpEdge - ); - } - } - - /** - * Determine the type of the concrete classes (ObjectNodes) of the class diagram contained in the sub graph rooted by the passed node - * @param node Node to start with - * @param [visitedNodes] List of node that already have been visited - * @returns {object} - */ - function getConcreteObjectNodeTypes(node, visitedNodes) { - var edgeId, - edge, - ingoingEdges, - source, - type, - classTypes = []; - - if (!visitedNodes) visitedNodes = []; - - if (visitedNodes.indexOf(node) !== -1) return []; - - visitedNodes.push(node); - - type = node.getLabel().getValue().getValue(); - if ( - (node instanceof ObjectNode || node instanceof ViewObjectNode) && - classTypes.indexOf(type) === -1 - ) { - classTypes.push(type); - } - - ingoingEdges = node.getIngoingEdges(); - for (edgeId in ingoingEdges) { - if (ingoingEdges.hasOwnProperty(edgeId)) { - edge = ingoingEdges[edgeId]; - source = edge.getSource(); - if ( - (edge instanceof GeneralisationEdge && - source instanceof ObjectNode) || - (edge instanceof GeneralisationEdge && - source instanceof AbstractClassNode) || - (edge instanceof GeneralisationEdge && - source instanceof ViewObjectNode) - ) { - classTypes = classTypes.concat( - getConcreteObjectNodeTypes(source, visitedNodes) - ); - } - } - } - return classTypes; - } - - /** - * Determine the attributes of the passed node by traversing the underlying class diagram - * @param node Node to start with - * @param [visitedNodes] List of node that already have been visited - * @returns {object} - */ - function getNodeAttributes(node, visitedNodes) { - var nodeAttributes, attributeId, attribute; - var edgeId, edge, outgoingEdges; - var source, target; - var neighbor, options; - var attributes = {}; - var obj = {}; - - if (!visitedNodes) visitedNodes = []; - - if (visitedNodes.indexOf(node) !== -1) return {}; - - visitedNodes.push(node); - - //Traverse outgoing edges to check for inheritance and linked enums - outgoingEdges = node.getOutgoingEdges(); - for (edgeId in outgoingEdges) { - if (outgoingEdges.hasOwnProperty(edgeId)) { - edge = outgoingEdges[edgeId]; - source = edge.getSource(); - target = edge.getTarget(); - - //Does the node inherit attributes from a parent node? - if ( - (edge instanceof GeneralisationEdge && - target instanceof AbstractClassNode) || - (edge instanceof GeneralisationEdge && - node instanceof ObjectNode && - target instanceof ObjectNode) || - (edge instanceof GeneralisationEdge && - node instanceof RelationshipNode && - target instanceof RelationshipNode) || - (edge instanceof GeneralisationEdge && - node instanceof EnumNode && - target instanceof EnumNode) - ) { - Util.merge(attributes, getNodeAttributes(target, visitedNodes)); - - //Is there an enum linked to the node - } else if ( - (edge instanceof BiDirAssociationEdge && - ((target === node && (neighbor = source) instanceof EnumNode) || - (source === node && (neighbor = target) instanceof EnumNode))) || - (edge instanceof UniDirAssociationEdge && - (neighbor = target) instanceof EnumNode) - ) { - options = {}; - nodeAttributes = {}; - Util.merge(nodeAttributes, getNodeAttributes(neighbor, [])); - for (attributeId in nodeAttributes) { - if (nodeAttributes.hasOwnProperty(attributeId)) { - attribute = nodeAttributes[attributeId]; - options[attribute.value] = attribute.value; - } - } - obj = {}; - obj[neighbor.getEntityId()] = { - key: edge.getLabel().getValue().getValue(), - value: neighbor.getLabel().getValue().getValue(), - options: options, - }; - Util.merge(attributes, obj); - } - } - } - //Compute node attributes - nodeAttributes = node.getAttribute("[attributes]").getAttributes(); - for (attributeId in nodeAttributes) { - if (nodeAttributes.hasOwnProperty(attributeId)) { - attribute = nodeAttributes[attributeId]; - if (node instanceof RelationshipNode) { - obj = {}; - obj[attributeId] = { - key: attribute.getKey().getValue(), - value: attribute.getValue().getValue(), - position: attribute.getValue2().getValue(), - }; - Util.merge(attributes, obj); - } else if (node instanceof ViewRelationshipNode) { - obj = {}; - obj[attributeId] = { - key: attribute.getKey().getValue(), - ref: attribute.getRef().getValue(), - position: attribute.getVis().getValue(), - }; - Util.merge(attributes, obj); - } else if (node instanceof EnumNode) { - obj = {}; - obj[attributeId] = { - value: attribute.getValue().getValue(), - }; - Util.merge(attributes, obj); - } else if (node instanceof ViewObjectNode) { - obj = {}; - obj[attributeId] = { - key: attribute.getKey().getValue(), - ref: attribute.getRef().getValue(), - visibility: attribute.getVis().getValue(), - }; - Util.merge(attributes, obj); - } else { - obj = {}; - obj[attributeId] = { - key: attribute.getKey().getValue(), - value: attribute.getValue().getValue(), - }; - Util.merge(attributes, obj); - } - } - } - return attributes; - } - - function getViewTypeAttributes(node) { - var target, targetName; - var conjunction; - var conditions = {}; - var nodeid = node.getEntityId(); - if (viewpointModel.nodes.hasOwnProperty(nodeid)) { - if ( - viewpointModel.nodes[nodeid].attributes.hasOwnProperty( - nodeid + "[target]" - ) - ) { - var attr = viewpointModel.nodes[nodeid].attributes[nodeid + "[target]"]; - target = attr.value.value; - targetName = attr.hasOwnProperty("option") ? attr.option : null; - } - if ( - viewpointModel.nodes[nodeid].attributes.hasOwnProperty("[condition]") - ) { - var conditionsList = - viewpointModel.nodes[nodeid].attributes["[condition]"].list; - for (var condId in conditionsList) { - if (conditionsList.hasOwnProperty(condId)) { - conditions[condId] = { - property: conditionsList[condId].property.value, - operator: conditionsList[condId].operator.value, - value: conditionsList[condId].val.value, - //conjunction: conditionsList[condId].operator2.value - }; - } - } - } - if ( - viewpointModel.nodes[nodeid].attributes.hasOwnProperty( - nodeid + "[conjunction]" - ) - ) { - conjunction = - viewpointModel.nodes[nodeid].attributes[nodeid + "[conjunction]"] - .value.value; - } - } - return { - target: target, - targetName: targetName, - conditions: conditions, - conjunction: conjunction, - }; - } - - var metamodel = { - attributes: {}, - nodes: {}, - edges: {}, - }; - - var nodeId, node; - var attributes; - var edge, edgeId, edges; - var source, target; - var neighbor; - var groupSource, groupTarget; - var groupNeighbor; - var shape; - var sourceTypes, targetTypes, concreteTypes; - var groupSourceTypes, groupTargetTypes, groupConcreteTypes; - var relations; - var groupEdge, groupEdgeId, groupEdges; - var viewtypeAttrs; - - var _nodes = EntityManagerInstance.getNodes(); - for (nodeId in _nodes) { - if (_nodes.hasOwnProperty(nodeId)) { - node = _nodes[nodeId]; - if (node instanceof ObjectNode || node instanceof ViewObjectNode) { - if (node.getLabel().getValue().getValue() === "Model Attributes") { - attributes = getNodeAttributes(node); - metamodel.attributes = attributes; - } else { - attributes = getNodeAttributes(node); - edges = node.getEdges(); - shape = null; - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - source = edge.getSource(); - target = edge.getTarget(); - if ( - (edge instanceof BiDirAssociationEdge && - ((target === node && - (neighbor = source) instanceof NodeShapeNode) || - (source === node && - (neighbor = target) instanceof NodeShapeNode))) || - (edge instanceof UniDirAssociationEdge && - (neighbor = target) instanceof NodeShapeNode) - ) { - shape = { - shape: neighbor - .getAttribute(neighbor.getEntityId() + "[shape]") - .getValue() - .getValue(), - color: neighbor - .getAttribute(neighbor.getEntityId() + "[color]") - .getValue() - .getValue(), - defaultWidth: parseInt( - neighbor - .getAttribute(neighbor.getEntityId() + "[defaultWidth]") - .getValue() - .getValue() - ), - defaultHeight: parseInt( - neighbor - .getAttribute(neighbor.getEntityId() + "[defaultHeight]") - .getValue() - .getValue() - ), - containment: neighbor - .getAttribute(neighbor.getEntityId() + "[containment]") - .getValue() - .getValue(), - customShape: neighbor - .getAttribute(neighbor.getEntityId() + "[customShape]") - .getValue() - .getValue(), - customAnchors: neighbor - .getAttribute(neighbor.getEntityId() + "[customAnchors]") - .getValue() - .getValue(), - }; - } - } - } - - metamodel.nodes[nodeId] = { - label: node.getLabel().getValue().getValue(), - attributes: attributes, - shape: shape || { - shape: "rectangle", - color: "white", - containment: false, - customShape: "", - customAnchors: "", - defaultWidth: 0, - defaultHeight: 0, - }, - }; - if (node instanceof ViewObjectNode) { - viewtypeAttrs = getViewTypeAttributes(node); - Util.merge(metamodel.nodes[nodeId], viewtypeAttrs); - } - } - } else if ( - node instanceof RelationshipNode || - node instanceof ViewRelationshipNode - ) { - attributes = getNodeAttributes(node); - edges = node.getEdges(); - sourceTypes = []; - targetTypes = []; - relations = []; - shape = null; - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - source = edge.getSource(); - target = edge.getTarget(); - if ( - edge instanceof BiDirAssociationEdge && - ((target === node && (neighbor = source) instanceof ObjectNode) || - (target === node && - (neighbor = source) instanceof ViewObjectNode) || - (source === node && - (neighbor = target) instanceof ObjectNode) || - (source === node && - (neighbor = target) instanceof ViewObjectNode)) - ) { - concreteTypes = getConcreteObjectNodeTypes(neighbor); - sourceTypes = sourceTypes.concat(concreteTypes); - targetTypes = targetTypes.concat(concreteTypes); - } else if ( - edge instanceof UniDirAssociationEdge && - source === node && - (target instanceof ObjectNode || target instanceof ViewObjectNode) - ) { - targetTypes = targetTypes.concat( - getConcreteObjectNodeTypes(target) - ); - } else if ( - edge instanceof UniDirAssociationEdge && - target === node && - (source instanceof ObjectNode || source instanceof ViewObjectNode) - ) { - sourceTypes = sourceTypes.concat( - getConcreteObjectNodeTypes(source) - ); - } else if ( - edge instanceof BiDirAssociationEdge && - ((target === node && - (neighbor = source) instanceof AbstractClassNode) || - (source === node && - (neighbor = target) instanceof AbstractClassNode)) - ) { - concreteTypes = getConcreteObjectNodeTypes(neighbor); - sourceTypes = sourceTypes.concat(concreteTypes); - targetTypes = targetTypes.concat(concreteTypes); - } else if ( - edge instanceof UniDirAssociationEdge && - source === node && - target instanceof AbstractClassNode - ) { - targetTypes = targetTypes.concat( - getConcreteObjectNodeTypes(target) - ); - } else if ( - edge instanceof UniDirAssociationEdge && - target === node && - source instanceof AbstractClassNode - ) { - sourceTypes = sourceTypes.concat( - getConcreteObjectNodeTypes(source) - ); - } else if ( - (edge instanceof BiDirAssociationEdge && - ((target === node && - (neighbor = source) instanceof EdgeShapeNode) || - (source === node && - (neighbor = target) instanceof EdgeShapeNode))) || - (edge instanceof UniDirAssociationEdge && - source === node && - (neighbor = target) instanceof EdgeShapeNode) - ) { - shape = { - arrow: neighbor - .getAttribute(neighbor.getEntityId() + "[arrow]") - .getValue() - .getValue(), - shape: neighbor - .getAttribute(neighbor.getEntityId() + "[shape]") - .getValue() - .getValue(), - color: neighbor - .getAttribute(neighbor.getEntityId() + "[color]") - .getValue() - .getValue(), - overlay: neighbor - .getAttribute(neighbor.getEntityId() + "[overlay]") - .getValue() - .getValue(), - overlayPosition: neighbor - .getAttribute(neighbor.getEntityId() + "[overlayPosition]") - .getValue() - .getValue(), - overlayRotate: neighbor - .getAttribute(neighbor.getEntityId() + "[overlayRotate]") - .getValue() - .getValue(), - }; - } else if ( - edge instanceof GeneralisationEdge && - target === node && - (neighbor = source) instanceof RelationshipGroupNode - ) { - groupEdges = neighbor.getEdges(); - groupSourceTypes = []; - groupTargetTypes = []; - for (groupEdgeId in groupEdges) { - if (groupEdges.hasOwnProperty(groupEdgeId)) { - groupEdge = groupEdges[groupEdgeId]; - groupSource = groupEdge.getSource(); - groupTarget = groupEdge.getTarget(); - if ( - groupEdge instanceof BiDirAssociationEdge && - ((groupTarget === neighbor && - (groupNeighbor = groupSource) instanceof ObjectNode) || - (groupSource === neighbor && - (groupNeighbor = groupTarget) instanceof ObjectNode) || - (groupTarget === neighbor && - (groupNeighbor = groupSource) instanceof - ViewObjectNode) || - (groupSource === neighbor && - (groupNeighbor = groupTarget) instanceof - ViewObjectNode)) - ) { - groupConcreteTypes = - getConcreteObjectNodeTypes(groupNeighbor); - groupSourceTypes = - groupSourceTypes.concat(groupConcreteTypes); - groupTargetTypes = - groupTargetTypes.concat(groupConcreteTypes); - } else if ( - groupEdge instanceof UniDirAssociationEdge && - groupSource === neighbor && - (groupTarget instanceof ObjectNode || - groupTarget instanceof ViewObjectNode) - ) { - groupTargetTypes = groupTargetTypes.concat( - getConcreteObjectNodeTypes(groupTarget) - ); - } else if ( - groupEdge instanceof UniDirAssociationEdge && - groupTarget === neighbor && - (groupSource instanceof ObjectNode || - groupSource instanceof ViewObjectNode) - ) { - groupSourceTypes = groupSourceTypes.concat( - getConcreteObjectNodeTypes(groupSource) - ); - } else if ( - groupEdge instanceof BiDirAssociationEdge && - ((groupTarget === neighbor && - (groupNeighbor = groupSource) instanceof - AbstractClassNode) || - (groupSource === neighbor && - (groupNeighbor = groupTarget) instanceof - AbstractClassNode)) - ) { - groupConcreteTypes = - getConcreteObjectNodeTypes(groupNeighbor); - groupSourceTypes = - groupSourceTypes.concat(groupConcreteTypes); - groupTargetTypes = - groupTargetTypes.concat(groupConcreteTypes); - } else if ( - groupEdge instanceof UniDirAssociationEdge && - groupSource === neighbor && - groupTarget instanceof AbstractClassNode - ) { - groupTargetTypes = groupTargetTypes.concat( - getConcreteObjectNodeTypes(groupTarget) - ); - } else if ( - groupEdge instanceof UniDirAssociationEdge && - groupTarget === neighbor && - groupSource instanceof AbstractClassNode - ) { - groupSourceTypes = groupSourceTypes.concat( - getConcreteObjectNodeTypes(groupSource) - ); - } - } - } - - if (groupSourceTypes.length > 0 && groupTargetTypes.length > 0) { - relations.push({ - sourceTypes: groupSourceTypes, - targetTypes: groupTargetTypes, - }); - } - } - } - } - - if (sourceTypes.length > 0 && targetTypes.length > 0) { - relations.push({ - sourceTypes: sourceTypes, - targetTypes: targetTypes, - }); - } - - metamodel.edges[nodeId] = { - label: node.getLabel().getValue().getValue(), - shape: shape || { - arrow: "bidirassociation", - shape: "straight", - color: "black", - overlay: "", - overlayPosition: "top", - overlayRotate: true, - }, - relations: relations, - attributes: attributes, - }; - if (node instanceof ViewRelationshipNode) { - viewtypeAttrs = getViewTypeAttributes(node); - Util.merge(metamodel.edges[nodeId], viewtypeAttrs); - } - } - } - } - metamodel["id"] = viewpointModel.id; - EntityManagerInstance.reset(); - return metamodel; -} - -function JSONtoGraph (json, canvas) { - if (!canvas) return new Error("No canvas object defined!"); - - //cleanUpYSpace('nodes'); - //cleanUpYSpace('edges'); - - $.Deferred(); - var numberOfNodes = lodash.keys(json.nodes).length; - var numberOfEdges = lodash.keys(json.edges).length; - var createdNodes = 0; - var createdEdges = 0; - var report = { - widget: "CANVAS", - createdYText: 0, - modelAttributes: { attributes: {} }, - nodes: {}, - edges: {}, - }; - - if (!lodash.isEmpty(json.attributes)) { - var modelAttributesNode = EntityManagerInstance.createModelAttributesNodeFromJSON( - json.attributes - ); - modelAttributesNode.registerYMap(); - canvas.setModelAttributesNode(modelAttributesNode); - modelAttributesNode.addToCanvas(canvas); - } - - function createNode(nodeId, jsonNode) { - const nodesMap = y.getMap("nodes"); - var map = nodesMap.get(nodeId); - - var node = null; - if (map) { - node = EntityManagerInstance.createNodeFromJSON( - jsonNode.type, - nodeId, - map.get("left") ? map.get("left") : jsonNode.left, - map.get("top") ? map.get("top") : jsonNode.top, - map.get("width") ? map.get("width") : jsonNode.width, - map.get("height") ? map.get("height") : jsonNode.height, - map.get("zIndex") ? map.get("zIndex") : jsonNode.zIndex, - map.get("containment") ? map.get("containment") : jsonNode.containment, - jsonNode - ); - } else { - node = EntityManagerInstance.createNodeFromJSON( - jsonNode.type, - nodeId, - jsonNode.left, - jsonNode.top, - jsonNode.width, - jsonNode.height, - jsonNode.zIndex, - jsonNode.containment, - jsonNode - ); - } - - if (node === undefined) { - console.error( - "SYNCMETA: Node undefined. Check if " + - jsonNode.type + - " type is defined in the VLS" - ); - var $errorMsg = $("#errorMsg"); - $("#loading").hide(); - $("#canvas-frame").hide(); - $errorMsg.parent().css("display", "inline-table"); - $errorMsg.text( - "SYNCMETA: Model is not compatible to the current Metamodel! Delete the current model or change the metamodel." - ); - return; - } - - node.registerYMap(); - node.addToCanvas(canvas); - node.bindMoveToolEvents(); - node.draw(); - } - - function createNodes(nodes) { - for (var nodeId in nodes) { - if (nodes.hasOwnProperty(nodeId)) { - createNode(nodeId, nodes[nodeId]); - createdNodes++; - } - } - } - - function createEdges(edges) { - for (const edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - //create edge - var edge = EntityManagerInstance.createEdgeFromJSON( - edges[edgeId].type, - edgeId, - edges[edgeId].source, - edges[edgeId].target, - edges[edgeId] - ); - - if (edge === undefined) { - console.error( - "SYNCMETA: Edge undefined. Check if " + - edges[edgeId].type + - " type is defined in the VLS" - ); - var $errorMsg = $("#errorMsg"); - $errorMsg.parent().show(); - $("#canvas-frame").hide(); - $("#loading").hide(); - $errorMsg.parent().css("display", "inline-table"); - $errorMsg.text( - "SYNCMETA: Model is not compatible to the current Metamodel! Delete the current model or change the metamodel." - ); - continue; - } - - //register it to Yjs and draw it to the canvas - edge.registerYMap(); - edge.addToCanvas(canvas); - edge.connect(); - edge.bindMoveToolEvents(); - createdEdges++; - } - } - } - - if (numberOfNodes > 0) { - createNodes(json.nodes); - if (createdNodes === numberOfNodes) { - if (numberOfEdges > 0) { - createEdges(json.edges); - if (createdEdges === numberOfEdges) { - canvas.resetTool(); - report.createdNodes = createdNodes; - report.createdEdges = createdEdges; - } - } else { - report.createdNodes = createdNodes; - report.createdEdges = 0; - } - } - } - return report; -} - -/** - * NodeShapeNodeTool - * @class canvas_widget.ClassNodeTool - * @extends canvas_widget.NodeTool - * @memberof canvas_widget - * @constructor - */ -class NodeShapeNodeTool extends NodeTool { - constructor() { - super( - NodeShapeNode.TYPE, - null, - null, - null, - NodeShapeNode.DEFAULT_WIDTH, - NodeShapeNode.DEFAULT_HEIGHT - ); - } -} - -/** - * ObjectNodeTool - * @class canvas_widget.ObjectNodeTool - * @memberof canvas_widget - * @constructor - */ -class ObjectNodeTool extends NodeTool { - constructor() { - super( - ObjectNode.TYPE, - null, - null, - null, - ObjectNode.DEFAULT_WIDTH, - ObjectNode.DEFAULT_HEIGHT - ); - } -} - -/** - * RelationshipGroupNodeTool - * @class canvas_widget.ClassNodeTool - * @extends canvas_widget.NodeTool - * @memberof canvas_widget - * @constructor - */ -class RelationshipGroupNodeTool extends NodeTool { - constructor() { - super( - RelationshipGroupNode.TYPE, - null, - null, - null, - RelationshipGroupNode.DEFAULT_WIDTH, - RelationshipGroupNode.DEFAULT_HEIGHT - ); - } -} - -/** - * RelationshipNodeTool - * @class canvas_widget.RelationshipNodeTool - * @extends canvas_widget.NodeTool - * @memberof canvas_widget - * @constructor - */ -class RelationshipNodeTool extends NodeTool { - constructor() { - super( - RelationshipNode.TYPE, - null, - null, - null, - RelationshipNode.DEFAULT_WIDTH, - RelationshipNode.DEFAULT_HEIGHT - ); - } -} - -/** - * BiDirAssociationEdgeTool - * @class canvas_widget.UniDirAssociationEdgeTool - * @extends canvas_widget.EdgeTool - * @memberof canvas_widget - * @constructor - */ -class UniDirAssociationEdgeTool extends EdgeTool { - constructor() { - super(UniDirAssociationEdge.TYPE, UniDirAssociationEdge.RELATIONS); - } -} - -/** - * Generates the Views - * @constructor - */ -function ViewGenerator() {} - -/** - * Applies a node type to a node - * @param {object} nodeType the node type object. Be found in the EntityManager via getNodeType(typeName) - * @param {canvas_widget.Node} node the node - */ -function applyNodeTypeToNode(nodeType, node) { - if (checkConditions(nodeType, node)) { - node.set$shape(nodeType.get$shape()); - node.setAnchorOptions(nodeType.getAnchors()); - node.setCurrentViewType(nodeType.TYPE); - node.show(); - } else { - node.setCurrentViewType(null); - node.hide(); - } -} - -/** - * check the condition for node - * @param type - * @param entity - * @returns {boolean} - */ -function checkConditions(type, entity) { - if (type.name === "Edge" || type.name === "Node") { - return true; - } - - var cond, - conj = type.getConditionConj(), - conditions = type.getConditions(); - - for (var cKey in conditions) { - if (conditions.hasOwnProperty(cKey)) { - cond = conditions[cKey]; - var attr = entity.getAttribute(cond.property); - if (attr) { - var res = resolveCondition( - attr.getValue().getValue(), - cond.operator, - cond.value - ); - if (conj === "AND" && !res) { - return false; - } else if (conj === "OR" && res) { - return true; - } - } - } - } - if (conj === "AND") { - return true; - } else if (conj === "OR") { - return false; - } -} - -/** - * resolves a condition - * @param attrValue the attribute value from the instance of a view type - * @param {string} operator the operator defined in the view type definition - * @param {string} value the value defined in the view type definition - * @returns {boolean} true if the condition is true else false - */ -function resolveCondition(attrValue, operator, value) { - var val = null; - try { - if (typeof val === "boolean") val = value; - else val = parseInt(value); - if (isNaN(val)) val = value; - } catch (e) { - val = value; - } - switch (operator) { - case "greater": - return attrValue > val; - case "smaller": - return attrValue < val; - case "equal": - return attrValue === val; - case "greater_eq": - return attrValue >= val; - case "smaller_eq": - return attrValue <= val; - case "nequal": - return attrValue != val; - } -} - -/** - * Applies a node type to a set of nodes - * @param {object} nodeType the node type object. Be found in the EntityManager via getNodeType(typeName) - * @param {object} nodes nodes as key value store - */ -function applyNodeTypeToNodes(nodeType, nodes) { - for (var nodeKey in nodes) { - if (nodes.hasOwnProperty(nodeKey)) { - applyNodeTypeToNode(nodeType, nodes[nodeKey]); - } - } -} - -/** - * Applies a edge type to a edge - * @param {object} edgeType the edge type object can be found in the EntityManager via getEdgeType(typeName) - * @param {canvas_widget.Edge} edge the edge to transform - */ -function applyEdgeTypeToEdge(edgeType, edge) { - if (checkConditions(edgeType, edge)) { - edge.restyle( - edgeType.getArrowType(), - edgeType.getColor(), - edgeType.getShapeType(), - null, - edgeType.getOverlay(), - edgeType.getOverlayPosition(), - edgeType.getOverlayRotate(), - edgeType.getAttributes() - ); - edge.setCurrentViewType(edgeType.TYPE); - } else { - edge.hide(); - } -} - -/** - * Applies a edge type to a set of nodes - * @param {object} edgeType the edge type object can be found in the EntityManager via getEdgeType(typeName) - * @param {object} edges the edges as key value store - */ -function applyEdgeTypeToEdges(edgeType, edges) { - for (var edgeKey in edges) { - if (edges.hasOwnProperty(edgeKey)) { - applyEdgeTypeToEdge(edgeType, edges[edgeKey]); - } - } -} - -/** - * Transforms a the nodes and edges of a model using a particular VLS to another VLS - * Currently only works if the vls is the meta-model (the initial VLS) but this should work in all directions as well as with vvs to vvs - * @param vls the current VLS - * @param vvs the target VLS the model should be transformed to - */ -ViewGenerator.generate = function (vls, vvs) { - var _processed = {}; - - //transform the view types - var viewpointNodes = vvs.nodes; - for (var vpNodeKey in viewpointNodes) { - if (viewpointNodes.hasOwnProperty(vpNodeKey)) { - var nodeViewType = viewpointNodes[vpNodeKey]; - if (nodeViewType.hasOwnProperty("target")) { - _processed[nodeViewType.target] = true; - var viewNodeTypeObject = EntityManagerInstance.getViewNodeType( - nodeViewType.label - ); - applyNodeTypeToNodes( - viewNodeTypeObject, - EntityManagerInstance.getNodesByType( - viewNodeTypeObject.getTargetNodeType().TYPE - ) - ); - } - } - } - - //Hide the other types - var nodeTypes = vls.nodes; - for (var nodeTypeKey in nodeTypes) { - if ( - nodeTypes.hasOwnProperty(nodeTypeKey) && - !_processed.hasOwnProperty(nodeTypeKey) - ) { - var nodes = EntityManagerInstance.getNodesByType(nodeTypes[nodeTypeKey].label); - for (var nodeKey in nodes) { - if (nodes.hasOwnProperty(nodeKey)) { - nodes[nodeKey].hide(); - } - } - } - } - - //transform edges - var viewpointEdges = vvs.edges; - for (var vpEdgeKey in viewpointEdges) { - if (viewpointEdges.hasOwnProperty(vpEdgeKey)) { - var edgeViewType = viewpointEdges[vpEdgeKey]; - if (edgeViewType.hasOwnProperty("target")) { - _processed[edgeViewType.target] = true; - var viewEdgeTypeObject = EntityManagerInstance.getViewEdgeType( - edgeViewType.label - ); - applyEdgeTypeToEdges( - viewEdgeTypeObject, - EntityManagerInstance.getEdgesByType( - viewEdgeTypeObject.getTargetEdgeType().TYPE - ) - ); - } - } - } - - //Hide the other types - var edgeTypes = vls.edges; - for (var edgeTypeKey in edgeTypes) { - if ( - edgeTypes.hasOwnProperty(edgeTypeKey) && - !_processed.hasOwnProperty(edgeTypeKey) - ) { - var edges = EntityManagerInstance.getEdgesByType(edgeTypes[edgeTypeKey].label); - for (var edgeKey in edges) { - if (edges.hasOwnProperty(edgeKey)) { - edges[edgeKey].hide(); - } - } - } - } - - //Repaint all jsPlumb connections - window.jsPlumbInstance.repaintEverything(); - _.each(EntityManagerInstance.getEdges(), function (e) { - e.setZIndex(); - }); -}; - -/** - * resets the view generator - * @param vls - */ -ViewGenerator.reset = function (vls) { - var typeName; - var nodes = vls.nodes; - for (var nodeKey in nodes) { - if (nodes.hasOwnProperty(nodeKey)) { - typeName = nodes[nodeKey].label; - applyNodeTypeToNodes( - EntityManagerInstance.getNodeType(typeName), - EntityManagerInstance.getNodesByType(typeName) - ); - } - } - - var edges = vls.edges; - for (var edgeKey in edges) { - if (edges.hasOwnProperty(edgeKey)) { - typeName = edges[edgeKey].label; - applyEdgeTypeToEdges( - EntityManagerInstance.getEdgeType(typeName), - EntityManagerInstance.getEdgesByType(typeName) - ); - } - } - - //Repaint all jsPlumb connections - window.jsPlumbInstance.repaintEverything(); - _.each(EntityManagerInstance.getEdges(), function (e) { - e.setZIndex(); - }); -}; +async function yjsSync( + spaceTitle, + yjsServer = "localhost:1234", + yjsProtocol = "ws" +) { + let title; -const optionHtml = ""; // replaced by importmap.plugin.js - -/** - * the view manager manges a arbitrary number of views - * @returns {{GetViewpointList: Function, existsView: Function, getViewIdOfSelected: Function, getViewUri: Function, getViewpointUri: Function, getSelected$node: Function, getResource: Function, addView: Function, deleteView: Function, initViewList: Function}} - * @constructor - */ -function ViewManager() { - /** - * represent a reference to the view selection html element - * @type {jQuery} - * @private - */ - var _$selection = $("#ddmViewSelection"); - - /** - * html option element template - * @type {function} - */ - var optionTpl = lodash.template(optionHtml); - - return { - /** - * initialize the viewpoint selection list of the generic editor instance - */ - GetViewpointList: function () { - y = window.y; - const viewsMap = y.getMap("views"); - _$selection.empty(); - var viewpointList = viewsMap.keys(); - for (var i = 0; i < viewpointList.length; i++) { - var viewpoint = viewsMap.get(viewpointList[i]); - if (viewpoint) { - _$selection.append( - $( - optionTpl({ - id: viewpointList[i], - }) - ) - ); - } else viewsMap.delete(viewpointList[i]); - } - }, - /** - * checks if a view exists - * @param viewId the viewId of the vie - * @returns {boolean} true if the view already exits false if not - */ - existsView: function (viewId) { - const viewsMap = y.getMap("views"); - return viewsMap.has(viewId); - }, - /** - * returns the view identifier of currently selected html selection element - * @returns {string} the identifier of the view - */ - getViewIdOfSelected: function () { - return this.getSelected$node().attr("id"); - }, - /** - * returns the currently selected option node of the html selection element - * @returns {object} jquery object - */ - getSelected$node: function () { - return _$selection.find("option:selected"); - }, - /** - * adds a view to the ViewManager - * @param {string} viewId the view identifier - */ - addView: function (viewId) { - const viewsMap = y.getMap("views"); - if (viewsMap.has(viewId)) { - viewsMap.set(viewId, { - viewId: viewId, - attributes: {}, - nodes: {}, - edges: {}, - }); - return true; - } else return false; - }, - /** - * deletes a view from the view manager - * @param {string} viewId the identifier of the view - */ - deleteView: function (viewId) { - const viewsMap = y.getMap("views"); - viewsMap.delete(viewId); - _$selection.find("#" + viewId).remove(); - }, - /** - * Update a view representation in the ROLE Space - * @param {string} viewId The view identifier - * @param {string} viewId The Identifier of the view - * @param {object} resource openapp.oo.resource of the the view - * @returns {object} jquery promise - */ - updateViewContent: function (viewId) { - const viewsMap = y.getMap("views"); - var data = this.viewToJSON(viewId); - viewsMap.set(viewId, data); - }, - /** - * generates the json representation of a view - * @param viewId the unique name of the view - * @returns {Object} - */ - viewToJSON: function (viewId) { - var vls = EntityManagerInstance.graphToJSON(); - vls["id"] = viewId; - return vls; - }, - }; -} -var ViewManager$1 = new ViewManager(); - -/** - * ViewObjectNodeTool - * @class canvas_widget.ViewObjectNodeTool - * @memberof canvas_widget - * @constructor - */ -class ViewObjectNodeTool extends NodeTool { - constructor() { - super( - ViewObjectNode.TYPE, - null, - null, - null, - ViewObjectNode.DEFAULT_WIDTH, - ViewObjectNode.DEFAULT_HEIGHT - ); - } -} - -/** - * ViewRelationshipNodeTool - * @class canvas_widget.ViewRelationshipNodeTool - * @extends canvas_widget.NodeTool - * @memberof canvas_widget - * @constructor - */ -class ViewRelationshipNodeTool extends NodeTool { - constructor() { - super( - ViewRelationshipNode.TYPE, - null, - null, - null, - ViewRelationshipNode.DEFAULT_WIDTH, - ViewRelationshipNode.DEFAULT_HEIGHT - ); - } -} - -function getGuidanceModeling() { - var guidancemodeling = {}; - - var activityName = $(".activityEntry.activitySel", parent.document) - .find(".activity-title") - .text(); - - // console.info( - // "Guidance promise by " + undefined + " Activity:" + activityName - // ); - guidancemodeling.INITIAL_NODE_LABEL = "Initial node"; - guidancemodeling.MERGE_NODE_LABEL = "Decision node"; - guidancemodeling.CALL_ACTIVITY_NODE_LABEL = "Call activity node"; - guidancemodeling.ACTIVITY_FINAL_NODE_LABEL = "Activity final node"; - guidancemodeling.CONCURRENCY_NODE_LABEL = "Fork node"; - - guidancemodeling.isGuidanceEditor = function () { - return activityName == "Guidance modeling"; - }; - - guidancemodeling.getCreateObjectNodeLabelForType = function (type) { - return "Create " + type + " object"; - }; - - guidancemodeling.isCreateObjectNodeLabel = function (label) { - var match = /Create (.*?) object/.exec(label); - if (match) return match[1]; - else return ""; - }; - - guidancemodeling.getCreateRelationshipNodeLabelForType = function (type) { - return "Create " + type + " relationship"; - }; - - guidancemodeling.isCreateRelationshipNodeLabel = function (label) { - var match = /Create (.*?) relationship/.exec(label); - if (match) return match[1]; - else return ""; - }; - - guidancemodeling.getSetPropertyNodeLabelForType = function (type) { - return "Set property for " + type; - }; - - guidancemodeling.isSetPropertyNodeLabel = function (label) { - var match = /Set property for (.*)/.exec(label); - if (match) return match[1]; - else return ""; - }; - - guidancemodeling.getEntityNodeLabelForType = function (type) { - return type + " entity"; - }; - - guidancemodeling.isEntityNodeLabel = function (label) { - var match = /(.*?) entity/.exec(label); - if (match) return match[1]; - else return ""; - }; - - guidancemodeling.getObjectContextLabelForType = function (type) { - return type + " Object Context"; - }; - - guidancemodeling.getObjectTypeForObjectContextType = function (type) { - var i = type.lastIndexOf(" Object Context"); - return type.substring(0, i); - }; - - guidancemodeling.isObjectContextType = function (type) { - return ( - type.indexOf( - " Object Context", - type.length - " Object Context".length - ) !== -1 - ); - }; - - guidancemodeling.getRelationshipContextLabelForType = function (type) { - return type + " Relationship Context"; - }; - - guidancemodeling.getRelationshipTypeForRelationshipContextType = function ( - type - ) { - var i = type.lastIndexOf(" Relationship Context"); - return type.substring(0, i); - }; - - guidancemodeling.isRelationshipContextType = function (type) { - return ( - type.indexOf( - " Relationship Context", - type.length - " Relationship Context".length - ) !== -1 - ); - }; - - guidancemodeling.getObjectToolLabelForType = function (type) { - return type + " Tool"; - }; - - guidancemodeling.getObjectTypeForObjectToolType = function (type) { - var i = type.lastIndexOf(" Tool"); - return type.substring(0, i); - }; - - guidancemodeling.isObjectToolType = function (type) { - return type.indexOf(" Tool", type.length - " Tool".length) !== -1; - }; - - return guidancemodeling; + if (!spaceTitle) { + if (window.caeRoom) { + title = window.caeRoom; + } else if (localStorage.getItem("syncmetaSpace")) { + title = localStorage.getItem("syncmetaSpace"); + } else { + title = Util.getSpaceTitle(location.href); + } + } + + if (window.y && title === spaceTitle) { + // yjs is already initialized and we are using the same spaceTitle + return new Promise((resolve) => resolve(window.y)); + } + + const doc = new Doc(); + + // Sync clients with the y-websocket provider + const websocketProvider = new WebsocketProvider( + `${yjsProtocol}://${yjsServer}`, + title, + doc + ); + + await new Promise((resolve, reject) => { + websocketProvider.on("status", (event) => { + // console.log(event.status); // logs "connected" or "disconnected" + + if (event.status == "connected") { + if (!window.y) { + window.y = doc; + } + resolve(title); + } + }); + setTimeout(() => { + reject("YJS connection timed out. This means syncmeta widgets wont work"); + }, 5000); + }); + if (window.y) { + // it could be that another yjsSync call was made before this one resolved + return window.y; + } + return doc; } -async function yjsSync( - spaceTitle, - yjsServer = "localhost:1234", - yjsProtocol = "ws" -) { - let title; - - if (!spaceTitle) { - if (window.caeRoom) { - title = window.caeRoom; - } else if (localStorage.getItem("syncmetaSpace")) { - title = localStorage.getItem("syncmetaSpace"); - } else { - title = Util.getSpaceTitle(location.href); - } - } - - if (window.y && title === spaceTitle) { - // yjs is already initialized and we are using the same spaceTitle - return new Promise((resolve) => resolve(window.y)); - } - - const doc = new Doc(); - - // Sync clients with the y-websocket provider - const websocketProvider = new WebsocketProvider( - `${yjsProtocol}://${yjsServer}`, - title, - doc - ); - - await new Promise((resolve, reject) => { - websocketProvider.on("status", (event) => { - // console.log(event.status); // logs "connected" or "disconnected" - - if (event.status == "connected") { - if (!window.y) { - window.y = doc; - } - resolve(title); - } - }); - setTimeout(() => { - reject("YJS connection timed out. This means syncmeta widgets wont work"); - }, 5000); - }); - if (window.y) { - // it could be that another yjsSync call was made before this one resolved - return window.y; - } - return doc; -} - -async function getUserInfo() { - const url = - localStorage.getItem("userinfo_endpoint") || - "https://auth.las2peer.org/auth/realms/main/protocol/openid-connect/userinfo"; - const response = await fetch(url, { - headers: { Authorization: "Bearer " + localStorage.access_token }, - }).catch((error) => { - console.warn("Error while fetching profile information : " + error); - }); - - try { - if (response && response.ok) { - const data = await response.json(); - const space = { user: {} }; - space.user[CONFIG.NS.PERSON.TITLE] = data.preferred_username; - space.user[CONFIG.NS.PERSON.JABBERID] = data.sub; - space.user[CONFIG.NS.PERSON.MBOX] = data.email; - space.user.globalId = -1; - space.user.self = true; - - return space; - } - } catch (error) { - console.error(error); - } - - return { user: Util.generateAnonymousUser() }; -} - -function createReloadHandler () { - var createReloadHandler = function () { - var iwcClient = window._iwc_instance_; - var intent_listener = []; - if (iwcClient && iwcClient.onIntent != null) { - var previous_iwc_onIntent = iwcClient.onIntent; - iwcClient.onIntent = function (message) { - if (message.action === "RELOAD") { - console.log(" K!!!!!!!!!!!!!!!!!!!!!!!!!!!! RELOAD!!!!!!!!!!!!!!!!!!!!!"); - window.location.reload(); - } - else { - for (var i = 0; i < intent_listener.length; i++) { - intent_listener[i].apply(this, arguments); - } - } - previous_iwc_onIntent.apply(this, arguments); - }; - window._addIwcIntentListener = function (f) { - intent_listener.push(f); - }; - window._reloadThisFuckingInstance = function () { - console.log("Reloading Everything"); - var message = { - action: "RELOAD", - component: "", - data: "", - dataType: "", - flags: ["PUBLISH_GLOBAL"], - extras: { - reload: true, - }, - }; - iwcClient.publish(message); - }; - } - else { - setTimeout(createReloadHandler, 5000); - } - }; - setTimeout(createReloadHandler, 10000); -} - -const SyncMetaWidget = (superClass, widgetName) => { - if (!widgetName) { - throw new Error("widgetName cannot be empty"); - } - class SyncMetaWidgetElement extends superClass { - constructor() { - super(...arguments); - this.widgetName = widgetName; - } - createRenderRoot() { - return this; - } - render() { - return html ` `; - } - firstUpdated() { - this.hideErrorAlert(); - } - connectedCallback() { - super.connectedCallback(); - createReloadHandler(); - if (!window.hasOwnProperty("y")) { - yjsSync().then((y) => { - if (!window.hasOwnProperty("y")) - window.y = y; - }); - } - } - disconnectedCallback() { - super.disconnectedCallback(); - } - hideErrorAlert() { - $(this.widgetName).find("#alert-message").text(""); - $(this.widgetName).find("error-alert").hide(); - } - showErrorAlert(message) { - $(this.widgetName).find("#alert-message").text(message); - $(this.widgetName).find("error-alert").hide(); - } - } - SyncMetaWidgetElement.styles = css ` - .loading { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - /*noinspection CssUnknownTarget*/ - background: white url("/img/loading.gif") no-repeat center center; - z-index: 32032; - opacity: 0.75; - } - - #oauthPersonalize, - #oauthPersonalizeDone, - #oauthPersonalizeComplete { - position: relative; - z-index: 32033; - } - - #q { - position: absolute; - width: 100%; - height: 3px; - bottom: 0; - left: 0; - cursor: s-resize; - } - `; - return SyncMetaWidgetElement; +async function getUserInfo() { + const url = + localStorage.getItem("userinfo_endpoint") || + "https://auth.las2peer.org/auth/realms/main/protocol/openid-connect/userinfo"; + const response = await fetch(url, { + headers: { Authorization: "Bearer " + localStorage.access_token }, + }).catch((error) => { + console.warn("Error while fetching profile information : " + error); + }); + + try { + if (response && response.ok) { + const data = await response.json(); + const space = { user: {} }; + space.user[CONFIG.NS.PERSON.TITLE] = data.preferred_username; + space.user[CONFIG.NS.PERSON.JABBERID] = data.sub; + space.user[CONFIG.NS.PERSON.MBOX] = data.email; + space.user.globalId = -1; + space.user.self = true; + + return space; + } + } catch (error) { + console.error(error); + } + + return { user: Util.generateAnonymousUser() }; +} + +function createReloadHandler () { + var createReloadHandler = function () { + var iwcClient = window._iwc_instance_; + var intent_listener = []; + if (iwcClient && iwcClient.onIntent != null) { + var previous_iwc_onIntent = iwcClient.onIntent; + iwcClient.onIntent = function (message) { + if (message.action === "RELOAD") { + console.log(" K!!!!!!!!!!!!!!!!!!!!!!!!!!!! RELOAD!!!!!!!!!!!!!!!!!!!!!"); + window.location.reload(); + } + else { + for (var i = 0; i < intent_listener.length; i++) { + intent_listener[i].apply(this, arguments); + } + } + previous_iwc_onIntent.apply(this, arguments); + }; + window._addIwcIntentListener = function (f) { + intent_listener.push(f); + }; + window._reloadThisFuckingInstance = function () { + console.log("Reloading Everything"); + var message = { + action: "RELOAD", + component: "", + data: "", + dataType: "", + flags: ["PUBLISH_GLOBAL"], + extras: { + reload: true, + }, + }; + iwcClient.publish(message); + }; + } + else { + setTimeout(createReloadHandler, 5000); + } + }; + setTimeout(createReloadHandler, 10000); +} + +const SyncMetaWidget = (superClass, widgetName) => { + if (!widgetName) { + throw new Error("widgetName cannot be empty"); + } + class SyncMetaWidgetElement extends superClass { + constructor() { + super(...arguments); + this.widgetName = widgetName; + } + createRenderRoot() { + return this; + } + render() { + return html ` `; + } + firstUpdated() { + this.hideErrorAlert(); + } + connectedCallback() { + super.connectedCallback(); + createReloadHandler(); + if (!window.hasOwnProperty("y")) { + yjsSync().then((y) => { + if (!window.hasOwnProperty("y")) + window.y = y; + }); + } + } + disconnectedCallback() { + super.disconnectedCallback(); + } + hideErrorAlert() { + $(this.widgetName).find("#alert-message").text(""); + $(this.widgetName).find("error-alert").hide(); + } + showErrorAlert(message) { + $(this.widgetName).find("#alert-message").text(message); + $(this.widgetName).find("error-alert").hide(); + } + } + SyncMetaWidgetElement.styles = css ` + .loading { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + /*noinspection CssUnknownTarget*/ + background: white url("/img/loading.gif") no-repeat center center; + z-index: 32032; + opacity: 0.75; + } + + #oauthPersonalize, + #oauthPersonalizeDone, + #oauthPersonalizeComplete { + position: relative; + z-index: 32033; + } + + #q { + position: absolute; + width: 100%; + height: 3px; + bottom: 0; + left: 0; + cursor: s-resize; + } + `; + return SyncMetaWidgetElement; }; -let CanvasWidget = class CanvasWidget extends SyncMetaWidget(LitElement, getWidgetTagName(CONFIG.WIDGET.NAME.MAIN)) { - render() { - return html ` - - - - - - - -
                  - -
                  -
                  -
                  - - - - - - - - - - - - - - - View: -
                  -
                  -
                  - - -
                  -
                  - - - -
                  - -
                  -
                  -
                  -
                  - -
                  - `; - } - connectedCallback() { - super.connectedCallback(); - } - disconnectedCallback() { - super.disconnectedCallback(); - } - async firstUpdated(e) { - super.firstUpdated(e); - const alertDiv = $(getWidgetTagName(CONFIG.WIDGET.NAME.MAIN)).find(".alert"); - alertDiv.attr("style", "display:none !important"); - const user = await getUserInfo(); - if (!user) { - console.error("user is undefined"); - } - yjsSync() - .then((y) => { - console.info("CANVAS: Yjs Initialized successfully in room " + - window.spaceTitle + - " with y-user-id: " + - y.clientID); - const _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); - _iwcw.setSpace(user); - const userMap = y.getMap("users"); - const dataMap = y.getMap("data"); - setTimeout(() => { - try { - const user = _iwcw.getUser(); - if (!user) { - throw new Error("User not set"); - } - if (user.globalId !== -1) { - userMap.set(y.clientID.toString(), _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]); - } - } - catch (error) { - console.error(error); - } - if (!userMap.get(_iwcw.getUser()[CONFIG.NS.PERSON.JABBERID])) { - var userInfo = _iwcw.getUser(); - userInfo.globalId = Util.getGlobalId(user, y); - userMap.set(_iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], userInfo); - } - let metamodel, model; - const guidancemodel = getGuidanceModeling(); - if (guidancemodel.isGuidanceEditor()) { - model = dataMap.get("guidancemodel"); - metamodel = dataMap.get("guidancemetamodel"); - } - else { - metamodel = dataMap.get("metamodel"); - model = dataMap.get("model"); - } - if (model) { - console.info("CANVAS: Found model in yjs room with " + - Object.keys(model.nodes).length + - " nodes and " + - Object.keys(model.edges).length + - " edges."); - } - EntityManagerInstance.init(metamodel); - EntityManagerInstance.setGuidance(guidancemodel); - InitMainWidget(metamodel, model, _iwcw, user, y); - window.onbeforeunload = function () { - const userList = y.getMap("userList"); - const userMap = y.getMap("users"); - userList.delete(_iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]); - userMap.delete(y.clientID.toString()); - const activityMap = y.getMap("activity"); - const leaveActivity = new ActivityOperation("UserLeftActivity", null, _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]); - activityMap.set("UserLeftActivity", leaveActivity.toJSON()); - }; - }, 1000); - }) - .catch(function (message) { - console.warn(message); - alertDiv.find("#alert-message").text("Cannot connect to Yjs server."); - alertDiv.show(); - const $mainWidgetRef = $(getWidgetTagName(CONFIG.WIDGET.NAME.MAIN)); - const $spinner = $mainWidgetRef.find("loading-spinner"); - $spinner.hide(); - alert("ERROR: " + message); - }); - } -}; -CanvasWidget = __decorate([ - e(getWidgetTagName(CONFIG.WIDGET.NAME.MAIN)) -], CanvasWidget); -function registerOnDataReceivedCallback(_iwcw, y, userList, user) { - _iwcw.registerOnDataReceivedCallback(function (operation) { - const canvasMap = y.getMap("canvas"); - if (operation instanceof SetModelAttributeNodeOperation) { - _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.ATTRIBUTE, new SetModelAttributeNodeOperation().toNonOTOperation()); - } - else if (operation instanceof UpdateViewListOperation) { - canvasMap.set(UpdateViewListOperation.TYPE, true); - } - else if (operation instanceof UpdateMetamodelOperation) { - const dataMap = y.getMap("data"); - var model = dataMap.get("model"); - var vls = GenerateViewpointModel(model); - yjsSync(operation.getModelingRoomName()) - .then(function (y) { - const dataMap = y.getMap("data"); - dataMap.set("metamodel", vls); - const metaModelStatus = y.getMap("metaModelStatus"); - metaModelStatus.set("uploaded", true); - }) - .fail(() => { - const metaModelStatus = y.getMap("metaModelStatus"); - metaModelStatus.set("error", true); - }); - } - else if (operation.hasOwnProperty("getType")) { - if (operation.getType() === "WaitForCanvasOperation") { - switch (operation.getData().widget) { - case CONFIG.WIDGET.NAME.ACTIVITY: - _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.ACTIVITY, new NonOTOperation("WaitForCanvasOperation", JSON.stringify({ local: user, list: userList }))); - break; - case CONFIG.WIDGET.NAME.HEATMAP: - _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.HEATMAP, new NonOTOperation("WaitForCanvasOperation", JSON.stringify(user))); - break; - case CONFIG.WIDGET.NAME.ATTRIBUTE: - _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.ATTRIBUTE, new NonOTOperation("WaitForCanvasOperation", JSON.stringify(user))); - break; - case CONFIG.WIDGET.NAME.PALETTE: - const dataMap = y.getMap("data"); - var metamodel = dataMap.get("metamodel"); - if (!metamodel) - metamodel = "{}"; - else - metamodel = JSON.stringify(metamodel); - _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.PALETTE, new NonOTOperation("WaitForCanvasOperation", metamodel)); - break; - } - } - } - }); -} -function InitMainWidget(metamodel, model, _iwcw, user, y) { - const $mainWidgetRef = $(getWidgetTagName(CONFIG.WIDGET.NAME.MAIN)); - const $spinner = $mainWidgetRef.find("loading-spinner"); - const userList = []; - const canvasElement = $("#canvas"); - const canvas = new Canvas(canvasElement); - const joinMap = y.getMap("join"); - HistoryManagerInstance.init(canvas); - joinMap.forEach(function (value, key) { - userList.push(key); - }); - joinMap.observe(function (event) { - event.keysChanged.forEach(function (key) { - const userId = event.keysChanged[key]; - if (userList.indexOf(userId) === -1) { - userList.push(userId); - } - if (userId !== _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]) { - const joinMap = y.getMap("join"); - if (!joinMap.has(_iwcw.getUser()[CONFIG.NS.PERSON.JABBERID])) - joinMap.set(_iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], true); - } - else { - canvas.resetTool(); - } - }); - const canvasMap = y.getMap("canvas"); - canvasMap.observe(function (event) { - event.keysChanged.forEach((key) => { - var _a; - switch (key) { - case UpdateViewListOperation.TYPE: { - ViewManager$1.GetViewpointList(); - break; - } - case "ReloadWidgetOperation": { - var text; - const value = event.currentTarget.get(key); - switch (value) { - case "import": { - const dataMap = y.getMap("data"); - var model = dataMap.get("model"); - text = - "ATTENTION! Imported new model containing " + - Object.keys(model.nodes).length + - " nodes and " + - Object.keys(model.edges).length + - " edges. Some widgets will reload"; - break; - } - case "delete": { - text = - "ATTENTION! Deleted current model. Some widgets will reload"; - break; - } - case "meta_delete": { - text = - "ATTENTION! Deleted current metamodel. Some widgets will reload"; - break; - } - case "meta_import": { - text = - "ATTENTION! Imported new metamodel. Some widgets will reload"; - break; - } - } - const dataMap = y.getMap("data"); - const nodesMap = y.getMap("nodes"); - for (var key of nodesMap.keys()) { - var nodeInModel = (_a = dataMap.get("model")) === null || _a === void 0 ? void 0 : _a.nodes[key]; - if (nodeInModel) { - nodesMap.get(key).set("left", nodeInModel.left); - nodesMap.get(key).set("top", nodeInModel.top); - } - } - const activityMap = y.getMap("activity"); - activityMap.set("ReloadWidgetOperation", new ActivityOperation("ReloadWidgetOperation", undefined, _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], text).toJSON()); - location.reload(); - } - } - }); - }); - }); - registerOnDataReceivedCallback(_iwcw, y, userList, user); - if (metamodel) { - if (metamodel.hasOwnProperty("nodes")) { - let nodes = metamodel.nodes, node; - for (const nodeId in nodes) { - if (nodes.hasOwnProperty(nodeId)) { - node = nodes[nodeId]; - canvas.addTool(node.label, new NodeTool(node.label, null, null, node.shape.containment, node.shape.defaultWidth, node.shape.defaultHeight)); - } - } - } - if (metamodel.hasOwnProperty("edges")) { - var edges = metamodel.edges, edge; - for (var edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - canvas.addTool(edge.label, new EdgeTool(edge.label, edge.relations)); - } - } - } - ViewManager$1.GetViewpointList(); - $("#btnCreateViewpoint").hide(); - $("#btnDelViewPoint").hide(); - var initTools = function (vvs) { - if (vvs && vvs.hasOwnProperty("nodes")) { - var nodes = vvs.nodes, node; - for (var nodeId in nodes) { - if (nodes.hasOwnProperty(nodeId)) { - node = nodes[nodeId]; - canvas.addTool(node.label, new NodeTool(node.label, null, null, node.shape.containment, node.shape.defaultWidth, node.shape.defaultHeight)); - } - } - } - if (vvs && vvs.hasOwnProperty("edges")) { - var edges = vvs.edges, edge; - for (var edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - canvas.addTool(edge.label, new EdgeTool(edge.label, edge.relations)); - } - } - } - }; - $("#btnShowView").click(function () { - var viewId = ViewManager$1.getViewIdOfSelected(); - var $currentViewIdLabel = $("#lblCurrentViewId"); - if (viewId === $currentViewIdLabel.text()) - return; - const viewsMap = y.getMap("views"); - var vvs = viewsMap.get(viewId); - EntityManagerInstance.initViewTypes(vvs); - var operation = new InitModelTypesOperation(vvs, true).toNonOTOperation(); - _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.PALETTE, operation); - _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.ATTRIBUTE, operation); - _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.METADATA, operation); - _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.OPENAPI, operation); - var activityOperation = new ActivityOperation("ViewApplyActivity", vvs.id, _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]); - _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.ACTIVITY, activityOperation.toNonOTOperation()); - const canvasMap = y.getMap("canvas"); - canvasMap.set("ViewApplyActivity", { - viewId: viewId, - jabberId: _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], - }); - initTools(vvs); - ViewGenerator.generate(metamodel, vvs); - $("#lblCurrentView").show(); - $currentViewIdLabel.text(viewId); - }); - $("#viewsHide").click(function () { - $(this).hide(); - $("#viewsShow").show(); - $("#ViewCtrlContainer").hide(); - var $lblCurrentViewId = $("#lblCurrentViewId"); - var viewpointId = $lblCurrentViewId.text(); - if (viewpointId.length > 0) { - var operation = new InitModelTypesOperation(metamodel, true); - _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.PALETTE, operation.toNonOTOperation()); - _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.ATTRIBUTE, operation.toNonOTOperation()); - var activityOperation = new ActivityOperation("ViewApplyActivity", "", _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]); - _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.ACTIVITY, activityOperation.toNonOTOperation()); - const canvasMap = y.getMap("canvas"); - canvasMap.set("ViewApplyActivity", { - viewId: "", - jabberId: _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], - }); - EntityManagerInstance.setViewId(null); - EntityManagerInstance.initModelTypes(metamodel); - initTools(metamodel); - ViewGenerator.reset(metamodel); - $("#lblCurrentView").hide(); - $lblCurrentViewId.text(""); - } - }); - var $saveImage = $("#save_image"); - $saveImage.show(); - $saveImage.click(function () { - canvas.toPNG().then(function (uri) { - var link = document.createElement("a"); - link.download = "export.png"; - link.href = uri; - link.click(); - }); - }); - } - else { - canvas.addTool(ObjectNode.TYPE, new ObjectNodeTool()); - canvas.addTool(AbstractClassNode.TYPE, new AbstractClassNodeTool()); - canvas.addTool(RelationshipNode.TYPE, new RelationshipNodeTool()); - canvas.addTool(RelationshipGroupNode.TYPE, new RelationshipGroupNodeTool()); - canvas.addTool(EnumNode.TYPE, new EnumNodeTool()); - canvas.addTool(NodeShapeNode.TYPE, new NodeShapeNodeTool()); - canvas.addTool(EdgeShapeNode.TYPE, new EdgeShapeNodeTool()); - canvas.addTool(GeneralisationEdge.TYPE, new GeneralisationEdgeTool()); - canvas.addTool(BiDirAssociationEdge.TYPE, new BiDirAssociationEdgeTool()); - canvas.addTool(UniDirAssociationEdge.TYPE, new UniDirAssociationEdgeTool()); - canvas.addTool(ViewObjectNode.TYPE, new ViewObjectNodeTool()); - canvas.addTool(ViewRelationshipNode.TYPE, new ViewRelationshipNodeTool()); - $("#btnCreateViewpoint").click(function () { - ShowViewCreateMenu(); - }); - $("#btnCancelCreateViewpoint").click(function () { - HideCreateMenu(); - }); - $("#btnShowView").click(function () { - var viewId = ViewManager$1.getViewIdOfSelected(); - if (viewId === $("#lblCurrentViewId").text()) - return; - $("#loading").show(); - $("#lblCurrentView").show(); - $("#lblCurrentViewId").text(viewId); - visualizeView(viewId); - }); - $("#btnDelViewPoint").click(function () { - const viewsMap = y.getMap("views"); - var viewId = ViewManager$1.getViewIdOfSelected(); - if (viewId && viewId !== $("#lblCurrentViewId").text()) { - viewsMap.delete(viewId); - _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.ATTRIBUTE, new DeleteViewOperation(viewId).toNonOTOperation()); - ViewManager$1.deleteView(viewId); - } - else { - viewsMap.set(viewId, null); - ViewManager$1.deleteView(viewId); - $("#viewsHide").click(); - } - }); - $("#btnAddViewpoint").click(function () { - var viewId = $("#txtNameViewpoint").val(); - if (ViewManager$1.existsView(viewId)) { - alert("View already exists"); - return; - } - ViewManager$1.addView(viewId); - HideCreateMenu(); - const canvasMap = y.getMap("canvas"); - canvasMap.set(UpdateViewListOperation.TYPE, true); - }); - $("#viewsHide").click(function () { - $(this).hide(); - $("#viewsShow").show(); - $("#ViewCtrlContainer").hide("fast"); - var $lblCurrentViewId = $("#lblCurrentViewId"); - const dataMap = y.getMap("data"); - if ($lblCurrentViewId.text().length > 0) { - var $loading = $("#loading"); - $loading.show(); - var model = dataMap.get("model"); - var operation = new SetViewTypesOperation(false); - _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.PALETTE, operation.toNonOTOperation()); - var activityOperation = new ActivityOperation("ViewApplyActivity", "", _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]); - _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.ACTIVITY, activityOperation.toNonOTOperation()); - const canvasMap = y.getMap("canvas"); - canvasMap.set("ViewApplyActivity", { - viewId: "", - jabberId: _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], - }); - resetCanvas(); - JSONtoGraph(model, canvas); - $("#loading").hide(); - canvas.resetTool(); - $("#lblCurrentView").hide(); - $lblCurrentViewId.text(""); - EntityManagerInstance.setViewId(null); - } - }); - } - var ShowViewCreateMenu = function () { - $("#btnCreateViewpoint").hide(); - $("#ddmViewSelection").hide(); - $("#btnShowView").hide(); - $("#btnDelViewPoint").hide(); - $("#txtNameViewpoint").show(); - $("#btnAddViewpoint").show(); - $("#btnCancelCreateViewpoint").show(); - }; - var HideCreateMenu = function () { - $("#btnCreateViewpoint").show(); - $("#ddmViewSelection").show(); - $("#btnDelViewPoint").show(); - $("#btnShowView").show(); - $("#txtNameViewpoint").hide(); - $("#btnAddViewpoint").hide(); - $("#btnCancelCreateViewpoint").hide(); - }; - function resetCanvas() { - var edges = EntityManagerInstance.getEdges(); - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - var edge = EntityManagerInstance.findEdge(edgeId); - edge.remove(); - } - } - var nodes = EntityManagerInstance.getNodes(); - for (const nodeId in nodes) { - if (nodes.hasOwnProperty(nodeId)) { - var node = EntityManagerInstance.findNode(nodeId); - node.remove(); - } - } - EntityManagerInstance.deleteModelAttribute(); - } - var visualizeView = function (viewId) { - const viewsMap = y.getMap("views"); - var viewData = viewsMap.get(viewId); - if (viewData) { - resetCanvas(); - ViewToGraph(viewData); - $("#lblCurrentView").show(); - $("#lblCurrentViewId").text(viewData.id); - EntityManagerInstance.setViewId(viewData.id); - canvas.resetTool(); - } - }; - function ViewToGraph(json) { - var operation = new ViewInitOperation(json); - _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.ATTRIBUTE, operation.toNonOTOperation()); - operation = new SetViewTypesOperation(true); - _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.PALETTE, operation.toNonOTOperation()); - var activityOperation = new ActivityOperation("ViewApplyActivity", json.id, _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]); - _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.ACTIVITY, activityOperation.toNonOTOperation()); - const canvasMap = y.getMap("canvas"); - canvasMap.set("ViewApplyActivity", { - viewId: json.id, - jabberId: _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], - }); - JSONtoGraph(json, canvas); - $("#loading").hide(); - canvas.resetTool(); - } - var $undo = $("#undo"); - $undo.prop("disabled", true); - var $redo = $("#redo"); - $redo.prop("disabled", true); - $undo.click(function () { - HistoryManagerInstance.undo(); - }); - $redo.click(function () { - HistoryManagerInstance.redo(); - }); - $("#showtype") - .click(function () { - canvas.get$node().removeClass("hide_type"); - $(this).hide(); - $("#hideType").show(); - }) - .hide(); - $("#hideType").click(function () { - canvas.get$node().addClass("hide_type"); - $(this).hide(); - $("#showtype").show(); - }); - $("#viewsShow").click(function () { - $(this).hide(); - $("#viewsHide").show(); - $("#ViewCtrlContainer").show("fast"); - }); - $("#zoomIn").click(function () { - canvas.setZoom(canvas.getZoom() + 0.1); - }); - $("#zoomOut").click(function () { - canvas.setZoom(canvas.getZoom() - 0.1); - }); - $("#applyLayout").click(function () { - const userMap = window.y.getMap("users"); - const canvasMap = window.y.getMap("canvas"); - canvasMap.set("applyLayout", userMap.get(window.y.clientID.toString())); - const activityMap = window.y.getMap("activity"); - activityMap.set("ApplyLayoutActivity", new ActivityOperation("ApplyLayoutActivity", null, userMap.get(window.y.clientID.toString()), "..applied Layout").toJSON()); - }); - var $feedback = $("#feedback"); - var saveFunction = function () { - $feedback.text("Saving..."); - var viewId = $("#lblCurrentViewId").text(); - if (viewId.length > 0 && !metamodel) { - ViewManager$1.updateViewContent(viewId); - $feedback.text("Saved!"); - setTimeout(function () { - $feedback.text(""); - }, 1000); - } - else { - EntityManagerInstance.storeDataYjs(); - $feedback.text("Saved!"); - setTimeout(function () { - $feedback.text(""); - }, 1000); - } - }; - $("#save").click(function () { - saveFunction(); - }); - $("#dialog").dialog({ - autoOpen: false, - resizable: false, - height: 350, - width: 400, - modal: true, - buttons: { - Generate: function (event) { - var title = $("#space_title").val(); - var label = $("#space_label") - .val() - .toString() - .replace(/[^a-zA-Z]/g, "") - .toLowerCase(); - if (title === "" || label === "") - return; - EntityManagerInstance.generateSpace(label, title).then(function (spaceObj) { - var operation = new ActivityOperation("EditorGenerateActivity", "-1", _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], '..generated new Editor ' + - spaceObj.spaceTitle + - "", {}).toNonOTOperation(); - _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.ACTIVITY, operation); - $("#space_link") - .text(spaceObj.spaceURI) - .attr({ href: spaceObj.spaceURI }) - .show(); - $("#space_link_text").show(); - $("#space_link_input").hide(); - $(event.target).parent().hide(); - }); - }, - Close: function () { - $(this).dialog("close"); - }, - }, - open: function () { - var name = canvas - .getModelAttributesNode() - .getAttribute("modelAttributes[name]") - .getValue() - .getValue(); - var $spaceTitle = $("#space_title"); - var $spaceLabel = $("#space_label"); - if ($spaceTitle.val() === "") - $spaceTitle.val(name); - if ($spaceLabel.val() === "") - $spaceLabel.val(name.replace(/[^a-zA-Z]/g, "").toLowerCase()); - $(":button:contains('Generate')").show(); - }, - close: function () { - $("#space_link_text").hide(); - $("#space_link_input").show(); - }, - }); - var $generate = $("#generate").click(function () { - $("#dialog").dialog("open"); - }); - if (!metamodel || - (!metamodel.hasOwnProperty("nodes") && !metamodel.hasOwnProperty("edges"))) { - $generate.show(); - } - if (metamodel) { - var op = new InitModelTypesOperation(metamodel); - _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.PALETTE, op.toNonOTOperation()); - _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.ATTRIBUTE, op.toNonOTOperation()); - } - const $searchInput = $("#searchNodeInput"); - const $searchButton = $("#searchNodeButton"); - $searchButton.click(function () { - const searchValue = $searchInput.val(); - const searchResultNode = EntityManagerInstance.findObjectNodeByLabel(searchValue); - if (searchResultNode) { - canvas.scrollNodeIntoView(searchResultNode); - canvas.select(searchResultNode); - } - }); - $searchInput.keypress(function (e) { - if (e.which == 13) { - $searchButton.click(); - } - }); - if (model) { - var report = JSONtoGraph(model, canvas); - console.info("CANVAS: Initialization of model completed ", report); - const dataMap = y.getMap("data"); - if (EntityManagerInstance.getLayer() === CONFIG.LAYER.META) { - dataMap.set("guidancemetamodel", EntityManagerInstance.generateGuidanceMetamodel()); - dataMap.set("metamodelpreview", EntityManagerInstance.generateMetaModel()); - } - } - else { - if (canvas.getModelAttributesNode() === null) { - var modelAttributesNode = EntityManagerInstance.createModelAttributesNode(y); - modelAttributesNode.registerYMap(); - canvas.setModelAttributesNode(modelAttributesNode); - modelAttributesNode.addToCanvas(canvas); - } - } - const userId = _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]; - if (!joinMap.has(_iwcw.getUser()[CONFIG.NS.PERSON.JABBERID])) - joinMap.set(userId.toString(), false); - ViewManager$1.GetViewpointList(); - $spinner.hide(); -} - -/** - * The closed-view-generation(CVG) algorithm - * Searches for neighbors of a referenced object/relationship node and adds the neighbors to the viewpoint model - * @param viewType the view type node - * @constructor - */ -function CVG(viewType) { - //the metamodel as json from the y-space - const dataMap = y.getMap("data"); - var metamodel = dataMap.get("model"); - //initilaize the current metamodel using the graphlib.Graph - var metaGraph = new graphlib.Graph(); - lodash.forEach(metamodel.nodes, function (value, index) { - metaGraph.setNode(index, value); - }); - lodash.forEach(metamodel.edges, function (value, index) { - value.id = index; - metaGraph.setEdge(value.source, value.target, value); - }); - - var originId = viewType - .getAttribute(viewType.getEntityId() + "[target]") - .getValue() - .getValue(); - var neighborsOfOrigin = metaGraph.neighbors(originId); - var canvas = viewType.getCanvas(); - var viewpointName = $("#lblCurrentView").text().replace("View:", ""); - - lodash.forEach(neighborsOfOrigin, function (neighborId) { - var node = metaGraph.node(neighborId); - var newNodeId; - //if neighbor is shape or relation just add it and the corresponding assocation - if ( - node.type === "Node Shape" || - node.type === "Edge Shape" || - node.type === "Relation" - ) { - newNodeId = viewpointName + "_" + neighborId; - if (!EntityManagerInstance.findNode(newNodeId)) - canvas.createNode( - node.type, - node.left, - node.top, - node.width, - node.height, - node.zIndex, - node.containment, - node, - newNodeId - ); - } else if ( - viewType.getType() === "ViewObject" && - node.type === "Relationship" - ) { - var viewtypes = EntityManagerInstance.getNodesByType("ViewRelationship"); - for (var key in viewtypes) { - if (viewtypes.hasOwnProperty(key)) { - var viewType2 = viewtypes[key]; - if ( - viewType2 - .getAttribute(viewType2.getEntityId() + "[target]") - .getValue() - .getValue() === neighborId - ) - newNodeId = viewType2.getEntityId(); - } - } - } else if ( - viewType.getType() === "ViewRelationship" && - node.type === "Object" - ) { - var viewtypes = EntityManagerInstance.getNodesByType("ViewObject"); - for (var key in viewtypes) { - if (viewtypes.hasOwnProperty(key)) { - var viewType2 = viewtypes[key]; - if ( - viewType2 - .getAttribute(viewType2.getEntityId() + "[target]") - .getValue() - .getValue() === neighborId - ) - newNodeId = viewType2.getEntityId(); - } - } - } - if (newNodeId) { - var edge = metaGraph.edge(originId, neighborId); - if (!edge) { - //try the other direction - edge = metaGraph.edge(neighborId, originId); - canvas.createEdge( - edge.type, - newNodeId, - viewType.getEntityId(), - edge, - viewpointName + "_" + edge.id, - viewpointName - ); - } else { - canvas.createEdge( - edge.type, - viewType.getEntityId(), - newNodeId, - edge, - viewpointName + "_" + edge.id, - viewpointName - ); - } - } - }); +let CanvasWidget = class CanvasWidget extends SyncMetaWidget(LitElement, getWidgetTagName(CONFIG.WIDGET.NAME.MAIN)) { + render() { + return html ` + + + + + + + +
                  + +
                  +
                  +
                  + + + + + + + + + + + + + + + View: +
                  +
                  +
                  + + +
                  +
                  + + + +
                  + +
                  +
                  +
                  +
                  + +
                  + `; + } + connectedCallback() { + super.connectedCallback(); + } + disconnectedCallback() { + super.disconnectedCallback(); + } + async firstUpdated(e) { + super.firstUpdated(e); + const alertDiv = $(getWidgetTagName(CONFIG.WIDGET.NAME.MAIN)).find(".alert"); + alertDiv.attr("style", "display:none !important"); + const user = await getUserInfo(); + if (!user) { + console.error("user is undefined"); + } + yjsSync() + .then((y) => { + console.info("CANVAS: Yjs Initialized successfully in room " + + window.spaceTitle + + " with y-user-id: " + + y.clientID); + const _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); + _iwcw.setSpace(user); + const userMap = y.getMap("users"); + const dataMap = y.getMap("data"); + setTimeout(() => { + try { + const user = _iwcw.getUser(); + if (!user) { + throw new Error("User not set"); + } + if (user.globalId !== -1) { + userMap.set(y.clientID.toString(), _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]); + } + } + catch (error) { + console.error(error); + } + if (!userMap.get(_iwcw.getUser()[CONFIG.NS.PERSON.JABBERID])) { + var userInfo = _iwcw.getUser(); + userInfo.globalId = Util.getGlobalId(user, y); + userMap.set(_iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], userInfo); + } + let metamodel, model; + const guidancemodel = getGuidanceModeling(); + if (guidancemodel.isGuidanceEditor()) { + model = dataMap.get("guidancemodel"); + metamodel = dataMap.get("guidancemetamodel"); + } + else { + metamodel = dataMap.get("metamodel"); + model = dataMap.get("model"); + } + if (model) { + console.info("CANVAS: Found model in yjs room with " + + Object.keys(model.nodes).length + + " nodes and " + + Object.keys(model.edges).length + + " edges."); + } + EntityManagerInstance.init(metamodel); + EntityManagerInstance.setGuidance(guidancemodel); + InitMainWidget(metamodel, model, _iwcw, user, y); + window.onbeforeunload = function () { + const userList = y.getMap("userList"); + const userMap = y.getMap("users"); + userList.delete(_iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]); + userMap.delete(y.clientID.toString()); + const activityMap = y.getMap("activity"); + const leaveActivity = new ActivityOperation("UserLeftActivity", null, _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]); + activityMap.set("UserLeftActivity", leaveActivity.toJSON()); + }; + }, 1000); + }) + .catch(function (message) { + console.warn(message); + alertDiv.find("#alert-message").text("Cannot connect to Yjs server."); + alertDiv.show(); + const $mainWidgetRef = $(getWidgetTagName(CONFIG.WIDGET.NAME.MAIN)); + const $spinner = $mainWidgetRef.find("loading-spinner"); + $spinner.hide(); + alert("ERROR: " + message); + }); + } +}; +CanvasWidget = __decorate([ + e(getWidgetTagName(CONFIG.WIDGET.NAME.MAIN)) +], CanvasWidget); +function registerOnDataReceivedCallback(_iwcw, y, userList, user) { + _iwcw.registerOnDataReceivedCallback(function (operation) { + const canvasMap = y.getMap("canvas"); + if (operation instanceof SetModelAttributeNodeOperation) { + _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.ATTRIBUTE, new SetModelAttributeNodeOperation().toNonOTOperation()); + } + else if (operation instanceof UpdateViewListOperation) { + canvasMap.set(UpdateViewListOperation.TYPE, true); + } + else if (operation instanceof UpdateMetamodelOperation) { + const dataMap = y.getMap("data"); + var model = dataMap.get("model"); + var vls = GenerateViewpointModel(model); + yjsSync(operation.getModelingRoomName()) + .then(function (y) { + const dataMap = y.getMap("data"); + dataMap.set("metamodel", vls); + const metaModelStatus = y.getMap("metaModelStatus"); + metaModelStatus.set("uploaded", true); + }) + .fail(() => { + const metaModelStatus = y.getMap("metaModelStatus"); + metaModelStatus.set("error", true); + }); + } + else if (operation.hasOwnProperty("getType")) { + if (operation.getType() === "WaitForCanvasOperation") { + switch (operation.getData().widget) { + case CONFIG.WIDGET.NAME.ACTIVITY: + _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.ACTIVITY, new NonOTOperation("WaitForCanvasOperation", JSON.stringify({ local: user, list: userList }))); + break; + case CONFIG.WIDGET.NAME.HEATMAP: + _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.HEATMAP, new NonOTOperation("WaitForCanvasOperation", JSON.stringify(user))); + break; + case CONFIG.WIDGET.NAME.ATTRIBUTE: + _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.ATTRIBUTE, new NonOTOperation("WaitForCanvasOperation", JSON.stringify(user))); + break; + case CONFIG.WIDGET.NAME.PALETTE: + const dataMap = y.getMap("data"); + var metamodel = dataMap.get("metamodel"); + if (!metamodel) + metamodel = "{}"; + else + metamodel = JSON.stringify(metamodel); + _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.PALETTE, new NonOTOperation("WaitForCanvasOperation", metamodel)); + break; + } + } + } + }); +} +function InitMainWidget(metamodel, model, _iwcw, user, y) { + const $mainWidgetRef = $(getWidgetTagName(CONFIG.WIDGET.NAME.MAIN)); + const $spinner = $mainWidgetRef.find("loading-spinner"); + const userList = []; + const canvasElement = $("#canvas"); + const canvas = new Canvas(canvasElement); + const joinMap = y.getMap("join"); + HistoryManagerInstance.init(canvas); + joinMap.forEach(function (value, key) { + userList.push(key); + }); + joinMap.observe(function (event) { + event.keysChanged.forEach(function (key) { + const userId = event.keysChanged[key]; + if (userList.indexOf(userId) === -1) { + userList.push(userId); + } + if (userId !== _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]) { + const joinMap = y.getMap("join"); + if (!joinMap.has(_iwcw.getUser()[CONFIG.NS.PERSON.JABBERID])) + joinMap.set(_iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], true); + } + else { + canvas.resetTool(); + } + }); + const canvasMap = y.getMap("canvas"); + canvasMap.observe(function (event) { + event.keysChanged.forEach((key) => { + var _a; + switch (key) { + case UpdateViewListOperation.TYPE: { + ViewManager$2.GetViewpointList(); + break; + } + case "ReloadWidgetOperation": { + var text; + const value = event.currentTarget.get(key); + switch (value) { + case "import": { + const dataMap = y.getMap("data"); + var model = dataMap.get("model"); + text = + "ATTENTION! Imported new model containing " + + Object.keys(model.nodes).length + + " nodes and " + + Object.keys(model.edges).length + + " edges. Some widgets will reload"; + break; + } + case "delete": { + text = + "ATTENTION! Deleted current model. Some widgets will reload"; + break; + } + case "meta_delete": { + text = + "ATTENTION! Deleted current metamodel. Some widgets will reload"; + break; + } + case "meta_import": { + text = + "ATTENTION! Imported new metamodel. Some widgets will reload"; + break; + } + } + const dataMap = y.getMap("data"); + const nodesMap = y.getMap("nodes"); + for (var key of nodesMap.keys()) { + var nodeInModel = (_a = dataMap.get("model")) === null || _a === void 0 ? void 0 : _a.nodes[key]; + if (nodeInModel) { + nodesMap.get(key).set("left", nodeInModel.left); + nodesMap.get(key).set("top", nodeInModel.top); + } + } + const activityMap = y.getMap("activity"); + activityMap.set("ReloadWidgetOperation", new ActivityOperation("ReloadWidgetOperation", undefined, _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], text).toJSON()); + location.reload(); + } + } + }); + }); + }); + registerOnDataReceivedCallback(_iwcw, y, userList, user); + if (metamodel) { + if (metamodel.hasOwnProperty("nodes")) { + let nodes = metamodel.nodes, node; + for (const nodeId in nodes) { + if (nodes.hasOwnProperty(nodeId)) { + node = nodes[nodeId]; + canvas.addTool(node.label, new NodeTool(node.label, null, null, node.shape.containment, node.shape.defaultWidth, node.shape.defaultHeight)); + } + } + } + if (metamodel.hasOwnProperty("edges")) { + var edges = metamodel.edges, edge; + for (var edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + canvas.addTool(edge.label, new EdgeTool(edge.label, edge.relations)); + } + } + } + ViewManager$2.GetViewpointList(); + $("#btnCreateViewpoint").hide(); + $("#btnDelViewPoint").hide(); + var initTools = function (vvs) { + if (vvs && vvs.hasOwnProperty("nodes")) { + var nodes = vvs.nodes, node; + for (var nodeId in nodes) { + if (nodes.hasOwnProperty(nodeId)) { + node = nodes[nodeId]; + canvas.addTool(node.label, new NodeTool(node.label, null, null, node.shape.containment, node.shape.defaultWidth, node.shape.defaultHeight)); + } + } + } + if (vvs && vvs.hasOwnProperty("edges")) { + var edges = vvs.edges, edge; + for (var edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + canvas.addTool(edge.label, new EdgeTool(edge.label, edge.relations)); + } + } + } + }; + $("#btnShowView").click(function () { + var viewId = ViewManager$2.getViewIdOfSelected(); + var $currentViewIdLabel = $("#lblCurrentViewId"); + if (viewId === $currentViewIdLabel.text()) + return; + const viewsMap = y.getMap("views"); + var vvs = viewsMap.get(viewId); + EntityManagerInstance.initViewTypes(vvs); + var operation = new InitModelTypesOperation(vvs, true).toNonOTOperation(); + _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.PALETTE, operation); + _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.ATTRIBUTE, operation); + _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.METADATA, operation); + _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.OPENAPI, operation); + var activityOperation = new ActivityOperation("ViewApplyActivity", vvs.id, _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]); + _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.ACTIVITY, activityOperation.toNonOTOperation()); + const canvasMap = y.getMap("canvas"); + canvasMap.set("ViewApplyActivity", { + viewId: viewId, + jabberId: _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], + }); + initTools(vvs); + ViewGenerator.generate(metamodel, vvs); + $("#lblCurrentView").show(); + $currentViewIdLabel.text(viewId); + }); + $("#viewsHide").click(function () { + $(this).hide(); + $("#viewsShow").show(); + $("#ViewCtrlContainer").hide(); + var $lblCurrentViewId = $("#lblCurrentViewId"); + var viewpointId = $lblCurrentViewId.text(); + if (viewpointId.length > 0) { + var operation = new InitModelTypesOperation(metamodel, true); + _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.PALETTE, operation.toNonOTOperation()); + _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.ATTRIBUTE, operation.toNonOTOperation()); + var activityOperation = new ActivityOperation("ViewApplyActivity", "", _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]); + _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.ACTIVITY, activityOperation.toNonOTOperation()); + const canvasMap = y.getMap("canvas"); + canvasMap.set("ViewApplyActivity", { + viewId: "", + jabberId: _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], + }); + EntityManagerInstance.setViewId(null); + EntityManagerInstance.initModelTypes(metamodel); + initTools(metamodel); + ViewGenerator.reset(metamodel); + $("#lblCurrentView").hide(); + $lblCurrentViewId.text(""); + } + }); + var $saveImage = $("#save_image"); + $saveImage.show(); + $saveImage.click(function () { + canvas.toPNG().then(function (uri) { + var link = document.createElement("a"); + link.download = "export.png"; + link.href = uri; + link.click(); + }); + }); + } + else { + canvas.addTool(ObjectNode.TYPE, new ObjectNodeTool()); + canvas.addTool(AbstractClassNode.TYPE, new AbstractClassNodeTool()); + canvas.addTool(RelationshipNode.TYPE, new RelationshipNodeTool()); + canvas.addTool(RelationshipGroupNode.TYPE, new RelationshipGroupNodeTool()); + canvas.addTool(EnumNode.TYPE, new EnumNodeTool()); + canvas.addTool(NodeShapeNode.TYPE, new NodeShapeNodeTool()); + canvas.addTool(EdgeShapeNode.TYPE, new EdgeShapeNodeTool()); + canvas.addTool(GeneralisationEdge.TYPE, new GeneralisationEdgeTool()); + canvas.addTool(BiDirAssociationEdge.TYPE, new BiDirAssociationEdgeTool()); + canvas.addTool(UniDirAssociationEdge.TYPE, new UniDirAssociationEdgeTool()); + canvas.addTool(ViewObjectNode.TYPE, new ViewObjectNodeTool()); + canvas.addTool(ViewRelationshipNode.TYPE, new ViewRelationshipNodeTool()); + $("#btnCreateViewpoint").click(function () { + ShowViewCreateMenu(); + }); + $("#btnCancelCreateViewpoint").click(function () { + HideCreateMenu(); + }); + $("#btnShowView").click(function () { + var viewId = ViewManager$2.getViewIdOfSelected(); + if (viewId === $("#lblCurrentViewId").text()) + return; + $("#loading").show(); + $("#lblCurrentView").show(); + $("#lblCurrentViewId").text(viewId); + visualizeView(viewId); + }); + $("#btnDelViewPoint").click(function () { + const viewsMap = y.getMap("views"); + var viewId = ViewManager$2.getViewIdOfSelected(); + if (viewId && viewId !== $("#lblCurrentViewId").text()) { + viewsMap.delete(viewId); + _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.ATTRIBUTE, new DeleteViewOperation(viewId).toNonOTOperation()); + ViewManager$2.deleteView(viewId); + } + else { + viewsMap.set(viewId, null); + ViewManager$2.deleteView(viewId); + $("#viewsHide").click(); + } + }); + $("#btnAddViewpoint").click(function () { + var viewId = $("#txtNameViewpoint").val(); + if (ViewManager$2.existsView(viewId)) { + alert("View already exists"); + return; + } + ViewManager$2.addView(viewId); + HideCreateMenu(); + const canvasMap = y.getMap("canvas"); + canvasMap.set(UpdateViewListOperation.TYPE, true); + }); + $("#viewsHide").click(function () { + $(this).hide(); + $("#viewsShow").show(); + $("#ViewCtrlContainer").hide("fast"); + var $lblCurrentViewId = $("#lblCurrentViewId"); + const dataMap = y.getMap("data"); + if ($lblCurrentViewId.text().length > 0) { + var $loading = $("#loading"); + $loading.show(); + var model = dataMap.get("model"); + var operation = new SetViewTypesOperation(false); + _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.PALETTE, operation.toNonOTOperation()); + var activityOperation = new ActivityOperation("ViewApplyActivity", "", _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]); + _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.ACTIVITY, activityOperation.toNonOTOperation()); + const canvasMap = y.getMap("canvas"); + canvasMap.set("ViewApplyActivity", { + viewId: "", + jabberId: _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], + }); + resetCanvas(); + JSONtoGraph(model, canvas); + $("#loading").hide(); + canvas.resetTool(); + $("#lblCurrentView").hide(); + $lblCurrentViewId.text(""); + EntityManagerInstance.setViewId(null); + } + }); + } + var ShowViewCreateMenu = function () { + $("#btnCreateViewpoint").hide(); + $("#ddmViewSelection").hide(); + $("#btnShowView").hide(); + $("#btnDelViewPoint").hide(); + $("#txtNameViewpoint").show(); + $("#btnAddViewpoint").show(); + $("#btnCancelCreateViewpoint").show(); + }; + var HideCreateMenu = function () { + $("#btnCreateViewpoint").show(); + $("#ddmViewSelection").show(); + $("#btnDelViewPoint").show(); + $("#btnShowView").show(); + $("#txtNameViewpoint").hide(); + $("#btnAddViewpoint").hide(); + $("#btnCancelCreateViewpoint").hide(); + }; + function resetCanvas() { + var edges = EntityManagerInstance.getEdges(); + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + var edge = EntityManagerInstance.findEdge(edgeId); + edge.remove(); + } + } + var nodes = EntityManagerInstance.getNodes(); + for (const nodeId in nodes) { + if (nodes.hasOwnProperty(nodeId)) { + var node = EntityManagerInstance.findNode(nodeId); + node.remove(); + } + } + EntityManagerInstance.deleteModelAttribute(); + } + var visualizeView = function (viewId) { + const viewsMap = y.getMap("views"); + var viewData = viewsMap.get(viewId); + if (viewData) { + resetCanvas(); + ViewToGraph(viewData); + $("#lblCurrentView").show(); + $("#lblCurrentViewId").text(viewData.id); + EntityManagerInstance.setViewId(viewData.id); + canvas.resetTool(); + } + }; + function ViewToGraph(json) { + var operation = new ViewInitOperation(json); + _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.ATTRIBUTE, operation.toNonOTOperation()); + operation = new SetViewTypesOperation(true); + _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.PALETTE, operation.toNonOTOperation()); + var activityOperation = new ActivityOperation("ViewApplyActivity", json.id, _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]); + _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.ACTIVITY, activityOperation.toNonOTOperation()); + const canvasMap = y.getMap("canvas"); + canvasMap.set("ViewApplyActivity", { + viewId: json.id, + jabberId: _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], + }); + JSONtoGraph(json, canvas); + $("#loading").hide(); + canvas.resetTool(); + } + var $undo = $("#undo"); + $undo.prop("disabled", true); + var $redo = $("#redo"); + $redo.prop("disabled", true); + $undo.click(function () { + HistoryManagerInstance.undo(); + }); + $redo.click(function () { + HistoryManagerInstance.redo(); + }); + $("#showtype") + .click(function () { + canvas.get$node().removeClass("hide_type"); + $(this).hide(); + $("#hideType").show(); + }) + .hide(); + $("#hideType").click(function () { + canvas.get$node().addClass("hide_type"); + $(this).hide(); + $("#showtype").show(); + }); + $("#viewsShow").click(function () { + $(this).hide(); + $("#viewsHide").show(); + $("#ViewCtrlContainer").show("fast"); + }); + $("#zoomIn").click(function () { + canvas.setZoom(canvas.getZoom() + 0.1); + }); + $("#zoomOut").click(function () { + canvas.setZoom(canvas.getZoom() - 0.1); + }); + $("#applyLayout").click(function () { + const userMap = window.y.getMap("users"); + const canvasMap = window.y.getMap("canvas"); + canvasMap.set("applyLayout", userMap.get(window.y.clientID.toString())); + const activityMap = window.y.getMap("activity"); + activityMap.set("ApplyLayoutActivity", new ActivityOperation("ApplyLayoutActivity", null, userMap.get(window.y.clientID.toString()), "..applied Layout").toJSON()); + }); + var $feedback = $("#feedback"); + var saveFunction = function () { + $feedback.text("Saving..."); + var viewId = $("#lblCurrentViewId").text(); + if (viewId.length > 0 && !metamodel) { + ViewManager$2.updateViewContent(viewId); + $feedback.text("Saved!"); + setTimeout(function () { + $feedback.text(""); + }, 1000); + } + else { + EntityManagerInstance.storeDataYjs(); + $feedback.text("Saved!"); + setTimeout(function () { + $feedback.text(""); + }, 1000); + } + }; + $("#save").click(function () { + saveFunction(); + }); + $("#dialog").dialog({ + autoOpen: false, + resizable: false, + height: 350, + width: 400, + modal: true, + buttons: { + Generate: function (event) { + var title = $("#space_title").val(); + var label = $("#space_label") + .val() + .toString() + .replace(/[^a-zA-Z]/g, "") + .toLowerCase(); + if (title === "" || label === "") + return; + EntityManagerInstance.generateSpace(label, title).then(function (spaceObj) { + var operation = new ActivityOperation("EditorGenerateActivity", "-1", _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], '..generated new Editor ' + + spaceObj.spaceTitle + + "", {}).toNonOTOperation(); + _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.ACTIVITY, operation); + $("#space_link") + .text(spaceObj.spaceURI) + .attr({ href: spaceObj.spaceURI }) + .show(); + $("#space_link_text").show(); + $("#space_link_input").hide(); + $(event.target).parent().hide(); + }); + }, + Close: function () { + $(this).dialog("close"); + }, + }, + open: function () { + var name = canvas + .getModelAttributesNode() + .getAttribute("modelAttributes[name]") + .getValue() + .getValue(); + var $spaceTitle = $("#space_title"); + var $spaceLabel = $("#space_label"); + if ($spaceTitle.val() === "") + $spaceTitle.val(name); + if ($spaceLabel.val() === "") + $spaceLabel.val(name.replace(/[^a-zA-Z]/g, "").toLowerCase()); + $(":button:contains('Generate')").show(); + }, + close: function () { + $("#space_link_text").hide(); + $("#space_link_input").show(); + }, + }); + var $generate = $("#generate").click(function () { + $("#dialog").dialog("open"); + }); + if (!metamodel || + (!metamodel.hasOwnProperty("nodes") && !metamodel.hasOwnProperty("edges"))) { + $generate.show(); + } + if (metamodel) { + var op = new InitModelTypesOperation(metamodel); + _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.PALETTE, op.toNonOTOperation()); + _iwcw.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.ATTRIBUTE, op.toNonOTOperation()); + } + const $searchInput = $("#searchNodeInput"); + const $searchButton = $("#searchNodeButton"); + $searchButton.click(function () { + const searchValue = $searchInput.val(); + const searchResultNode = EntityManagerInstance.findObjectNodeByLabel(searchValue); + if (searchResultNode) { + canvas.scrollNodeIntoView(searchResultNode); + canvas.select(searchResultNode); + } + }); + $searchInput.keypress(function (e) { + if (e.which == 13) { + $searchButton.click(); + } + }); + if (model) { + var report = JSONtoGraph(model, canvas); + console.info("CANVAS: Initialization of model completed ", report); + const dataMap = y.getMap("data"); + if (EntityManagerInstance.getLayer() === CONFIG.LAYER.META) { + dataMap.set("guidancemetamodel", EntityManagerInstance.generateGuidanceMetamodel()); + dataMap.set("metamodelpreview", EntityManagerInstance.generateMetaModel()); + } + } + else { + if (canvas.getModelAttributesNode() === null) { + var modelAttributesNode = EntityManagerInstance.createModelAttributesNode(y); + modelAttributesNode.registerYMap(); + canvas.setModelAttributesNode(modelAttributesNode); + modelAttributesNode.addToCanvas(canvas); + } + } + const userId = _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]; + if (!joinMap.has(_iwcw.getUser()[CONFIG.NS.PERSON.JABBERID])) + joinMap.set(userId.toString(), false); + ViewManager$2.GetViewpointList(); + $spinner.hide(); +} + +/** + * The closed-view-generation(CVG) algorithm + * Searches for neighbors of a referenced object/relationship node and adds the neighbors to the viewpoint model + * @param viewType the view type node + * @constructor + */ +function CVG(viewType) { + //the metamodel as json from the y-space + const dataMap = y.getMap("data"); + var metamodel = dataMap.get("model"); + //initilaize the current metamodel using the graphlib.Graph + var metaGraph = new graphlib.Graph(); + lodash.forEach(metamodel.nodes, function (value, index) { + metaGraph.setNode(index, value); + }); + lodash.forEach(metamodel.edges, function (value, index) { + value.id = index; + metaGraph.setEdge(value.source, value.target, value); + }); + + var originId = viewType + .getAttribute(viewType.getEntityId() + "[target]") + .getValue() + .getValue(); + var neighborsOfOrigin = metaGraph.neighbors(originId); + var canvas = viewType.getCanvas(); + var viewpointName = $("#lblCurrentView").text().replace("View:", ""); + + lodash.forEach(neighborsOfOrigin, function (neighborId) { + var node = metaGraph.node(neighborId); + var newNodeId; + //if neighbor is shape or relation just add it and the corresponding assocation + if ( + node.type === "Node Shape" || + node.type === "Edge Shape" || + node.type === "Relation" + ) { + newNodeId = viewpointName + "_" + neighborId; + if (!EntityManagerInstance.findNode(newNodeId)) + canvas.createNode( + node.type, + node.left, + node.top, + node.width, + node.height, + node.zIndex, + node.containment, + node, + newNodeId + ); + } else if ( + viewType.getType() === "ViewObject" && + node.type === "Relationship" + ) { + var viewtypes = EntityManagerInstance.getNodesByType("ViewRelationship"); + for (var key in viewtypes) { + if (viewtypes.hasOwnProperty(key)) { + var viewType2 = viewtypes[key]; + if ( + viewType2 + .getAttribute(viewType2.getEntityId() + "[target]") + .getValue() + .getValue() === neighborId + ) + newNodeId = viewType2.getEntityId(); + } + } + } else if ( + viewType.getType() === "ViewRelationship" && + node.type === "Object" + ) { + var viewtypes = EntityManagerInstance.getNodesByType("ViewObject"); + for (var key in viewtypes) { + if (viewtypes.hasOwnProperty(key)) { + var viewType2 = viewtypes[key]; + if ( + viewType2 + .getAttribute(viewType2.getEntityId() + "[target]") + .getValue() + .getValue() === neighborId + ) + newNodeId = viewType2.getEntityId(); + } + } + } + if (newNodeId) { + var edge = metaGraph.edge(originId, neighborId); + if (!edge) { + //try the other direction + edge = metaGraph.edge(neighborId, originId); + canvas.createEdge( + edge.type, + newNodeId, + viewType.getEntityId(), + edge, + viewpointName + "_" + edge.id, + viewpointName + ); + } else { + canvas.createEdge( + edge.type, + viewType.getEntityId(), + newNodeId, + edge, + viewpointName + "_" + edge.id, + viewpointName + ); + } + } + }); } var ClosedViewGeneration = /*#__PURE__*/Object.freeze({ diff --git a/build/widgets/partials/main.widget.js.map b/build/widgets/partials/main.widget.js.map index c3bcd591..7410e056 100644 --- a/build/widgets/partials/main.widget.js.map +++ b/build/widgets/partials/main.widget.js.map @@ -1 +1 @@ -{"version":3,"file":"main.widget.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"} \ No newline at end of file +{"version":3,"file":"main.widget.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"} \ No newline at end of file diff --git a/build/widgets/partials/palette.widget.js b/build/widgets/partials/palette.widget.js index 0872c4f5..3e4cd66b 100644 --- a/build/widgets/partials/palette.widget.js +++ b/build/widgets/partials/palette.widget.js @@ -4,26 +4,26 @@ import { css, html, LitElement } from 'lit'; import { Doc } from 'yjs'; import { WebsocketProvider } from 'y-websocket'; -/****************************************************************************** -Copyright (c) Microsoft Corporation. - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. -***************************************************************************** */ - -function __decorate(decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; +/****************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */ + +function __decorate(decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; } /** @@ -19580,7 +19580,7 @@ if (symIterator) { lodash.prototype[symIterator] = seq.toIterator; } -const abstractToolHtml = "\r\n"; // replaced by importmap.plugin.js +const abstractToolHtml = "\n"; // replaced by importmap.plugin.js const DEFAULT_NODE_TOOL_ICON = ``; @@ -24717,14 +24717,14 @@ const DEFAULT_EDGE_ICONS = { bidirassociation: ``, }; -const circleNodeHtml = "
                  \r\n
                  <%= type %>
                  \r\n \r\n \"\r\n stroke=\"lightgray\"\r\n stroke-width=\"2\"\r\n />\r\n \r\n
                  \r\n
                  \r\n
                  \r\n\r\n"; // replaced by importmap.plugin.js -const diamondNodeHtml = "
                  \r\n
                  <%= type %>
                  \r\n \r\n \"\r\n stroke=\"lightgray\"\r\n stroke-width=\"2\"\r\n transform=\"rotate(-45 50 50)\"\r\n />\r\n \r\n
                  \r\n
                  \r\n
                  \r\n\r\n"; // replaced by importmap.plugin.js +const circleNodeHtml = "
                  \n
                  <%= type %>
                  \n \n \"\n stroke=\"lightgray\"\n stroke-width=\"2\"\n />\n \n
                  \n
                  \n
                  \n\n"; // replaced by importmap.plugin.js +const diamondNodeHtml = "
                  \n
                  <%= type %>
                  \n \n \"\n stroke=\"lightgray\"\n stroke-width=\"2\"\n transform=\"rotate(-45 50 50)\"\n />\n \n
                  \n
                  \n
                  \n\n"; // replaced by importmap.plugin.js -const rectangleNodeHtml = "
                  \r\n
                  <%= type %>
                  \r\n \r\n \"\r\n stroke=\"lightgray\"\r\n stroke-width=\"2\"\r\n />\r\n \r\n
                  \r\n
                  \r\n
                  \r\n\r\n"; // replaced by importmap.plugin.js +const rectangleNodeHtml = "
                  \n
                  <%= type %>
                  \n \n \"\n stroke=\"lightgray\"\n stroke-width=\"2\"\n />\n \n
                  \n
                  \n
                  \n\n"; // replaced by importmap.plugin.js -const roundedRectangleNodeHtml = "
                  \r\n
                  <%= type %>
                  \r\n \r\n \"\r\n stroke=\"lightgray\"\r\n stroke-width=\"2\"\r\n />\r\n \r\n
                  \r\n
                  \r\n
                  \r\n\r\n"; // replaced by importmap.plugin.js +const roundedRectangleNodeHtml = "
                  \n
                  <%= type %>
                  \n \n \"\n stroke=\"lightgray\"\n stroke-width=\"2\"\n />\n \n
                  \n
                  \n
                  \n\n"; // replaced by importmap.plugin.js -const triangleNodeHtml = "
                  \r\n
                  <%= type %>
                  \r\n \r\n \"\r\n stroke=\"lightgray\"\r\n stroke-width=\"2\"\r\n />\r\n \r\n
                  \r\n
                  \r\n
                  \r\n\r\n"; // replaced by importmap.plugin.js +const triangleNodeHtml = "
                  \n
                  <%= type %>
                  \n \n \"\n stroke=\"lightgray\"\n stroke-width=\"2\"\n />\n \n
                  \n
                  \n
                  \n\n"; // replaced by importmap.plugin.js /** * Palette diff --git a/build/widgets/partials/test.widget.js b/build/widgets/partials/test.widget.js index 931b6eb0..fed26441 100644 --- a/build/widgets/partials/test.widget.js +++ b/build/widgets/partials/test.widget.js @@ -3,26 +3,26 @@ import 'https://unpkg.com/jquery@3.6.0/dist/jquery.js'; import { Doc } from 'yjs'; import { WebsocketProvider } from 'y-websocket'; -/****************************************************************************** -Copyright (c) Microsoft Corporation. - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. -***************************************************************************** */ - -function __decorate(decorators, target, key, desc) { - var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; - if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); - else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; - return c > 3 && r && Object.defineProperty(target, key, r), r; +/****************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */ + +function __decorate(decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; } /** diff --git a/build/widgets/partials/viewcontrol.widget.js b/build/widgets/partials/viewcontrol.widget.js index e0dfdaf3..e979c152 100644 --- a/build/widgets/partials/viewcontrol.widget.js +++ b/build/widgets/partials/viewcontrol.widget.js @@ -18050,1720 +18050,1720 @@ if (symIterator) { lodash.prototype[symIterator] = seq.toIterator; } -const CONFIG = { - TEST: { - USER: "Luigi Test", - EMAIL: "luigi.test05@gmail.com", - CANVAS: false, - ATTRIBUTE: false, - PALETTE: false, - ACTIVITY: false, - }, - LAYER: { - META: "META", - MODEL: "MODEL", - }, - WIDGET: { - NAME: { - MAIN: "Canvas", - PALETTE: "Palette", - ATTRIBUTE: "Property Browser", - ACTIVITY: "User Activity", - GUIDANCE: "Guidance", - HEATMAP: "Heatmap", - METADATA: "METADATA", - OPENAPI: "Metadata Widget", - DEBUG: "Debug", - IMSLD_EXPORT: "IMSLD Export", - JSON_EXPORT: "JSON Export", - VIEWCONTROL: "View Control", - }, - }, - ENTITY: { - NODE: "node", - EDGE: "edge", - ATTR: "attr", - VAL: "val", - }, - IWC: { - FLAG: { - PUBLISH_GLOBAL: "PUBLISH_GLOBAL", - PUBLISH_LOCAL: "PUBLISH_LOCAL", - }, - ACTION: { - SYNC: "ACTION_SYNC", - DATA: "ACTION_DATA", - DATA_ARRAY: "ACTION_DATA_ARRAY", - }, - POSITION: { - NODE: { - ADD: 0, - DEL: 0, - POS: 1, - Z: 2, - DIM: 3, - }, - EDGE: { - ADD: 0, - DEL: 0, - MOV: 1, - }, - ATTR: { - ADD: 0, - DEL: 0, - }, - }, - }, - OPERATION: { - TYPE: { - INSERT: "insert", - UPDATE: "update", - DELETE: "delete", - }, - }, - ACTIVITY: { - TYPE: { - NODEADD: 0, - EDGEADD: 1, - NODEDEL: 2, - EDGEDEL: 3, - NODEATTRCHANGE: 4, - }, - }, - DATA: { - RELATION: { - GLOBAL: { - MAIN: { - MAIN: { - OPERATION: "MAIN2MAIN4OPERATION", - }, - }, - }, - LOCAL: { - PALETTE: { - MAIN: { - TOOLSELECTION: "PALETTE2MAIN4TOOLSELECTION", - }, - }, - MAIN: { - ATTRIBUTE: { - NODESELECTION: "MAIN2ATTRIBUTE4NODESELECTION", - NODEADDITION: "MAIN2ATTRIBUTE4NODEADDITION", - ATTRIBUTECHANGE: "MAIN2ATTRIBUTE4ATTRIBUTECHANGE", - }, - ACTIVITY: { - NEWACTIVITY: "MAIN2ACTIVITY4NEWACTIVITY", - }, - PALETTE: { - TOOLSELECTION: "MAIN2PALETTE4TOOLSELECTION", - }, - }, - ATTRIBUTE: { - MAIN: { - ATTRIBUTECHANGE: "ATTRIBUTE2MAIN4ATTRIBUTECHANGE", - }, - }, - }, - }, - }, - NS: { - PERSON: { - TITLE: "http://purl.org/dc/terms/title", - JABBERID: "http://xmlns.com/foaf/0.1/jabberID", - MBOX: "http://xmlns.com/foaf/0.1/mbox", - }, - MY: { - MODEL: "my:ns:model", - METAMODEL: "my:ns:metamodel", - INSTANCE: "my:ns:instance", - VIEWPOINT: "my:ns:viewpoint", - VIEW: "my:ns:view", - COPY: "my:ns:copy", - GUIDANCEMODEL: "my:ns:guidancemodel", - METAMODELPREVIEW: "my:ns:metamodelpreview", - GUIDANCEMETAMODEL: "my:ns:guidancemetamodel", - LOGICALGUIDANCEREPRESENTATION: "my:ns:logicalguidancerepresentation", - }, - }, -}; - - /** - * Gets the html tag name of a widget. - * Use this function to get the tag name of a or your own widget. - * @example getWidgetTagName("My Widget") // returns "my-widget-widget" - * @param {*} name name of the widget - * @returns {string} tag name of the widget - */ -function getWidgetTagName(name) { - if (!name) return; - if ( - !Object.values(CONFIG.WIDGET.NAME).some( - (n) => n.toLocaleLowerCase() === name.toLocaleLowerCase() - ) - ) { - console.warn( - `Widget name ${name} is not defined in config.js. Add it to the CONFIG.WIDGET.NAME object.` - ); - } - let widgetName = name; - widgetName = widgetName.replace(/\s+/g, "-"); - return `${widgetName}-widget`.toLowerCase(); -} - -class OpenAppProvider { - openapp; - gadgets; - constructor() { - var openapp = {}; - this.openapp = openapp; - openapp["event"] = {}; - var gadgets = "undefined" !== typeof this.gadgets ? this.gadgets : {}; - this.gadgets = gadgets; - gadgets.openapp = gadgets.openapp || {}; - var usePostMessage = - "undefined" !== typeof window && - "undefined" !== typeof window.parent && - "undefined" !== typeof window.postMessage && - "undefined" !== typeof JSON && - "undefined" !== typeof JSON.parse && - "undefined" !== typeof JSON.stringify, - usePubSub = - !usePostMessage && - "undefined" !== typeof gadgets && - "undefined" !== typeof gadgets.pubsub && - "undefined" !== typeof gadgets.pubsub.subscribe && - "undefined" !== typeof gadgets.pubsub.unsubscribe && - "undefined" !== typeof gadgets.pubsub.publish, - init = { postParentOnly: true }, - ownData, - doCallback, - onMessage; - usePostMessage - ? ((onMessage = function (a) { - if ( - "string" === typeof a.data && - '{"OpenApplicationEvent":{' === a.data.slice(0, 25) - ) { - var b = JSON.parse(a.data).OpenApplicationEvent; - if ( - "openapp" === b.event && - !0 === b.welcome && - a.source === window.parent - ) { - for (var d in b.message) { - b.message.hasOwnProperty(d) && (init[d] = b.message[d]); - } - } else { - (b.source = a.source), - (b.origin = a.origin), - (b.toJSON = function () { - var a = {}, - b; - for (b in this) { - this.hasOwnProperty(b) && - "function" !== typeof this[b] && - "source" !== b && - "origin" !== b && - (a[b] = this[b]); - } - return a; - }), - "function" === typeof doCallback && - // @ts-ignore - !0 === doCallback(b, b.message) && - window.parent.postMessage( - JSON.stringify({ - OpenApplicationEvent: { event: "openapp", receipt: !0 }, - }), - "*" - ); - } - } - }), - // @ts-ignore - "undefined" !== typeof window.attachEvent - ? // @ts-ignore - window.attachEvent("onmessage", onMessage) - : window.addEventListener("message", onMessage, !1), - "undefined" !== typeof window.parent && - window.parent.postMessage( - JSON.stringify({ - OpenApplicationEvent: { event: "openapp", hello: !0 }, - }), - "*" - )) - : usePubSub && - (onMessage = function (a, b) { - b.source = void 0; - b.origin = void 0; - b.sender = a; - "function" === typeof doCallback && - // @ts-ignore - !0 === doCallback(b, b.message) && - gadgets.pubsub.publish("openapp-recieve", !0); - }); - gadgets.openapp.RDF = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; - gadgets.openapp.connect = function (a) { - doCallback = a; - usePubSub && gadgets.pubsub.subscribe("openapp", onMessage); - }; - gadgets.openapp.disconnect = function () { - usePubSub && gadgets.pubsub.unsubscribe("openapp"); - doCallback = null; - }; - gadgets.openapp.publish = function (a, b) { - a.event = a.event || "select"; - a.type = a.type || "namespaced-properties"; - a.sharing = a.sharing || "public"; - a.date = a.date || new Date(); - a.message = b || a.message; - if (usePostMessage) { - if (!1 === init.postParentOnly && null === ownData) { - // @ts-ignore - ownData = { sender: "unknown", viewer: "unknown" }; - if ( - "undefined" !== typeof window.location && - "string" === typeof window.location.search && - "function" === typeof window.unescape - ) { - var d = window.location.search.substring(1).split("&"), - c, - e = {}; - if (!(1 == d.length && "" === d[0])) { - for (var f = 0; f < d.length; f++) { - (c = d[f].split("=")), - 2 == c.length && (e[c[0]] = window.unescape(c[1])); - } - } - // @ts-ignore - "string" === typeof e.url && (ownData.sender = e.url); - } - if ( - // @ts-ignore - "undefined" !== typeof opensocial && - // @ts-ignore - "function" === typeof opensocial.newDataRequest - ) { - // @ts-ignore - d = opensocial.newDataRequest(); - // @ts-ignore - d.add( - // @ts-ignore - d.newFetchPersonRequest(opensocial.IdSpec.PersonId.VIEWER), - "viewer" - ); - var g = this; - // @ts-ignore - d.send(function (c) { - c = c.get("viewer").getData(); - "object" === typeof c && - null !== c && - "function" === typeof c.getId && - ((c = c.getId()), - // @ts-ignore - "string" === typeof c && (ownData.viewer = c)); - g.publish(a, b); - }); - return; - } - } - null !== ownData && - // @ts-ignore - ("string" === typeof ownData.sender && (a.sender = ownData.sender), - // @ts-ignore - "string" === typeof ownData.viewer && (a.viewer = ownData.viewer)); - // @ts-ignore - d = JSON.stringify({ OpenApplicationEvent: a }); - // @ts-ignore - if ("undefined" !== window.parent) { - if ((window.parent.postMessage(d, "*"), !init.postParentOnly)) { - c = window.parent.frames; - // @ts-ignore - for (e = 0; e < c.length; e++) { - // @ts-ignore - c[e].postMessage(d, "*"); - } - } - } else { - window.postMessage(d, "*"); - } - } else { - usePubSub && gadgets.pubsub.publish("openapp", a); - } - }; - openapp["io"] = {}; - openapp["io"].createXMLHttpRequest = function () { - if ("undefined" !== typeof XMLHttpRequest) { - return new XMLHttpRequest(); - } - // @ts-ignore - if ("undefined" !== typeof ActiveXObject) { - // @ts-ignore - return new ActiveXObject("Microsoft.XMLHTTP"); - } - throw { - name: "XMLHttpRequestError", - message: "XMLHttpRequest not supported", - }; - }; - openapp["io"].makeRequest = function (a, b, d) { - gadgets.io.makeRequest( - a, - function (c) { - var e, f, g, h, j, k, l, p; - if (null === document.getElementById("oauthPersonalize")) { - e = document.createElement("div"); - f = document.createElement("input"); - g = document.createElement("input"); - h = document.createElement("div"); - j = document.createElement("input"); - k = document.createElement("div"); - l = document.createElement("span"); - p = document.createElement("input"); - e.id = "oauthPersonalize"; - f.id = "oauthPersonalizeButton"; - g.id = "oauthPersonalizeDenyButton"; - h.id = "oauthPersonalizeDone"; - j.id = "oauthPersonalizeDoneButton"; - k.id = "oauthPersonalizeComplete"; - l.id = "oauthPersonalizeMessage"; - p.id = "oauthPersonalizeHideButton"; - f.id = "oauthPersonalizeButton"; - e.style.display = "none"; - h.style.display = "none"; - k.style.display = "none"; - f.type = "button"; - g.type = "button"; - j.type = "button"; - p.type = "button"; - f.value = "Continue"; - g.value = "Ignore"; - j.value = "Done"; - p.value = "Hide"; - e.appendChild( - document.createTextNode( - "In order to provide the full functionality of this tool, access to your personal data is being requested." - ) - ); - h.appendChild( - document.createTextNode( - "If you have provided authorization and are still reading this, click the Done button." - ) - ); - var m = document.getElementById("openappDialog"); - null == m && - ((m = document.createElement("div")), - null != document.body.firstChild - ? document.body.insertBefore(m, document.body.firstChild) - : document.body.appendChild(m)); - m.appendChild(e); - m.appendChild(h); - m.appendChild(k); - e.appendChild(f); - e.appendChild(g); - h.appendChild(j); - k.appendChild(l); - k.appendChild(p); - g.onclick = function () { - e.style.display = "none"; - }; - p.onclick = function () { - k.style.display = "none"; - }; - } - if (c.oauthApprovalUrl) { - var r = function () { - q && (window.clearInterval(q), (q = null)); - // @ts-ignore - n && (n.close(), (n = null)); - // @ts-ignore - document.getElementById("oauthPersonalizeDone").style.display = - "none"; - // @ts-ignore - document.getElementById( - "oauthPersonalizeComplete" - ).style.display = "block"; - openapp["io"].makeRequest(a, b, d); - return !1; - }, - s = function () { - // @ts-ignore - if (!n || n.closed) { - (n = null), r(); - } - }, - t = c.oauthApprovalUrl, - n = null, - q = null; - c = { - createOpenerOnClick: function () { - return function () { - // @ts-ignore - if ((n = window.open(t, "_blank", "width=450,height=500"))) { - // @ts-ignore - (q = window.setInterval(s, 100)), - // @ts-ignore - (document.getElementById( - "oauthPersonalize" - ).style.display = "none"), - // @ts-ignore - (document.getElementById( - "oauthPersonalizeDone" - ).style.display = "block"); - } - return !1; - }; - }, - createApprovedOnClick: function () { - return r; - }, - }; - // @ts-ignore - document.getElementById("oauthPersonalizeButton").onclick = - c.createOpenerOnClick(); - // @ts-ignore - document.getElementById("oauthPersonalizeDoneButton").onclick = - c.createApprovedOnClick(); - f = "Please wait."; - document.all - ? // @ts-ignore - (document.getElementById("oauthPersonalizeMessage").innerText = - f) - : // @ts-ignore - (document.getElementById( - "oauthPersonalizeMessage" - ).textContent = f); - // @ts-ignore - document.getElementById("oauthPersonalize").style.display = "block"; - } else { - c.oauthError - ? ((f = - "The authorization was not completed successfully. (" + - c.oauthError + - ")"), - document.all - ? // @ts-ignore - (document.getElementById( - "oauthPersonalizeMessage" - ).innerText = f) - : // @ts-ignore - (document.getElementById( - "oauthPersonalizeMessage" - ).textContent = f), - // @ts-ignore - (document.getElementById( - "oauthPersonalizeComplete" - ).style.display = "block")) - : ((f = - "You have now granted authorization. To revoke authorization, go to your Privacy settings."), - document.all - ? // @ts-ignore - (document.getElementById( - "oauthPersonalizeMessage" - ).innerText = f) - : // @ts-ignore - (document.getElementById( - "oauthPersonalizeMessage" - ).textContent = f), - b(c)); - } - }, - d - ); - }; - openapp["ns"] = {}; - openapp["ns"].rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; - openapp["ns"].rdfs = "http://www.w3.org/2000/01/rdf-schema#"; - openapp["ns"].dcterms = "http://purl.org/dc/terms/"; - openapp["ns"].foaf = "http://xmlns.com/foaf/0.1/"; - openapp["ns"].rest = "http://purl.org/openapp/"; - openapp["ns"].conserve = "http://purl.org/openapp/"; - openapp["ns"].openapp = "http://purl.org/openapp/"; - openapp["ns"].role = "http://purl.org/role/terms/"; - openapp["ns"].widget = "http://purl.org/role/widget/"; - openapp["resource"] = {}; - var linkexp = - /<[^>]*>\s*(\s*;\s*[^\(\)<>@,;:"\/\[\]\?={} \t]+=(([^\(\)<>@,;:"\/\[\]\?={} \t]+)|("[^"]*")))*(,|\$)/g, - paramexp = - /[^\(\)<>@,;:"\/\[\]\?={} \t]+=(([^\(\)<>@,;:"\/\[\]\?={} \t]+)|("[^"]*"))/g; - function unquote(a) { - return '"' === a.charAt(0) && '"' === a.charAt(a.length - 1) - ? a.substring(1, a.length - 1) - : a; - } - function parseLinkHeader(a) { - var b = (a + ",").match(linkexp); - a = {}; - var d = {}, - c = {}, - e, - f, - g, - h, - j, - k; - for (e = 0; e < b.length; e++) { - f = b[e].split(">"); - g = f[0].substring(1); - h = f[1]; - f = {}; - f.href = g; - g = h.match(paramexp); - for (h = 0; h < g.length; h++) { - (j = g[h]), (j = j.split("=")), (k = j[0]), (f[k] = unquote(j[1])); - } - void 0 !== f.rel && "undefined" === typeof f.anchor && (a[f.rel] = f); - void 0 !== f.title && - "undefined" === typeof f.anchor && - (d[f.title] = f); - g = c[f.anchor || ""] || {}; - h = g[f.rel || "http://purl.org/dc/terms/relation"] || []; - h.push({ type: "uri", value: f.href }); - g[f.rel || "http://purl.org/dc/terms/relation"] = h; - c[f.anchor || ""] = g; - } - // @ts-ignore - b = {}; - // @ts-ignore - b.rels = a; - // @ts-ignore - b.titles = d; - // @ts-ignore - b.rdf = c; - return b; - } - var isStringValue = function (a) { - return "" !== a && "string" === typeof a; - }; - openapp["resource"].makeRequest = function (a, b, d, c, e, f) { - var g = openapp["io"].createXMLHttpRequest(), - h, - j = 0; - if ("undefined" !== typeof c) { - for (h in c) { - c.hasOwnProperty(h) && j++; - } - if (0 < j) { - // @ts-ignore - j = ""; - -1 !== b?.indexOf("?") && - ((j = b?.substring(b.indexOf("?"))), - // @ts-ignore - (b = b?.substring(0, b.length - j.length))); - switch (b?.substring(b.length - 1)) { - case "/": - b += ":"; - break; - case ":": - break; - default: - b += "/:"; - } - for (h in c) { - c.hasOwnProperty(h) && - (b = - h === openapp["ns"].rdf + "predicate" - ? b + (";predicate=" + encodeURIComponent(c[h])) - : b + - (";" + - encodeURIComponent(h) + - "=" + - encodeURIComponent(c[h]))); - } - b += j; - } - } - g.open(a, b, !0); - g.setRequestHeader("Accept", "application/json"); - e = e || ""; - if (0 < e.length || "POST" === a || "PUT" === a) { - g.setRequestHeader( - "Content-Type", - "undefined" !== typeof f ? f : "application/json" - ); - } - d = d || function () {}; - g.onreadystatechange = function () { - if (4 === g.readyState) { - var a = { - data: g.responseText, - link: isStringValue(g.getResponseHeader("link")) - ? parseLinkHeader(g.getResponseHeader("link")) - : {}, - }; - isStringValue(g.getResponseHeader("location")) - ? (a["uri"] = g.getResponseHeader("location")) - : isStringValue(g.getResponseHeader("content-base")) - ? (a["uri"] = g.getResponseHeader("content-base")) - : a["link"].hasOwnProperty("http://purl.org/dc/terms/subject") && - (a["uri"] = a["link"]["http://purl.org/dc/terms/subject"].href); - isStringValue(g.getResponseHeader("content-location")) && - (a["contentUri"] = g.getResponseHeader("content-location")); - isStringValue(g.getResponseHeader("content-type")) && - "application/json" === - g.getResponseHeader("content-type").split(";")[0] && - (a.data = JSON.parse(a.data)); - a["subject"] = - "undefined" !== typeof g.responseText - ? a.data.hasOwnProperty("") - ? a.data[""] - : a.data[a["uri"]] || {} - : {}; - d(a); - } - }; - g.send(e); - }; - // @ts-ignore - "undefined" === typeof openapp_forceXhr && - "undefined" !== typeof gadgets && - "undefined" !== typeof gadgets.io && - "undefined" !== typeof gadgets.io.makeRequest && - (openapp["resource"].makeRequest = function (a, b, d, c, e, f) { - var g = {}, - h, - j = 0; - if ("undefined" !== typeof c) { - for (h in c) { - c.hasOwnProperty(h) && j++; - } - if (0 < j) { - // @ts-ignore - j = ""; - -1 !== b.indexOf("?") && - ((j = b.substring(b.indexOf("?"))), - // @ts-ignore - (b = b.substring(0, b.length - j.length))); - switch (b.substring(b.length - 1)) { - case "/": - b += ":"; - break; - case ":": - break; - default: - b += "/:"; - } - for (h in c) { - c.hasOwnProperty(h) && - (b = - h === openapp["ns"].rdf + "predicate" - ? b + (";predicate=" + encodeURIComponent(c[h])) - : b + - (";" + - encodeURIComponent(h) + - "=" + - encodeURIComponent(c[h]))); - } - b += j; - } - } - g[gadgets.io.RequestParameters.GET_FULL_HEADERS] = !0; - g[gadgets.io.RequestParameters.CONTENT_TYPE] = - gadgets.io.ContentType.TEXT; - g[gadgets.io.RequestParameters.AUTHORIZATION] = - gadgets.io.AuthorizationType.OAUTH; - g[gadgets.io.RequestParameters.OAUTH_SERVICE_NAME] = "openapp"; - g[gadgets.io.RequestParameters.OAUTH_USE_TOKEN] = "always"; - g[gadgets.io.RequestParameters.METHOD] = a; - g[gadgets.io.RequestParameters.HEADERS] = - g[gadgets.io.RequestParameters.HEADERS] || {}; - "undefined" !== typeof e && - null !== e && - ((g[gadgets.io.RequestParameters.HEADERS]["Content-Type"] = - "undefined" !== typeof f ? f : "application/json"), - (g[gadgets.io.RequestParameters.POST_DATA] = e)); - g[gadgets.io.RequestParameters.HEADERS].Accept = "application/json"; - d = d || function () {}; - openapp["io"].makeRequest( - b, - function (a) { - var b = { - data: a.data, - link: - "undefined" !== typeof a.headers.link - ? parseLinkHeader(a.headers.link[0]) - : {}, - }; - a.headers.hasOwnProperty("location") - ? (b["uri"] = a.headers.location[0]) - : a.headers.hasOwnProperty("content-base") - ? (b["uri"] = a.headers["content-base"][0]) - : // @ts-ignore - b["link"].hasOwnProperty("http://purl.org/dc/terms/subject") && - // @ts-ignore - (b["uri"] = b["link"]["http://purl.org/dc/terms/subject"].href); - a.headers.hasOwnProperty("content-location") && - (b["contentUri"] = a.headers["content-location"][0]); - a.headers.hasOwnProperty("content-type") && - "application/json" === - a.headers["content-type"][0].split(";")[0] && - (b.data = gadgets.json.parse(b.data)); - b["subject"] = - "undefined" !== typeof a.data - ? b.data.hasOwnProperty("") - ? b.data[""] - : b.data[b["uri"]] || {} - : {}; - d(b); - }, - g - ); - }); - openapp["resource"].get = function (a, b, d) { - return openapp["resource"].makeRequest( - "GET", - a, - b, - d || { - "http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate": - openapp["ns"].conserve + "info", - } - ); - }; - openapp["resource"].post = function (a, b, d, c, e) { - return openapp["resource"].makeRequest("POST", a, b, d, c, e); - }; - openapp["resource"].put = function (a, b, d, c, e) { - return openapp["resource"].makeRequest("PUT", a, b, d, c, e); - }; - openapp["resource"].del = function (a, b, d) { - return openapp["resource"].makeRequest("DELETE", a, b, d); - }; - openapp["resource"].context = function (a) { - return { - sub: function (b) { - var d = {}; - return { - control: function (a, b) { - d[a] = b; - return this; - }, - type: function (a) { - return this.control(openapp["ns"].rdf + "type", a); - }, - seeAlso: function (a) { - return this.control(openapp["ns"].rdfs + "seeAlso", a); - }, - list: function () { - var c = [], - e = a["subject"][b], - f, - g, - h, - j, - k, - l; - if ("undefined" === typeof e) { - return c; - } - h = 0; - a: for (; h < e.length; h++) { - f = e[h]; - g = a.data[f.value]; - for (j in d) { - if (d.hasOwnProperty(j)) { - if (!g.hasOwnProperty(j)) { - continue a; - } - l = !1; - for (k = 0; k < g[j].length; k++) { - if (g[j][k].value === d[j]) { - l = !0; - break; - } - } - if (!l) { - continue a; - } - } - } - // @ts-ignore - c.push({ data: a.data, link: {}, uri: f.value, subject: g }); - } - return c; - }, - create: function (c) { - if (!a["link"].rdf.hasOwnProperty(b)) { - throw ( - "The context does not support the requested relation: " + b - ); - } - var e = a["uri"]; - d[openapp["ns"].rdf + "predicate"] = b; - openapp["resource"].post( - e, - function (a) { - c(a); - }, - d - ); - }, - }; - }, - metadata: function () { - return openapp["resource"] - .context(a) - .content(openapp["ns"].rest + "metadata"); - }, - representation: function () { - return openapp["resource"] - .context(a) - .content(openapp["ns"].rest + "representation"); - }, - content: function (b) { - return { - get: function (d) { - openapp["resource"].get( - a["uri"], - function (a) { - d(a); - }, - { "http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate": b } - ); - }, - mediaType: function (d) { - var c = null; - return { - string: function (a) { - c = a; - return this; - }, - json: function (a) { - c = JSON.stringify(a); - return this; - }, - put: function (e) { - openapp["resource"].put( - a["uri"], - function (a) { - "function" === typeof e && e(a); - }, - { - "http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate": b, - }, - c, - d - ); - }, - }; - }, - string: function (a) { - return this.mediaType("text/plain").string(a); - }, - json: function (a) { - return this.mediaType("application/json").json(a); - }, - graph: function () { - var d = {}, - c = ""; - return { - subject: function (a) { - c = a; - return this; - }, - resource: function (a, b) { - d[c] = d[c] || {}; - d[c][a] = d[c][a] || []; - d[c][a].push({ value: b, type: "uri" }); - return this; - }, - literal: function (a, b, g, h) { - d[c] = d[c] || {}; - d[c][a] = d[c][a] || []; - d[c][a].push({ - value: b, - type: "literal", - lang: g, - datatype: h, - }); - return this; - }, - put: function (c) { - openapp["resource"].put( - a["uri"], - function (a) { - "function" === typeof c && c(a); - }, - { - "http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate": b, - }, - JSON.stringify(d) - ); - }, - }; - }, - }; - }, - properties: function () { - var b = {}, - d; - for (d in a["subject"]) { - a["subject"].hasOwnProperty(d) && (b[d] = a["subject"][d][0].value); - } - return b; - }, - string: function () { - return "string" === typeof a.data - ? a.data - : gadgets.json.stringify(a.data); - }, - json: function () { - return "string" === typeof a.data ? null : a.data; - }, - followSeeAlso: function () { - var b = a["subject"][openapp["ns"].rdfs + "seeAlso"], - d = 0, - c, - e; - if ("undefined" !== typeof b) { - b = b[0].value; - for ( - e = 0; - e < b.length && - e < a["uri"].length && - b.charAt(e) === a["uri"].charAt(e); - e++ - ) { - "/" === b.charAt(e) && d++; - } - for (c = d; e < b.length; e++) { - "/" === b.charAt(e) && c++; - } - return 3 > d || 4 < c - ? this - : openapp["resource"].context({ - data: a.data, - link: {}, - uri: b, - subject: a.data[b], - }); - } - return this; - }, - }; - }; - openapp["resource"].content = function (a) { - return { - properties: function () { - return openapp["resource"].context(a).properties(); - }, - string: function () { - return openapp["resource"].context(a).string(); - }, - json: function () { - return openapp["resource"].context(a).json(); - }, - }; - }; - openapp["oo"] = {}; - openapp["oo"].Resource = function (a, b, d) { - this.uri = a; - this.context = b; - this.info = d; - }; - var OARP = openapp["oo"].Resource.prototype; - OARP.getURI = function () { - return this.uri; - }; - OARP._call = function (a) { - var b = this; - null == this.context - ? null == this._deferred - ? ((this._deferred = [a]), - openapp["resource"].get(this.uri, function (a) { - b.context = a; - a = b._deferred; - delete b._deferred; - for (var c = 0; c < a.length; c++) { - a[c].call(b); - } - })) - : this._deferred.push(a) - : a.call(b); - }; - OARP.refresh = function (a) { - delete this.context; - delete this.info; - a && - this._call(function () { - a(); - }); - }; - OARP.getSubResources = function (a) { - this._call(function () { - for ( - var b = - null != a.type - ? openapp["resource"] - .context(this.context) - .sub(a.relation) - .type(a.type) - .list() - : openapp["resource"] - .context(this.context) - .sub(a.relation) - .list(), - d = [], - c = 0; - c < b.length; - c++ - ) { - var e = b[c].uri; - if (a.followReference) { - var f = - this.context.data[e]["http://www.w3.org/2002/07/owl#sameAs"]; - null != f && 0 < f.length && (e = f[0].value); - } - f = new openapp["oo"].Resource(e, null, b[c]); - null == a.followReference && - ((f._referenceLoaded = !0), - (e = this.context.data[e]["http://www.w3.org/2002/07/owl#sameAs"]), - null != e && 0 < e.length && (f._reference = e[0].value)); - if (a.onEach) { - a.onEach(f); - } - a.onAll && d.push(f); - } - if (a.onAll) { - a.onAll(d); - } - }); - }; - OARP.followReference = function (a) { - this._referenceLoaded - ? a( - null != this._reference - ? new openapp["oo"].Resource(this._reference) - : this - ) - : this._call(function () { - var b = - this.context.data[this.uri][ - "http://www.w3.org/2002/07/owl#sameAs" - ]; - null != b && 0 < b.length - ? a(new openapp["oo"].Resource(b[0].value)) - : a(this); - }); - }; - OARP.getReference = function (a) { - this._referenceLoaded - ? a(this._reference) - : this._call(function () { - var b = this.context.subject[openapp["ns"].rdfs + "seeAlso"]; - null != b && 0 < b.length - ? a(this.context.subject[openapp["ns"].rdfs + "seeAlso"][0].value) - : a(); - }); - }; - OARP.getMetadata = function (a, b) { - this._call(function () { - openapp["resource"] - .context(this.context) - .metadata() - .get(function (d) { - switch (a || "properties") { - case "properties": - b(openapp["resource"].context(d).properties()); - break; - case "graph": - b(openapp["resource"].content(d).graph()); - break; - case "rdfjson": - b(openapp["resource"].content(d).json()); - } - }); - }); - }; - OARP.getInfo = function (a) { - if (a) { - this.context || this.info - ? a( - openapp["resource"] - .context(this.context || this.info) - .properties() - ) - : this._call(function () { - a( - openapp["resource"] - .context(this.context || this.info) - .properties() - ); - }); - } else { - if (this.context || this.info) { - return openapp["resource"] - .context(this.context || this.info) - .properties(); - } - } - }; - OARP.getRepresentation = function (a, b) { - this._call(function () { - openapp["resource"] - .context(this.context) - .representation() - .get(function (d) { - switch (a || "text/html") { - case "properties": - b(openapp["resource"].context(d).properties()); - break; - case "graph": - b(openapp["resource"].content(d).graph()); - break; - case "rdfjson": - b(openapp["resource"].content(d).json()); - break; - case "text/html": - b(openapp["resource"].content(d).string()); - } - }); - }); - }; - OARP.setMetadata = function (a, b, d) { - var c = {}; - switch (b || "properties") { - case "properties": - b = {}; - for (var e in a) { - b[e] = [{ type: "literal", value: a[e] }]; - } - c[this.context.uri] = b; - break; - case "rdfjson": - c = a; - break; - case "graph": - // @ts-ignore - graph.put(d); - return; - } - openapp["resource"].put( - this.context.uri, - d, - { - "http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate": - openapp["ns"].rest + "metadata", - }, - JSON.stringify(c) - ); - }; - OARP.setRepresentation = function (a, b, d) { - this._call(function () { - var c = openapp["resource"] - .context(this.context) - .representation() - .mediaType(b); - "string" === typeof a ? c.string(a).put(d) : c.json(a).put(d); - }); - }; - OARP.create = function (a) { - this._call(function () { - var b = openapp["resource"] - .context(this.context) - .sub(a.relation || openapp["ns"].role + "data"); - null != a.referenceTo && (b = b.seeAlso(a.referenceTo)); - null != a.type && (b = b.type(a.type)); - b.create(function (b) { - var c = new openapp["oo"].Resource(b["uri"], b); - a.metadata - ? c.setMetadata(a.metadata, a.format, function () { - a.representation - ? c.setRepresentation( - a.representation, - a.medieType || "application/json", - function () { - a.callback(c); - } - ) - : a.callback(c); - }) - : a.representation - ? c.setRepresentation( - a.representation, - a.medieType || "application/json", - function () { - a.callback(c); - } - ) - : a.callback(c); - }); - }); - }; - OARP.del = function (a) { - openapp["resource"].del(this.uri, a); - }; - openapp["param"] = {}; - var parseQueryParams = function (a) { - var b, - d, - c = {}; - if (0 > a.indexOf("?")) { - return {}; - } - a = a.substr(a.indexOf("?") + 1).split("&"); - if (!(1 == a.length && "" === a[0])) { - for (d = 0; d < a.length; d++) { - (b = a[d].split("=")), - 2 == b.length && (c[b[0]] = window.unescape(b[1])); - } - } - return c; - }, - parseOpenAppParams = function (a) { - var b = {}, - d = {}, - c, - e; - for (c in a) { - a.hasOwnProperty(c) && - "openapp['ns']." === c.substring(0, 11) && - (b[c.substr(11)] = a[c]); - } - for (c in a) { - a.hasOwnProperty(c) && - ((e = c.split(".")), - 3 === e.length && - "openapp" === e[0] && - b.hasOwnProperty(e[1]) && - (d[b[e[1]] + e[2]] = a[c])); - } - return d; - }, - _openAppParams = parseOpenAppParams( - parseQueryParams(parseQueryParams(window.location.href)["url"] || "") - ); - openapp["param"].get = function (a) { - return _openAppParams[a]; - }; - openapp["param"].space = function () { - return openapp["param"].get("http://purl.org/role/terms/space"); - }; - openapp["param"].user = function () { - return openapp["param"].get("http://purl.org/role/terms/user"); - }; - } -} - -const openapp$2 = new OpenAppProvider().openapp; -/** - * Util - * @class Util - * @name Util - * @constructor - */ -var Util = { - /** - * Generate random hex string - * @param {number} [length] Length of string (Default=24) - * @returns {string} - */ - generateRandomId: function (length) { - var chars = "1234567890abcdef"; - var numOfChars = chars.length; - var i, rand; - var res = ""; - - if (typeof length === "undefined") length = 24; - - for (i = 0; i < length; i++) { - rand = Math.floor(Math.random() * numOfChars); - res += chars[rand]; - } - return res; - }, - - generateAnonymousUser: function () { - const user = {}; - var id = this.generateRandomId(); - user[CONFIG.NS.PERSON.TITLE] = "Anonymous"; - user[CONFIG.NS.PERSON.JABBERID] = id; - user[CONFIG.NS.PERSON.MBOX] = id + "@anonym.com"; - user.globalId = -1; - user.self = true; - return user; - }, - - /** - * Wait for delay milliseconds then return - * @param delay - * @returns {promise} - */ - delay: function (delay) { - var deferred = jQuery.Deferred(); - setTimeout(function () { - deferred.resolve(); - }, delay); - return deferred.promise(); - }, - - /** - * Union the two passed objects into a new object (on a duplicate key, the first object has priority) - * @param {object} obj1 - * @param {object} obj2 - * @returns {object} - */ - union: function (obj1, obj2) { - var res = {}, - i; - for (i in obj1) { - if (obj1.hasOwnProperty(i)) { - res[i] = obj1[i]; - } - } - for (i in obj2) { - if (obj2.hasOwnProperty(i) && !obj1.hasOwnProperty(i)) { - res[i] = obj2[i]; - } - } - return res; - }, - - /** - * Merge the elements of the second object into the first (on a duplicate key, the first object has priority) - * @param {object} obj1 - * @param {object} obj2 - * @returns {object} - */ - merge: function (obj1, obj2) { - var i; - for (i in obj2) { - if (obj2.hasOwnProperty(i) && !obj1.hasOwnProperty(i)) { - obj1[i] = obj2[i]; - } - } - return obj1; - }, - - /** - * Converts an async function that expects a callback as last parameter into a promise - * @param func - * @returns {promise} - */ - toPromise: function (func) { - return function () { - //noinspection JSAccessibilityCheck - var args = Array.prototype.slice.call(arguments); - var deferred = jQuery.Deferred(); - args.push(function () { - deferred.resolve.apply(this, arguments); - }); - func.apply(this, args); - return deferred.promise(); - }; - }, - - COLORS: [ - "#8AFFC8", //türkis - "#8A9FFF", //light blue - "#FF8A8A", //Rot - "#FFC08A", //Orange - "#FF8AD2", //Pink - "#8AEBFF", //Blue - "#C68AFF", //Lila - "#8EFF8A", //green - ], - - /** - * Map an integer to one of ten colors - * @param id - * @returns {string} - */ - getColor: function (id) { - return this.COLORS[id % this.COLORS.length]; - }, - - /*function hashCode(s){ - return s.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0); - };*/ - /** - * Returns the id of the given user (will be its index in the user list) - * @param {*} user - * @param {*} y the shared yjs document - * @returns - */ - getGlobalId: function (user, y) { - var mbox = user.user[CONFIG.NS.PERSON.MBOX]; // mailbox of the user - const userMap = y.getMap("users"); - var users = Array.from(userMap.values()); // get all users - var id = users.indexOf(mbox); - if (id === -1) { - id = users.length; - userMap.set(y.clientID, mbox); - } - return id; - }, - - /** - * Get the current state of the primary document store - * @returns {*} - * @constructor - */ - GetCurrentBaseModel: function () { - var resourceSpace = new openapp$2.oo.Resource(openapp$2.param.space()); - var deferred = jQuery.Deferred(); - resourceSpace.getSubResources({ - relation: openapp$2.ns.role + "data", - type: CONFIG.NS.MY.MODEL, - onAll: function (data) { - if (data === null || data.length === 0) { - deferred.resolve([]); - } else { - data[0].getRepresentation("rdfjson", function (representation) { - if (!representation) { - deferred.resolve([]); - } else { - deferred.resolve(representation); - } - }); - } - }, - }); - return deferred.promise(); - }, - - getSpaceTitle: function (url) { - return url - .substring(url.lastIndexOf("spaces/")) - .replace(/spaces|#\S*|\?\S*|\//g, ""); - }, +const CONFIG = { + TEST: { + USER: "Luigi Test", + EMAIL: "luigi.test05@gmail.com", + CANVAS: false, + ATTRIBUTE: false, + PALETTE: false, + ACTIVITY: false, + }, + LAYER: { + META: "META", + MODEL: "MODEL", + }, + WIDGET: { + NAME: { + MAIN: "Canvas", + PALETTE: "Palette", + ATTRIBUTE: "Property Browser", + ACTIVITY: "User Activity", + GUIDANCE: "Guidance", + HEATMAP: "Heatmap", + METADATA: "METADATA", + OPENAPI: "Metadata Widget", + DEBUG: "Debug", + IMSLD_EXPORT: "IMSLD Export", + JSON_EXPORT: "JSON Export", + VIEWCONTROL: "View Control", + }, + }, + ENTITY: { + NODE: "node", + EDGE: "edge", + ATTR: "attr", + VAL: "val", + }, + IWC: { + FLAG: { + PUBLISH_GLOBAL: "PUBLISH_GLOBAL", + PUBLISH_LOCAL: "PUBLISH_LOCAL", + }, + ACTION: { + SYNC: "ACTION_SYNC", + DATA: "ACTION_DATA", + DATA_ARRAY: "ACTION_DATA_ARRAY", + }, + POSITION: { + NODE: { + ADD: 0, + DEL: 0, + POS: 1, + Z: 2, + DIM: 3, + }, + EDGE: { + ADD: 0, + DEL: 0, + MOV: 1, + }, + ATTR: { + ADD: 0, + DEL: 0, + }, + }, + }, + OPERATION: { + TYPE: { + INSERT: "insert", + UPDATE: "update", + DELETE: "delete", + }, + }, + ACTIVITY: { + TYPE: { + NODEADD: 0, + EDGEADD: 1, + NODEDEL: 2, + EDGEDEL: 3, + NODEATTRCHANGE: 4, + }, + }, + DATA: { + RELATION: { + GLOBAL: { + MAIN: { + MAIN: { + OPERATION: "MAIN2MAIN4OPERATION", + }, + }, + }, + LOCAL: { + PALETTE: { + MAIN: { + TOOLSELECTION: "PALETTE2MAIN4TOOLSELECTION", + }, + }, + MAIN: { + ATTRIBUTE: { + NODESELECTION: "MAIN2ATTRIBUTE4NODESELECTION", + NODEADDITION: "MAIN2ATTRIBUTE4NODEADDITION", + ATTRIBUTECHANGE: "MAIN2ATTRIBUTE4ATTRIBUTECHANGE", + }, + ACTIVITY: { + NEWACTIVITY: "MAIN2ACTIVITY4NEWACTIVITY", + }, + PALETTE: { + TOOLSELECTION: "MAIN2PALETTE4TOOLSELECTION", + }, + }, + ATTRIBUTE: { + MAIN: { + ATTRIBUTECHANGE: "ATTRIBUTE2MAIN4ATTRIBUTECHANGE", + }, + }, + }, + }, + }, + NS: { + PERSON: { + TITLE: "http://purl.org/dc/terms/title", + JABBERID: "http://xmlns.com/foaf/0.1/jabberID", + MBOX: "http://xmlns.com/foaf/0.1/mbox", + }, + MY: { + MODEL: "my:ns:model", + METAMODEL: "my:ns:metamodel", + INSTANCE: "my:ns:instance", + VIEWPOINT: "my:ns:viewpoint", + VIEW: "my:ns:view", + COPY: "my:ns:copy", + GUIDANCEMODEL: "my:ns:guidancemodel", + METAMODELPREVIEW: "my:ns:metamodelpreview", + GUIDANCEMETAMODEL: "my:ns:guidancemetamodel", + LOGICALGUIDANCEREPRESENTATION: "my:ns:logicalguidancerepresentation", + }, + }, }; -function filterList(list, value, missingIsFalse) { - if (list === "*") { - return true; - } - return list.length > 0 ? list.indexOf(value) !== -1 : !missingIsFalse; -} -function extend(o1, o2, keys) { - var i; - o1 = o1 || {}; - o2 = o2 || {}; - var _o1 = o1, - _o2 = o2; - if (keys) { - for (i = 0; i < keys.length; i++) { - _o1[keys[i]] = _o2[keys[i]]; - } - } else { - for (i in _o2) { - _o1[i] = _o2[i]; - } - } - return o1; -} -function isNumber(n) { - return Object.prototype.toString.call(n) === "[object Number]"; -} -function isString(s) { - return typeof s === "string"; -} -function isBoolean(s) { - return typeof s === "boolean"; -} -function isObject(o) { - return o == null ? false : Object.prototype.toString.call(o) === "[object Object]"; -} -function isDate(o) { - return Object.prototype.toString.call(o) === "[object Date]"; -} -function isFunction(o) { - return Object.prototype.toString.call(o) === "[object Function]"; -} -function clone(a) { - if (isString(a)) { - return "" + a; - } else if (isBoolean(a)) { - return !!a; - } else if (isDate(a)) { - return new Date(a.getTime()); - } else if (isFunction(a)) { - return a; - } else if (Array.isArray(a)) { - var _b = []; - for (var i = 0; i < a.length; i++) { - _b.push(clone(a[i])); - } - return _b; - } else if (isObject(a)) { - var c = {}; - for (var j in a) { - c[j] = clone(a[j]); - } - return c; - } else { - return a; - } -} -function merge(a, b, collations, overwrites) { - var cMap = {}, - ar, - i, - oMap = {}; - collations = collations || []; - overwrites = overwrites || []; - for (i = 0; i < collations.length; i++) { - cMap[collations[i]] = true; - } - for (i = 0; i < overwrites.length; i++) { - oMap[overwrites[i]] = true; - } - var c = clone(a); - for (i in b) { - if (c[i] == null || oMap[i]) { - c[i] = b[i]; - } else if (cMap[i]) { - ar = []; - ar.push.apply(ar, Array.isArray(c[i]) ? c[i] : [c[i]]); - ar.push(b[i]); - c[i] = ar; - } else if (isString(b[i]) || isBoolean(b[i]) || isFunction(b[i]) || isNumber(b[i])) { - c[i] = b[i]; - } else { - if (Array.isArray(b[i])) { - ar = []; - if (Array.isArray(c[i])) { - ar.push.apply(ar, c[i]); - } - ar.push.apply(ar, b[i]); - c[i] = ar; - } else if (isObject(b[i])) { - if (!isObject(c[i])) { - c[i] = {}; + /** + * Gets the html tag name of a widget. + * Use this function to get the tag name of a or your own widget. + * @example getWidgetTagName("My Widget") // returns "my-widget-widget" + * @param {*} name name of the widget + * @returns {string} tag name of the widget + */ +function getWidgetTagName(name) { + if (!name) return; + if ( + !Object.values(CONFIG.WIDGET.NAME).some( + (n) => n.toLocaleLowerCase() === name.toLocaleLowerCase() + ) + ) { + console.warn( + `Widget name ${name} is not defined in config.js. Add it to the CONFIG.WIDGET.NAME object.` + ); + } + let widgetName = name; + widgetName = widgetName.replace(/\s+/g, "-"); + return `${widgetName}-widget`.toLowerCase(); +} + +class OpenAppProvider { + openapp; + gadgets; + constructor() { + var openapp = {}; + this.openapp = openapp; + openapp["event"] = {}; + var gadgets = "undefined" !== typeof this.gadgets ? this.gadgets : {}; + this.gadgets = gadgets; + gadgets.openapp = gadgets.openapp || {}; + var usePostMessage = + "undefined" !== typeof window && + "undefined" !== typeof window.parent && + "undefined" !== typeof window.postMessage && + "undefined" !== typeof JSON && + "undefined" !== typeof JSON.parse && + "undefined" !== typeof JSON.stringify, + usePubSub = + !usePostMessage && + "undefined" !== typeof gadgets && + "undefined" !== typeof gadgets.pubsub && + "undefined" !== typeof gadgets.pubsub.subscribe && + "undefined" !== typeof gadgets.pubsub.unsubscribe && + "undefined" !== typeof gadgets.pubsub.publish, + init = { postParentOnly: true }, + ownData, + doCallback, + onMessage; + usePostMessage + ? ((onMessage = function (a) { + if ( + "string" === typeof a.data && + '{"OpenApplicationEvent":{' === a.data.slice(0, 25) + ) { + var b = JSON.parse(a.data).OpenApplicationEvent; + if ( + "openapp" === b.event && + !0 === b.welcome && + a.source === window.parent + ) { + for (var d in b.message) { + b.message.hasOwnProperty(d) && (init[d] = b.message[d]); + } + } else { + (b.source = a.source), + (b.origin = a.origin), + (b.toJSON = function () { + var a = {}, + b; + for (b in this) { + this.hasOwnProperty(b) && + "function" !== typeof this[b] && + "source" !== b && + "origin" !== b && + (a[b] = this[b]); + } + return a; + }), + "function" === typeof doCallback && + // @ts-ignore + !0 === doCallback(b, b.message) && + window.parent.postMessage( + JSON.stringify({ + OpenApplicationEvent: { event: "openapp", receipt: !0 }, + }), + "*" + ); + } + } + }), + // @ts-ignore + "undefined" !== typeof window.attachEvent + ? // @ts-ignore + window.attachEvent("onmessage", onMessage) + : window.addEventListener("message", onMessage, !1), + "undefined" !== typeof window.parent && + window.parent.postMessage( + JSON.stringify({ + OpenApplicationEvent: { event: "openapp", hello: !0 }, + }), + "*" + )) + : usePubSub && + (onMessage = function (a, b) { + b.source = void 0; + b.origin = void 0; + b.sender = a; + "function" === typeof doCallback && + // @ts-ignore + !0 === doCallback(b, b.message) && + gadgets.pubsub.publish("openapp-recieve", !0); + }); + gadgets.openapp.RDF = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; + gadgets.openapp.connect = function (a) { + doCallback = a; + usePubSub && gadgets.pubsub.subscribe("openapp", onMessage); + }; + gadgets.openapp.disconnect = function () { + usePubSub && gadgets.pubsub.unsubscribe("openapp"); + doCallback = null; + }; + gadgets.openapp.publish = function (a, b) { + a.event = a.event || "select"; + a.type = a.type || "namespaced-properties"; + a.sharing = a.sharing || "public"; + a.date = a.date || new Date(); + a.message = b || a.message; + if (usePostMessage) { + if (!1 === init.postParentOnly && null === ownData) { + // @ts-ignore + ownData = { sender: "unknown", viewer: "unknown" }; + if ( + "undefined" !== typeof window.location && + "string" === typeof window.location.search && + "function" === typeof window.unescape + ) { + var d = window.location.search.substring(1).split("&"), + c, + e = {}; + if (!(1 == d.length && "" === d[0])) { + for (var f = 0; f < d.length; f++) { + (c = d[f].split("=")), + 2 == c.length && (e[c[0]] = window.unescape(c[1])); + } + } + // @ts-ignore + "string" === typeof e.url && (ownData.sender = e.url); + } + if ( + // @ts-ignore + "undefined" !== typeof opensocial && + // @ts-ignore + "function" === typeof opensocial.newDataRequest + ) { + // @ts-ignore + d = opensocial.newDataRequest(); + // @ts-ignore + d.add( + // @ts-ignore + d.newFetchPersonRequest(opensocial.IdSpec.PersonId.VIEWER), + "viewer" + ); + var g = this; + // @ts-ignore + d.send(function (c) { + c = c.get("viewer").getData(); + "object" === typeof c && + null !== c && + "function" === typeof c.getId && + ((c = c.getId()), + // @ts-ignore + "string" === typeof c && (ownData.viewer = c)); + g.publish(a, b); + }); + return; + } } - for (var j in b[i]) { - c[i][j] = b[i][j]; + null !== ownData && + // @ts-ignore + ("string" === typeof ownData.sender && (a.sender = ownData.sender), + // @ts-ignore + "string" === typeof ownData.viewer && (a.viewer = ownData.viewer)); + // @ts-ignore + d = JSON.stringify({ OpenApplicationEvent: a }); + // @ts-ignore + if ("undefined" !== window.parent) { + if ((window.parent.postMessage(d, "*"), !init.postParentOnly)) { + c = window.parent.frames; + // @ts-ignore + for (e = 0; e < c.length; e++) { + // @ts-ignore + c[e].postMessage(d, "*"); + } + } + } else { + window.postMessage(d, "*"); } + } else { + usePubSub && gadgets.pubsub.publish("openapp", a); } - } - } - return c; -} -function functionChain(successValue, failValue, fns) { - for (var i = 0; i < fns.length; i++) { - var o = fns[i][0][fns[i][1]].apply(fns[i][0], fns[i][2]); - if (o === failValue) { - return o; - } - } - return successValue; -} -function populate(model, values, functionPrefix, doNotExpandFunctions) { - var getValue = function getValue(fromString) { - var matches = fromString.match(/(\${.*?})/g); - if (matches != null) { - for (var i = 0; i < matches.length; i++) { - var val = values[matches[i].substring(2, matches[i].length - 1)] || ""; - if (val != null) { - fromString = fromString.replace(matches[i], val); - } + }; + openapp["io"] = {}; + openapp["io"].createXMLHttpRequest = function () { + if ("undefined" !== typeof XMLHttpRequest) { + return new XMLHttpRequest(); } - } - matches = fromString.match(/({{.*?}})/g); - if (matches != null) { - for (var _i = 0; _i < matches.length; _i++) { - var _val = values[matches[_i].substring(2, matches[_i].length - 2)] || ""; - if (_val != null) { - fromString = fromString.replace(matches[_i], _val); - } + // @ts-ignore + if ("undefined" !== typeof ActiveXObject) { + // @ts-ignore + return new ActiveXObject("Microsoft.XMLHTTP"); } - } - return fromString; - }; - var _one = function _one(d) { - if (d != null) { - if (isString(d)) { - return getValue(d); - } else if (isFunction(d) && !doNotExpandFunctions && (functionPrefix == null || (d.name || "").indexOf(functionPrefix) === 0)) { - return d(values); - } else if (Array.isArray(d)) { - var r = []; - for (var i = 0; i < d.length; i++) { - r.push(_one(d[i])); + throw { + name: "XMLHttpRequestError", + message: "XMLHttpRequest not supported", + }; + }; + openapp["io"].makeRequest = function (a, b, d) { + gadgets.io.makeRequest( + a, + function (c) { + var e, f, g, h, j, k, l, p; + if (null === document.getElementById("oauthPersonalize")) { + e = document.createElement("div"); + f = document.createElement("input"); + g = document.createElement("input"); + h = document.createElement("div"); + j = document.createElement("input"); + k = document.createElement("div"); + l = document.createElement("span"); + p = document.createElement("input"); + e.id = "oauthPersonalize"; + f.id = "oauthPersonalizeButton"; + g.id = "oauthPersonalizeDenyButton"; + h.id = "oauthPersonalizeDone"; + j.id = "oauthPersonalizeDoneButton"; + k.id = "oauthPersonalizeComplete"; + l.id = "oauthPersonalizeMessage"; + p.id = "oauthPersonalizeHideButton"; + f.id = "oauthPersonalizeButton"; + e.style.display = "none"; + h.style.display = "none"; + k.style.display = "none"; + f.type = "button"; + g.type = "button"; + j.type = "button"; + p.type = "button"; + f.value = "Continue"; + g.value = "Ignore"; + j.value = "Done"; + p.value = "Hide"; + e.appendChild( + document.createTextNode( + "In order to provide the full functionality of this tool, access to your personal data is being requested." + ) + ); + h.appendChild( + document.createTextNode( + "If you have provided authorization and are still reading this, click the Done button." + ) + ); + var m = document.getElementById("openappDialog"); + null == m && + ((m = document.createElement("div")), + null != document.body.firstChild + ? document.body.insertBefore(m, document.body.firstChild) + : document.body.appendChild(m)); + m.appendChild(e); + m.appendChild(h); + m.appendChild(k); + e.appendChild(f); + e.appendChild(g); + h.appendChild(j); + k.appendChild(l); + k.appendChild(p); + g.onclick = function () { + e.style.display = "none"; + }; + p.onclick = function () { + k.style.display = "none"; + }; + } + if (c.oauthApprovalUrl) { + var r = function () { + q && (window.clearInterval(q), (q = null)); + // @ts-ignore + n && (n.close(), (n = null)); + // @ts-ignore + document.getElementById("oauthPersonalizeDone").style.display = + "none"; + // @ts-ignore + document.getElementById( + "oauthPersonalizeComplete" + ).style.display = "block"; + openapp["io"].makeRequest(a, b, d); + return !1; + }, + s = function () { + // @ts-ignore + if (!n || n.closed) { + (n = null), r(); + } + }, + t = c.oauthApprovalUrl, + n = null, + q = null; + c = { + createOpenerOnClick: function () { + return function () { + // @ts-ignore + if ((n = window.open(t, "_blank", "width=450,height=500"))) { + // @ts-ignore + (q = window.setInterval(s, 100)), + // @ts-ignore + (document.getElementById( + "oauthPersonalize" + ).style.display = "none"), + // @ts-ignore + (document.getElementById( + "oauthPersonalizeDone" + ).style.display = "block"); + } + return !1; + }; + }, + createApprovedOnClick: function () { + return r; + }, + }; + // @ts-ignore + document.getElementById("oauthPersonalizeButton").onclick = + c.createOpenerOnClick(); + // @ts-ignore + document.getElementById("oauthPersonalizeDoneButton").onclick = + c.createApprovedOnClick(); + f = "Please wait."; + document.all + ? // @ts-ignore + (document.getElementById("oauthPersonalizeMessage").innerText = + f) + : // @ts-ignore + (document.getElementById( + "oauthPersonalizeMessage" + ).textContent = f); + // @ts-ignore + document.getElementById("oauthPersonalize").style.display = "block"; + } else { + c.oauthError + ? ((f = + "The authorization was not completed successfully. (" + + c.oauthError + + ")"), + document.all + ? // @ts-ignore + (document.getElementById( + "oauthPersonalizeMessage" + ).innerText = f) + : // @ts-ignore + (document.getElementById( + "oauthPersonalizeMessage" + ).textContent = f), + // @ts-ignore + (document.getElementById( + "oauthPersonalizeComplete" + ).style.display = "block")) + : ((f = + "You have now granted authorization. To revoke authorization, go to your Privacy settings."), + document.all + ? // @ts-ignore + (document.getElementById( + "oauthPersonalizeMessage" + ).innerText = f) + : // @ts-ignore + (document.getElementById( + "oauthPersonalizeMessage" + ).textContent = f), + b(c)); + } + }, + d + ); + }; + openapp["ns"] = {}; + openapp["ns"].rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; + openapp["ns"].rdfs = "http://www.w3.org/2000/01/rdf-schema#"; + openapp["ns"].dcterms = "http://purl.org/dc/terms/"; + openapp["ns"].foaf = "http://xmlns.com/foaf/0.1/"; + openapp["ns"].rest = "http://purl.org/openapp/"; + openapp["ns"].conserve = "http://purl.org/openapp/"; + openapp["ns"].openapp = "http://purl.org/openapp/"; + openapp["ns"].role = "http://purl.org/role/terms/"; + openapp["ns"].widget = "http://purl.org/role/widget/"; + openapp["resource"] = {}; + var linkexp = + /<[^>]*>\s*(\s*;\s*[^\(\)<>@,;:"\/\[\]\?={} \t]+=(([^\(\)<>@,;:"\/\[\]\?={} \t]+)|("[^"]*")))*(,|\$)/g, + paramexp = + /[^\(\)<>@,;:"\/\[\]\?={} \t]+=(([^\(\)<>@,;:"\/\[\]\?={} \t]+)|("[^"]*"))/g; + function unquote(a) { + return '"' === a.charAt(0) && '"' === a.charAt(a.length - 1) + ? a.substring(1, a.length - 1) + : a; + } + function parseLinkHeader(a) { + var b = (a + ",").match(linkexp); + a = {}; + var d = {}, + c = {}, + e, + f, + g, + h, + j, + k; + for (e = 0; e < b.length; e++) { + f = b[e].split(">"); + g = f[0].substring(1); + h = f[1]; + f = {}; + f.href = g; + g = h.match(paramexp); + for (h = 0; h < g.length; h++) { + (j = g[h]), (j = j.split("=")), (k = j[0]), (f[k] = unquote(j[1])); + } + void 0 !== f.rel && "undefined" === typeof f.anchor && (a[f.rel] = f); + void 0 !== f.title && + "undefined" === typeof f.anchor && + (d[f.title] = f); + g = c[f.anchor || ""] || {}; + h = g[f.rel || "http://purl.org/dc/terms/relation"] || []; + h.push({ type: "uri", value: f.href }); + g[f.rel || "http://purl.org/dc/terms/relation"] = h; + c[f.anchor || ""] = g; + } + // @ts-ignore + b = {}; + // @ts-ignore + b.rels = a; + // @ts-ignore + b.titles = d; + // @ts-ignore + b.rdf = c; + return b; + } + var isStringValue = function (a) { + return "" !== a && "string" === typeof a; + }; + openapp["resource"].makeRequest = function (a, b, d, c, e, f) { + var g = openapp["io"].createXMLHttpRequest(), + h, + j = 0; + if ("undefined" !== typeof c) { + for (h in c) { + c.hasOwnProperty(h) && j++; + } + if (0 < j) { + // @ts-ignore + j = ""; + -1 !== b?.indexOf("?") && + ((j = b?.substring(b.indexOf("?"))), + // @ts-ignore + (b = b?.substring(0, b.length - j.length))); + switch (b?.substring(b.length - 1)) { + case "/": + b += ":"; + break; + case ":": + break; + default: + b += "/:"; + } + for (h in c) { + c.hasOwnProperty(h) && + (b = + h === openapp["ns"].rdf + "predicate" + ? b + (";predicate=" + encodeURIComponent(c[h])) + : b + + (";" + + encodeURIComponent(h) + + "=" + + encodeURIComponent(c[h]))); + } + b += j; + } + } + g.open(a, b, !0); + g.setRequestHeader("Accept", "application/json"); + e = e || ""; + if (0 < e.length || "POST" === a || "PUT" === a) { + g.setRequestHeader( + "Content-Type", + "undefined" !== typeof f ? f : "application/json" + ); + } + d = d || function () {}; + g.onreadystatechange = function () { + if (4 === g.readyState) { + var a = { + data: g.responseText, + link: isStringValue(g.getResponseHeader("link")) + ? parseLinkHeader(g.getResponseHeader("link")) + : {}, + }; + isStringValue(g.getResponseHeader("location")) + ? (a["uri"] = g.getResponseHeader("location")) + : isStringValue(g.getResponseHeader("content-base")) + ? (a["uri"] = g.getResponseHeader("content-base")) + : a["link"].hasOwnProperty("http://purl.org/dc/terms/subject") && + (a["uri"] = a["link"]["http://purl.org/dc/terms/subject"].href); + isStringValue(g.getResponseHeader("content-location")) && + (a["contentUri"] = g.getResponseHeader("content-location")); + isStringValue(g.getResponseHeader("content-type")) && + "application/json" === + g.getResponseHeader("content-type").split(";")[0] && + (a.data = JSON.parse(a.data)); + a["subject"] = + "undefined" !== typeof g.responseText + ? a.data.hasOwnProperty("") + ? a.data[""] + : a.data[a["uri"]] || {} + : {}; + d(a); } - return r; - } else if (isObject(d)) { - var s = {}; - for (var j in d) { - s[j] = _one(d[j]); + }; + g.send(e); + }; + // @ts-ignore + "undefined" === typeof openapp_forceXhr && + "undefined" !== typeof gadgets && + "undefined" !== typeof gadgets.io && + "undefined" !== typeof gadgets.io.makeRequest && + (openapp["resource"].makeRequest = function (a, b, d, c, e, f) { + var g = {}, + h, + j = 0; + if ("undefined" !== typeof c) { + for (h in c) { + c.hasOwnProperty(h) && j++; + } + if (0 < j) { + // @ts-ignore + j = ""; + -1 !== b.indexOf("?") && + ((j = b.substring(b.indexOf("?"))), + // @ts-ignore + (b = b.substring(0, b.length - j.length))); + switch (b.substring(b.length - 1)) { + case "/": + b += ":"; + break; + case ":": + break; + default: + b += "/:"; + } + for (h in c) { + c.hasOwnProperty(h) && + (b = + h === openapp["ns"].rdf + "predicate" + ? b + (";predicate=" + encodeURIComponent(c[h])) + : b + + (";" + + encodeURIComponent(h) + + "=" + + encodeURIComponent(c[h]))); + } + b += j; + } } - return s; - } else { - return d; - } - } - }; - return _one(model); -} -function forEach(a, f) { - if (a) { - for (var i = 0; i < a.length; i++) { - f(a[i]); - } - } else { - return null; + g[gadgets.io.RequestParameters.GET_FULL_HEADERS] = !0; + g[gadgets.io.RequestParameters.CONTENT_TYPE] = + gadgets.io.ContentType.TEXT; + g[gadgets.io.RequestParameters.AUTHORIZATION] = + gadgets.io.AuthorizationType.OAUTH; + g[gadgets.io.RequestParameters.OAUTH_SERVICE_NAME] = "openapp"; + g[gadgets.io.RequestParameters.OAUTH_USE_TOKEN] = "always"; + g[gadgets.io.RequestParameters.METHOD] = a; + g[gadgets.io.RequestParameters.HEADERS] = + g[gadgets.io.RequestParameters.HEADERS] || {}; + "undefined" !== typeof e && + null !== e && + ((g[gadgets.io.RequestParameters.HEADERS]["Content-Type"] = + "undefined" !== typeof f ? f : "application/json"), + (g[gadgets.io.RequestParameters.POST_DATA] = e)); + g[gadgets.io.RequestParameters.HEADERS].Accept = "application/json"; + d = d || function () {}; + openapp["io"].makeRequest( + b, + function (a) { + var b = { + data: a.data, + link: + "undefined" !== typeof a.headers.link + ? parseLinkHeader(a.headers.link[0]) + : {}, + }; + a.headers.hasOwnProperty("location") + ? (b["uri"] = a.headers.location[0]) + : a.headers.hasOwnProperty("content-base") + ? (b["uri"] = a.headers["content-base"][0]) + : // @ts-ignore + b["link"].hasOwnProperty("http://purl.org/dc/terms/subject") && + // @ts-ignore + (b["uri"] = b["link"]["http://purl.org/dc/terms/subject"].href); + a.headers.hasOwnProperty("content-location") && + (b["contentUri"] = a.headers["content-location"][0]); + a.headers.hasOwnProperty("content-type") && + "application/json" === + a.headers["content-type"][0].split(";")[0] && + (b.data = gadgets.json.parse(b.data)); + b["subject"] = + "undefined" !== typeof a.data + ? b.data.hasOwnProperty("") + ? b.data[""] + : b.data[b["uri"]] || {} + : {}; + d(b); + }, + g + ); + }); + openapp["resource"].get = function (a, b, d) { + return openapp["resource"].makeRequest( + "GET", + a, + b, + d || { + "http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate": + openapp["ns"].conserve + "info", + } + ); + }; + openapp["resource"].post = function (a, b, d, c, e) { + return openapp["resource"].makeRequest("POST", a, b, d, c, e); + }; + openapp["resource"].put = function (a, b, d, c, e) { + return openapp["resource"].makeRequest("PUT", a, b, d, c, e); + }; + openapp["resource"].del = function (a, b, d) { + return openapp["resource"].makeRequest("DELETE", a, b, d); + }; + openapp["resource"].context = function (a) { + return { + sub: function (b) { + var d = {}; + return { + control: function (a, b) { + d[a] = b; + return this; + }, + type: function (a) { + return this.control(openapp["ns"].rdf + "type", a); + }, + seeAlso: function (a) { + return this.control(openapp["ns"].rdfs + "seeAlso", a); + }, + list: function () { + var c = [], + e = a["subject"][b], + f, + g, + h, + j, + k, + l; + if ("undefined" === typeof e) { + return c; + } + h = 0; + a: for (; h < e.length; h++) { + f = e[h]; + g = a.data[f.value]; + for (j in d) { + if (d.hasOwnProperty(j)) { + if (!g.hasOwnProperty(j)) { + continue a; + } + l = !1; + for (k = 0; k < g[j].length; k++) { + if (g[j][k].value === d[j]) { + l = !0; + break; + } + } + if (!l) { + continue a; + } + } + } + // @ts-ignore + c.push({ data: a.data, link: {}, uri: f.value, subject: g }); + } + return c; + }, + create: function (c) { + if (!a["link"].rdf.hasOwnProperty(b)) { + throw ( + "The context does not support the requested relation: " + b + ); + } + var e = a["uri"]; + d[openapp["ns"].rdf + "predicate"] = b; + openapp["resource"].post( + e, + function (a) { + c(a); + }, + d + ); + }, + }; + }, + metadata: function () { + return openapp["resource"] + .context(a) + .content(openapp["ns"].rest + "metadata"); + }, + representation: function () { + return openapp["resource"] + .context(a) + .content(openapp["ns"].rest + "representation"); + }, + content: function (b) { + return { + get: function (d) { + openapp["resource"].get( + a["uri"], + function (a) { + d(a); + }, + { "http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate": b } + ); + }, + mediaType: function (d) { + var c = null; + return { + string: function (a) { + c = a; + return this; + }, + json: function (a) { + c = JSON.stringify(a); + return this; + }, + put: function (e) { + openapp["resource"].put( + a["uri"], + function (a) { + "function" === typeof e && e(a); + }, + { + "http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate": b, + }, + c, + d + ); + }, + }; + }, + string: function (a) { + return this.mediaType("text/plain").string(a); + }, + json: function (a) { + return this.mediaType("application/json").json(a); + }, + graph: function () { + var d = {}, + c = ""; + return { + subject: function (a) { + c = a; + return this; + }, + resource: function (a, b) { + d[c] = d[c] || {}; + d[c][a] = d[c][a] || []; + d[c][a].push({ value: b, type: "uri" }); + return this; + }, + literal: function (a, b, g, h) { + d[c] = d[c] || {}; + d[c][a] = d[c][a] || []; + d[c][a].push({ + value: b, + type: "literal", + lang: g, + datatype: h, + }); + return this; + }, + put: function (c) { + openapp["resource"].put( + a["uri"], + function (a) { + "function" === typeof c && c(a); + }, + { + "http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate": b, + }, + JSON.stringify(d) + ); + }, + }; + }, + }; + }, + properties: function () { + var b = {}, + d; + for (d in a["subject"]) { + a["subject"].hasOwnProperty(d) && (b[d] = a["subject"][d][0].value); + } + return b; + }, + string: function () { + return "string" === typeof a.data + ? a.data + : gadgets.json.stringify(a.data); + }, + json: function () { + return "string" === typeof a.data ? null : a.data; + }, + followSeeAlso: function () { + var b = a["subject"][openapp["ns"].rdfs + "seeAlso"], + d = 0, + c, + e; + if ("undefined" !== typeof b) { + b = b[0].value; + for ( + e = 0; + e < b.length && + e < a["uri"].length && + b.charAt(e) === a["uri"].charAt(e); + e++ + ) { + "/" === b.charAt(e) && d++; + } + for (c = d; e < b.length; e++) { + "/" === b.charAt(e) && c++; + } + return 3 > d || 4 < c + ? this + : openapp["resource"].context({ + data: a.data, + link: {}, + uri: b, + subject: a.data[b], + }); + } + return this; + }, + }; + }; + openapp["resource"].content = function (a) { + return { + properties: function () { + return openapp["resource"].context(a).properties(); + }, + string: function () { + return openapp["resource"].context(a).string(); + }, + json: function () { + return openapp["resource"].context(a).json(); + }, + }; + }; + openapp["oo"] = {}; + openapp["oo"].Resource = function (a, b, d) { + this.uri = a; + this.context = b; + this.info = d; + }; + var OARP = openapp["oo"].Resource.prototype; + OARP.getURI = function () { + return this.uri; + }; + OARP._call = function (a) { + var b = this; + null == this.context + ? null == this._deferred + ? ((this._deferred = [a]), + openapp["resource"].get(this.uri, function (a) { + b.context = a; + a = b._deferred; + delete b._deferred; + for (var c = 0; c < a.length; c++) { + a[c].call(b); + } + })) + : this._deferred.push(a) + : a.call(b); + }; + OARP.refresh = function (a) { + delete this.context; + delete this.info; + a && + this._call(function () { + a(); + }); + }; + OARP.getSubResources = function (a) { + this._call(function () { + for ( + var b = + null != a.type + ? openapp["resource"] + .context(this.context) + .sub(a.relation) + .type(a.type) + .list() + : openapp["resource"] + .context(this.context) + .sub(a.relation) + .list(), + d = [], + c = 0; + c < b.length; + c++ + ) { + var e = b[c].uri; + if (a.followReference) { + var f = + this.context.data[e]["http://www.w3.org/2002/07/owl#sameAs"]; + null != f && 0 < f.length && (e = f[0].value); + } + f = new openapp["oo"].Resource(e, null, b[c]); + null == a.followReference && + ((f._referenceLoaded = !0), + (e = this.context.data[e]["http://www.w3.org/2002/07/owl#sameAs"]), + null != e && 0 < e.length && (f._reference = e[0].value)); + if (a.onEach) { + a.onEach(f); + } + a.onAll && d.push(f); + } + if (a.onAll) { + a.onAll(d); + } + }); + }; + OARP.followReference = function (a) { + this._referenceLoaded + ? a( + null != this._reference + ? new openapp["oo"].Resource(this._reference) + : this + ) + : this._call(function () { + var b = + this.context.data[this.uri][ + "http://www.w3.org/2002/07/owl#sameAs" + ]; + null != b && 0 < b.length + ? a(new openapp["oo"].Resource(b[0].value)) + : a(this); + }); + }; + OARP.getReference = function (a) { + this._referenceLoaded + ? a(this._reference) + : this._call(function () { + var b = this.context.subject[openapp["ns"].rdfs + "seeAlso"]; + null != b && 0 < b.length + ? a(this.context.subject[openapp["ns"].rdfs + "seeAlso"][0].value) + : a(); + }); + }; + OARP.getMetadata = function (a, b) { + this._call(function () { + openapp["resource"] + .context(this.context) + .metadata() + .get(function (d) { + switch (a || "properties") { + case "properties": + b(openapp["resource"].context(d).properties()); + break; + case "graph": + b(openapp["resource"].content(d).graph()); + break; + case "rdfjson": + b(openapp["resource"].content(d).json()); + } + }); + }); + }; + OARP.getInfo = function (a) { + if (a) { + this.context || this.info + ? a( + openapp["resource"] + .context(this.context || this.info) + .properties() + ) + : this._call(function () { + a( + openapp["resource"] + .context(this.context || this.info) + .properties() + ); + }); + } else { + if (this.context || this.info) { + return openapp["resource"] + .context(this.context || this.info) + .properties(); + } + } + }; + OARP.getRepresentation = function (a, b) { + this._call(function () { + openapp["resource"] + .context(this.context) + .representation() + .get(function (d) { + switch (a || "text/html") { + case "properties": + b(openapp["resource"].context(d).properties()); + break; + case "graph": + b(openapp["resource"].content(d).graph()); + break; + case "rdfjson": + b(openapp["resource"].content(d).json()); + break; + case "text/html": + b(openapp["resource"].content(d).string()); + } + }); + }); + }; + OARP.setMetadata = function (a, b, d) { + var c = {}; + switch (b || "properties") { + case "properties": + b = {}; + for (var e in a) { + b[e] = [{ type: "literal", value: a[e] }]; + } + c[this.context.uri] = b; + break; + case "rdfjson": + c = a; + break; + case "graph": + // @ts-ignore + graph.put(d); + return; + } + openapp["resource"].put( + this.context.uri, + d, + { + "http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate": + openapp["ns"].rest + "metadata", + }, + JSON.stringify(c) + ); + }; + OARP.setRepresentation = function (a, b, d) { + this._call(function () { + var c = openapp["resource"] + .context(this.context) + .representation() + .mediaType(b); + "string" === typeof a ? c.string(a).put(d) : c.json(a).put(d); + }); + }; + OARP.create = function (a) { + this._call(function () { + var b = openapp["resource"] + .context(this.context) + .sub(a.relation || openapp["ns"].role + "data"); + null != a.referenceTo && (b = b.seeAlso(a.referenceTo)); + null != a.type && (b = b.type(a.type)); + b.create(function (b) { + var c = new openapp["oo"].Resource(b["uri"], b); + a.metadata + ? c.setMetadata(a.metadata, a.format, function () { + a.representation + ? c.setRepresentation( + a.representation, + a.medieType || "application/json", + function () { + a.callback(c); + } + ) + : a.callback(c); + }) + : a.representation + ? c.setRepresentation( + a.representation, + a.medieType || "application/json", + function () { + a.callback(c); + } + ) + : a.callback(c); + }); + }); + }; + OARP.del = function (a) { + openapp["resource"].del(this.uri, a); + }; + openapp["param"] = {}; + var parseQueryParams = function (a) { + var b, + d, + c = {}; + if (0 > a.indexOf("?")) { + return {}; + } + a = a.substr(a.indexOf("?") + 1).split("&"); + if (!(1 == a.length && "" === a[0])) { + for (d = 0; d < a.length; d++) { + (b = a[d].split("=")), + 2 == b.length && (c[b[0]] = window.unescape(b[1])); + } + } + return c; + }, + parseOpenAppParams = function (a) { + var b = {}, + d = {}, + c, + e; + for (c in a) { + a.hasOwnProperty(c) && + "openapp['ns']." === c.substring(0, 11) && + (b[c.substr(11)] = a[c]); + } + for (c in a) { + a.hasOwnProperty(c) && + ((e = c.split(".")), + 3 === e.length && + "openapp" === e[0] && + b.hasOwnProperty(e[1]) && + (d[b[e[1]] + e[2]] = a[c])); + } + return d; + }, + _openAppParams = parseOpenAppParams( + parseQueryParams(parseQueryParams(window.location.href)["url"] || "") + ); + openapp["param"].get = function (a) { + return _openAppParams[a]; + }; + openapp["param"].space = function () { + return openapp["param"].get("http://purl.org/role/terms/space"); + }; + openapp["param"].user = function () { + return openapp["param"].get("http://purl.org/role/terms/user"); + }; } } -function findWithFunction(a, f) { - if (a) { - for (var i = 0; i < a.length; i++) { - if (f(a[i])) { - return i; + +const openapp$2 = new OpenAppProvider().openapp; +/** + * Util + * @class Util + * @name Util + * @constructor + */ +var Util = { + /** + * Generate random hex string + * @param {number} [length] Length of string (Default=24) + * @returns {string} + */ + generateRandomId: function (length) { + var chars = "1234567890abcdef"; + var numOfChars = chars.length; + var i, rand; + var res = ""; + + if (typeof length === "undefined") length = 24; + + for (i = 0; i < length; i++) { + rand = Math.floor(Math.random() * numOfChars); + res += chars[rand]; + } + return res; + }, + + generateAnonymousUser: function () { + const user = {}; + var id = this.generateRandomId(); + user[CONFIG.NS.PERSON.TITLE] = "Anonymous"; + user[CONFIG.NS.PERSON.JABBERID] = id; + user[CONFIG.NS.PERSON.MBOX] = id + "@anonym.com"; + user.globalId = -1; + user.self = true; + return user; + }, + + /** + * Wait for delay milliseconds then return + * @param delay + * @returns {promise} + */ + delay: function (delay) { + var deferred = jQuery.Deferred(); + setTimeout(function () { + deferred.resolve(); + }, delay); + return deferred.promise(); + }, + + /** + * Union the two passed objects into a new object (on a duplicate key, the first object has priority) + * @param {object} obj1 + * @param {object} obj2 + * @returns {object} + */ + union: function (obj1, obj2) { + var res = {}, + i; + for (i in obj1) { + if (obj1.hasOwnProperty(i)) { + res[i] = obj1[i]; + } + } + for (i in obj2) { + if (obj2.hasOwnProperty(i) && !obj1.hasOwnProperty(i)) { + res[i] = obj2[i]; + } + } + return res; + }, + + /** + * Merge the elements of the second object into the first (on a duplicate key, the first object has priority) + * @param {object} obj1 + * @param {object} obj2 + * @returns {object} + */ + merge: function (obj1, obj2) { + var i; + for (i in obj2) { + if (obj2.hasOwnProperty(i) && !obj1.hasOwnProperty(i)) { + obj1[i] = obj2[i]; } } + return obj1; + }, + + /** + * Converts an async function that expects a callback as last parameter into a promise + * @param func + * @returns {promise} + */ + toPromise: function (func) { + return function () { + //noinspection JSAccessibilityCheck + var args = Array.prototype.slice.call(arguments); + var deferred = jQuery.Deferred(); + args.push(function () { + deferred.resolve.apply(this, arguments); + }); + func.apply(this, args); + return deferred.promise(); + }; + }, + + COLORS: [ + "#8AFFC8", //türkis + "#8A9FFF", //light blue + "#FF8A8A", //Rot + "#FFC08A", //Orange + "#FF8AD2", //Pink + "#8AEBFF", //Blue + "#C68AFF", //Lila + "#8EFF8A", //green + ], + + /** + * Map an integer to one of ten colors + * @param id + * @returns {string} + */ + getColor: function (id) { + return this.COLORS[id % this.COLORS.length]; + }, + + /*function hashCode(s){ + return s.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0); + };*/ + /** + * Returns the id of the given user (will be its index in the user list) + * @param {*} user + * @param {*} y the shared yjs document + * @returns + */ + getGlobalId: function (user, y) { + var mbox = user.user[CONFIG.NS.PERSON.MBOX]; // mailbox of the user + const userMap = y.getMap("users"); + var users = Array.from(userMap.values()); // get all users + var id = users.indexOf(mbox); + if (id === -1) { + id = users.length; + userMap.set(y.clientID, mbox); + } + return id; + }, + + /** + * Get the current state of the primary document store + * @returns {*} + * @constructor + */ + GetCurrentBaseModel: function () { + var resourceSpace = new openapp$2.oo.Resource(openapp$2.param.space()); + var deferred = jQuery.Deferred(); + resourceSpace.getSubResources({ + relation: openapp$2.ns.role + "data", + type: CONFIG.NS.MY.MODEL, + onAll: function (data) { + if (data === null || data.length === 0) { + deferred.resolve([]); + } else { + data[0].getRepresentation("rdfjson", function (representation) { + if (!representation) { + deferred.resolve([]); + } else { + deferred.resolve(representation); + } + }); + } + }, + }); + return deferred.promise(); + }, + + getSpaceTitle: function (url) { + return url + .substring(url.lastIndexOf("spaces/")) + .replace(/spaces|#\S*|\?\S*|\//g, ""); + }, +}; + +function filterList(list, value, missingIsFalse) { + if (list === "*") { + return true; } - return -1; + return list.length > 0 ? list.indexOf(value) !== -1 : !missingIsFalse; } -function findAllWithFunction(a, predicate) { - var o = []; - if (a) { - for (var i = 0; i < a.length; i++) { - if (predicate(a[i])) { - o.push(i); - } +function extend(o1, o2, keys) { + var i; + o1 = o1 || {}; + o2 = o2 || {}; + var _o1 = o1, + _o2 = o2; + if (keys) { + for (i = 0; i < keys.length; i++) { + _o1[keys[i]] = _o2[keys[i]]; + } + } else { + for (i in _o2) { + _o1[i] = _o2[i]; } } - return o; + return o1; } -function getWithFunction(a, f) { - var idx = findWithFunction(a, f); - return idx === -1 ? null : a[idx]; +function isNumber(n) { + return Object.prototype.toString.call(n) === "[object Number]"; } -function getAllWithFunction(a, f) { - var indexes = findAllWithFunction(a, f); - return indexes.map(function (i) { - return a[i]; - }); +function isString(s) { + return typeof s === "string"; } -function getFromSetWithFunction(s, f) { - var out = null; - s.forEach(function (t) { - if (f(t)) { - out = t; - } - }); - return out; +function isBoolean(s) { + return typeof s === "boolean"; } -function setToArray(s) { - var a = []; - s.forEach(function (t) { - a.push(t); - }); - return a; +function isObject(o) { + return o == null ? false : Object.prototype.toString.call(o) === "[object Object]"; } -function removeWithFunction(a, f) { - var idx = findWithFunction(a, f); - if (idx > -1) { - a.splice(idx, 1); - } - return idx !== -1; +function isDate(o) { + return Object.prototype.toString.call(o) === "[object Date]"; } -function fromArray(a) { - if (Array.fromArray != null) { - return Array.from(a); - } else { - var arr = []; - Array.prototype.push.apply(arr, a); +function isFunction(o) { + return Object.prototype.toString.call(o) === "[object Function]"; +} +function clone(a) { + if (isString(a)) { + return "" + a; + } else if (isBoolean(a)) { + return !!a; + } else if (isDate(a)) { + return new Date(a.getTime()); + } else if (isFunction(a)) { + return a; + } else if (Array.isArray(a)) { + var _b = []; + for (var i = 0; i < a.length; i++) { + _b.push(clone(a[i])); + } + return _b; + } else if (isObject(a)) { + var c = {}; + for (var j in a) { + c[j] = clone(a[j]); + } + return c; + } else { + return a; + } +} +function merge(a, b, collations, overwrites) { + var cMap = {}, + ar, + i, + oMap = {}; + collations = collations || []; + overwrites = overwrites || []; + for (i = 0; i < collations.length; i++) { + cMap[collations[i]] = true; + } + for (i = 0; i < overwrites.length; i++) { + oMap[overwrites[i]] = true; + } + var c = clone(a); + for (i in b) { + if (c[i] == null || oMap[i]) { + c[i] = b[i]; + } else if (cMap[i]) { + ar = []; + ar.push.apply(ar, Array.isArray(c[i]) ? c[i] : [c[i]]); + ar.push(b[i]); + c[i] = ar; + } else if (isString(b[i]) || isBoolean(b[i]) || isFunction(b[i]) || isNumber(b[i])) { + c[i] = b[i]; + } else { + if (Array.isArray(b[i])) { + ar = []; + if (Array.isArray(c[i])) { + ar.push.apply(ar, c[i]); + } + ar.push.apply(ar, b[i]); + c[i] = ar; + } else if (isObject(b[i])) { + if (!isObject(c[i])) { + c[i] = {}; + } + for (var j in b[i]) { + c[i][j] = b[i][j]; + } + } + } + } + return c; +} +function functionChain(successValue, failValue, fns) { + for (var i = 0; i < fns.length; i++) { + var o = fns[i][0][fns[i][1]].apply(fns[i][0], fns[i][2]); + if (o === failValue) { + return o; + } + } + return successValue; +} +function populate(model, values, functionPrefix, doNotExpandFunctions) { + var getValue = function getValue(fromString) { + var matches = fromString.match(/(\${.*?})/g); + if (matches != null) { + for (var i = 0; i < matches.length; i++) { + var val = values[matches[i].substring(2, matches[i].length - 1)] || ""; + if (val != null) { + fromString = fromString.replace(matches[i], val); + } + } + } + matches = fromString.match(/({{.*?}})/g); + if (matches != null) { + for (var _i = 0; _i < matches.length; _i++) { + var _val = values[matches[_i].substring(2, matches[_i].length - 2)] || ""; + if (_val != null) { + fromString = fromString.replace(matches[_i], _val); + } + } + } + return fromString; + }; + var _one = function _one(d) { + if (d != null) { + if (isString(d)) { + return getValue(d); + } else if (isFunction(d) && !doNotExpandFunctions && (functionPrefix == null || (d.name || "").indexOf(functionPrefix) === 0)) { + return d(values); + } else if (Array.isArray(d)) { + var r = []; + for (var i = 0; i < d.length; i++) { + r.push(_one(d[i])); + } + return r; + } else if (isObject(d)) { + var s = {}; + for (var j in d) { + s[j] = _one(d[j]); + } + return s; + } else { + return d; + } + } + }; + return _one(model); +} +function forEach(a, f) { + if (a) { + for (var i = 0; i < a.length; i++) { + f(a[i]); + } + } else { + return null; + } +} +function findWithFunction(a, f) { + if (a) { + for (var i = 0; i < a.length; i++) { + if (f(a[i])) { + return i; + } + } + } + return -1; +} +function findAllWithFunction(a, predicate) { + var o = []; + if (a) { + for (var i = 0; i < a.length; i++) { + if (predicate(a[i])) { + o.push(i); + } + } + } + return o; +} +function getWithFunction(a, f) { + var idx = findWithFunction(a, f); + return idx === -1 ? null : a[idx]; +} +function getAllWithFunction(a, f) { + var indexes = findAllWithFunction(a, f); + return indexes.map(function (i) { + return a[i]; + }); +} +function getFromSetWithFunction(s, f) { + var out = null; + s.forEach(function (t) { + if (f(t)) { + out = t; + } + }); + return out; +} +function setToArray(s) { + var a = []; + s.forEach(function (t) { + a.push(t); + }); + return a; +} +function removeWithFunction(a, f) { + var idx = findWithFunction(a, f); + if (idx > -1) { + a.splice(idx, 1); + } + return idx !== -1; +} +function fromArray(a) { + if (Array.fromArray != null) { + return Array.from(a); + } else { + var arr = []; + Array.prototype.push.apply(arr, a); return arr; } } @@ -34938,19137 +34938,19151 @@ var interact_min = { var interact = /*@__PURE__*/getDefaultExportFromCjs(interact_minExports); -/** - * Function to check if the event was triggered by the current user - * @param {YEvent} yEvent YEvent - * @returns {boolean} true if the event was triggered by the current user - */ -function eventWasTriggeredByMe(yEvent) { - const array = Array.from(yEvent.changes.keys.keys()); - if (!array) return false; - const modifiedByKey = array.find((key) => key === "modifiedBy"); - if ( - modifiedByKey && - yEvent.currentTarget.get(modifiedByKey) === window.y.clientID - ) - // modified by us - return true; - return false; -} - -function getQuerySelectorFromNode(node) { - if (node instanceof jQuery) { - node = node.get(0); - } - if (node.id) { - return `[id="${node.id}"]`; - // return `#${node.id}`; // This is not working since the implementation of querySelectorAll disallows getting elements by id with a hash if the id starts with a number - } - if (node.className) { - return `.${node.className}`; - } - return null; -} - -/** - * Namespace for operations - * @namespace operations - */ - -/** - * Operation - * @class operations.Operation - * @memberof operations - * @constructor - */ -class Operation { - constructor() {} -} - -/** - * Namespace for ot operations - * @namespace operations.ot - */ - - /** - * OTOperation - * @class operations.ot.OTOperation - * @memberof operations.ot - * @constructor - * @param {string} name Name of operation - * @param {string} value Value of operation - * @param {string} type Type of operation - * @param {number} position Position of operation - */ - class OTOperation extends Operation { - constructor(name, value, type, position) { - super(); - /** - * JabberId of the user who issued this activity - * @type {string} - * @private - */ - var _sender = null; - - - /** - * Operation details - * @type {{name: string, value: string, type: string, position: number}} - * @private - */ - var _operation = { - name: name, - value: value, - type: type, - position: position - }; - - /** - * Set JabberId of the user who issued this activity - * @param sender - */ - this.setSender = function (sender) { - _sender = sender; - }; - - /** - * Get JabberId of the user who issued this activity - */ - this.getSender = function () { - return _sender; - }; - - /** - * Get name of operation - * @returns {string} - */ - this.getName = function () { - return _operation.name; - }; - - /** - * Get value of operation - * @returns {string} - */ - this.getValue = function () { - return _operation.value; - }; - - /** - * Get type of operation - * @returns {string} - */ - this.getType = function () { - return _operation.type; - }; - - /** - * Get position of operation - * @returns {number} - */ - this.getPosition = function () { - return _operation.position; - }; - - /** - * Get JSON Representation of operation - * @returns {{type: string, data: string}} - */ - this.getOperationObject = function () { - return _operation; - }; - } -} - -/** - * Namespace for non ot operations - * @namespace operations.non_ot - */ - - NonOTOperation.prototype = new Operation(); - NonOTOperation.prototype.constructor = NonOTOperation; - /** - * NonOTOperation - * @class operations.non_ot.NonOTOperation - * @memberof operations.non_ot - * @constructor - * @param {string} type Type of Operation - * @param {string} data Additional data for operation - */ - function NonOTOperation(type,data){ - /** - * JabberId of the user who issued this activity - * @type {string} - * @private - */ - var _sender = null; - - /** - * Operation details - * @type {{type: string, data: string}} - * @private - */ - var _operation = { - type: type, - data: data - }; - - /** - * Set JabberId of the user who issued this activity - * @param sender - */ - this.setSender = function(sender){ - _sender = sender; - }; - - /** - * Get JabberId of the user who issued this activity - * @returns {string} - */ - this.getSender = function(){ - return _sender; - }; - - /** - * Get type of Operation - * @returns {string} - */ - this.getType = function(){ - //noinspection JSAccessibilityCheck - return _operation.type; - }; - - /** - * Get additional data for operation - * @returns {string} - */ - this.getData = function(){ - return _operation.data; - }; - - /** - * Get JSON Representation of operation - * @returns {{type: string, data: string}} - */ - this.getOperationObject = function(){ - return _operation; - }; - } - -/** - * EntityOperation - * @class operations.ot.EntityOperation - * @memberof operations.ot - * @param {string} operationType Type of operation - * @param {string} entityId Entity id of the entity this activity works on - * @param {string} entityType Type of the entity this activity works on - * @constructor - */ -class EntityOperation { - static TYPES = { - AttributeAddOperation: "AttributeAddOperation", - AttributeDeleteOperation: "AttributeDeleteOperation", - EdgeAddOperation: "EdgeAddOperation", - EdgeDeleteOperation: "EdgeDeleteOperation", - NodeAddOperation: "NodeAddOperation", - NodeDeleteOperation: "NodeDeleteOperation", - NodeMoveOperation: "NodeMoveOperation", - NodeMoveZOperation: "NodeMoveZOperation", - NodeResizeOperation: "NodeResizeOperation", - ValueChangeOperation: "ValueChangeOperation", - }; - getOperationType; - setOTOperation; - _getOTOperation; - getEntityId; - getEntityType; - adjust; - inverse; - toJSON; - - triggeredBy; - constructor(operationType, entityId, entityType) { - this.triggeredBy = window.y.clientID; - - /** - * Type of operation - * @type {string} - * @private - */ - var _operationType = operationType; - - /** - * Corresponding OtOperation - * @type {operations.ot.OTOperation} - * @private - */ - var _otOperation = null; - - /** - * Entity id of the entity this activity works on - * @type {string} - * @private - */ - var _entityId = entityId; - - /** - * Type of the entity this activity works on - * @type {string} - * @private - */ - var _entityType = entityType; - - /** - * Get type of operation - * @returns {string} - */ - this.getOperationType = function () { - return _operationType; - }; - - /** - * Set corresponding ot operation - * @param {operations.ot.OTOperation} otOperation - */ - this.setOTOperation = function (otOperation) { - _otOperation = otOperation; - }; - - /** - * Get corresponding ot operation - * @returns {operations.ot.OTOperation} - * @private - */ - this._getOTOperation = function () { - return _otOperation; - }; - - /** - * Get entity id of the entity this activity works onf - * @returns {string} - */ - this.getEntityId = function () { - return _entityId; - }; - - //noinspection JSUnusedGlobalSymbols - /** - * Get type of the entity this activity works on - * @returns {string} - */ - this.getEntityType = function () { - return _entityType; - }; - - /** - * Adjust the passed operation in the history of operation - * when this operation is applied remotely after the passed operation - * on an graph instance stored in the passed EntityManager - * @param {canvas_widget.EntityManager} EntityManager - * @param {EntityOperation} operation Remote operation - * @returns {EntityOperation} - */ - this.adjust = function (EntityManager, operation) { - return operation; - }; - - /** - * Compute the inverse of the operation - * @returns {operations.ot.EntityOperation} - */ - this.inverse = function () { - return this; - }; - } - //noinspection JSAccessibilityCheck - /** - * Get corresponding ot operation - * @returns {operations.ot.OTOperation} - */ - getOTOperation() { - return this._getOTOperation(); - } -} - -/** - * NodeDeleteOperation - * @class operations.ot.NodeDeleteOperation - * @memberof operations.ot - * @extends operations.ot.EntityOperation - * @param {String} entityId Entity id of the entity this activity works on - * @param {String} type Type of node to delete - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {number} zIndex Position of node on z-axis - * @param {boolean} containment containment - * @param {object} json JSON representation of node - * @constructor - */ -class NodeDeleteOperation extends EntityOperation { - static TYPE = "NodeDeleteOperation"; - getType; - getLeft; - getTop; - getWidth; - getHeight; - getZIndex; - getContainment; - getJSON; - constructor( - entityId, - type, - left, - top, - width, - height, - zIndex, - containment, - json - ) { - super( - EntityOperation.TYPES.NodeDeleteOperation, - entityId, - CONFIG.ENTITY.NODE - ); - var that = this; - - /** - * Type of node to add - * @type {String} - * @private - */ - var _type = type; - - /** - * x-coordinate of node position - * @type {number} - * @private - */ - var _left = left; - - /** - * y-coordinate of node position - * @type {number} - * @private - */ - var _top = top; - - /** - * Width of node - * @type {number} - * @private - */ - var _width = width; - - /** - * Height of node - * @type {number} - * @private - */ - var _height = height; - - /** - * Position of node on z-axis - * @type {number} - * @private - */ - var _zIndex = zIndex; - - /** - * is containment type - * @type {boolean} - * @private - */ - var _containment = containment; - - /** - * JSON representation of node - * @type {Object} - * @private - */ - var _json = json; - - /** - * Create OTOperation for operation - * @returns {operations.ot.OTOperation} - */ - var createOTOperation = function () { - return new OTOperation( - CONFIG.ENTITY.NODE + ":" + that.getEntityId(), - JSON.stringify({ - type: _type, - left: _left, - top: _top, - width: _width, - height: _height, - zIndex: _zIndex, - containment: _containment, - json: _json, - }), - CONFIG.OPERATION.TYPE.UPDATE, - CONFIG.IWC.POSITION.NODE.DEL - ); - }; - - /** - * Get type of node to add - * @returns {String} - */ - this.getType = function () { - return _type; - }; - - /** - * Get x-coordinate of node position - * @returns {number} - */ - this.getLeft = function () { - return _left; - }; - - /** - * Get y-coordinate of node position - * @returns {number} - */ - this.getTop = function () { - return _top; - }; - - /** - * Get width of node - * @returns {number} - */ - this.getWidth = function () { - return _width; - }; - - /** - * Get height of node - * @returns {number} - */ - this.getHeight = function () { - return _height; - }; - - /** - * Get position of node on z-axis - * @returns {number} - */ - this.getZIndex = function () { - return _zIndex; - }; - - /** - * is containment type - * @returns {boolean} - */ - this.getContainment = function () { - return _containment; - }; - - /** - * Get JSON representation of node - * @return {Object} - */ - this.getJSON = function () { - return _json; - }; - - /** - * Get corresponding ot operation - * @returns {operations.ot.OTOperation} - * @private - */ - this.getOTOperation = function () { - var otOperation = EntityOperation.prototype.getOTOperation.call(this); - if (otOperation === null) { - otOperation = createOTOperation(); - this.setOTOperation(otOperation); - } - return otOperation; - }; - - /** - * Adjust the passed operation in the history of operation - * when this operation is applied remotely after the passed operation - * on an graph instance stored in the passed EntityManager - * @param {canvas_widget.EntityManager} EntityManager - * @param {EntityOperation} operation Remote operation - * @returns {EntityOperation} - */ - this.adjust = function (EntityManager, operation) { - var edge; - switch (operation.getOperationType()) { - case EntityOperation.TYPES.AttributeAddOperation: - case EntityOperation.TYPES.AttributeDeleteOperation: - edge = EntityManager.findEdge(operation.getRootSubjectEntityId()); - if ( - edge && - (edge.getSource().getEntityId() === this.getEntityId() || - edge.getTarget().getEntityId() === this.getEntityId()) - ) { - return null; - } - if (this.getEntityId() === operation.getRootSubjectEntityId()) { - return null; - } - break; - case EntityOperation.TYPES.EdgeAddOperation: - case EntityOperation.TYPES.EdgeDeleteOperation: - edge = EntityManager.findEdge(operation.getEntityId()); - if ( - edge && - (edge.getSource().getEntityId() === this.getEntityId() || - edge.getTarget().getEntityId() === this.getEntityId()) - ) { - return null; - } - break; - case EntityOperation.TYPES.NodeAddOperation: - case EntityOperation.TYPES.NodeDeleteOperation: - case EntityOperation.TYPES.NodeMoveOperation: - case EntityOperation.TYPES.NodeResizeOperation: - if (this.getEntityId() === operation.getEntityId()) { - return null; - } - break; - case EntityOperation.TYPES.ValueChangeOperation: - edge = EntityManager.findEdge(operation.getRootSubjectEntityId()); - if ( - edge && - (edge.getSource().getEntityId() === this.getEntityId() || - edge.getTarget().getEntityId() === this.getEntityId()) - ) { - return null; - } - if (operation.getRootSubjectEntityId() === this.getEntityId()) { - return null; - } - break; - } - - return operation; - }; - - /** - * Compute the inverse of the operation - * @returns {operations.ot.NodeAddOperation} - */ - this.inverse = function () { - return new NodeAddOperation( - this.getEntityId(), - this.getType(), - this.getLeft(), - this.getTop(), - this.getWidth(), - this.getHeight(), - this.getZIndex(), - this.getContainment(), - this.getContainment(), - json - ); - }; - } - static getOperationDescription(nodeType, nodeLabel, viewId) { - if (!nodeLabel && !viewId) { - return "..deleted " + nodeType; - } else if (!viewId) { - return "..deleted " + nodeType + " " + nodeLabel; - } else - return "..deleted " + nodeType + " " + nodeLabel + " in View " + viewId; - } - toJSON = function () { - return { - id: this.getEntityId(), - type: this.getType(), - left: this.getLeft(), - top: this.getTop(), - width: this.getWidth(), - height: this.getHeight(), - zIndex: this.getZIndex(), - containment: this.getContainment(), - json: this.getJSON(), - }; - }; -} - -class NodeAddOperation extends EntityOperation { - static TYPE = "NodeAddOperation"; - getType; - getOriginType; - getLeft; - getTop; - getWidth; - getHeight; - getZIndex; - getContainment; - getJSON; - getViewId; - getJabberId; - getDefaultLabel; - getDefaultAttributeValues; - toJSON; - - constructor( - entityId, - type, - left, - top, - width, - height, - zIndex, - containment, - json = null, - viewId = null, - oType = null, - jabberId = null, - defaultLabel = null, - defaultAttributeValues = null - ) { - super(EntityOperation.TYPES.NodeAddOperation, entityId, CONFIG.ENTITY.NODE); - var that = this; - - /** - * the identifier of the view - * @type {string} - * @private - */ - var _viewId = viewId; - - /** - * the jabberId of the user - * @type {string} - * @private - */ - var _jabberId = jabberId; - - var _oType = oType; - - /** - * Type of node to add - * @type {String} - * @private - */ - var _type = type; - - /** - * x-coordinate of node position - * @type {number} - * @private - */ - var _left = left; - - /** - * y-coordinate of node position - * @type {number} - * @private - */ - var _top = top; - - /** - * Width of node - * @type {number} - * @private - */ - var _width = width; - - /** - * Height of node - * @type {number} - * @private - */ - var _height = height; - - /** - * Position of node on z-axis - * @type {number} - * @private - */ - var _zIndex = zIndex; - - /** - * is containment type - * @type {boolean} - * @private - */ - var _containment = containment; - - /** - * JSON representation of node - * @type {Object} - * @private - */ - var _json = json; - - /** - * Default label of node - * @type {String} - * @private - */ - var _defaultLabel = defaultLabel; - - /** - * May be used to set default values for node attributes. - */ - var _defaultAttributeValues = defaultAttributeValues; - - /** - * Create OTOperation for operation - * @returns {operations.ot.OTOperation} - */ - var createOTOperation = function () { - return new OTOperation( - CONFIG.ENTITY.NODE + ":" + that.getEntityId(), - JSON.stringify({ - type: _type, - left: _left, - top: _top, - width: _width, - height: _height, - zIndex: _zIndex, - containment: _containment, - json: _json, - viewId: _viewId, - oType: _oType, - jabberId: _jabberId, - }), - CONFIG.OPERATION.TYPE.INSERT, - CONFIG.IWC.POSITION.NODE.ADD - ); - }; - - /** - * Get type of node to add - * @returns {String} - */ - this.getType = function () { - return _type; - }; - - this.getOriginType = function () { - return _oType; - }; - - /** - * Get x-coordinate of node position - * @returns {number} - */ - this.getLeft = function () { - return _left; - }; - - /** - * Get y-coordinate of node position - * @returns {number} - */ - this.getTop = function () { - return _top; - }; - - /** - * Get width of node - * @returns {number} - */ - this.getWidth = function () { - return _width; - }; - - /** - * Get height of node - * @returns {number} - */ - this.getHeight = function () { - return _height; - }; - - /** - * Get position of node on z-axis - * @returns {number} - */ - this.getZIndex = function () { - return _zIndex; - }; - - /** - * Get containment - * @returns {boolean} - */ - this.getContainment = function () { - return _containment; - }; - - /** - * Get JSON representation of node - * @return {Object} - */ - this.getJSON = function () { - return _json; - }; - - /** - * the identifier of the view - * @returns {string} - */ - this.getViewId = function () { - return _viewId; - }; - - /** - * Get the jabberid - * @returns {string} - */ - this.getJabberId = function () { - return _jabberId; - }; - - /** - * Get default label of node - * @returns {string} - */ - this.getDefaultLabel = function () { - return _defaultLabel; - }; - - /** - * Get default values for node attributes. - * @returns {*} - */ - this.getDefaultAttributeValues = function () { - return _defaultAttributeValues; - }; - - /** - * Get corresponding ot operation - * @returns {operations.ot.OTOperation} - * @private - */ - this.getOTOperation = function () { - var otOperation = EntityOperation.prototype.getOTOperation.call(this); - if (otOperation === null) { - otOperation = createOTOperation(); - this.setOTOperation(otOperation); - } - return otOperation; - }; - - /** - * Adjust the passed operation in the history of operation - * when this operation is applied remotely after the passed operation - * on an graph instance stored in the passed EntityManager - * @param {canvas_widget.EntityManager} EntityManager - * @param {EntityOperation} operation Remote operation - * @returns {EntityOperation} - */ - this.adjust = function (EntityManager, operation) { - return operation; - }; - - /** - * Compute the inverse of the operation - * @returns {NodeDeleteOperation} - */ - this.inverse = function () { - return new NodeDeleteOperation( - this.getEntityId(), - this.getType(), - this.getLeft(), - this.getTop(), - this.getWidth(), - this.getHeight(), - this.getZIndex(), - this.getContainment(), - json - ); - }; - - this.toJSON = function () { - return { - id: this.getEntityId(), - type: this.getType(), - left: this.getLeft(), - top: this.getTop(), - width: this.getWidth(), - height: this.getHeight(), - zIndex: this.getZIndex(), - containment: this.getContainment(), - json: this.getJSON(), - viewId: this.getViewId(), - oType: this.getOriginType(), - jabberId: this.getJabberId(), - defaultLabel: this.getDefaultLabel(), - defaultAttributeValues: this.getDefaultAttributeValues(), - triggeredBy: this.triggeredBy, - }; - }; - } - static getOperationDescription(nodeType, nodeLabel, viewId) { - if (!nodeLabel && !viewId) { - return "..created a new " + nodeType; - } else if (!viewId) { - return "..created " + nodeType + " " + nodeLabel; - } else - return ".. created " + nodeType + " " + nodeLabel + " in View " + viewId; - } -} - -/** - * EdgeDeleteOperation - * @class operations.ot.EdgeDeleteOperation - * @memberof operations.ot - * @extends operations.ot.EntityOperation - * @param entityId Entity id of the entity this activity works on - * @param {String} type Type of edge to delete - * @param {String} source Entity id of source node - * @param {String} target Entity id of target node - * @param {object} json JSON representation of edge - * @constructor - */ -class EdgeDeleteOperation extends EntityOperation { - static TYPE = "EdgeDeleteOperation"; - getType; - getSource; - getTarget; - getJSON; - constructor(entityId, type, source, target, json = null) { - super( - EntityOperation.TYPES.EdgeDeleteOperation, - entityId, - CONFIG.ENTITY.EDGE - ); - var that = this; - - /** - * Type of edge to delte - * @type {String} - * @private - */ - var _type = type; - - /** - * Entity id of source node - * @type {String} - * @private - */ - var _source = source; - - /** - * Entity id of target node - * @type {String} - * @private - */ - var _target = target; - - /** - * JSON representation of node - * @type {Object} - * @private - */ - var _json = json; - - /** - * Create OTOperation for operation - * @returns {operations.ot.OTOperation} - */ - var createOTOperation = function () { - return new OTOperation( - CONFIG.ENTITY.EDGE + ":" + that.getEntityId(), - JSON.stringify({ - type: _type, - source: _source, - target: _target, - json: _json, - }), - CONFIG.OPERATION.TYPE.UPDATE, - CONFIG.IWC.POSITION.EDGE.DEL - ); - }; - - /** - * Get type of edge to delete - * @returns {String} - */ - this.getType = function () { - return _type; - }; - - /** - * Get entity id of source node - * @returns {String} - */ - this.getSource = function () { - return _source; - }; - - /** - * Get entity id of target node - * @returns {String} - */ - this.getTarget = function () { - return _target; - }; - - /** - * Get JSON representation of edge - * @return {Object} - */ - this.getJSON = function () { - return _json; - }; - - /** - * Get corresponding ot operation - * @returns {operations.ot.OTOperation} - * @private - */ - this.getOTOperation = function () { - var otOperation = EntityOperation.prototype.getOTOperation.call(this); - if (otOperation === null) { - otOperation = createOTOperation(); - this.setOTOperation(otOperation); - } - return otOperation; - }; - - /** - * Adjust the passed operation in the history of operation - * when this operation is applied remotely after the passed operation - * on an graph instance stored in the passed EntityManager - * @param {canvas_widget.EntityManager} EntityManager - * @param {EntityOperation} operation Remote operation - * @returns {EntityOperation} - */ - this.adjust = function (EntityManager, operation) { - switch (operation.getOperationType()) { - case EntityOperation.TYPES.AttributeAddOperation: - case EntityOperation.TYPES.AttributeDeleteOperation: - if (this.getEntityId() === operation.getRootSubjectEntityId()) { - return null; - } - break; - case EntityOperation.TYPES.EdgeAddOperation: - case EntityOperation.TYPES.EdgeDeleteOperation: - if (this.getEntityId() === operation.getEntityId()) { - return null; - } - break; - case EntityOperation.TYPES.ValueChangeOperation: - if (this.getEntityId() === operation.getRootSubjectEntityId()) { - return null; - } - break; - } - - return operation; - }; - - /** - * Compute the inverse of the operation - * @returns {EdgeAddOperation} - */ - this.inverse = function () { - return new EdgeAddOperation( - this.getEntityId(), - this.getType(), - this.getSource(), - this.getTarget() - ); - }; - } - static getOperationDescription(edgeType, edgeLabel, viewId) { - if (!edgeLabel && !viewId) { - return "..deleted " + edgeType; - } else if (!viewId) { - return "..deleted " + edgeType + " " + edgeLabel; - } else { - return "..deleted " + edgeType + " " + edgeLabel + "in View " + viewId; - } - } - toJSON = function () { - return { - id: this.getEntityId(), - type: this.getType(), - source: this.getSource(), - target: this.getTarget(), - json: this.getJSON(), - }; - }; -} - -/** - * EdgeAddOperation - * @class operations.ot.EdgeAddOperation - * @memberof operations.ot - * @extends operations.ot.EntityOperation - * @param {String} entityId Entity id of the entity this activity works on - * @param {String} type Type of edge to add - * @param {String} source Entity id of source node - * @param {String} target Entity id of target node - * @param {object} json JSON representation of edge - * @param {string} viewId the identifier of the view - * @param {string} oType oType the original Type, only set in views - * @param {string} jabberId the jabberId of the user - * @constructor - */ -class EdgeAddOperation extends EntityOperation { - static TYPE = "EdgeAddOperation"; - getOriginType; - getType; - getSource; - getTarget; - getViewId; - getJabberId; - getJSON; - constructor( - entityId, - type, - source, - target, - json = null, - viewId = null, - oType = null, - jabberId = null - ) { - super(EntityOperation.TYPES.EdgeAddOperation, entityId, CONFIG.ENTITY.EDGE); - var that = this; - - var _oType = oType; - - var _jabberId = jabberId; - - this.getOriginType = function () { - return _oType; - }; - - /** - * the identifier of the view - * @type {string} - * @private - */ - var _viewId = viewId; - - /** - * Type of edge to add - * @type {String} - * @private - */ - var _type = type; - - /** - * Entity id of source node - * @type {String} - * @private - */ - var _source = source; - - /** - * Entity id of target node - * @type {String} - * @private - */ - var _target = target; - - /** - * JSON representation of edge - * @type {Object} - * @private - */ - var _json = json; - - /** - * Create OTOperation for operation - * @returns {operations.ot.OTOperation} - */ - var createOTOperation = function () { - return new OTOperation( - CONFIG.ENTITY.EDGE + ":" + that.getEntityId(), - JSON.stringify({ - type: _type, - source: _source, - target: _target, - json: _json, - viewId: _viewId, - oType: _oType, - jabberId: _jabberId, - }), - CONFIG.OPERATION.TYPE.INSERT, - CONFIG.IWC.POSITION.EDGE.ADD - ); - }; - - /** - * Get type of edge to add - * @returns {String} - */ - this.getType = function () { - return _type; - }; - - /** - * Get entity id of source node - * @returns {String} - */ - this.getSource = function () { - return _source; - }; - - /** - * Get entity id of target node - * @returns {String} - */ - this.getTarget = function () { - return _target; - }; - - /** - * get the identifier of the view - * @returns {string} - */ - this.getViewId = function () { - return _viewId; - }; - - /** - * Get the jabber id - * @returns {string} - */ - this.getJabberId = function () { - return _jabberId; - }; - - /** - * Get JSON representation of edge - * @return {Object} - */ - this.getJSON = function () { - return _json; - }; - - /** - * Get corresponding ot operation - * @returns {operations.ot.OTOperation} - * @private - */ - this.getOTOperation = function () { - var otOperation = EntityOperation.prototype.getOTOperation.call(this); - if (otOperation === null) { - otOperation = createOTOperation(); - this.setOTOperation(otOperation); - } - return otOperation; - }; - - /** - * Adjust the passed operation in the history of operation - * when this operation is applied remotely after the passed operation - * on an graph instance stored in the passed EntityManager - * @param {canvas_widget.EntityManager} EntityManager - * @param {EntityOperation} operation Remote operation - * @returns {EntityOperation} - */ - this.adjust = function (EntityManager, operation) { - return operation; - }; - - /** - * Compute the inverse of the operation - * @returns {EdgeDeleteOperation} - */ - this.inverse = function () { - return new EdgeDeleteOperation( - this.getEntityId(), - this.getType(), - this.getSource(), - this.getTarget() - ); - }; - } - static getOperationDescription( - edgeType, - edgeLabel, - sourceNodeType, - sourceNodeLabel, - targetNodeType, - targetNodeLabel, - viewId - ) { - if (!edgeLabel && !viewId) { - return ( - "..created a new " + - edgeType + - " between " + - sourceNodeType + - " " + - sourceNodeLabel + - " and " + - targetNodeType + - " " + - targetNodeLabel - ); - } else if (!viewId) { - return ( - "..created " + - edgeType + - " " + - edgeLabel + - " between " + - sourceNodeType + - " " + - sourceNodeLabel + - " and " + - targetNodeType + - " " + - targetNodeLabel - ); - } else { - return ( - "..created " + - edgeType + - " " + - edgeLabel + - " between " + - sourceNodeType + - " " + - sourceNodeLabel + - " and " + - targetNodeType + - " " + - targetNodeLabel + - " in View " + - viewId - ); - } - } - toJSON = function () { - return { - id: this.getEntityId(), - type: this.getType(), - source: this.getSource(), - target: this.getTarget(), - json: this.getJSON(), - viewId: this.getViewId(), - oType: this.getOriginType(), - jabberId: this.getJabberId(), - }; - }; -} - -/** - * AttributeAddOperation - * @class operations.ot.AttributeAddOperation - * @memberof operations.ot - * @extends operations.ot.EntityOperation - * @param {String} entityId Entity id of the entity this activity works on - * @param {String} subjectEntityId Id of the entity the attribute is assigned to - * @param {String} rootSubjectEntityId Id of topmost entity in the chain of entities the attribute is assigned to - * @param {String} type Type of attribute to add - * @constructor - */ -class AttributeAddOperation extends EntityOperation { - static TYPE = "AttributeAddOperation"; - getSubjectEntityId; - getRootSubjectEntityId; - getType; - getData; - toJSON; - constructor( - entityId, - subjectEntityId, - rootSubjectEntityId, - type, - data = null - ) { - super( - EntityOperation.TYPES.AttributeAddOperation, - entityId, - CONFIG.ENTITY.ATTR - ); - var that = this; - - /** - * Id of the entity the attribute is assigned to - * @type {String} - * @private - */ - var _subjectEntityId = subjectEntityId; - - /** - * Id of topmost entity in the chain of entities the attribute is assigned to - * @type {String} - * @private - */ - var _rootSubjectEntityId = rootSubjectEntityId; - - /** - * Type of attribute to add - * @type {String} - * @private - */ - var _type = type; - - var _data = data; - - /** - * Create OTOperation for operation - * @returns {operations.ot.OTOperation} - */ - var createOTOperation = function () { - return new OTOperation( - CONFIG.ENTITY.ATTR + ":" + that.getEntityId(), - JSON.stringify({ - type: _type, - subjectEntityId: _subjectEntityId, - rootSubjectEntityId: _rootSubjectEntityId, - data: _data, - }), - CONFIG.OPERATION.TYPE.INSERT, - CONFIG.IWC.POSITION.ATTR.ADD - ); - }; - - /** - * Get id of the entity the attribute is assigned to - * @returns {*} - */ - this.getSubjectEntityId = function () { - return _subjectEntityId; - }; - - /** - * Get id of topmost entity in the chain of entities the attribute is assigned to - * @returns {*} - */ - this.getRootSubjectEntityId = function () { - return _rootSubjectEntityId; - }; - - /** - * Get type of attribute to add - * @returns {*} - */ - this.getType = function () { - return _type; - }; - - /** - * Get corresponding ot operation - * @returns {operations.ot.OTOperation} - * @private - */ - this.getOTOperation = function () { - var otOperation = EntityOperation.prototype.getOTOperation.call(this); - if (otOperation === null) { - otOperation = createOTOperation(); - that.setOTOperation(otOperation); - } - return otOperation; - }; - - this.getData = function () { - return _data; - }; - - /** - * Adjust the passed operation in the history of operation - * when this operation is applied remotely after the passed operation - * on an graph instance stored in the passed EntityManager - * @param {canvas_widget.EntityManager} EntityManager - * @param {EntityOperation} operation Remote operation - * @returns {EntityOperation} - */ - this.adjust = function (EntityManager, operation) { - return operation; - }; - - /** - * Compute the inverse of the operation - * @returns {AttributeDeleteOperation} - */ - this.inverse = function () { - return new AttributeDeleteOperation( - that.getEntityId(), - that.getSubjectEntityId(), - that.getRootSubjectEntityId(), - that.getType() - ); - }; - - this.toJSON = function () { - return { - entityId: this.getEntityId(), - type: this.getType(), - subjectEntityId: this.getSubjectEntityId(), - rootSubjectEntityId: this.getRootSubjectEntityId(), - data: this.getData(), - }; - }; - } -} - -/** - * AttributeDeleteOperation - * @class operations.ot.AttributeDeleteOperation - * @memberof operations.ot - * @extends operations.ot.EntityOperation - * @param {String} entityId Entity id of the entity this activity works on - * @param {String} subjectEntityId Id of the entity the attribute is assigned to - * @param {String} rootSubjectEntityId Id of topmost entity in the chain of entities the attribute is assigned to - * @param {String} type Type of attribute to delete - * @constructor - */ -class AttributeDeleteOperation extends EntityOperation { - static TYPE = "AttributeDeleteOperation"; - getSubjectEntityId; - getRootSubjectEntityId; - getType; - toJSON; - constructor(entityId, subjectEntityId, rootSubjectEntityId, type) { - super( - EntityOperation.TYPES.AttributeDeleteOperation, - entityId, - CONFIG.ENTITY.ATTR - ); - var that = this; - - /** - * Id of the entity the attribute is assigned to - * @type {String} - * @private - */ - var _subjectEntityId = subjectEntityId; - - /** - * Id of topmost entity in the chain of entities the attribute is assigned to - * @type {String} - * @private - */ - var _rootSubjectEntityId = rootSubjectEntityId; - - /** - * Type of attribute to add - * @type {String} - * @private - */ - var _type = type; - - /** - * Create OTOperation for operation - * @returns {operations.ot.OTOperation} - */ - var createOTOperation = function () { - return new OTOperation( - CONFIG.ENTITY.ATTR + ":" + that.getEntityId(), - JSON.stringify({ - type: _type, - subjectEntityId: _subjectEntityId, - rootSubjectEntityId: _rootSubjectEntityId, - }), - CONFIG.OPERATION.TYPE.UPDATE, - CONFIG.IWC.POSITION.ATTR.DEL - ); - }; - - /** - * Get id of the entity the attribute is assigned to - * @returns {*} - */ - this.getSubjectEntityId = function () { - return _subjectEntityId; - }; - - /** - * Get id of topmost entity in the chain of entities the attribute is assigned to - * @returns {*} - */ - this.getRootSubjectEntityId = function () { - return _rootSubjectEntityId; - }; - - /** - * Get type of attribute to add - * @returns {*} - */ - this.getType = function () { - return _type; - }; - - /** - * Get corresponding ot operation - * @returns {operations.ot.OTOperation} - * @private - */ - this.getOTOperation = function () { - var otOperation = EntityOperation.prototype.getOTOperation.call(this); - if (otOperation === null) { - otOperation = createOTOperation(); - that.setOTOperation(otOperation); - } - return otOperation; - }; - - /** - * Adjust the passed operation in the history of operation - * when this operation is applied remotely after the passed operation - * on an graph instance stored in the passed EntityManager - * @param {canvas_widget.EntityManager} EntityManager - * @param {operations.ot.EntityOperation} operation Remote operation - * @returns {operations.ot.EntityOperation} - */ - this.adjust = function (EntityManager, operation) { - switch (operation.getOperationType()) { - case EntityOperation.TYPES.AttributeAddOperation: - case EntityOperation.TYPES.AttributeDeleteOperation: - if ( - that.getRootSubjectEntityId() === operation.getRootSubjectEntityId() - ) { - return null; - } - break; - case EntityOperation.TYPES.ValueChangeOperation: - if (operation.getEntityIdChain().indexOf(this.getEntityId()) !== -1) { - return null; - } - break; - } - - return operation; - }; - - /** - * Compute the inverse of the operation - * @returns {operations.ot.AttributeAddOperation} - */ - this.inverse = function () { - return new AttributeAddOperation( - this.getEntityId(), - this.getSubjectEntityId(), - this.getRootSubjectEntityId(), - this.getType() - ); - }; - this.toJSON = function () { - return { - entityId: this.getEntityId(), - type: this.getType(), - subjectEntityId: this.getSubjectEntityId(), - rootSubjectEntityId: this.getRootSubjectEntityId(), - }; - }; - } -} - -/** - * NodeMoveOperation - * @class operations.ot.NodeMoveOperation - * @memberof operations.ot - * @extends operations.ot.EntityOperation - * @param {String} entityId Entity id of the entity this activity works on - * @param {number} offsetX Offset in x-direction - * @param {number} offsetY Offset in y-direction - * @param {string} optional: jabberId the jabberId of the user (is automatically set by propagateNodeMoveOperation) - * @constructor - */ -class NodeMoveOperation extends EntityOperation { - static TYPE = "NodeMoveOperation"; - getOffsetX; - getOffsetY; - getJabberId; - setJabberId; - constructor(entityId, offsetX, offsetY, jabberId) { - super( - EntityOperation.TYPES.NodeMoveOperation, - entityId, - CONFIG.ENTITY.NODE - ); - var that = this; - - /** - * Offset in x-direction - * @type {number} - * @private - */ - var _offsetX = offsetX; - - /** - * Offset in y-direction - * @type {number} - * @private - */ - var _offsetY = offsetY; - - /** - * jabber id of the user - * @type {string} - * @private - */ - var _jabberId = jabberId; - - /** - * Create OTOperation for operation - * @returns {operations.ot.OTOperation} - */ - var createOTOperation = function () { - return new OTOperation( - CONFIG.ENTITY.NODE + ":" + that.getEntityId(), - JSON.stringify({ - offsetX: _offsetX, - offsetY: _offsetY, - jabberId: _jabberId, - }), - CONFIG.OPERATION.TYPE.UPDATE, - CONFIG.IWC.POSITION.NODE.POS - ); - }; - - /** - * Get offset in x-direction - * @returns {number} - */ - this.getOffsetX = function () { - return _offsetX; - }; - - /** - * Get offset in y-direction - * @returns {number} - */ - this.getOffsetY = function () { - return _offsetY; - }; - - /** - * Get the JabberId - * @returns {string} - */ - this.getJabberId = function () { - return _jabberId; - }; - /** - * Set the JabberId - * @param {string} jabberId - */ - this.setJabberId = function (jabberId) { - _jabberId = jabberId; - }; - - /** - * Get corresponding ot operation - * @returns {operations.ot.OTOperation} - * @private - */ - this.getOTOperation = function () { - var otOperation = EntityOperation.prototype.getOTOperation.call(this); - if (otOperation === null) { - otOperation = createOTOperation(); - this.setOTOperation(otOperation); - } - return otOperation; - }; - - /** - * Adjust the passed operation in the history of operation - * when this operation is applied remotely after the passed operation - * on an graph instance stored in the passed EntityManager - * @param {canvas_widget.EntityManager} EntityManager - * @param {EntityOperation} operation Remote operation - * @returns {EntityOperation} - */ - this.adjust = function (EntityManager, operation) { - return operation; - }; - - /** - * Compute the inverse of the operation - * @returns {NodeMoveOperation} - */ - this.inverse = function () { - return new NodeMoveOperation( - this.getEntityId(), - -this.getOffsetX(), - -this.getOffsetY(), - this.getJabberId() - ); - }; - } - static getOperationDescription(nodeType, nodeLabel, viewId) { - if (!nodeLabel && !viewId) { - return "..moved " + nodeType; - } else if (!viewId) { - return "..moved " + nodeType + " " + nodeLabel; - } else { - return "..moved " + nodeType + " " + nodeLabel + " in View " + viewId; - } - } - toJSON = function () { - return { - id: this.getEntityId(), - offsetX: this.getOffsetX(), - offsetY: this.getOffsetY(), - jabberId: this.getJabberId(), - }; - }; -} - -/** - * NodeMoveZOperation - * @class operations.ot.NodeMoveZOperation - * @memberof operations.ot - * @extends operations.ot.EntityOperation - * @param {String} entityId Entity id of the entity this activity works on - * @param {number} offsetZ Offset in z-direction - * @param {string} optional: jabberId the jabberId of the user (is automatically set by propagateNodeMoveOperation) - * @constructor - */ -class NodeMoveZOperation extends EntityOperation { - static TYPE = "NodeMoveZOperation"; - getOffsetZ; - getJabberId; - setJabberId; - constructor(entityId, offsetZ, jabberId) { - super( - EntityOperation.TYPES.NodeMoveZOperation, - entityId, - CONFIG.ENTITY.NODE - ); - var that = this; - - /** - * Offset in y-direction - * @type {number} - * @private - */ - var _offsetZ = offsetZ; - - /** - * the jabberId - * @type {string} - * @private - */ - var _jabberId = jabberId; - - /** - * Create OTOperation for operation - * @returns {operations.ot.OTOperation} - */ - var createOTOperation = function () { - return new OTOperation( - CONFIG.ENTITY.NODE + ":" + that.getEntityId(), - JSON.stringify({ - offsetZ: _offsetZ, - jabberId: _jabberId, - }), - CONFIG.OPERATION.TYPE.UPDATE, - CONFIG.IWC.POSITION.NODE.Z - ); - }; - - /** - * Get offset in z-direction - * @returns {number} - */ - this.getOffsetZ = function () { - return _offsetZ; - }; - - this.getJabberId = function () { - return _jabberId; - }; - - this.setJabberId = function (jabberId) { - _jabberId = jabberId; - }; - - /** - * Get corresponding ot operation - * @returns {operations.ot.OTOperation} - * @private - */ - this.getOTOperation = function () { - var otOperation = EntityOperation.prototype.getOTOperation.call(this); - if (otOperation === null) { - otOperation = createOTOperation(); - this.setOTOperation(otOperation); - } - return otOperation; - }; - - /** - * Adjust the passed operation in the history of operation - * when this operation is applied remotely after the passed operation - * on an graph instance stored in the passed EntityManager - * @param {canvas_widget.EntityManager} EntityManager - * @param {EntityOperation} operation Remote operation - * @returns {EntityOperation} - */ - this.adjust = function (EntityManager, operation) { - return operation; - }; - - /** - * Compute the inverse of the operation - * @returns {NodeMoveZOperation} - */ - this.inverse = function () { - return new NodeMoveZOperation( - this.getEntityId(), - -this.getOffsetZ(), - this.getJabberId() - ); - }; - } - static getOperationDescription(nodeType, nodeLabel, viewId) { - if (!nodeLabel && !viewId) { - return "..moved " + nodeType + " on on Z-Axis"; - } else if (!viewId) { - return "..moved " + nodeType + " " + nodeLabel + " on Z-Axis"; - } else { - return ( - "..moved " + - nodeType + - " " + - nodeLabel + - " in View " + - viewId + - " on Z-Axis" - ); - } - } - toJSON = function () { - return { - id: this.getEntityId(), - offsetZ: this.getOffsetZ(), - jabberId: this.getJabberId(), - }; - }; -} - -/** - * NodeResizeOperation - * @class operations.ot.NodeResizeOperation - * @memberof operations.ot - * @extends operations.ot.EntityOperation - * @param {String} entityId Entity id of the entity this activity works on - * @param {number} offsetX Offset in x-direction - * @param {number} offsetY Offset in y-direction - * @param {string} optional: jabberId the jabberId of the user (is automatically set by propagateNodeMoveOperation) - * @constructor - */ -class NodeResizeOperation extends EntityOperation { - static TYPE = "NodeResizeOperation"; - getOffsetX - getOffsetY - getJabberId - setJabberId - constructor(entityId, offsetX, offsetY, jabberId) { - super( - EntityOperation.TYPES.NodeResizeOperation, - entityId, - CONFIG.ENTITY.NODE - ); - var that = this; - - var _jabberId = jabberId; - - /** - * Offset in x-direction - * @type {number} - * @private - */ - var _offsetX = offsetX; - - /** - * Offset in y-direction - * @type {number} - * @private - */ - var _offsetY = offsetY; - - /** - * Create OTOperation for operation - * @returns {operations.ot.OTOperation} - */ - var createOTOperation = function () { - return new OTOperation( - CONFIG.ENTITY.NODE + ":" + that.getEntityId(), - JSON.stringify({ - offsetX: _offsetX, - offsetY: _offsetY, - jabberId: _jabberId, - }), - CONFIG.OPERATION.TYPE.UPDATE, - CONFIG.IWC.POSITION.NODE.DIM - ); - }; - - /** - * Get offset in x-direction - * @returns {number} - */ - this.getOffsetX = function () { - return _offsetX; - }; - - /** - * Get offset in y-direction - * @returns {number} - */ - this.getOffsetY = function () { - return _offsetY; - }; - - this.getJabberId = function () { - return _jabberId; - }; - - this.setJabberId = function (jabberId) { - _jabberId = jabberId; - }; - - /** - * Get corresponding ot operation - * @returns {operations.ot.OTOperation} - * @private - */ - this.getOTOperation = function () { - var otOperation = EntityOperation.prototype.getOTOperation.call(this); - if (otOperation === null) { - otOperation = createOTOperation(); - this.setOTOperation(otOperation); - } - return otOperation; - }; - - /** - * Adjust the passed operation in the history of operation - * when this operation is applied remotely after the passed operation - * on an graph instance stored in the passed EntityManager - * @param {canvas_widget.EntityManager} EntityManager - * @param {EntityOperation} operation Remote operation - * @returns {EntityOperation} - */ - this.adjust = function (EntityManager, operation) { - return operation; - }; - - /** - * Compute the inverse of the operation - * @returns {NodeResizeOperation} - */ - this.inverse = function () { - return new NodeResizeOperation( - this.getEntityId(), - -this.getOffsetX(), - -this.getOffsetY(), - this.getJabberId() - ); - }; - } - static getOperationDescription(nodeType, nodeLabel, viewId) { - if (!nodeLabel && !viewId) { - return "..resized " + nodeType; - } else if (!viewId) { - return "..resized " + nodeType + " " + nodeLabel; - } else { - return "..resized " + nodeType + " " + nodeLabel + " in View " + viewId; - } - } - toJSON=function() { - return { - id: this.getEntityId(), - offsetX: this.getOffsetX(), - offsetY: this.getOffsetY(), - jabberId: this.getJabberId(), - }; - } -} - -/** - * ValueChangeOperation - * @class operations.ot.ValueChangeOperation - * @memberof operations.ot - * @extends operations.ot.EntityOperation - * @param entityId Entity id of the entity this activity works on - * @param {string} value Char that has been added resp. deleted - * @param {string} type Type of operation (insertion resp. deletion) - * @param {number} position Position where the char has been added resp. deleted - * @constructor - */ -class ValueChangeOperation extends EntityOperation { - static TYPE = "ValueChangeOperation"; - getJabberId; - setJabberId; - getFromView; - setFromView; - getValue; - getType; - setPosition; - getPosition; - setRemote; - getRemote; - setEntityIdChain; - getEntityIdChain; - getRootSubjectEntityId; - constructor( - entityId, - value, - type, - position, - jabberId = null, - fromView = null - ) { - if (!entityId) throw new Error("Entity id is required"); - super( - EntityOperation.TYPES.ValueChangeOperation, - entityId, - CONFIG.ENTITY.VAL - ); - var that = this; - - var _fromView = fromView; - - var _jabberId = jabberId; - - /** - * Char that has been added resp. deleted - * @type {string} - * @private - */ - var _value = value; - - /** - * Type of operation (insertion resp. deletion) - * @type {string} - * @private - */ - var _type = type; - - /** - * Position where the char has been added resp. deleted - * @type {number} - * @private - */ - var _position = position; - - /** - * Is the change issued by a remote user - * @type {boolean} - * @private - */ - var _remote = true; - - /** - * Chain of entities the value is assigned to - * @type {string[]} - * @private - */ - var _entityIdChain = []; - - /** - * Create OTOperation for operation - * @returns {operations.ot.OTOperation} - */ - var createOTOperation = function () { - return new OTOperation( - CONFIG.ENTITY.VAL + ":" + that.getEntityId(), - _value, - _type, - _position, - _jabberId, - _fromView - ); - }; - - this.getJabberId = function () { - return _jabberId; - }; - this.setJabberId = function (jabberId) { - _jabberId = jabberId; - }; - - this.getFromView = function () { - return _fromView; - }; - - this.setFromView = function (fromView) { - _fromView = fromView; - }; - /** - * Get char that has been added resp. deleted - * @returns {string} - */ - this.getValue = function () { - return _value; - }; - - /** - * Get type of operation (insertion resp. deletion) - * @returns {string} - */ - this.getType = function () { - return _type; - }; - - /** - * Set type of operation (insertion resp. deletion) - * @param position - */ - this.setPosition = function (position) { - _position = position; - }; - - /** - * Get position where the char has been added resp. deleted - * @returns {number} - */ - this.getPosition = function () { - return _position; - }; - - /** - * Set if the change is issued by a remote user - * @param remote - */ - this.setRemote = function (remote) { - _remote = remote; - }; - - /** - * Get if the change is issued by a remote user - * @returns {boolean} - */ - this.getRemote = function () { - return _remote; - }; - - /** - * Set chain of entities the value is assigned to - * @param {string[]} entityIdChain - */ - this.setEntityIdChain = function (entityIdChain) { - _entityIdChain = entityIdChain; - }; - - /** - * Get chain of entities the value is assigned to - * @returns {string[]} - */ - this.getEntityIdChain = function () { - return _entityIdChain; - }; - - /** - * Get topmost entity in the chain of entity the value is assigned to - * @returns {string} - */ - this.getRootSubjectEntityId = function () { - return _entityIdChain[0]; - }; - - /** - * Get corresponding ot operation - * @returns {operations.ot.OTOperation} - * @private - */ - this.getOTOperation = function () { - var otOperation = EntityOperation.prototype.getOTOperation.call(this); - if (otOperation === null) { - otOperation = createOTOperation(); - this.setOTOperation(otOperation); - } - return otOperation; - }; - - /** - * Adjust the passed operation in the history of operation - * when this operation is applied remotely after the passed operation - * on an graph instance stored in the passed EntityManager - * @param {canvas_widget.EntityManager} EntityManager - * @param {operations.ot.EntityOperation} operation Remote operation - * @returns {operations.ot.EntityOperation} - */ - this.adjust = function (EntityManager, operation) { - switch (operation.getOperationType()) { - case EntityOperation.TYPES.ValueChangeOperation: - if (this.getEntityId() === operation.getEntityId()) { - if ( - (this.getPosition() === operation.getPosition && - this.getValue() === operation.getValue && - this.getType() === CONFIG.OPERATION.TYPE.INSERT && - operation.getType() === CONFIG.OPERATION.TYPE.DELETE) || - (this.getType() === CONFIG.OPERATION.TYPE.DELETE && - operation.getType() === CONFIG.OPERATION.TYPE.INSERT) - ) { - return null; - } - if (this.getPosition() <= operation.getPosition()) { - switch (this.getType()) { - case CONFIG.OPERATION.TYPE.INSERT: - operation.setPosition(operation.getPosition() + 1); - break; - case CONFIG.OPERATION.TYPE.DELETE: - operation.setPosition(operation.getPosition() - 1); - break; - } - } - } - break; - } - - return operation; - }; - - /** - * Compute the inverse of the operation - * @returns {ValueChangeOperation} - */ - this.inverse = function () { - var newType, - ValueChangeOperation = ValueChangeOperation; - - switch (this.getType()) { - case CONFIG.OPERATION.TYPE.INSERT: - newType = CONFIG.OPERATION.TYPE.DELETE; - break; - case CONFIG.OPERATION.TYPE.DELETE: - newType = CONFIG.OPERATION.TYPE.INSERT; - break; - case CONFIG.OPERATION.TYPE.UPDATE: - newType = CONFIG.OPERATION.TYPE.UPDATE; - break; - } - return new ValueChangeOperation( - this.getEntityId(), - this.getValue(), - newType, - this.getPosition() - ); - }; - this.toJSON = function () { - return { - entityId: this.getEntityId(), - value: this.getValue(), - position: this.getPosition(), - type: this.getType(), - jabberId: this.getJabberId(), - }; - }; - } - - static getOperationDescription(valueKey, entityType, entityName, viewId) { - if (!viewId) - return ( - ".. changed " + - valueKey + - " of " + - entityType + - (entityName ? " " : "") + - entityName - ); - else - return ( - ".. changed " + - valueKey + - " of " + - entityType + - (entityName ? " " : "") + - entityName + - " in View " + - viewId - ); - } -} - -EntitySelectOperation.TYPE = "EntitySelectOperation"; - -/** - * Entity Select Operation - * @class operations.non_ot.EntitySelectOperation - * @memberof operations.non_ot - * @constructor - * @param {string} selectedEntityId Entity id of the selected entity - * @param {string} selectedEntityType - * @param {string} jabberId - */ - -function EntitySelectOperation(selectedEntityId, selectedEntityType, jabberId) { - /** - * Entity id of the selected entity - * @type {string} - * @private - */ - var _selectedEntityId = selectedEntityId; - - var _jabberId = jabberId; - - var _selectedEntityType = selectedEntityType; - - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var _nonOTOperation = null; - - /** - * Get entity id of the selected entity - * @returns {string} - */ - this.getSelectedEntityId = function () { - return _selectedEntityId; - }; - - this.getSelectedEntityType = function () { - return _selectedEntityType; - }; - - this.getJabberId = function () { - return _jabberId; - }; - - /** - * Set corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - */ - this.setNonOTOperation = function (nonOTOperation) { - _nonOTOperation = nonOTOperation; - }; - - /** - * Get corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - */ - this.getNonOTOperation = function () { - return _nonOTOperation; - }; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (_nonOTOperation === null) { - _nonOTOperation = new NonOTOperation( - EntitySelectOperation.TYPE, - JSON.stringify({ - selectedEntityId: _selectedEntityId, - selectedEntityType: _selectedEntityType, - }) - ); - } - return _nonOTOperation; - }; -} - -EntitySelectOperation.prototype.toJSON = function () { - return { - selectedEntityId: this.getSelectedEntityId(), - selectedEntityType: this.getSelectedEntityType(), - jabberId: this.getJabberId(), - }; -}; +/** + * Function to check if the event was triggered by the current user + * @param {YEvent} yEvent YEvent + * @returns {boolean} true if the event was triggered by the current user + */ +function eventWasTriggeredByMe(yEvent) { + const array = Array.from(yEvent.changes.keys.keys()); + if (!array) return false; + const modifiedByKey = array.find((key) => key === "modifiedBy"); + if ( + modifiedByKey && + yEvent.currentTarget.get(modifiedByKey) === window.y.clientID + ) + // modified by us + return true; + return false; +} -/** - * ToolSelectOperation - * @class operations.non_ot.ToolSelectOperation.non_ot.ToolSelectOperation - * @memberof operations.non_ot - * @constructor - * @param {string} toolName Name of selected tool - * @param label - * @param {map} defaultAttributeValues Map containing default values for the attributes of a node. - */ -class ToolSelectOperation { - static TYPE = "ToolSelectOperation"; - /** - * Name of selected tool - * @type {string} - */ - selectedToolName; - - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - nonOTOperation; - - /** - * Default label of selected tool - * @type {string} - */ - defaultLabel; - - /** - * May be used to set default values for node attributes. - * @type {map} - */ - defaultAttributeValues; - - /** - * Get name of selected tool - * @returns {string} - */ - getSelectedToolName; - - /** - * Get default label of selected tool - * @returns {string} - */ - getDefaultLabel; - - /** - * Get default values for node attributes. - * @returns {map} - */ - getDefaultAttributeValues; - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - toNonOTOperation; - constructor(toolName, label, defaultAttributeValues = {}) { - /** - * Name of selected tool - * @type {string} - */ - var selectedToolName = toolName; - - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var nonOTOperation = null; - - /** - * Default label of selected tool - * @type {string} - */ - var defaultLabel = label; - - /** - * May be used to set default values for node attributes. - * @type {map} - */ - var defaultAttributeValues = defaultAttributeValues; - - /** - * Get name of selected tool - * @returns {string} - */ - this.getSelectedToolName = function () { - return selectedToolName; - }; - - /** - * Get default label of selected tool - * @returns {string} - */ - this.getDefaultLabel = function () { - return defaultLabel; - }; - - /** - * Get default values for node attributes. - * @returns {map} - */ - this.getDefaultAttributeValues = function () { - return defaultAttributeValues; - }; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (nonOTOperation === null) { - nonOTOperation = new NonOTOperation( - ToolSelectOperation.TYPE, - JSON.stringify({ selectedToolName: selectedToolName }) - ); - } - return nonOTOperation; - }; - } -} - -/** - * ActivityOperation - * @class operations.non_ot.ActivityOperation - * @memberof operations.non_ot - * @constructor - * @param {string} type Type of activity - * @param {string} entityId Entity id of the entity this activity works on - * @param {string} sender JabberId of the user who issued this activity - * @param {string} text Text of this activity which is displayed in the activity widget - * @param {object} data Additional data for the activity - */ -class ActivityOperation { - static TYPE = "ActivityOperation"; - constructor(type, entityId, sender, text, data) { - /** - * Type of activity - * @type {string} - * @private - */ - var _type = type; - - /** - * Entity id of the entity this activity works on - * @type {string} - * @private - */ - var _entityId = entityId; - - /** - * JabberId of the user who issued this activity - * @type {string} - * @private - */ - var _sender = sender; - - /** - * Text of this activity which is displayed in the activity widget - * @type {string} - * @private - */ - var _text = text; - - /** - * Additional data for the activity - * @type {Object} - * @private - */ - var _data = data; - - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var _nonOTOperation = null; - - /** - * Get type of activity - * @returns {string} - */ - this.getType = function () { - return _type; - }; - - /** - * Get entity id of the entity this activity works on - * @returns {string} - */ - this.getEntityId = function () { - return _entityId; - }; - - /** - * Get JabberId of the user who issued this activity - * @returns {string} - */ - this.getSender = function () { - return _sender; - }; - - /** - * Get text of this activity which is displayed in the activity widget - * @returns {string} - */ - this.getText = function () { - return _text; - }; - - /** - * Get additional data for the activity - * @returns {Object} - */ - this.getData = function () { - return _data; - }; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (_nonOTOperation === null) { - _nonOTOperation = new NonOTOperation( - ActivityOperation.TYPE, - JSON.stringify({ - type: _type, - entityId: _entityId, - sender: _sender, - text: _text, - data: _data, - }) - ); - } - return _nonOTOperation; - }; - } - toJSON() { - return { - type: this.getType(), - entityId: this.getEntityId(), - sender: this.getSender(), - text: this.getText(), - data: this.getData(), - }; - } -} - -ExportMetaModelOperation.TYPE = "ExportMetaModelOperation"; - -/** - * Export Image Operation - * @class operations.non_ot.ExportMetaModelOperation - * @memberof operations.non_ot - * @constructor - * @param {string} requestingComponent Name of requesting Component - * @param {string} data Meta model - */ -function ExportMetaModelOperation(requestingComponent, data) { - /** - * Name of requesting Component - * @type {string} - * @private - */ - var _requestingComponent = requestingComponent; - /** - * Meta model - * @type {object} - * @private - */ - var _data = data; - - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var _nonOTOperation = null; - - /** - * Get name of requesting Component - * @returns {string} - */ - this.getRequestingComponent = function () { - return _requestingComponent; - }; - - /** - * Get data URL of image - * @returns {object} - */ - this.getData = function () { - return _data; - }; - - /** - * Get exported JSON representation of the graph - * @param {object} data - */ - this.setData = function (data) { - _data = data; - }; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (_nonOTOperation === null) { - _nonOTOperation = new NonOTOperation( - ExportMetaModelOperation.TYPE, - JSON.stringify({ - requestingComponent: _requestingComponent, - data: _data, - }) - ); - } - return _nonOTOperation; - }; -} - -ExportLogicalGuidanceRepresentationOperation.TYPE = - "ExportLogicalGuidanceRepresentationOperation"; - -/** - * Export Image Operation - * @class operations.non_ot.ExportLogicalGuidanceRepresentationOperation - * @memberof operations.non_ot - * @constructor - * @param {string} requestingComponent Name of requesting Component - * @param {string} data Meta model - */ -function ExportLogicalGuidanceRepresentationOperation( - requestingComponent, - data -) { - /** - * Name of requesting Component - * @type {string} - * @private - */ - var _requestingComponent = requestingComponent; - /** - * Guidance rules - * @type {object} - * @private - */ - var _data = data; - - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var _nonOTOperation = null; - - /** - * Get name of requesting Component - * @returns {string} - */ - this.getRequestingComponent = function () { - return _requestingComponent; - }; - - /** - * Get data URL of image - * @returns {object} - */ - this.getData = function () { - return _data; - }; - - /** - * Get exported JSON representation of the graph - * @param {object} data - */ - this.setData = function (data) { - _data = data; - }; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (_nonOTOperation === null) { - _nonOTOperation = new NonOTOperation( - ExportLogicalGuidanceRepresentationOperation.TYPE, - JSON.stringify({ - requestingComponent: _requestingComponent, - data: _data, - }) - ); - } - return _nonOTOperation; - }; -} - -ExportImageOperation.TYPE = "ExportImageOperation"; - -/** - * Export Image Operation - * @class operations.non_ot.ExportImageOperation - * @memberof operations.non_ot - * @constructor - * @param {string} requestingComponent Name of requesting Component - * @param {string} data Data URL of image - */ -function ExportImageOperation(requestingComponent, data) { - /** - * Name of requesting Component - * @type {string} - * @private - */ - var _requestingComponent = requestingComponent; - /** - * Data URL of image - * @type {object} - * @private - */ - var _data = data; - - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var _nonOTOperation = null; - - /** - * Get name of requesting Component - * @returns {string} - */ - this.getRequestingComponent = function () { - return _requestingComponent; - }; - - /** - * Get data URL of image - * @returns {object} - */ - this.getData = function () { - return _data; - }; - - /** - * Get exported JSON representation of the graph - * @param {object} data - */ - this.setData = function (data) { - _data = data; - }; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (_nonOTOperation === null) { - _nonOTOperation = new NonOTOperation( - ExportImageOperation.TYPE, - JSON.stringify({ - requestingComponent: _requestingComponent, - data: _data, - }) - ); - } - return _nonOTOperation; - }; -} - -/** - * SetViewTypesOperation - * @class operations.non_ot.WidgetEnterOperation - * @memberof operations.non_ot - * @constructor - * @param {boolean} flag enable (true)/disable(false) the view types of the vml in the palette widget - */ -class SetViewTypesOperation { - static TYPE = "SetViewTypesOperation"; - _flag; - nonOTOperation; - /** - * Get name of selected tool - * @returns {string} - */ - getFlag = function () { - return this._flag; - }; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - toNonOTOperation = function () { - if (this.nonOTOperation === null) { - this.nonOTOperation = new NonOTOperation( - SetViewTypesOperation.TYPE, - JSON.stringify({ flag: this._flag }) - ); - } - return this.nonOTOperation; - }; - - constructor(flag) { - /** - * Enable or disable the view types of the vml - * @type {boolean} - * @private - */ - this._flag = flag; - - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - this.nonOTOperation = null; - } -} - -/** - * InitModelTypesOperation - * @class operations.non_ot.InitModelTypesOperation - * @memberof operations.non_ot - * @constructor - * @param {string} vls the visual language specification - * @param {bool} startViewGeneration - */ -class InitModelTypesOperation { - static TYPE = "InitModelTypesOperation"; - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - nonOTOperation = null; - _vls; - _startViewGeneration; - getVLS = function () { - return this._vls; - }; - - /** - * Get name of selected tool - * @returns {string} - */ - getViewGenerationFlag = function () { - return this._startViewGeneration; - }; - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - toNonOTOperation = function () { - if (this.nonOTOperation === null) { - this.nonOTOperation = new NonOTOperation( - InitModelTypesOperation.TYPE, - JSON.stringify({ - vls: this._vls, - startViewGeneration: this._startViewGeneration, - }) - ); - } - return this.nonOTOperation; - }; - constructor(vls, startViewGeneration) { - /** - * Name of selected tool - * @type {string} - */ - this._vls = vls; - - this._startViewGeneration = startViewGeneration; - } +function getQuerySelectorFromNode(node) { + if (node instanceof jQuery) { + node = node.get(0); + } + if (node.id) { + return `[id="${node.id}"]`; + // return `#${node.id}`; // This is not working since the implementation of querySelectorAll disallows getting elements by id with a hash if the id starts with a number + } + if (node.className) { + return `.${node.className}`; + } + return null; } -ViewInitOperation.TYPE = "ViewInitOperation"; - -/** - * ViewInitOperation - * @class operations.non_ot.ViewInitOperation - * @memberof operations.non_ot - * @constructor - * @param {object} data the view as json - * @param {object} viewpoint the viewpoint vls as json - */ -function ViewInitOperation(data, viewpoint) { - /** - * Name of selected tool - * @type {string} - */ - var _data = data; - - var _viewpoint = viewpoint; - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var nonOTOperation = null; - - /** - * Get name of selected tool - * @returns {string} - */ - this.getData = function () { - return _data; - }; - - this.getViewpoint = function () { - return _viewpoint; - }; - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (nonOTOperation === null) { - nonOTOperation = new NonOTOperation( - ViewInitOperation.TYPE, - JSON.stringify({ data: _data, viewpoint: _viewpoint }) - ); - } - return nonOTOperation; - }; -} - -/** - * DeleteViewOperation - * @class operations.non_ot.DeleteViewOperation - * @memberof operations.non_ot - * @constructor - * @param {string} viewId identifier of the view - */ -class DeleteViewOperation { - static TYPE = "DeleteViewOperation"; - constructor(viewId) { - /** - * Name of selected tool - * @type {string} - */ - var _viewId = viewId; - - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var nonOTOperation = null; - - /** - * Get the list with node ids to delete - * @returns {string} - */ - this.getViewId = function () { - return _viewId; - }; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (nonOTOperation === null) { - nonOTOperation = new NonOTOperation( - DeleteViewOperation.TYPE, - JSON.stringify({ viewId: _viewId }) - ); - } - return nonOTOperation; - }; - } -} - -SetModelAttributeNodeOperation.TYPE = "SetModelAttributeNodeOperation"; - -/** - * SetModelAttributeNodeOperation - * @class operations.non_ot.SetModelAttributeNodeOperation - * @memberof operations.non_ot - * @constructor - */ -function SetModelAttributeNodeOperation() { - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var nonOTOperation = null; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (nonOTOperation === null) { - nonOTOperation = new NonOTOperation( - SetModelAttributeNodeOperation.TYPE, - JSON.stringify({ empty: "empty" }) - ); - } - return nonOTOperation; - }; -} - -UpdateViewListOperation.TYPE = "UpdateViewListOperation"; - -/** - * UpdateViewListOperation - * @class operations.non_ot.UpdateViewListOperation - * @memberof operations.non_ot - * @constructor - */ -function UpdateViewListOperation() { - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var nonOTOperation = null; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (nonOTOperation === null) { - nonOTOperation = new NonOTOperation( - UpdateViewListOperation.TYPE, - JSON.stringify({}) - ); - } - return nonOTOperation; - }; -} - -ShowGuidanceBoxOperation.TYPE = "ShowGuidanceBoxOperation"; - -/** - * ToolGuidanceOperation - * @class operations.non_ot.ToolGuidanceOperation - * @memberof operations.non_ot - * @constructor - * @param {string} toolName Name of selected tool - */ -function ShowGuidanceBoxOperation(label, guidance, entityId) { - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var nonOTOperation = null; - var _label = label; - var _guidance = guidance; - var _entityId = entityId; - - this.getLabel = function () { - return _label; - }; - - this.getGuidance = function () { - return _guidance; - }; - - this.getEntityId = function () { - return _entityId; - }; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (nonOTOperation === null) { - nonOTOperation = new NonOTOperation( - ShowGuidanceBoxOperation.TYPE, - JSON.stringify({ - label: _label, - guidance: _guidance, - entityId: _entityId, - }) - ); - } - return nonOTOperation; - }; -} - -CanvasViewChangeOperation.TYPE = "CanvasViewChangeOperation"; - -/** - * Entity Select Operation - * @class operations.non_ot.EntitySelectOperation - * @memberof operations.non_ot - * @constructor - * @param {string} selectedEntityId Entity id of the selected entity - */ -function CanvasViewChangeOperation(left, top, width, height, zoom) { - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var _nonOTOperation = null; - - this.getLeft = function () { - return left; - }; - - this.getTop = function () { - return top; - }; - - this.getWidth = function () { - return width; - }; - - this.getHeight = function () { - return height; - }; - - this.getZoom = function () { - return zoom; - }; - - /** - * Set corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - */ - this.setNonOTOperation = function (nonOTOperation) { - _nonOTOperation = nonOTOperation; - }; - - /** - * Get corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - */ - this.getNonOTOperation = function () { - return _nonOTOperation; - }; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (_nonOTOperation === null) { - _nonOTOperation = new NonOTOperation( - CanvasViewChangeOperation.TYPE, - JSON.stringify({ - left: left, - top: top, - width: width, - height: height, - zoom: zoom, - }) - ); - } - return _nonOTOperation; - }; -} - -RevokeSharedActivityOperation.TYPE = "RevokeSharedActivityOperation"; - -/** - * Entity Select Operation - * @class operations.non_ot.EntitySelectOperation - * @memberof operations.non_ot - * @constructor - * @param {string} selectedEntityId Entity id of the selected entity - */ -function RevokeSharedActivityOperation(id) { - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var _nonOTOperation = null; - - this.getId = function () { - return id; - }; - - /** - * Set corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - */ - this.setNonOTOperation = function (nonOTOperation) { - _nonOTOperation = nonOTOperation; - }; - - /** - * Get corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - */ - this.getNonOTOperation = function () { - return _nonOTOperation; - }; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (_nonOTOperation === null) { - _nonOTOperation = new NonOTOperation( - RevokeSharedActivityOperation.TYPE, - JSON.stringify({ - id: id, - }) - ); - } - return _nonOTOperation; - }; -} - -RevokeSharedActivityOperation.prototype.toJSON = function () { - return { id: this.getId() }; -}; +/** + * Namespace for operations + * @namespace operations + */ -CollaborateInActivityOperation.TYPE = "CollaborateInActivityOperation"; - -/** - * Entity Select Operation - * @class operations.non_ot.EntitySelectOperation - * @memberof operations.non_ot - * @constructor - * @param {string} selectedEntityId Entity id of the selected entity - */ -function CollaborateInActivityOperation(id) { - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var _nonOTOperation = null; - - this.getId = function () { - return id; - }; - - /** - * Set corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - */ - this.setNonOTOperation = function (nonOTOperation) { - _nonOTOperation = nonOTOperation; - }; - - /** - * Get corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - */ - this.getNonOTOperation = function () { - return _nonOTOperation; - }; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (_nonOTOperation === null) { - _nonOTOperation = new NonOTOperation( - CollaborateInActivityOperation.TYPE, - JSON.stringify({ - id: id, - }) - ); - } - return _nonOTOperation; - }; -} - -MoveCanvasOperation.TYPE = "MoveCanvasOperation"; - -/** - * Entity Select Operation - * @class operations.non_ot.EntitySelectOperation - * @memberof operations.non_ot - * @constructor - * @param {string} selectedEntityId Entity id of the selected entity - */ -function MoveCanvasOperation(objectId, transition) { - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var _nonOTOperation = null; - - this.getObjectId = function () { - return objectId; - }; - - this.getTransition = function () { - return transition; - }; - - /** - * Set corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - */ - this.setNonOTOperation = function (nonOTOperation) { - _nonOTOperation = nonOTOperation; - }; - - /** - * Get corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - */ - this.getNonOTOperation = function () { - return _nonOTOperation; - }; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (_nonOTOperation === null) { - _nonOTOperation = new NonOTOperation( - MoveCanvasOperation.TYPE, - JSON.stringify({ - objectId: objectId, - transition: transition, - }) - ); - } - return _nonOTOperation; - }; -} - -/** - * Entity Select Operation - * @class operations.non_ot.EntitySelectOperation - * @memberof operations.non_ot - * @constructor - * @param {string} data - */ -class GuidanceStrategyOperation { - static TYPE = "GuidanceStrategyOperation"; - constructor(data) { - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var _nonOTOperation = null; - - this.getData = function () { - return data; - }; - - /** - * Set corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - */ - this.setNonOTOperation = function (nonOTOperation) { - _nonOTOperation = nonOTOperation; - }; - - /** - * Get corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - */ - this.getNonOTOperation = function () { - return _nonOTOperation; - }; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (_nonOTOperation === null) { - _nonOTOperation = new NonOTOperation( - GuidanceStrategyOperation.TYPE, - JSON.stringify({ - data: data, - }) - ); - } - return _nonOTOperation; - }; - } - toJSON() { - return { data: this.getData() }; - } -} - -UpdateMetamodelOperation.TYPE = "UpdateMetamodelOperation"; - -/** - * UpdateMetamodelOperation - * @class operations.non_ot.UpdateMetamodelOperation - * @memberof operations.non_ot - * @constructor - */ -function UpdateMetamodelOperation(metaModelingRoomName, modelingRoomName) { - /** - * Room name of metamodel is created - * @type {string} - */ - var _metaModelingRoomName = metaModelingRoomName; - - /** - * Room name to upload created metamodel - * @type {string} - */ - var _modelingRoomName = modelingRoomName; - - /** - * Corresponding NonOtOperation - * @type {operations.non_ot.NonOTOperation} - * @private - */ - var _nonOTOperation = null; - - /** - * Get metamodeling room name - * @returns {string} - */ - this.getMetaModelingRoomName = function () { - return _metaModelingRoomName; - }; - - /** - * Get modeling room name - * @returns {string} - */ - this.getModelingRoomName = function () { - return _modelingRoomName; - }; - - /** - * Convert operation to NonOTOperation - * @returns {operations.non_ot.NonOTOperation} - */ - this.toNonOTOperation = function () { - if (_nonOTOperation === null) { - _nonOTOperation = new NonOTOperation( - UpdateMetamodelOperation.TYPE, - JSON.stringify({ empty: "empty" }) - ); - } - return _nonOTOperation; - }; -} -UpdateMetamodelOperation.prototype.toJSON = function () { - return {}; -}; +/** + * Operation + * @class operations.Operation + * @memberof operations + * @constructor + */ +class Operation { + constructor() {} +} -/** - * OperationFactory - * @class operations.OperationFactory - * @memberof operations.ot - * @constructor - */ -function OperationFactory() { - return { - /** - * Creates an Operation from a received NonOTOperation - * @memberof operations.OperationFactory# - * @param operation - * @returns {operations.non_ot.ToolSelectOperation|EntitySelectOperation|ToolSelectOperation} - */ - createOperationFromNonOTOperation: function (operation) { - var type = operation.getType(), - data, - resOperation; - - try { - data = JSON.parse(operation.getData()); - } catch (e) { - console.error( - "Not able to parse data to JSON. Check the corresponding operation" - ); - return null; - } - - switch (type) { - case EntitySelectOperation.TYPE: - resOperation = new EntitySelectOperation( - data.selectedEntityId, - data.selectedEntityType, - data.jabberId - ); - resOperation.setNonOTOperation(operation); - break; - case ToolSelectOperation.TYPE: - resOperation = new ToolSelectOperation( - data.selectedToolName, - data.name, - data.defaultAttributeValues - ); - break; - case ActivityOperation.TYPE: - resOperation = new ActivityOperation( - data.type, - data.entityId, - data.sender, - data.text, - data.data - ); - break; - case ExportMetaModelOperation.TYPE: - resOperation = new ExportMetaModelOperation( - data.requestingComponent, - data.data - ); - break; - case ExportLogicalGuidanceRepresentationOperation.TYPE: - resOperation = new ExportLogicalGuidanceRepresentationOperation( - data.requestingComponent, - data.data - ); - break; - case ExportImageOperation.TYPE: - resOperation = new ExportImageOperation( - data.requestingComponent, - data.data - ); - break; - case SetViewTypesOperation.TYPE: - resOperation = new SetViewTypesOperation(data.flag); - break; - case InitModelTypesOperation.TYPE: - resOperation = new InitModelTypesOperation( - data.vls, - data.startViewGeneration - ); - break; - case ViewInitOperation.TYPE: - resOperation = new ViewInitOperation(data.data, data.viewpoint); - break; - case DeleteViewOperation.TYPE: - resOperation = new DeleteViewOperation(data.viewId); - break; - case ShowGuidanceBoxOperation.TYPE: - resOperation = new ShowGuidanceBoxOperation( - data.label, - data.guidance, - data.entityId - ); - break; - case SetModelAttributeNodeOperation.TYPE: - resOperation = new SetModelAttributeNodeOperation(); - break; - case UpdateViewListOperation.TYPE: - resOperation = new UpdateViewListOperation(); - break; - case CanvasViewChangeOperation.TYPE: - resOperation = new CanvasViewChangeOperation( - data.left, - data.top, - data.width, - data.height, - data.zoom - ); - resOperation.setNonOTOperation(operation); - break; - case RevokeSharedActivityOperation.TYPE: - resOperation = new RevokeSharedActivityOperation(data.id); - break; - case CollaborateInActivityOperation.TYPE: - resOperation = new CollaborateInActivityOperation(data.id); - break; - case MoveCanvasOperation.TYPE: - resOperation = new MoveCanvasOperation( - data.objectId, - data.transition - ); - break; - case GuidanceStrategyOperation.TYPE: - resOperation = new GuidanceStrategyOperation(data.data); - resOperation.setNonOTOperation(operation); - break; - case UpdateMetamodelOperation.TYPE: - resOperation = new UpdateMetamodelOperation( - data.metamodelingRoomName, - data.modelingRoomName - ); - break; - default: - resOperation = new NonOTOperation(type, data); - break; - } - return resOperation; - }, - /** - * Creates an entity operation from a received OTOperation - * @memberof operations.OperationFactory# - * @param operation - * @returns {EntityOperation} - */ - createOperationFromOTOperation: function (operation) { - var value; - var entityType; - var entityId; - var components = operation.getName().split(":"); - - var resOperation; - - if (components.length === 2) { - entityType = components[0]; - entityId = components[1]; - - switch (entityType) { - case CONFIG.ENTITY.NODE: - try { - value = JSON.parse(operation.getValue()); - } catch (e) { - return null; - } - switch (operation.getPosition()) { - case CONFIG.IWC.POSITION.NODE.ADD: - switch (operation.getType()) { - case CONFIG.OPERATION.TYPE.INSERT: - resOperation = new NodeAddOperation( - entityId, - value.type, - value.left, - value.top, - value.width, - value.height, - value.zIndex, - value.containment, - value.json, - value.viewId, - value.oType, - value.jabberId - ); - break; - case CONFIG.OPERATION.TYPE.UPDATE: - resOperation = new NodeDeleteOperation( - entityId, - value.type, - value.left, - value.top, - value.width, - value.height, - value.zIndex, - value.containment, - value.json - ); - break; - } - break; - case CONFIG.IWC.POSITION.NODE.POS: - resOperation = new NodeMoveOperation( - entityId, - value.offsetX, - value.offsetY, - value.jabberId - ); - break; - case CONFIG.IWC.POSITION.NODE.Z: - resOperation = new NodeMoveZOperation( - entityId, - value.offsetZ, - value.jabberId - ); - break; - case CONFIG.IWC.POSITION.NODE.DIM: - resOperation = new NodeResizeOperation( - entityId, - value.offsetX, - value.offsetY, - value.jabberId - ); - break; - } - break; - case CONFIG.ENTITY.EDGE: - try { - value = JSON.parse(operation.getValue()); - } catch (e) { - return null; - } - switch (operation.getType()) { - case CONFIG.OPERATION.TYPE.INSERT: - resOperation = new EdgeAddOperation( - entityId, - value.type, - value.source, - value.target, - value.json, - value.viewId, - value.oType, - value.jabberId - ); - break; - case CONFIG.OPERATION.TYPE.UPDATE: - resOperation = new EdgeDeleteOperation( - entityId, - value.type, - value.source, - value.target, - value.json - ); - break; - } - break; - case CONFIG.ENTITY.ATTR: - try { - value = JSON.parse(operation.getValue()); - } catch (e) { - return null; - } - switch (operation.getType()) { - case CONFIG.OPERATION.TYPE.INSERT: - resOperation = new AttributeAddOperation( - entityId, - value.subjectEntityId, - value.rootSubjectEntityId, - value.type, - value.data - ); - break; - case CONFIG.OPERATION.TYPE.UPDATE: - resOperation = new AttributeDeleteOperation( - entityId, - value.subjectEntityId, - value.rootSubjectEntityId, - value.type - ); - break; - } - break; - case CONFIG.ENTITY.VAL: - resOperation = new ValueChangeOperation( - entityId, - operation.getValue(), - operation.getType(), - operation.getPosition(), - null - ); - break; - } - } - if (resOperation !== null) { - resOperation.setOTOperation(operation); - } - return resOperation; - }, - }; -} - -var OperationFactory$1 = OperationFactory(); +/** + * Namespace for ot operations + * @namespace operations.ot + */ -/** - * Provides messaging functionality. - * @param {Array} categories - (currently not implemented) categories of widgets that shall process the intent (e.g. ["editor","proxy" ]) - * @param {String} origin - The origin (i.e. the url where your application script lives) is needed for messaging - * @param {} y - A reference to yjs' Y object for global messaging - */ -class Client { - //console.log(y); - _y; - _componentName = "unknown"; - - //private variables - _connected = false; - _categories; - _callback; - - // Needed for HTML5 messaging - _origin; - - constructor(componentName, categories, origin, y) { - //console.log(y); - this._y = y; - - this._componentName = componentName; - this._categories = categories; - // Needed for HTML5 messaging - this._origin = origin; - } - - /** - * Connect widget to messaging. This sets up the callback function and creates - * an event listener for HTML5 messaging and a yjs observer for global messaging. - * If yjs is not available only local messaging is set up. - * @param {function} callback - The callback function used for receiving messages. - */ - connect(callback) { - this._callback = callback; - var handler = this.receiveMessage.bind(this); - //Todo - const widgetTageName = getWidgetTagName(this._componentName); - try { - const _node = document.querySelector(widgetTageName); - - if (!_node) { - throw new Error( - "html tag not found in document. Please make sure that you added the " + - widgetTageName + - " to the document. Hint: do not use the shadow dom." - ); - } - _node.addEventListener("syncmeta-message", handler); - } catch (error) { - console.error(error); - } - - - if (this._y) { - // If yjs is available also connect a global listener - const intents = this._y.getMap("intents"); - if (intents) intents.observe(handler); - } - } - - /** - * Disconnect the widget from messaging. This removes the event listener - * and the callback for both local and global messaging. If yjs is not available, - * only local messaging will be available. - */ - disconnect() { - //THISELEMENT.removeEventListener("syncmeta-message", this.receiveMessage, false); - this._callback = null; - - if (!(this._y === null || this._y === undefined)) { - this._y.getMap("intents").unobserve(this.receiveMessage); - } - } - - /** - * Publishes an intent, - * @param {intent} - The intent about to be published, this object contains all information. - */ - publish(intent) { - if (util.validateIntent(intent)) { - if (intent.flags[0] === util.FLAGS.PUBLISH_GLOBAL) { - this.publishGlobal(intent, this._y); - } else if (intent.flags[0] === util.FLAGS.PUBLISH_LOCAL) { - this.publishLocal(intent, this._origin); - } - } - } - - publishLocal(intent, origin) { - //Find iframe and post message - const widgets = []; - for (const el of document.querySelectorAll("*")) { - if (el.tagName.match(/-widget$/i)) { - widgets.push(el); - } - } - - widgets.forEach(function (widget) { - const receiverTagName = getWidgetTagName(intent.receiver.toLowerCase()); - if (widget.tagName.toLowerCase() === receiverTagName.toLowerCase()) { - const event = new CustomEvent("syncmeta-message", { - detail: { - intent, - origin, - }, - }); - widget.dispatchEvent(event); - } - }); - } - - publishGlobal(intent, y) { - //y.share.intents.push(intent); - y.getMap("intents").set(intent.receiver, intent); - } - - /** - * Unpack events and pre process them. This unwraps HTML5 messages and manages the yjs map - * used for global messaging. - * @param {Event} event - The event that activated the callback - */ - receiveMessage(event) { - // Local messaging events - if (event.type === "syncmeta-message") { - //Unpack message events - if (event instanceof CustomEvent) { - this._callback(event.detail.intent); - } - } else if (event.type === "add" || event.type == "update") { - //Unpack yjs event and remove from map - var intent = event.object.get(event.name); - event.object.delete(event.name); - console.log(intent); - this._callback(intent); - } - } -} - -//======================= IWC.util ============================== - -class util { - /** - * Used to determine whether global or local messaging should be used. - * Local messaging uses HTML5 messaging, global messaging uses yjs. - */ - static FLAGS = { - PUBLISH_LOCAL: "PUBLISH_LOCAL", - PUBLISH_GLOBAL: "PUBLISH_GLOBAL", - }; - - /** - * Check intent for correctness. - */ - static validateIntent(intent) { - if (typeof intent.sender != "string") { - throw new Error( - "Intent object must possess property 'component' of type 'String'" - ); - } - if (typeof intent.data != "string") { - throw new Error( - "Intent object must possess property 'data' of type 'String'" - ); - } - if (typeof intent.dataType != "string") { - throw new Error( - "Intent object must possess property 'dataType' of type 'String'" - ); - } - return true; - } -} - -var PAYLOAD_DATA_TYPE = { - OT_OPERATION: "OTOperation", - NON_OT_OPERATION: "NonOTOperation", -}; - -class IWCWrapper { - /** - * Inter-widget communication wrapper - * @class IWCWrapper - * @constructor - * @param componentName Name of component (widget) using the wrapper - */ - - /** - * Set if local messages should be buffered - * @type {boolean} - */ - BUFFER_ENABLED = false; - - /** - * Interval for sending buffered local messages - * @type {number} - */ - INTERVAL_SEND = 25; - - Space = null; - - //noinspection JSMismatchedCollectionQueryUpdate - /** - * Buffer for local messages - * @type {Array} - * @private - */ - _messageBuffer = []; - - //noinspection JSMismatchedCollectionQueryUpdate - /** - * Set of registered Callbacks for local data receive events - * @type {Array} - * @private - */ - _onDataReceivedCallbacks = []; - - _onDataReceivedCallers = []; - - /** - * Stores (for each user) the times an inocming messages has been received to drop duplicate (same time) messages - * @type {object} - * @private - */ - _times = {}; - - /** - * Inter widget communication client - * @type {iwc.Client} - * @private - */ - _iwc; - /** - * Disconnect the iwc client - * @memberof IWCWrapper# - */ - disconnect; - /** - * Connect the iwc client - * @memberof IWCWrapper# - */ - connect; - sendLocalMessage; - sendLocalOTOperation; - sendLocalNonOTOperation; - getUserColor; - registerOnDataReceivedCallback; - unregisterOnDataReceivedCallback; - getUser; - getMembers; - getSpaceTitle; - setSpace; - componentName; - - /** - * Encapsulates the passed message information into the Android Intent-like format required by the iwc client - * @param {string} receiver Component name of the receiving component (widget), empty string for remote messages - * @param {string|string[]} flags Single flag or array of flags to indicate if the messages should be propagate locally or remotely - * @param {string} action Type of data (DATA, DATA_ARRAY, SYNC) - * @param {object} payload Message Payload - * @returns {Object} - */ - encapsulateMessage(receiver, flags, action, payload) { - var i, numOfFlags, flag; - // @ts-ignore - var validatedFlags = []; - - if (flags instanceof Array) { - for (i = 0, numOfFlags = flags.length; i < numOfFlags; i++) { - flag = flags[i]; - if ( - flag === CONFIG.IWC.FLAG.PUBLISH_LOCAL || - flag === CONFIG.IWC.FLAG.PUBLISH_GLOBAL - ) { - // @ts-ignore - validatedFlags.push(flag); - } - } - } else if (typeof flags === "string") { - if ( - flags === CONFIG.IWC.FLAG.PUBLISH_LOCAL || - flags === CONFIG.IWC.FLAG.PUBLISH_GLOBAL - ) { - // @ts-ignore - validatedFlags.push(flags); - } - } else { - throw "Parameter flags has wrong type. Array or String expected."; - } - - if (typeof action !== "string") { - throw "Parameter action has wrong type. String expected."; - } - - receiver = receiver || ""; - - return { - receiver: receiver, - sender: this.componentName, - data: "", - dataType: "", - action: action, - flags: validatedFlags, - extras: { - payload: payload, - time: new Date().getTime(), - }, - }; - } - - /** - * Send all buffered local messages encapsulated in one message - */ - sendBufferedMessages() { - var intent; - var data = null; - - for (var receiver in this._messageBuffer) { - if (this._messageBuffer.hasOwnProperty(receiver)) { - data = this._messageBuffer[receiver].splice( - 0, - this._messageBuffer[receiver].length - ); - //sendBufferTimer.pause(); - if (data.length == 1) { - intent = this.encapsulateMessage( - receiver, - CONFIG.IWC.FLAG.PUBLISH_LOCAL, - CONFIG.IWC.ACTION.DATA, - data[0] - ); - if (util.validateIntent(intent)) { - //console.log("=== " + intent.flags.toString().replace(/PUBLISH_/g, "") + " INTENT TRANSMITTED AT COMPONENT " + componentName + " ==="); - //console.log(intent); - - this._iwc.publish(intent); - } - } else if (data.length > 1) { - intent = this.encapsulateMessage( - receiver, - CONFIG.IWC.FLAG.PUBLISH_LOCAL, - CONFIG.IWC.ACTION.DATA_ARRAY, - data - ); - if (util.validateIntent(intent)) { - //console.log("=== " + intent.flags.toString().replace(/PUBLISH_/g, "") + " INTENT TRANSMITTED AT COMPONENT " + componentName + " ==="); - //console.log(intent); - - this._iwc.publish(intent); - } - } - } - } - //sendBufferTimer.resume(); - } - - /** - * Callback for received local messages - * @param {object} intent Message content in Android Intent-like format required by the iwc client - */ - onIntentReceivedCallback(_self, intent) { - //some CAE widgets still use the old iwc.js library - //then it happens that intent are not parsed and processes correctly by the new iwc and then - //the complete message as string is returned - //this workaround should help for now to make it work with syncmeta - if (typeof intent === "string") { - try { - intent = JSON.parse(intent); - if (intent.hasOwnProperty("OpenApplicationEvent")) { - intent = intent["OpenApplicationEvent"]; - if (intent.hasOwnProperty("message")) intent = intent.message; - } - } catch (e) { - return; - } - } - - if ( - !intent.hasOwnProperty("extras") || - !intent.extras.hasOwnProperty("payload") - ) { - return; - } - - var payload = intent.extras.payload, - senderTime = intent.extras.time, - senderTimes = _self._times[intent.sender]; - - var i, numOfSenderTimes, numOfMessages; - - function handleMessage(payload) { - var type, data, sender, operation, resOperation, i, numOfCallbacks; - - if ( - !payload || - !payload.hasOwnProperty("type") || - !payload.hasOwnProperty("data") - ) { - return; - } - type = payload.type; - data = payload.data; - sender = payload.sender; - switch (type) { - case PAYLOAD_DATA_TYPE.OT_OPERATION: - operation = new OTOperation( - data.name, - data.value, - data.type, - data.position - ); - operation.setSender(sender); - resOperation = - OperationFactory$1.createOperationFromOTOperation(operation); - //adjustHistory(remoteOp); - for ( - i = 0, numOfCallbacks = _self._onDataReceivedCallbacks.length; - i < numOfCallbacks; - i++ - ) { - if (typeof _self._onDataReceivedCallbacks[i] === "function") { - var caller = _self._onDataReceivedCallers[i] || _self; - _self._onDataReceivedCallbacks[i].call(caller, resOperation); - } - } - break; - case PAYLOAD_DATA_TYPE.NON_OT_OPERATION: - operation = new NonOTOperation(data.type, data.data); - operation.setSender(sender); - resOperation = - OperationFactory$1.createOperationFromNonOTOperation(operation); - //adjustHistory(remoteOp); - for ( - i = 0, numOfCallbacks = _self._onDataReceivedCallbacks.length; - i < numOfCallbacks; - i++ - ) { - if (typeof _self._onDataReceivedCallbacks[i] === "function") { - var caller = _self._onDataReceivedCallers[i] || _self; - _self._onDataReceivedCallbacks[i].call(caller, resOperation); - } - } - break; - } - } - - if (intent.flags.indexOf(CONFIG.IWC.FLAG.PUBLISH_GLOBAL) !== -1) return; - - if (typeof senderTimes === "undefined") { - senderTimes = _self._times[intent.sender] = []; - } else { - for ( - i = 0, numOfSenderTimes = senderTimes.length; - i < numOfSenderTimes; - i++ - ) { - if (senderTime === senderTimes[i]) { - return; - } - } - } - - senderTimes.push(senderTime); - - //console.log("=== " + intent.flags.toString().replace(/PUBLISH_/g,"") + " INTENT RECEIVED AT COMPONENT " + componentName + " ==="); - //console.log(intent); - - switch (intent.action) { - case CONFIG.IWC.ACTION.DATA: - handleMessage(payload); - break; - case CONFIG.IWC.ACTION.DATA_ARRAY: - for (i = 0, numOfMessages = payload.length; i < numOfMessages; i++) { - handleMessage(payload[i]); - } - break; - } - } - - constructor(componentName, y) { - this.componentName = componentName; - this._iwc = new Client(componentName, "*", null, y); - window._iwc_instance_ = this._iwc; - - //var sendBufferTimer; - //if(BUFFER_ENABLED) sendBufferTimer = new IWCWrapper.PausableInterval(sendBufferedMessages, INTERVAL_SEND); - if (this.BUFFER_ENABLED) - setInterval(this.sendBufferedMessages, this.INTERVAL_SEND); - - this.connect = () => - this._iwc.connect((intent) => - this.onIntentReceivedCallback(this, intent) - ); - this.disconnect = () => this._iwc.disconnect; - - /** - * Send data locally to an other component - * @memberof IWCWrapper# - * @param {string} receiver Component name of receiving component, empty string for broadcast - * @param {object} data Data to send - */ - this.sendLocalMessage = function (receiver, data) { - var intent; - - if (!receiver || receiver === "") return; - - if (this.BUFFER_ENABLED) { - //sendBufferTimer.pause(); - if (this._messageBuffer.hasOwnProperty(receiver)) { - this._messageBuffer[receiver].push(data); - } else { - this._messageBuffer[receiver] = [data]; - } - //sendBufferTimer.resume(); - } else { - intent = this.encapsulateMessage( - receiver, - CONFIG.IWC.FLAG.PUBLISH_LOCAL, - CONFIG.IWC.ACTION.DATA, - data - ); - if (util.validateIntent(intent)) { - //console.log("=== " + intent.flags.toString().replace(/PUBLISH_/g,"") + " INTENT TRANSMITTED AT COMPONENT " + componentName + " ==="); - //console.log(intent); - - this._iwc.publish(intent); - } - } - }; - /** - * Send OTOperation locally to an other component - * @memberof IWCWrapper# - * @param {string} receiver Component name of receiving component, empty string for broadcast - * @param {operations.ot.OTOperation} operation Operation to send - */ - this.sendLocalOTOperation = function (receiver, operation) { - this.sendLocalMessage(receiver, { - type: PAYLOAD_DATA_TYPE.OT_OPERATION, - data: operation.getOperationObject(), - sender: operation.getSender(), - }); - }; - /** - * Send NonOTOperation locally to an other component - * @memberof IWCWrapper# - * @param {string} receiver Component name of receiving component, empty string for broadcast - * @param {operations.non_ot.NonOTOperation} operation Operation to send - */ - this.sendLocalNonOTOperation = function (receiver, operation) { - this.sendLocalMessage(receiver, { - type: PAYLOAD_DATA_TYPE.NON_OT_OPERATION, - data: operation.getOperationObject(), - sender: operation.getSender(), - }); - }; - this.getUserColor = function (jabberId) { - return Util.getColor(this.Space.members[jabberId].globalId); - }; - /** - * Register callback for local data receive events - * @memberof IWCWrapper# - * @param {function} callback - */ - this.registerOnDataReceivedCallback = function (callback, caller) { - if (typeof callback === "function") { - this.unregisterOnDataReceivedCallback(callback); - this._onDataReceivedCallbacks.push(callback); - this._onDataReceivedCallers.push(caller); - } - }; - /** - * Unregister callback for local data receive events - * @memberof IWCWrapper# - * @param {function} callback - */ - this.unregisterOnDataReceivedCallback = function (callback) { - var i, numOfCallbacks; - - if (typeof callback === "function") { - for ( - i = 0, numOfCallbacks = this._onDataReceivedCallbacks.length; - i < numOfCallbacks; - i++ - ) { - if (callback === this._onDataReceivedCallbacks[i]) { - this._onDataReceivedCallbacks.splice(i, 1); - this._onDataReceivedCallers.splice(i, 1); - } - } - } - }; - this.getUser = function () { - if (!this.Space) { - console.error("Space is null"); - this.Space = { user: {} }; - } else if (!this.Space.user) { - console.error("User in space is null, generating new anonymous user"); - this.Space.user = Util.generateAnonymousUser(); - } - return this.Space.user; - }; - this.getMembers = function () { - return this.Space.members; - }; - this.getSpaceTitle = function () { - return this.Space.title; - }; - this.setSpace = function (s) { - this.Space = s; - }; - - return this; - } -} - -/** - * Inter widget communication and OT client module - * @exports IWCW - */ -class IWCW { - static instances = {}; //static variable to store instances of IWCWrapper. One for each widget - constructor() {} - /** - * Instance of IWCWrapper - * @type {IWCWrapper} - */ - - static hasInstance(componentName) { - return componentName in IWCW.instances; - } - - /** - * Get instance of IWCOTWrapper - * @param {string} componentName Name of component (widget) using the wrapper - * @returns {IWCWrapper} - */ - static getInstance(componentName, y) { - if (!this.hasInstance(componentName)) { - y = y || window.y; - if (!y) { - console.error( - "y is null, y is the shared y document that should be passed along when calling getInstance, proceed with caution" - ); - } - IWCW.instances[componentName] = new IWCWrapper(componentName, y); - IWCW.instances[componentName].connect(); - } - return IWCW.instances[componentName]; - } -} - -$.fn.autoGrowInput = function (o) { - o = $.extend( - { - maxWidth: 1000, - minWidth: 0, - comfortZone: 70, - }, - o - ); - - this.filter("input:text").each(function () { - var minWidth = o.minWidth || $(this).width(), - val = "", - input = $(this), - testSubject = $("").css({ - position: "absolute", - top: -9999, - left: -9999, - width: "auto", - fontSize: input.css("fontSize"), - fontFamily: input.css("fontFamily"), - fontWeight: input.css("fontWeight"), - letterSpacing: input.css("letterSpacing"), - whiteSpace: "nowrap", - }), - check = function () { - val = input.val(); - - // Enter new content into testSubject - var escaped = val - .replace(/&/g, "&") - .replace(/\s/g, " ") - .replace(//g, ">"); - testSubject.html(escaped); - - // Calculate new width + whether to change - var testerWidth = testSubject.width(), - newWidth = - testerWidth + o.comfortZone >= minWidth - ? testerWidth + o.comfortZone - : minWidth, - currentWidth = input.width(), - isValidWidthChange = - (newWidth < currentWidth && newWidth >= minWidth) || - (newWidth > minWidth && newWidth < o.maxWidth); - - // Animate width - if (isValidWidthChange) { - input.width(newWidth); - } - }; - - $("body").append(testSubject); - - $(this).bind("keyup keydown blur update", check); - }); - - return this; -}; + /** + * OTOperation + * @class operations.ot.OTOperation + * @memberof operations.ot + * @constructor + * @param {string} name Name of operation + * @param {string} value Value of operation + * @param {string} type Type of operation + * @param {number} position Position of operation + */ + class OTOperation extends Operation { + constructor(name, value, type, position) { + super(); + /** + * JabberId of the user who issued this activity + * @type {string} + * @private + */ + var _sender = null; + + + /** + * Operation details + * @type {{name: string, value: string, type: string, position: number}} + * @private + */ + var _operation = { + name: name, + value: value, + type: type, + position: position + }; -/** - * AbstractEntity - * @class canvas_widget.AbstractEntity - * @memberof canvas_widget - * @constructor - * @param {string} id Identifier of this entity - */ - class AbstractEntity { - static MAX_Z_INDEX = 32000; - static MIN_Z_INDEX = 1; - static CONTEXT_MENU_Z_INDEX = 32000 + 1; - - static maxZIndex = 16000; - static minZIndex = 16000; - constructor(id) { - /** - * Entity identifier - * @type {string} - * @private - */ - var _id = id; - - /** - * Get the entity identifier - * @returns {string} entity id - */ - this.getEntityId = function () { - return _id; - }; - } - } + /** + * Set JabberId of the user who issued this activity + * @param sender + */ + this.setSender = function (sender) { + _sender = sender; + }; -const abstractAttributeHtml = "
                  "; // replaced by importmap.plugin.js - -/** - * AbstractAttribute - * @class canvas_widget.AbstractAttribute - * @extends canvas_widget.AbstractEntity - * @memberof canvas_widget - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to - */ -class AbstractAttribute extends AbstractEntity { - constructor(id, name, subjectEntity) { - super(id); - - /** - * Entity id - * @type {string} - * @private - */ - var _id = id; - - /** - * Name of Attribute - * @type {string} - * @private - */ - var _name = name; - - /** - * jQuery object of DOM node representing the attribute - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(abstractAttributeHtml)()); - - /** - * Entity the attribute is assigned to - * @type {canvas_widget.AbstractEntity} - * @private - */ - var _subjectEntity = subjectEntity; - - /** - * Set name of the attribute - * @param {string} name - */ - this.setName = function (name) { - _name = name; - }; - - /** - * Get name of the attribute - * @returns {String} - */ - this.getName = function () { - return _name; - }; - - /** - * Get entity the attribute is assigned to - * @returns {canvas_widget.AbstractEntity} - */ - this.getSubjectEntity = function () { - return _subjectEntity; - }; - - /** - * Get topmost entity in the chain of entities the attribute is assigned to - * @returns {canvas_widget.AbstractEdge|canvas_widget.AbstractNode} - */ - this.getRootSubjectEntity = function () { - var rootSubjectEntity = this.getSubjectEntity(); - while (rootSubjectEntity instanceof AbstractAttribute) { - rootSubjectEntity = rootSubjectEntity.getSubjectEntity(); - } - return rootSubjectEntity; - }; - - /** - * Get id of the entity the attribute is assigned to - * @returns {String} - */ - this.getSubjectEntityId = function () { - return _subjectEntity.getEntityId(); - }; - - /** - * Get jQuery object of the DOM node representing the attribute - * @returns {jQuery} - * @private - */ - this._get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the attribute - * @returns {Object} - * @private - */ - this._toJSON = function () { - return { - id: _id, - name: _name, - }; - }; - } - /** - * Get jQuery object of the DOM node representing the attribute - * @returns {jQuery} - */ - get$node() { - return this._get$node(); - } - /** - * Get JSON representation of the attribute - * @returns {Object} - */ - toJSON() { - return this._toJSON(); - } - registerYTypeForValue(map, value) { - var deferred = $.Deferred(); - map.get(value.getEntityId()).then(function (type) { - value.registerYType(type); - deferred.resolve(); - }); - return deferred.promise(); - } -} - -/** - * AbstractValue - * @class canvas_widget.AbstractValue - * @member of canvas_widget - * @constructor - * @param {string} id Entity identifier - * @param {string} name Name of attribute - * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {canvas_widget.AbstractNode|canvas_widget.AbstractEdge} rootSubjectEntity Topmost entity in the chain of entity the attribute is assigned to - */ - class AbstractValue { - constructor(id, name, subjectEntity, rootSubjectEntity) { - var that = this; - - /** - * The entity identifier - * @returns {string} entity id - */ - var _id = id; - - /** - * Name of Attribute - * @type {string} - * @private - */ - var _name = name; - - /** - * Entity the attribute is assigned to - * @type {canvas_widget.AbstractEntity} - * @private - */ - var _subjectEntity = subjectEntity; - - /** - * Topmost entity in the chain of entity the attribute is assigned to - * @type {canvas_widget.AbstractEdge|canvas_widget.AbstractNode} - * @private - */ - var _rootSubjectEntity = rootSubjectEntity; - - /** - * Get the entity identifier - * @returns {string} entity id - */ - this.getEntityId = function () { - return _id; - }; - - /** - * Get name of value - * @returns {string} - */ - this.getName = function () { - return _name; - }; - - /** - * Get entity the attribute is assigned to - * @returns {canvas_widget.AbstractEntity} - */ - this.getSubjectEntity = function () { - return _subjectEntity; - }; - - /** - * Get topmost entity in the chain of entity the attribute is assigned to - * @returns {canvas_widget.AbstractEdge|canvas_widget.AbstractNode} - */ - this.getRootSubjectEntity = function () { - return _rootSubjectEntity; - }; - - /** - * Get JSON representation of the edge - * @returns {Object} - */ - this._toJSON = function () { - return { - id: that.getEntityId(), - name: _name, - }; - }; - } - //noinspection JSAccessibilityCheck - toJSON() { - return this._toJSON(); - } - } - -function Arrows(color){ - return { - //"bidirassociation": {}, //No overlays for bi-dir-association - unidirassociation: { - type: "Arrow", - options: { - width: 20, - length: 30, - location: 1, - foldback: 0.1, - paintStyle: { - fill: "#ffffff", - outlineWidth: 2, - outlineStroke: color, - }, - }, - }, - generalisation: { - type: "Arrow", - options: { - width: 20, - length: 30, - location: 1, - foldback: 1, - paintStyle: { - fill: "#ffffff", - outlineWidth: 2, - outlineStroke: color, - }, - }, - }, - diamond: { - type: "Arrow", - options: { - width: 20, - length: 20, - location: 1, - foldback: 2, - paintStyle: { - fill: "#ffffff", - outlineWidth: 2, - outlineStroke: color, - }, - }, - }, - }; - } - -let booleanValueHtml = "
                  <%= value %>
                  "; // replaced by importmap.plugin.js -const attributeBooleanValueHtml = "\"\r\n <% if (value) { %> checked=\"checked\" <% } %> />\r\n"; // replaced by importmap.plugin.js - -/** - * BooleanValue - * @class canvas_widget.BooleanValue - * @extends canvas_widget.AbstractValue - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier - * @param {string} name Name of attribute - * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {canvas_widget.AbstractNode|canvas_widget.AbstractEdge} rootSubjectEntity Topmost entity in the chain of entity the attribute is assigned to - */ -class BooleanValue extends AbstractValue { - constructor(id, name, subjectEntity, rootSubjectEntity, useAttributeHtml) { - if (useAttributeHtml) booleanValueHtml = attributeBooleanValueHtml; - - super(id, name, subjectEntity, rootSubjectEntity); - var that = this; - /** - * Value - * @type {boolean} - * @private - */ - var _value = false; - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(booleanValueHtml)({ value: _value })); - - /** - * Inter widget communication wrapper - * @type {Object} - * @private - */ - y = y || window.y; - var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); - - /** - * Apply a Value Change Operation - * @param {operations.ot.ValueChangeOperation} operation - */ - var processValueChangeOperation = function (operation) { - that.setValue(operation.getValue()); - }; - - var init = function () { - _$node.off(); - }; - - /** - * Set value - * @param {boolean} value - */ - this.setValue = function (value) { - _value = value; - if (useAttributeHtml) _$node.prop("checked", value); - else _$node.text(value); - }; - - /** - * Get value - * @returns {boolean} - */ - this.getValue = function () { - return _value; - }; - - /** - * Get jQuery object of DOM node representing the value - * @returns {jQuery} - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the edge - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractValue.prototype.toJSON.call(this); - json.value = _value; - return json; - }; - - /** - * Set value by its JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - this.setValue(json.value); - }; - - this.registerYType = function () { - that - .getRootSubjectEntity() - .getYMap() - .observe(function (event) { - const array = Array.from(event.changes.keys.entries()); - array.forEach(function ([key, change]) { - if (change.action !== "update" || key !== that.getEntityId()) { - return; - } - const map = event.currentTarget.get(key); - const json = map; - - var operation = new ValueChangeOperation( - json.entityId, - json.value, - json.type, - json.position, - json.jabberId - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.getOTOperation() - ); - processValueChangeOperation(operation); - - //Only the local user Propagates the activity - if ( - _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID] === - operation.getJabberId() - ) { - const activityMap = y.getMap("activity"); - activityMap.set( - ActivityOperation.TYPE, - new ActivityOperation( - "ValueChangeActivity", - that.getEntityId(), - _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], - ValueChangeOperation.getOperationDescription( - that.getSubjectEntity().getName(), - that.getRootSubjectEntity().getType(), - that.getRootSubjectEntity().getLabel().getValue().getValue() - ), - { - value: operation.getValue(), - subjectEntityName: that.getSubjectEntity().getName(), - rootSubjectEntityType: that - .getRootSubjectEntity() - .getType(), - rootSubjectEntityId: that - .getRootSubjectEntity() - .getEntityId(), - } - ).toJSON() - ); - } else { - //the remote users propagtes the change to their local attribute widget - //TODO(PENDING): can be replace with yjs as well - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.ATTRIBUTE, - operation.getOTOperation() - ); - } - }); - }); - - //Debounce the save function - that - .getRootSubjectEntity() - .getYMap() - .observe( - lodash.debounce(function (event) { - event.keysChanged.forEach(function (key) { - if ( - key == "jabberId" && - key === _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID] - ) - EntityManager.storeDataYjs(); - }); - }, 500) - ); - }; - - init(); - } -} + /** + * Get JabberId of the user who issued this activity + */ + this.getSender = function () { + return _sender; + }; -const booleanAttributeHtml = "
                  \r\n
                  \r\n
                  \r\n
                  "; // replaced by importmap.plugin.js - -/** - * BooleanAttribute - * @class canvas_widget.BooleanAttribute - * @extends canvas_widget.AbstractAttribute - * @memberof canvas_widget - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to - */ -class BooleanAttribute extends AbstractAttribute { - constructor(id, name, subjectEntity, useAttributeHtml) { - useAttributeHtml = - typeof useAttributeHtml !== "undefined" ? useAttributeHtml : false; - super(id, name, subjectEntity); - - /*** - * Value object of value - * @type {canvas_widget.BooleanValue} - * @private - */ - var _value = new BooleanValue( - id, - name, - this, - this.getRootSubjectEntity(), - useAttributeHtml - ); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(booleanAttributeHtml)()); - - /** - * Set Value object of value - * @param {canvas_widget.BooleanValue} value - */ - this.setValue = function (value) { - _value = value; - _$node.val(value); - }; - - /** - * Get Value object of value - * @return {canvas_widget.BooleanValue} value - */ - this.getValue = function () { - return _value; - }; - - /** - * jQuery object of DOM node representing the attribute - * @type {jQuery} - * @private - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the attribute - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.value = _value.toJSON(); - return json; - }; - - /** - * Set attribute value by its JSON representation - * @param {Object} json - */ - this.setValueFromJSON = function (json) { - _value.setValueFromJSON(json.value); - }; - - _$node.find(".name").text(this.getName()); - _$node.find(".value").append(_value.get$node()); - } -} + /** + * Get name of operation + * @returns {string} + */ + this.getName = function () { + return _operation.name; + }; -const openapp$1 = new OpenAppProvider().openapp; - -let fileValueHtml = "
                  <%= value %>
                  "; // replaced by importmap.plugin.js -const attributeFileValueHtml = "
                  \r\n
                  \r\n \r\n \r\n
                  \r\n
                  \r\n \r\n \r\n \r\n \r\n
                  \r\n
                  \r\n"; // replaced by importmap.plugin.js - -FileValue.prototype = new AbstractValue(); -FileValue.prototype.constructor = FileValue; -/** - * FileValue - * @class canvas_widget.FileValue - * @extends canvas_widget.AbstractValue - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier - * @param {string} name Name of attribute - * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {canvas_widget.AbstractNode|canvas_widget.AbstractEdge} rootSubjectEntity Topmost entity in the chain of entity the attribute is assigned to - */ -function FileValue( - id, - name, - subjectEntity, - rootSubjectEntity, - useAttributeHtml -) { - var that = this; - - if (useAttributeHtml) fileValueHtml = attributeFileValueHtml; - - AbstractValue.call(this, id, name, subjectEntity, rootSubjectEntity); - - /** - * Value - * @type {string} - * @private - */ - var _value = ""; - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node; - - if (useAttributeHtml) _$node = $(lodash.template(fileValueHtml)({ name: name })); - else _$node = $(lodash.template(fileValueHtml)({ value: _value })); - - var _$selectFile = _$node.find(".select_file"); - - var _$manageFile = _$node.find(".manage_file"); - - /** - * Inter widget communication wrapper - * @type {Object} - * @private - */ - y = y || window.y; - var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); - - /** - * Get chain of entities the attribute is assigned to - * @returns {string[]} - */ - var getEntityIdChain = function () { - var chain = [that.getEntityId()], - entity = that; - while (entity instanceof AbstractAttribute) { - chain.unshift(entity.getSubjectEntity().getEntityId()); - entity = entity.getSubjectEntity(); - } - return chain; - }; - - var uploadFile = function (name, type, data) { - var resourceSpace = new openapp$1.oo.Resource(openapp$1.param.space()); - - resourceSpace.create({ - relation: openapp$1.ns.role + "data", - type: "my:ns:file", - representation: { - name: name, - type: type, - data: data, - }, - callback: function (d) { - if (d.uri) { - propagateValueChange(CONFIG.OPERATION.TYPE.UPDATE, d.uri, 0); - } - }, - }); - }; - - /** - * Apply a Value Change Operation - * @param {operations.ot.ValueChangeOperation} operation - */ - var processValueChangeOperation = function (operation) { - that.setValue(operation.getValue()); - }; - - var propagateValueChange = function (type, value, position) { - var operation = new ValueChangeOperation( - that.getEntityId(), - value, - type, - position - ); - propagateValueChangeOperation(operation); - }; - - /** - * Propagate a Value Change Operation to the remote users and the local widgets - * @param {operations.ot.ValueChangeOperation} operation - */ - var propagateValueChangeOperation = function (operation) { - operation.setEntityIdChain(getEntityIdChain()); - processValueChangeOperation(operation); - if (_iwcw.sendRemoteOTOperation(operation)) { - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.ATTRIBUTE, - operation.getOTOperation() - ); - const activityMap = y.getMap("activity"); - - activityMap.set( - ActivityOperation.TYPE, - new ActivityOperation( - "ValueChangeActivity", - that.getEntityId(), - _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], - ValueChangeOperation.getOperationDescription( - that.getSubjectEntity().getName(), - that.getRootSubjectEntity().getType(), - that.getRootSubjectEntity().getLabel().getValue().getValue() - ), - { - value: operation.getValue(), - subjectEntityName: that.getSubjectEntity().getName(), - rootSubjectEntityType: that.getRootSubjectEntity().getType(), - rootSubjectEntityId: that.getRootSubjectEntity().getEntityId(), - } - ).toJSON() - ); - } - }; - - /** - * Callback for a local Value Change Operation - * @param {operations.ot.ValueChangeOperation} operation - */ - var localValueChangeCallback = function (operation) { - if ( - operation instanceof ValueChangeOperation && - operation.getEntityId() === that.getEntityId() - ) { - propagateValueChangeOperation(operation); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.getOTOperation() - ); - } - }; - - var init = function () { - if (!useAttributeHtml) return; - - _$selectFile.find("#file_object").change(function () { - var files = $(this)[0].files, - file; - - if (!files || files.length === 0) return; - file = files[0]; - if (file.size > 1048576) { - alert("Chosen file is too large. Maximum size: 1MB"); - } - }); - - _$selectFile.find("#file_submit").click(function () { - var fileReader, - files = _$selectFile.find("#file_object")[0].files, - file; - - if (!files || files.length === 0) return; - file = files[0]; - - fileReader = new FileReader(); - fileReader.onload = function (e) { - uploadFile(file.name, file.type, e.target.result); - }; - fileReader.readAsDataURL(file); - }); - - _$manageFile.find("#file_delete").click(function () { - //openapp.resource.del(_value); - propagateValueChange(CONFIG.OPERATION.TYPE.UPDATE, "", 0); - }); - - _$selectFile.show(); - _$manageFile.hide(); - }; - - /** - * Set value - * @param {string} value - */ - this.setValue = function (value) { - _value = value; - if (_value === "") { - _$node.text(""); - } else { - $.get(_value + "/:representation").done(function (data) { - _$node.text(data.name); - }); - } - }; - - /** - * Get value - * @returns {string} - */ - this.getValue = function () { - return _value; - }; - - /** - * Get jQuery object of DOM node representing the value - * @returns {jQuery} - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the edge - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractValue.prototype.toJSON.call(this); - json.value = _value; - return json; - }; - - /** - * Set value by its JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - this.setValue(json.value); - }; - - /** - * Register inter widget communication callbacks - */ - this.registerCallbacks = function () { - //_iwcw.registerOnRemoteDataReceivedCallback(remoteValueChangeCallback); - _iwcw.registerOnDataReceivedCallback(localValueChangeCallback); - //_iwcw.registerOnHistoryChangedCallback(historyValueChangeCallback); - }; - - /** - * Unregister inter widget communication callbacks - */ - this.unregisterCallbacks = function () { - //_iwcw.unregisterOnRemoteDataReceivedCallback(remoteValueChangeCallback); - _iwcw.unregisterOnDataReceivedCallback(localValueChangeCallback); - //_iwcw.unregisterOnHistoryChangedCallback(historyValueChangeCallback); - }; - - if (_iwcw) { - that.registerCallbacks(); - } - - init(); -} + /** + * Get value of operation + * @returns {string} + */ + this.getValue = function () { + return _operation.value; + }; -const fileAttributeHtml = "
                  \r\n
                  \r\n
                  \r\n
                  "; // replaced by importmap.plugin.js - -/** - * FileAttribute - * @class canvas_widget.FileAttribute - * @extends canvas_widget.AbstractAttribute - * @memberof canvas_widget - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to - */ -class FileAttribute extends AbstractAttribute { - constructor(id, name, subjectEntity, useAttributeHtml) { - useAttributeHtml = - typeof useAttributeHtml !== "undefined" ? useAttributeHtml : false; - super(id, name, subjectEntity); - - /*** - * Value object of value - * @type {canvas_widget.FileValue} - * @private - */ - var _value = new FileValue( - id, - name, - this, - this.getRootSubjectEntity(), - useAttributeHtml - ); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(fileAttributeHtml)()); - - /** - * Set Value object of value - * @param {canvas_widget.FileValue} value - */ - this.setValue = function (value) { - _value = value; - _$node.val(value); - }; - - /** - * Get Value object of value - * @return {canvas_widget.FileValue} value - */ - this.getValue = function () { - return _value; - }; - - /** - * jQuery object of DOM node representing the attribute - * @type {jQuery} - * @private - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the attribute - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.value = _value.toJSON(); - return json; - }; - - /** - * Set attribute value by its JSON representation - * @param {Object} json - */ - this.setValueFromJSON = function (json) { - _value.setValueFromJSON(json.value); - }; - - _$node.find(".name").text(this.getName()); - _$node.find(".value").append(_value.get$node()); - } -} + /** + * Get type of operation + * @returns {string} + */ + this.getType = function () { + return _operation.type; + }; -const multiLineValueHtml = "
                  <%= value %>
                  "; // replaced by importmap.plugin.js - -/** - * MultiLineValue - * @class canvas_widget.MultiLineValue - * @extends canvas_widget.AbstractValue - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier - * @param {string} name Name of attribute - * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {canvas_widget.AbstractNode|canvas_widget.AbstractEdge} rootSubjectEntity Topmost entity in the chain of entity the attribute is assigned to - */ -class MultiLineValue extends AbstractValue { - constructor(id, name, subjectEntity, rootSubjectEntity, y) { - super(id, name, subjectEntity, rootSubjectEntity); - var that = this; - - var _ytext = null; - y = y || window.y; - if (y) { - const yMap = rootSubjectEntity.getYMap(); - if (!yMap) { - rootSubjectEntity.registerYMap(); - } - - if (rootSubjectEntity.getYMap()?.has(id)) - _ytext = rootSubjectEntity.getYMap().get(id); - else { - _ytext = new Text(); - rootSubjectEntity.getYMap().set(id, _ytext); - } - } - - /** - * MultiLineValue - * @type {string} - * @private - */ - var _value = ""; - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(multiLineValueHtml)({ value: _value })); - - /** - * Inter widget communication wrapper - * @type {Object} - * @private - */ - y = y || window.y; - var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); - - /** - * Get chain of entities the attribute is assigned to - * @returns {string[]} - */ - var getEntityIdChain = function () { - var chain = [that.getEntityId()], - entity = that; - while (entity instanceof AbstractAttribute) { - chain.unshift(entity.getSubjectEntity().getEntityId()); - entity = entity.getSubjectEntity(); - } - return chain; - }; - - /** - * Propagate a Value Change Operation to the remote users and the local widgets - * @param {operations.ot.ValueChangeOperation} operation - */ - var propagateValueChangeOperation = function (operation) { - operation.setEntityIdChain(getEntityIdChain()); - operation.setRemote(false); - that.setValue(operation.getValue()); - operation.setRemote(true); - const activityMap = y.getMap("activity"); - - activityMap.set( - ActivityOperation.TYPE, - new ActivityOperation( - "ValueChangeActivity", - that.getEntityId(), - _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], - ValueChangeOperation.getOperationDescription( - that.getSubjectEntity().getName(), - that.getRootSubjectEntity().getType(), - that.getRootSubjectEntity().getLabel().getValue().getValue() - ), - { - value: _value, - subjectEntityName: that.getSubjectEntity().getName(), - rootSubjectEntityType: that.getRootSubjectEntity().getType(), - rootSubjectEntityId: that.getRootSubjectEntity().getEntityId(), - } - ) - .toNonOTOperation() - .toJSON() - ); - - /*if(that.getRootSubjectEntity().getYMap()){ - that.getRootSubjectEntity().getYMap().set(that.getEntityId(),operation.toJSON()); - }*/ - }; - - /** - * Callback for a local Value Change Operation - * @param {operations.ot.ValueChangeOperation} operation - */ - var localValueChangeCallback = function (operation) { - if ( - operation instanceof ValueChangeOperation && - operation.getEntityId() === that.getEntityId() - ) { - propagateValueChangeOperation(operation); - } - }; - - /** - * Set value - * @param {string} value - */ - this.setValue = function (value) { - _value = value; - _$node.text(value); - }; - - /** - * Get value - * @returns {string} - */ - this.getValue = function () { - return _value; - }; - - /** - * Get jQuery object of DOM node representing the value - * @returns {jQuery} - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the edge - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractValue.prototype.toJSON.call(this); - json.value = _value; - return json; - }; - - /** - * Set value by its JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - this.setValue(json.value); - }; - - /** - * Register inter widget communication callbacks - */ - this.registerCallbacks = function () { - _iwcw.registerOnDataReceivedCallback(localValueChangeCallback); - //_iwcw.registerOnHistoryChangedCallback(historyValueChangeCallback); - }; - - /** - * Unregister inter widget communication callbacks - */ - this.unregisterCallbacks = function () { - _iwcw.unregisterOnDataReceivedCallback(localValueChangeCallback); - //_iwcw.unregisterOnHistoryChangedCallback(historyValueChangeCallback); - }; - - this.registerYType = function () { - if (!_ytext) throw new Error("_ytext is undefined"); - // _ytext.bind(_$node[0]); - - if (that.getValue() !== _ytext.toString()) { - if (_ytext.toString().length > 0) - _ytext.delete(0, _ytext.toString().length - 1); - _ytext.insert(0, that.getValue()); - } - - _ytext.observe(function (event) { - _value = _ytext.toString(); - - //TODO i can not find out who triggered the delete :-(. Therefore do this only for non delete event types - if (event.type !== "delete") { - y.getMap("users"); - var jabberId = "User"; - const activityMap = y.getMap("activity"); - - activityMap.set( - ActivityOperation.TYPE, - new ActivityOperation( - "ValueChangeActivity", - that.getEntityId(), - jabberId, - ValueChangeOperation.getOperationDescription( - that.getSubjectEntity().getName(), - that.getRootSubjectEntity().getType(), - that.getRootSubjectEntity().getLabel().getValue().getValue() - ), - { - value: "", - subjectEntityName: that.getSubjectEntity().getName(), - rootSubjectEntityType: that.getRootSubjectEntity().getType(), - rootSubjectEntityId: that.getRootSubjectEntity().getEntityId(), - } - ).toJSON() - ); - } - }); - }; - - if (_iwcw) { - that.registerCallbacks(); - } - } -} + /** + * Get position of operation + * @returns {number} + */ + this.getPosition = function () { + return _operation.position; + }; -const singleMultiLineValueAttributeHtml = "
                  \r\n
                  \r\n
                  \r\n
                  "; // replaced by importmap.plugin.js - -/** - * SingleMultiLineValueAttribute - * @class canvas_widget.SingleMultiLineValueAttribute - * @extends canvas_widget.AbstractAttribute - * @memberof canvas_widget - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to - */ -class SingleMultiLineValueAttribute extends AbstractAttribute { - constructor(id, name, subjectEntity, y) { - super(id, name, subjectEntity); - - /*** - * Value object of value - * @type {canvas_widget.MultiLineValue} - * @private - */ - var _value = new MultiLineValue( - id, - name, - this, - this.getRootSubjectEntity(), - y - ); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(singleMultiLineValueAttributeHtml)()); - - /** - * Set Value object of value - * @param {canvas_widget.MultiLineValue} value - */ - this.setValue = function (value) { - _value = value; - }; - - /** - * Get Value object of value - * @returns {canvas_widget.MultiLineValue} - */ - this.getValue = function () { - return _value; - }; - - /** - * jQuery object of DOM node representing the attribute - * @type {jQuery} - * @private - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the attribute - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.value = _value.toJSON(); - return json; - }; - - /** - * Set attribute value by its JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - _value.setValueFromJSON(json.value); - }; - - _$node.find(".name").text(this.getName()); - _$node.find(".value").append(_value.get$node()); - } -} - -function makeViewEdge( - type, - arrowType, - shapeType, - color, - dashstyle, - overlay, - overlayPosition, - overlayRotate, - attributes, - edgeType, - conditions, - conj -) { - function ViewEdge(id, source, target) { - var viewEdge = new edgeType(id, source, target); - viewEdge.restyle( - arrowType, - color, - shapeType, - dashstyle, - overlay, - overlayPosition, - overlayRotate, - attributes - ); - viewEdge.setCurrentViewType(type); - return viewEdge; - } - - ViewEdge.getConditions = function () { - return conditions; - }; - - ViewEdge.getConditionConj = function () { - return conj; - }; - - ViewEdge.getArrowType = function () { - return arrowType; - }; - ViewEdge.getShapeType = function () { - return shapeType; - }; - ViewEdge.getColor = function () { - return color; - }; - ViewEdge.getOverlay = function () { - return overlay; - }; - ViewEdge.getOverlayPosition = function () { - return overlayPosition; - }; - ViewEdge.getOverlayRotate = function () { - return overlayRotate; - }; - ViewEdge.getAttributes = function () { - return attributes; - }; - ViewEdge.getTargetEdgeType = function () { - return edgeType; - }; - ViewEdge.getType = function () { - return type; - }; - ViewEdge.getArrowOverlays = function () { - var overlays = []; - if (Arrows().hasOwnProperty(arrowType)) { - overlays.push(Arrows(color)[arrowType]); - } - return overlays; - }; - ViewEdge.getShape = function () { - return this.getTargetEdgeType().getShape(); - }; - - return ViewEdge; + /** + * Get JSON Representation of operation + * @returns {{type: string, data: string}} + */ + this.getOperationObject = function () { + return _operation; + }; + } } -function makeViewNode(type, $shape, anchors, attributes, nodeType, conditions, conj) { - - ViewNode.prototype.constructor = ViewNode; - function ViewNode(id, left, top, width, height, zIndex) { - var viewNode = new nodeType(id, left, top, width, height, zIndex); - - viewNode.set$shape($shape); - viewNode.setAnchorOptions(anchors); - viewNode.setCurrentViewType(type); - - return viewNode; - - } - - ViewNode.getConditions = function(){ - return conditions; - }; - - ViewNode.getConditionConj = function(){ - return conj; - }; - - ViewNode.get$shape = function(){ - return $shape; - }; - - ViewNode.getAnchors = function(){ - return anchors; - }; - - ViewNode.getTargetNodeType = function(){ - return nodeType; - }; - return ViewNode; - } +/** + * Namespace for non ot operations + * @namespace operations.non_ot + */ -var LogicalConjunctions = { - "AND" : "&&", - "OR" : "||" - }; + NonOTOperation.prototype = new Operation(); + NonOTOperation.prototype.constructor = NonOTOperation; + /** + * NonOTOperation + * @class operations.non_ot.NonOTOperation + * @memberof operations.non_ot + * @constructor + * @param {string} type Type of Operation + * @param {string} data Additional data for operation + */ + function NonOTOperation(type,data){ + /** + * JabberId of the user who issued this activity + * @type {string} + * @private + */ + var _sender = null; + + /** + * Operation details + * @type {{type: string, data: string}} + * @private + */ + var _operation = { + type: type, + data: data + }; -var LogicalOperator = { - "greater" : ">", - "smaller" : "<", - "equal" : "==", - "greater_eq" : ">=", - "smaller_eq" : "<=", - "nequal" : "!=" - }; + /** + * Set JabberId of the user who issued this activity + * @param sender + */ + this.setSender = function(sender){ + _sender = sender; + }; -function ViewTypesUtil() {} - -ViewTypesUtil.GetAllNodesOfBaseModelAsSelectionList = function (nodes) { - var selectionList = {}; - for (var key in nodes) { - if (nodes.hasOwnProperty(key)) { - selectionList[key] = nodes[key].getLabel().getValue().getValue(); - } - } - return selectionList; -}; -ViewTypesUtil.GetAllNodesOfBaseModelAsSelectionList2 = function (nodes, types) { - var selectionList = {}; - selectionList["empty"] = ""; - for (var key in nodes) { - if (nodes.hasOwnProperty(key)) { - if (lodash.indexOf(types, nodes[key].type) != -1) - selectionList[key] = nodes[key].label.value.value; - } - } - return selectionList; -}; - -ViewTypesUtil.createReferenceToOrigin = function (viewtype) { - const dataMap = y.getMap("data"); - var vls = dataMap.get("metamodelpreview"); - var originEntity; - if (vls) { - var targetAttr = viewtype.getAttribute(viewtype.getEntityId() + "[target]"); - var originId = targetAttr.getValue().getValue(); - if (viewtype.getType() === "ViewObject") { - if (vls.nodes.hasOwnProperty(originId)) { - originEntity = vls.nodes[originId]; - //By default the label for the ViewObject is the same as for the Origin - viewtype.getLabel().getValue().setValue(originEntity.label); - } - } else { - if (vls.edges.hasOwnProperty(originId)) { - originEntity = vls.edges[originId]; - //By default the label for the ViewObject is the same as for the Origin - viewtype.getLabel().getValue().setValue(originEntity.label); - } - } - //Initialize the Renaming list Attribute - var originAttrs = originEntity.attributes; - var renamingList = viewtype.getAttribute("[attributes]"); - var optionMap = {}; - for (var attrKey in originAttrs) { - if (originAttrs.hasOwnProperty(attrKey)) { - var attr = originAttrs[attrKey]; - var id = Util.generateRandomId(); - var operation = new AttributeAddOperation( - id, - renamingList.getEntityId(), - viewtype.getEntityId, - "RenamingAttribute" - ); - var renamingAttr = - renamingList.propagateAttributeAddOperation(operation); - renamingAttr.getKey().setValue(attr.key); - renamingAttr.getRef().setValue(attr.key); - optionMap[id] = attr.key; - } - } - //Initialize the Condition list attribute - viewtype.getYMap().set("updateConditionOption", optionMap); - - //targetAttr.get$node().hide(); - renamingList.get$node().show(); - viewtype - .getAttribute(viewtype.getEntityId() + "[conjunction]") - .get$node() - .show(); - viewtype.getAttribute("[condition]").get$node().show(); - } -}; + /** + * Get JabberId of the user who issued this activity + * @returns {string} + */ + this.getSender = function(){ + return _sender; + }; -const keySelectionValueSelectionValueListAttributeHtml = "
                  \r\n
                  \r\n
                    \r\n
                    "; // replaced by importmap.plugin.js - -const singleQuizAttributeHtml = "
                    \r\n
                    \r\n
                    \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
                    Assessment Name :
                    NrQuestionCorrect IntentOptional Hint
                    \r\n \r\n +\r\n \r\n \r\n -\r\n \r\n \r\n Submit\r\n \r\n \r\n Display\r\n \r\n
                    \r\n"; // replaced by importmap.plugin.js - -const singleValueListAttributeHtml = "
                    \r\n
                    \r\n
                      \r\n
                      "; // replaced by importmap.plugin.js - -const canvasSingleValueAttributeHtml = "
                      \r\n
                      \r\n
                      \r\n
                      "; // replaced by importmap.plugin.js - -const listHtml = "
                      \r\n
                      \r\n
                        \r\n
                        "; // replaced by importmap.plugin.js - -const renamingAttrHTML = "
                      • \r\n
                        \r\n
                        \r\n
                        \r\n
                      • "; // replaced by importmap.plugin.js - -const singleSelectionAttributeHtml = "
                        \r\n
                        \r\n
                        \r\n
                        "; // replaced by importmap.plugin.js - -const singleColorValueAttributeHtml = "
                        \r\n
                        \r\n
                        \r\n
                        "; // replaced by importmap.plugin.js - -const keySelectionValueSelectionValueAttributeHtml = "
                      • \">\r\n
                        \r\n
                        \r\n
                      • "; // replaced by importmap.plugin.js - -const keySelectionValueListAttributeHtml = "
                        \r\n
                        \r\n
                          \r\n
                          "; // replaced by importmap.plugin.js - -const keySelectionValueAttributeHtml = "
                        • \">\r\n
                          \r\n
                          \r\n
                        • "; // replaced by importmap.plugin.js -const integerAttributeHtml = "
                          \r\n
                          \r\n
                          \r\n
                          "; // replaced by importmap.plugin.js - -let integerValueHtml = "
                          <%= value %>
                          "; // replaced by importmap.plugin.js -const attributeIntegerValueHtml = "\"\r\n value=\"0\"\r\n/>\r\n"; // replaced by importmap.plugin.js - -const valueHtml = "\"\r\n disabled=\"disabled\"\r\n/>\r\n"; // replaced by importmap.plugin.js - -let selectionValueHtml = "
                          <%= options[_.keys(options)[0]] %>
                          "; // replaced by importmap.plugin.js -const attributeSelectionValueHtml = "\r\n"; // replaced by importmap.plugin.js - -const viewrelationshipNodeHtml$1 = "
                          \r\n
                          <%= type %>
                          \r\n
                          <<ViewRelationship>>
                          \r\n
                          \r\n
                          "; // replaced by importmap.plugin.js - -const viewobjectNodeHtml = "
                          \r\n
                          <%= type %>
                          \r\n
                          <<ViewObject>>
                          \r\n
                          \r\n
                          "; // replaced by importmap.plugin.js - -const nodeShapeNodeHtml = "
                          \r\n
                          <%= type %>
                          \r\n
                          <<NodeShape>>
                          \r\n
                          \r\n
                          "; // replaced by importmap.plugin.js - -const modelAttributesNodeHtml = "
                          \r\n
                          \r\n
                          \r\n
                          "; // replaced by importmap.plugin.js - -const relationshipGroupNodeHtml = "
                          \r\n
                          <%= type %>
                          \r\n
                          <<Relation>>
                          \r\n
                          \r\n
                          "; // replaced by importmap.plugin.js - -const enumNodeHtml = "
                          \r\n
                          <%= type %>
                          \r\n
                          <<Enumeration>>
                          \r\n
                          \r\n
                          "; // replaced by importmap.plugin.js - -const abstractEdgeHtml = "
                          \r\n
                          <%= type %>
                          \r\n
                          \r\n
                          "; // replaced by importmap.plugin.js - -const edgeShapeNodeHtml = "
                          \r\n
                          <%= type %>
                          \r\n
                          <<EdgeShape>>
                          \r\n
                          \r\n
                          "; // replaced by importmap.plugin.js - -const abstractNodeHtml = "
                          \" class=\"node\">\r\n
                          "; // replaced by importmap.plugin.js -const awarenessTraceHtml = "
                          \" class=\"trace_awareness\">\r\n\r\n \r\n\r\n
                          "; // replaced by importmap.plugin.js - -const abstractClassNodeHtml = "
                          \r\n
                          <%= type %>
                          \r\n
                          <<abstract>>
                          \r\n
                          \r\n
                          \r\n"; // replaced by importmap.plugin.js - -const relationshipNodeHtml = "
                          \r\n
                          <%= type %>
                          \r\n
                          <<Relationship>>
                          \r\n
                          \r\n
                          "; // replaced by importmap.plugin.js -const actionNodeHtml = "
                          \r\n
                          <%= \"<\\%= type %\\>\" %>
                          \r\n \r\n \r\n \r\n
                          \r\n \t\r\n\t\t \r\n\t\t \r\n\t\t \t\t\r\n\t\t \r\n\t\t
                          fa-2x\"><%= label %>
                          \r\n
                          \r\n
                          "; // replaced by importmap.plugin.js -const circleNodeHtml = "
                          \r\n
                          <%= type %>
                          \r\n \r\n \"\r\n stroke=\"lightgray\"\r\n stroke-width=\"2\"\r\n />\r\n \r\n
                          \r\n
                          \r\n
                          \r\n\r\n"; // replaced by importmap.plugin.js -const diamondNodeHtml = "
                          \r\n
                          <%= type %>
                          \r\n \r\n \"\r\n stroke=\"lightgray\"\r\n stroke-width=\"2\"\r\n transform=\"rotate(-45 50 50)\"\r\n />\r\n \r\n
                          \r\n
                          \r\n
                          \r\n\r\n"; // replaced by importmap.plugin.js -const objectNodeHtml = "
                          \r\n
                          <%= type %>
                          \r\n
                          <<Object>>
                          \r\n
                          \r\n
                          "; // replaced by importmap.plugin.js -const rectangleNodeHtml = "
                          \r\n
                          <%= type %>
                          \r\n \r\n \"\r\n stroke=\"lightgray\"\r\n stroke-width=\"2\"\r\n />\r\n \r\n
                          \r\n
                          \r\n
                          \r\n\r\n"; // replaced by importmap.plugin.js -const roundedRectangleNodeHtml = "
                          \r\n
                          <%= type %>
                          \r\n \r\n \"\r\n stroke=\"lightgray\"\r\n stroke-width=\"2\"\r\n />\r\n \r\n
                          \r\n
                          \r\n
                          \r\n\r\n"; // replaced by importmap.plugin.js -const startActivityNodeHtml = "
                          \r\n
                          <%= type %>
                          \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
                          \r\n \t\r\n\t\t \r\n\t\t \r\n\t\t \t\t\r\n\t\t \r\n\t\t
                          \r\n
                          \r\n
                          "; // replaced by importmap.plugin.js -const triangleNodeHtml = "
                          \r\n
                          <%= type %>
                          \r\n \r\n \"\r\n stroke=\"lightgray\"\r\n stroke-width=\"2\"\r\n />\r\n \r\n
                          \r\n
                          \r\n
                          \r\n\r\n"; // replaced by importmap.plugin.js -const activityFinalNodeHtml = "
                          \r\n
                          <%= type %>
                          \r\n \r\n \r\n \r\n \r\n
                          \r\n
                          \r\n
                          "; // replaced by importmap.plugin.js -const callActivityNodeHtml = "
                          \r\n
                          <%= type %>
                          \r\n \r\n \r\n \r\n
                          \r\n \r\n \r\n \r\n \r\n \r\n
                          \r\n
                          \r\n
                          "; // replaced by importmap.plugin.js -const entityNodeHtml = "
                          \r\n
                          <%= \"<\\%= type %\\>\" %>
                          \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
                          \r\n \t\r\n\t\t \r\n\t\t \r\n\t\t \t\t\r\n\t\t \r\n\t\t
                          fa-2x\"><%= label %>
                          \r\n
                          \r\n
                          "; // replaced by importmap.plugin.js -const setPropertyNodeHtml = "
                          \r\n
                          <%= \"<\\%= type %\\>\" %>
                          \r\n \r\n \r\n \r\n
                          \r\n \t\r\n\t\t \r\n\t\t \r\n\t\t \t\t\r\n\t\t \r\n\t\t
                          \r\n
                          \r\n
                          "; // replaced by importmap.plugin.js - -var shapes = { - straight: { - type: StraightConnector.type, - options: { gap: 0 }, - }, - curved: { - type: BezierConnector.type, - options: { gap: 0 }, - }, - segmented: { - type: FlowchartConnector.type, - options: { gap: 0 }, - }, -}; - -function HistoryManager() { - var bufferSize = 20; - - var _canvas = null; - - var latestOp = null; - var undo = []; - var redo = []; - - var $undo = $("#undo"); - - var $redo = $("#redo"); - - var propagateHistoryOperationFromJson = function (json) { - var EntityManager = EntityManager; - var operation = null, - data = null, - entity; - switch (json.TYPE) { - case NodeDeleteOperation.TYPE: { - entity = EntityManager.findNode(json.id); - if (entity) { - entity.triggerDeletion(true); - operation = new NodeDeleteOperation( - json.id, - json.type, - json.left, - json.top, - json.width, - json.height, - json.zIndex, - json.containment, - json.json - ); - } - break; - } - case NodeAddOperation.TYPE: { - _canvas.createNode( - json.type, - json.left, - json.top, - json.width, - json.height, - json.zIndex, - json.containment, - json.json, - json.id, - true - ); - operation = new NodeAddOperation( - json.id, - json.type, - json.left, - json.top, - json.width, - json.height, - json.zIndex, - json.containment, - json.json - ); - break; - } - case EdgeAddOperation.TYPE: { - _canvas.createEdge( - json.type, - json.source, - json.target, - json.json, - json.id, - true - ); - operation = new EdgeAddOperation( - json.id, - json.type, - json.source, - json.target, - json.json - ); - break; - } - case EdgeDeleteOperation.TYPE: { - entity = EntityManager.findEdge(json.id); - if (entity) { - entity.triggerDeletion(true); - operation = new EdgeDeleteOperation( - json.id, - json.type, - json.source, - json.target, - json.json - ); - } - break; - } - case NodeMoveOperation.TYPE: { - entity = EntityManager.findNode(json.id); - if (entity) { - const nodesMap = y.getMap("nodes"); - operation = new NodeMoveOperation( - json.id, - json.offsetX, - json.offsetY - ); - var ymap = nodesMap.get(json.id); - data = operation.toJSON(); - data.historyFlag = true; - ymap.set(NodeMoveOperation.TYPE, data); - } - break; - } - case NodeMoveZOperation.TYPE: { - entity = EntityManager.findNode(json.id); - if (entity) { - operation = new NodeMoveZOperation(json.id, json.offsetZ); - const nodesMap = y.getMap("nodes"); - var ymap = nodesMap.get(json.id); - data = operation.toJSON(); - data.historyFlag = true; - ymap.set(NodeMoveZOperation.TYPE, data); - } - break; - } - case NodeResizeOperation.TYPE: { - entity = EntityManager.findNode(json.id); - if (entity) { - operation = new NodeResizeOperation( - json.id, - json.offsetX, - json.offsetY - ); - const nodesMap = y.getMap("nodes"); - var ymap = nodesMap.get(json.id); - data = operation.toJSON(); - data.historyFlag = true; - ymap.set(NodeResizeOperation.TYPE, data); - } - break; - } - } - return operation; - }; - - return { - init: function (canvas) { - if (!canvas) throw new Error("Canvas is null"); - _canvas = canvas; - }, - add: function (operation) { - if (operation.hasOwnProperty("inverse")) { - var inverseOp = operation.inverse(); - var json = inverseOp.toJSON(); - json.TYPE = inverseOp.constructor.name; - undo.push(json); - redo = []; - $undo.prop("disabled", false); - $redo.prop("disabled", true); - } - if (undo.length > bufferSize) { - undo.shift(); - } - }, - undo: function () { - if (undo.length > 0) { - var jsonOp = undo.pop(); - if (undo.length === 0) { - $undo.prop("disabled", true); - } - var operation = propagateHistoryOperationFromJson(jsonOp); - if (!operation) { - this.undo(); - return; - } else latestOp = operation; - - var inverseOp = operation.inverse(); - var json = inverseOp.toJSON(); - json.TYPE = inverseOp.constructor.name; - - if (redo.length === 0) $redo.prop("disabled", false); - redo.push(json); - } else { - $undo.prop("disabled", true); - } - }, - redo: function () { - if (redo.length > 0) { - var jsonOp = redo.pop(); - if (redo.length === 0) { - $redo.prop("disabled", true); - } - var operation = propagateHistoryOperationFromJson(jsonOp); - if (!operation) { - this.redo(); - return; - } else latestOp = operation; - var inverseOp = operation.inverse(); - var json = inverseOp.toJSON(); - json.TYPE = inverseOp.constructor.name; - - if (undo.length === 0) $undo.prop("disabled", false); - undo.push(json); - } else { - $redo.prop("disabled", true); - } - }, - clean: function (entityId) { - var entityIdFilter = function (value, idx) { - if (value.id === entityId) return false; - else return true; - }; - undo = undo.filter(entityIdFilter); - redo = redo.filter(entityIdFilter); - if (undo.length === 0) { - $undo.prop("disabled", true); - } - if (redo.length === 0) { - $redo.prop("disabled", true); - } - }, - getLatestOperation: function () { - return latestOp; - }, - getUndoList: function () { - return undo; - }, - getRedoList: function () { - return redo; - }, - }; -} - -const HistoryManagerInstance = new HistoryManager(); - -const openapp = new OpenAppProvider().openapp; - -/** - * Predefined node shapes, first is default - * @type {{circle: *, diamond: *, rectangle: *, triangle: *}} - */ -var nodeShapeTypes = { - circle: circleNodeHtml, - diamond: diamondNodeHtml, - rectangle: rectangleNodeHtml, - rounded_rectangle: roundedRectangleNodeHtml, - triangle: triangleNodeHtml, -}; - -/** - * jQuery object to test for valid color - * @type {$} - */ -var $colorTestElement = $("
                          "); - -/** Determines the current layer of syncmeta. - * can be CONFIG.LAYER.MODEL or CONFIG.LAYER.META*/ -var _layer = null; - -/** - * Different node types - * @type {object} - */ -var nodeTypes = {}; - -var _initNodeTypes = function (vls) { - var _nodeTypes = {}; - - var nodes = vls.nodes, - node, - shape, - anchors; - - // Start creating nodes based on metamodel - for (var nodeId in nodes) { - if (nodes.hasOwnProperty(nodeId)) { - node = nodes[nodeId]; - if (node.shape.customShape) { - shape = node.shape.customShape; - } else { - shape = nodeShapeTypes.hasOwnProperty(node.shape.shape) - ? nodeShapeTypes[node.shape.shape] - : lodash.keys(nodeShapeTypes)[0]; - } - if (node.shape.customAnchors) { - try { - if (node.shape.customAnchors) { - anchors = JSON.parse(node.shape.customAnchors); - } - if (!node.shape.customAnchors instanceof Array) { - anchors = { - type: "Perimeter", - options: { - shape: "Rectangle", - anchorCount: 10, - }, - }; - } - } catch (e) { - anchors = { - type: "Perimeter", - options: { - shape: "Rectangle", - anchorCount: 10, - }, - }; - } - } else { - switch (node.shape.shape) { - case "circle": - anchors = { - type: "Perimeter", - options: { - shape: "Circle", - anchorCount: 10, - }, - }; - break; - case "diamond": - anchors = { - type: "Perimeter", - options: { - shape: "Diamond", - anchorCount: 10, - }, - }; - break; - case "rounded_rectangle": - anchors = { - type: "Perimeter", - options: { - shape: "Rectangle", - anchorCount: 10, - }, - }; - break; - case "triangle": - anchors = { - type: "Perimeter", - options: { - shape: "Triangle", - anchorCount: 10, - }, - }; - break; - default: - case "rectangle": - anchors = { - type: "Perimeter", - options: { - shape: "Rectangle", - anchorCount: 10, - }, - }; - break; - } - } - var color = node.shape.color - ? $colorTestElement - .css("color", "#FFFFFF") - .css("color", node.shape.color) - .css("color") - : "#FFFFFF"; - var $shape = $(lodash.template(shape)({ color: color, type: node.label })); - - if ( - node.hasOwnProperty("targetName") && - !$.isEmptyObject(nodeTypes) && - nodeTypes.hasOwnProperty(node.targetName) - ) { - _nodeTypes[node.label] = makeViewNode( - node.label, - $shape, - anchors, - node.attributes, - nodeTypes[node.targetName], - node.conditions, - node.conjunction - ); - nodeTypes[node.targetName].VIEWTYPE = node.label; - } else { - _nodeTypes[node.label] = makeNode( - node.label, - $shape, - anchors, - node.attributes - ); - } - _nodeTypes[node.label].TYPE = node.label; - _nodeTypes[node.label].DEFAULT_WIDTH = node.shape.defaultWidth; - _nodeTypes[node.label].DEFAULT_HEIGHT = node.shape.defaultHeight; - _nodeTypes[node.label].CONTAINMENT = node.shape.containment; - _nodeTypes[node.label].SHAPE = $shape; - /* - nodeTypes[node.label] = Node(node.label, $shape, anchors, node.attributes, node.jsplumb); - nodeTypes[node.label].TYPE = node.label; - nodeTypes[node.label].SHAPE = $shape; - nodeTypes[node.label].DEFAULT_WIDTH = node.shape.defaultWidth; - nodeTypes[node.label].DEFAULT_HEIGHT = node.shape.defaultHeight;*/ - } - } - return _nodeTypes; -}; - -var _initEdgeTypes = function (vls) { - var _edgeTypes = {}; - var _relations = {}; - var edges = vls.edges, - edge; - for (var edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - - if ( - edge.hasOwnProperty("targetName") && - !$.isEmptyObject(edgeTypes) && - edgeTypes.hasOwnProperty(edge.targetName) - ) { - _edgeTypes[edge.label] = makeViewEdge( - edge.label, - edge.shape.arrow, - edge.shape.shape, - edge.shape.color, - edge.shape.dashstyle, - edge.shape.overlay, - edge.shape.overlayPosition, - edge.shape.overlayRotate, - edge.attributes, - edgeTypes[edge.targetName], - edge.conditions, - edge.conjunction - ); - edgeTypes[edge.targetName].VIEWTYPE = edge.label; - } else { - _edgeTypes[edge.label] = makeEdge( - edge.label, - edge.shape.arrow, - edge.shape.shape, - edge.shape.color, - edge.shape.dashstyle, - edge.shape.overlay, - edge.shape.overlayPosition, - edge.shape.overlayRotate, - edge.attributes - ); - } - - _edgeTypes[edge.label].TYPE = edge.label; - _relations[edge.label] = edge.relations; - } - } - return { - edgeTypes: _edgeTypes, - relations: _relations, - }; -}; - -/** - * contains all view node types of the current view - * @type {{}} - */ -var viewNodeTypes = {}; - -/** - * contains all view edge types of the current view - * @type {{}} - */ -var viewEdgeTypes = {}; - -/** - * Different edge types - * @type {object} - */ -var edgeTypes = {}; -var relations = {}; -/* - if (metamodel && metamodel.hasOwnProperty("edges")) { - var res = _initEdgeTypes(metamodel); - edgeTypes = res.edgeTypes; - relations = res.relations; - } else { - edgeTypes[GeneralisationEdge.TYPE] = GeneralisationEdge; - edgeTypes[BiDirAssociationEdge.TYPE] = BiDirAssociationEdge; - edgeTypes[UniDirAssociationEdge.TYPE] = UniDirAssociationEdge; - - relations[BiDirAssociationEdge.TYPE] = BiDirAssociationEdge.RELATIONS; - relations[UniDirAssociationEdge.TYPE] = UniDirAssociationEdge.RELATIONS; - relations[GeneralisationEdge.TYPE] = GeneralisationEdge.RELATIONS; - }*/ - -/** - * AbstractEdge - * @class canvas_widget.AbstractEdge - * @extends canvas_widget.AbstractEntity - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of edge - * @param {string} type Type of edge - * @param {canvas_widget.AbstractNode} source Source node - * @param {canvas_widget.AbstractNode} target Target node - * @param {boolean} [overlayRotate] Flag if edge overlay should be flipped automatically to avoid being upside down - */ -class AbstractEdge extends AbstractEntity { - constructor(id, type, source, target, overlayRotate, y) { - super(id); - y = y || window.y; - var that = this; - - /** - * Inter widget communication wrapper - * @type {Object} - */ - var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); // y comes from the window object but should in the future be passed through the constructor since we should avoid binding to window - - var _ymap = null; - if (!y) { - throw new Error("y is not defined"); - } - - const edgeMap = y.getMap("edges"); - if (edgeMap.has(id)) { - _ymap = edgeMap.get(id); - } else if (id && type && source && target) { - _ymap = new Map$2(); - edgeMap.set(id, new Map$2()); - y.transact(() => { - _ymap.set("id", id); - _ymap.set("type", type); - _ymap.set("source", source.getEntityId()); - _ymap.set("target", target.getEntityId()); - _ymap.set("jabberId", _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]); - }); - } - - this.getYMap = function () { - return _ymap; - }; - - /** - * Type of edge - * @type {string} - * @private - */ - var _type = type; - - /** - * Label of edge - * @type {canvas_widget.SingleValueAttribute} - * @private - */ - var _label = new SingleValueAttribute(id + "[label]", "Label", this, y); - - /** - * Appearance information of edge - * @type {{source: (canvas_widget.AbstractNode), target: (canvas_widget.AbstractNode)}} - * @private - */ - var _appearance = { - source: source, - target: target, - }; - - /** - * Flag if edge overlay should be flipped automatically to avoid being upside down - * @type {boolean} - * @private - */ - var _overlayRotate = overlayRotate !== false; - - /** - * jQuery object of DOM node representing the edge's overlay - * @type {jQuery} - * @private - */ - var _$overlay = $(lodash.template(abstractEdgeHtml)({ type: type })) - .find(".edge_label") - .append(_label.get$node()) - .parent(); - - /** - * Canvas the edge is drawn on - * @type {canvas_widget.AbstractCanvas} - * @private - */ - var _canvas = null; - - /** - * jsPlumb object representing the edge - * @type {Object} - * @private - */ - var _jsPlumbConnection = null; - - /** - * Attributes of edge - * @type {Object} - * @private - */ - var _attributes = {}; - - /** - * Stores current highlighting color - * @type {string} - * @private - */ - var _highlightColor = null; - - /** - * Callback to generate list of context menu items - * @type {function} - */ - var _contextMenuItemCallback = function () { - return {}; - }; - - //noinspection JSUnusedLocalSymbols - /** - * Apply an Edge Delete Operation - * @param {operations.ot.EdgeDeleteOperation} operation - */ - var processEdgeDeleteOperation = function (operation) { - that.remove(); - }; - - /** - * Propagate an Edge Delete Operation to the remote users and the local widgets - * @param {operations.ot.EdgeDeleteOperation} operation - */ - var propagateEdgeDeleteOperation = function (operation) { - processEdgeDeleteOperation(); - - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.ATTRIBUTE, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.getOTOperation() - ); - const activityMap = y.getMap("activity"); - activityMap.set( - ActivityOperation.TYPE, - new ActivityOperation( - "EdgeDeleteActivity", - operation.getEntityId(), - _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], - EdgeDeleteOperation.getOperationDescription( - that.getType(), - that.getLabel().getValue().getValue() - ), - {} - ).toJSON() - ); - }; - - /** - * Callback for a remote Edge Delete Operation - * @param {operations.ot.EdgeDeleteOperation} operation - */ - this.remoteEdgeDeleteCallback = function (operation) { - if ( - operation instanceof EdgeDeleteOperation && - operation.getEntityId() == that.getEntityId() - ) { - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.ATTRIBUTE, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.getOTOperation() - ); - processEdgeDeleteOperation(); - } - }; - - /** - * Get jQuery object of all DOM nodes belonging to the edge - */ - var getAllAssociatedDOMNodes = function () { - var overlays, - i, - numOfOverlays, - $e = $("." + id); - - if (_jsPlumbConnection) { - overlays = _jsPlumbConnection.getOverlays(); - for (i = 0, numOfOverlays = overlays.length; i < numOfOverlays; i++) { - if (overlays[i] instanceof jsPlumb.Overlays.Custom) { - $e = $e.add(overlays[i].getElement()); - } - } - } else throw new Error("jsPlumbConnection is null"); - return $e; - }; - - /** - * Default paint style of edge - */ - var _defaultPaintStyle; - - /** - * Set the default paint style - * @param paintStyle - */ - this.setDefaultPaintStyle = function (paintStyle) { - _defaultPaintStyle = paintStyle; - }; - - /** - * Get the default paint style - * @returns {*} - */ - this.getDefaultPaintStyle = function () { - return _defaultPaintStyle; - }; - - /** - * Send NodeDeleteOperation for node - */ - this.triggerDeletion = function (historyFlag) { - _canvas.select(null); - var operation = new EdgeDeleteOperation( - id, - that.getType(), - that.getSource().getEntityId(), - that.getTarget().getEntityId() - ); - - if (_ymap) { - propagateEdgeDeleteOperation(operation); - const edgeMap = y.getMap("edges"); - edgeMap.delete(that.getEntityId()); - } else { - propagateEdgeDeleteOperation(operation); - } - if (!historyFlag) HistoryManagerInstance.add(operation); - }; - - //noinspection JSUnusedGlobalSymbols - /** - * Get callback to generate list of context menu items - * @returns {object} - */ - this.getContextMenuItemCallback = function () { - return _contextMenuItemCallback; - }; - - /** - * Set callback to generate list of context menu items - * @param {function} contextMenuItemCallback - */ - this.setContextMenuItemCallback = function (contextMenuItemCallback) { - _contextMenuItemCallback = contextMenuItemCallback; - }; - - /** - * Adds edge to canvas - * @param {canvas_widget.AbstractCanvas} canvas - */ - this.addToCanvas = function (canvas) { - if (!canvas) throw new Error("Canvas is null"); - _canvas = canvas; - }; - - /** - * Get associated canvas - * @returns {canvas_widget.AbstractCanvas} - */ - this.getCanvas = function () { - return _canvas; - }; - - /** - * Removes edge from canvas - */ - this.removeFromCanvas = function () { - _canvas = null; - $.contextMenu("destroy", "." + that.getEntityId()); - window.jsPlumbInstance.deleteConnection(_jsPlumbConnection, { - fireEvent: false, - }); - _jsPlumbConnection = null; - }; - - /** - * Add attribute to edge - * @param {canvas_widget.AbstractAttribute} attribute - */ - this.addAttribute = function (attribute) { - var id = attribute.getEntityId(); - if (!_attributes.hasOwnProperty(id)) { - _attributes[id] = attribute; - } - }; - - /** - * Set edge's attributes - * @param {Object} attributes - */ - this.setAttributes = function (attributes) { - _attributes = attributes; - }; - - /** - * Get edge's attributes - * @returns {Object} - */ - this.getAttributes = function () { - return _attributes; - }; - - /** - * Get attribute by id - * @param {String} id Attribute's entity id - * @returns {canvas_widget.AbstractAttribute} - */ - this.getAttribute = function (id) { - if (_attributes.hasOwnProperty(id)) { - return _attributes[id]; - } - return null; - }; - - /** - * Delete attribute by id - * @param {String} id Attribute's entity id - */ - this.deleteAttribute = function (id) { - if (!_attributes.hasOwnProperty(id)) { - delete _attributes[id]; - } - }; - - /** - * Set edge label - * @param {canvas_widget.SingleValueAttribute} label - */ - this.setLabel = function (label) { - _label = label; - }; - - /** - * Get edge label - * @returns {canvas_widget.SingleValueAttribute} - */ - this.getLabel = function () { - return _label; - }; - - /** - * Get edge type - * @returns {string} - */ - this.getType = function () { - return _type; - }; - - /** - * Get source node - * @returns {canvas_widget.AbstractNode} - */ - this.getSource = function () { - return _appearance.source; - }; - - /** - * Get target node - * @returns {canvas_widget.AbstractNode} - */ - this.getTarget = function () { - //noinspection JSAccessibilityCheck - return _appearance.target; - }; - - /** - * Get jQuery object of DOM node representing the edge's overlay - * @returns {jQuery} - */ - this.get$overlay = function () { - return _$overlay; - }; - - //noinspection JSUnusedGlobalSymbols - /** - * Set flag if edge overlay should be flipped automatically to avoid being upside down - * @param {boolean} rotateOverlay - */ - this.setRotateOverlay = function (rotateOverlay) { - _overlayRotate = rotateOverlay; - }; - - //noinspection JSUnusedGlobalSymbols - /** - * Get flag if edge overlay should be flipped automatically to avoid being upside down - * @return {boolean} rotateOverlay - */ - this.isRotateOverlay = function () { - return _overlayRotate; - }; - - /** - * Set jsPlumb object representing the edge - * @param {Object} jsPlumbConnection - */ - this.setJsPlumbConnection = function (jsPlumbConnection) { - _jsPlumbConnection = jsPlumbConnection; - _defaultPaintStyle = jsPlumbConnection.getPaintStyle(); - }; - - //noinspection JSUnusedGlobalSymbols - /** - * Get jsPlumb object representing the edge - * @return {Object} jsPlumbConnection - */ - this.getJsPlumbConnection = function () { - return _jsPlumbConnection; - }; - - /** - * Repaint edge overlays (adjust angle of fixed overlays) - */ - this.repaintOverlays = function () { - function makeRotateOverlayCallback(angle) { - return function rotateOverlay() { - var $this = $(this), - oldTransform = $this.css("transform", "").css("transform"); - - if (oldTransform === "none") oldTransform = ""; - - $this.css({ - transform: oldTransform + " rotate(" + angle + "rad)", - "-o-transform": oldTransform + " rotate(" + angle + "rad)", - "-ms-transform": oldTransform + " rotate(" + angle + "rad)", - "-moz-transform": oldTransform + " rotate(" + angle + "rad)", - "-webkit-transform": oldTransform + " rotate(" + angle + "rad)", - }); - }; - } - - var i, numOfOverlays, overlays, sourceEndpoint, targetEndpoint, angle; - - if (_jsPlumbConnection) { - sourceEndpoint = _jsPlumbConnection.endpoints[0].endpoint; - targetEndpoint = _jsPlumbConnection.endpoints[1].endpoint; - angle = Math.atan2( - sourceEndpoint.y - targetEndpoint.y, - sourceEndpoint.x - targetEndpoint.x - ); - if (!_overlayRotate || Math.abs(angle) > Math.PI / 2) { - angle += Math.PI; - } - overlays = _jsPlumbConnection.getOverlays(); - for (i = 0, numOfOverlays = overlays.length; i < numOfOverlays; i++) { - if (overlays[i] instanceof jsPlumb.Overlays.Custom) { - $(overlays[i].getElement()) - .find(".fixed") - .not(".segmented") - .each(makeRotateOverlayCallback(angle)); - //Always flip type overlay - $(overlays[i].getElement()) - .find(".fixed.type") - .not(".segmented") - .each( - makeRotateOverlayCallback( - Math.abs(angle - Math.PI) > Math.PI / 2 - ? angle - : angle + Math.PI - ) - ); - } - } - } else throw new Error("jsPlumbConnection is null"); - }; - - /** - * Sets position of edge on z-axis as max of the z-indices of source and target - */ - this.setZIndex = function () { - var $e = getAllAssociatedDOMNodes(), - zIndex = Math.max(source.getZIndex(), target.getZIndex()); - $e.css("zIndex", zIndex); - }; - - /** - * Connect source and target node and draw the edge on canvas - */ - this.connect = function () { - source.addOutgoingEdge(this); - target.addIngoingEdge(this); - //noinspection JSAccessibilityCheck - _jsPlumbConnection = window.jsPlumbInstance.connect({ - source: _appearance.source.get$node().get(0), - target: _appearance.target.get$node().get(0), - paintStyle: { stroke: "black", outlineWidth: 4 }, - endpoint: "Dot", - connector: { type: FlowchartConnector.type }, - anchors: [source.getAnchorOptions(), target.getAnchorOptions()], - overlays: [ - { - type: "Custom", - options: { - create: function () { - return _$overlay.get(0); - }, - location: 0.5, - id: "label", - }, - }, - ], - cssClass: id, - }); - this.repaintOverlays(); - lodash.each(EntityManagerInstance.getEdges(), function (e) { - e.setZIndex(); - }); - }; - - /** - * Lowlight the edge - */ - this.lowlight = function () { - $("." + id).addClass("lowlighted"); - }; - - /** - * Unlowlight the edge - */ - this.unlowlight = function () { - $("." + id).removeClass("lowlighted"); - }; - - /** - * Select the edge - */ - this.select = function () { - var paintStyle = lodash.clone(_defaultPaintStyle), - overlays, - i, - numOfOverlays; - - function makeBold() { - $(this).css("fontWeight", "bold"); - } - this.unhighlight(); - if (_jsPlumbConnection) { - paintStyle.lineWidth = 4; - _jsPlumbConnection.setPaintStyle(paintStyle); - overlays = _jsPlumbConnection.getOverlays(); - for (i = 0, numOfOverlays = overlays.length; i < numOfOverlays; i++) { - if (overlays[i] instanceof jsPlumb.Overlays.Custom) { - $(overlays[i].getElement()).find(".fixed").each(makeBold); - } - } - } else throw new Error("jsPlumbConnection is null"); - }; - - /** - * Unselect the edge - */ - this.unselect = function () { - var overlays, i, numOfOverlays; - - function unmakeBold() { - $(this).css("fontWeight", ""); - } - this.highlight(_highlightColor); - if (_jsPlumbConnection) { - _jsPlumbConnection.setPaintStyle(_defaultPaintStyle); - overlays = _jsPlumbConnection.getOverlays(); - for (i = 0, numOfOverlays = overlays.length; i < numOfOverlays; i++) { - if (overlays[i] instanceof jsPlumb.Overlays.Custom) { - $(overlays[i].getElement()).find(".fixed").each(unmakeBold); - } - } - } - }; - - /** - * Highlight the edge - * @param {String} color - */ - this.highlight = function (color) { - var paintStyle = lodash.clone(_defaultPaintStyle); - - if (color) { - paintStyle.strokeStyle = color; - paintStyle.lineWidth = 4; - if (_jsPlumbConnection) _jsPlumbConnection.setPaintStyle(paintStyle); - else throw new Error("jsPlumbConnection is null"); - } - }; - - /** - * Unhighlight the edge - */ - this.unhighlight = function () { - if (_jsPlumbConnection) { - _jsPlumbConnection.setPaintStyle(_defaultPaintStyle); - } else throw new Error("jsPlumbConnection is null"); - }; - - /** - * Remove the edge - */ - this.remove = function () { - source.deleteOutgoingEdge(this); - target.deleteIngoingEdge(this); - this.removeFromCanvas(); - //this.unregisterCallbacks(); - EntityManagerInstance.deleteEdge(this.getEntityId()); - if (_ymap) { - _ymap = null; - } - }; - - /** - * Get JSON representation of the edge - * @returns {Object} - * @private - */ - this._toJSON = function () { - var attr = {}; - lodash.forEach(this.getAttributes(), function (val, key) { - attr[key] = val.toJSON(); - }); - return { - label: _label.toJSON(), - source: source.getEntityId(), - target: target.getEntityId(), - attributes: attr, - type: _type, - }; - }; - - /** - * Bind events for move tool - */ - this.bindMoveToolEvents = function () { - if (_jsPlumbConnection) { - //Enable Edge Select - $("." + id).on("click", function (e) { - _canvas.select(that); - }); - - $(_jsPlumbConnection.getOverlay("label").canvas) - .find("input") - .prop("disabled", false) - .css("pointerEvents", ""); - - /*$(_jsPlumbConnection.getOverlay("label").canvas).find("input[type=text]").autoGrowInput({ - comfortZone: 10, - minWidth: 40, - maxWidth: 100 - }).trigger("blur");*/ - } else throw new Error("jsPlumbConnection is null"); - - if (id) { - // view_only is used by the CAE and allows to show a model in the Canvas which is not editable - // therefore, the context menu of every edge must be disabled - const widgetConfigMap = y.getMap("widgetConfig"); - var viewOnly = widgetConfigMap.get("view_only"); - if (viewOnly) return; - } - - //Define Edge Rightclick Menu - $.contextMenu({ - selector: "." + id, - zIndex: AbstractEntity.CONTEXT_MENU_Z_INDEX, - build: function () { - var menuItems = lodash.extend(_contextMenuItemCallback(), { - delete: { - name: "Delete", - callback: function (/*key, opt*/) { - that.triggerDeletion(); - }, - }, - }); - - return { - items: menuItems, - events: { - show: function (/*opt*/) { - _canvas.select(that); - }, - }, - }; - }, - }); - - //$("."+id).contextMenu(true); - }; - - /** - * Unbind events for move tool - */ - this.unbindMoveToolEvents = function () { - if (_jsPlumbConnection) { - //Disable Edge Select - _jsPlumbConnection.unbind("click"); - - $(_jsPlumbConnection.getOverlay("label").canvas) - .find("input") - .prop("disabled", true) - .css("pointerEvents", "none"); - } else throw new Error("jsPlumbConnection is null"); - - //$("."+id).contextMenu(false); - }; - - this._registerYMap = function () { - that.getLabel().getValue().registerYType(); - }; - } - /** - * Get JSON representation of the edge - * @returns {{label: Object, source: string, target: string, attributes: Object, type: string}} - */ - toJSON() { - return this._toJSON(); - } - /** - * Hide a jsPlumb connection - */ - hide() { - var connector = this.getJsPlumbConnection(); - connector.setVisible(false); - } - /** - * Show a jsPlumb connection - */ - show() { - var connector = this.getJsPlumbConnection(); - connector.setVisible(true); - } - registerYMap() { - this._registerYMap(); - } -} - -/** - * AbstractNode - * @class canvas_widget.AbstractNode - * @extends canvas_widget.AbstractEntity - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of node - * @param {string} type Type of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {boolean} containment containment - * @param {number} zIndex Position of node on z-axis - */ -class AbstractNode extends AbstractEntity { - nodeSelector; - _$node; - constructor( - id, - type, - left, - top, - width, - height, - zIndex, - containment, - json, - y - ) { - super(id); - var that = this; - y = y || window.y; - if (!y) { - throw new Error("y is undefined"); - } - - /** - * Inter widget communication wrapper - * @type {Object} - * @private - */ - var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); - /**y-map instances which belongs to the node - * @type {YMap} - * @private - * */ - var _ymap = null; - y = y || window.y; - if (!y) { - throw new Error("y is undefined"); - } - const nodesMap = y.getMap("nodes"); - - if (nodesMap.has(id)) { - _ymap = nodesMap.get(id); - } else { - window.y.transact(() => { - _ymap = new Map$2(); - nodesMap.set(id, _ymap); - _ymap.set("modifiedBy", window.y.clientID); - _ymap.set("left", left); - _ymap.set("top", top); - _ymap.set("width", width); - _ymap.set("height", height); - _ymap.set("zIndex", zIndex); - _ymap.set("containment", containment); - _ymap.set("type", type); - _ymap.set("id", id); - if (json) _ymap.set("json", json); - if (_iwcw.getUser().globalId !== -1) - _ymap.set("jabberId", _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]); - }); - } - - this.getYMap = function () { - return _ymap; - }; - - /** - * Type of node - * @type {string} - * @private - */ - var _type = type; - - /** - * Label of edge - * @type {canvas_widget.SingleValueAttribute} - * @private - */ - var _label = new SingleValueAttribute(id + "[label]", "Label", this, y); - - /** - * Appearance information of edge - * @type {{left: number, top: number, width: number, height: number}} - * @private - */ - var _appearance = { - left: left, - top: top, - width: width, - height: height, - containment: containment, - }; - - /** - * Position of node on z-axis - * @type {number} - * @private - */ - var _zIndex = zIndex; - - /** - * Type of node - * @containment {boolean} - * @private - */ - var _containment = containment; - - /** - * Canvas the node is drawn on - * @type {canvas_widget.AbstractCanvas} - * @private - */ - var _canvas = null; - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(abstractNodeHtml)({ id: id })); - this._$node = _$node; - const resizeHandle = $( - `
                          ` - ); - resizeHandle.css({ - position: "absolute", - bottom: "0", - right: "0", - cursor: "nwse-resize", - zIndex: 100000, - }); - - // append to node - _$node.append(resizeHandle); - resizeHandle.on("mouseover", () => { - this.disableDraggable(); - }); - resizeHandle.on("mouseout", () => { - this.enableDraggable(); - }); - - this.nodeSelector = getQuerySelectorFromNode(this._$node[0]); - - // this is the node's awareness trace. - // If I understand correctly, it is showing the activity of other users on the node. - var _$awarenessTrace = $( - lodash.template(awarenessTraceHtml)({ id: id + "_awareness" }) - ); - - var _awarenessTimer = setInterval(function () { - var opacity = _$awarenessTrace.css("opacity"); - opacity -= 0.1; - if (opacity < 0) opacity = 0; - _$awarenessTrace.css({ - opacity: opacity, - }); - }, 3000); - - this._$node.on("mousedown", function (e) { - _canvas.select(that); - _canvas.unbindMoveToolEvents(); - }); - - this._$node.on("mouseup", function (e) { - _canvas.bindMoveToolEvents(); - }); - - /** - * Attributes of node - * @type {Object} - * @private - */ - var _attributes = {}; - - /** - * Callback to generate list of context menu items - * @type {function} - */ - var _contextMenuItemCallback = function () { - return {}; - }; - - /** - * Set of ingoing edges - * @type {Object} - * @private - */ - var _ingoingEdges = {}; - - /** - * Set of outgoing edges - * @type {Object} - * @private - */ - var _outgoingEdges = {}; - - /** - * Set of nodes with an edge to the node - * @type {Object} - * @private - */ - var _ingoingNeighbors = {}; - - /** - * Set of nodes with an edge from the node - * @type {Object} - * @private - */ - var _outgoingNeighbors = {}; - - var _relatedGhostEdges = []; - - /** - * Apply a Node Move Operation - * @param {operations.ot.NodeMoveOperation} operation - */ - var processNodeMoveOperation = function (operation) { - _canvas.hideGuidanceBox(); - that.move(operation.getOffsetX(), operation.getOffsetY(), 0); - _canvas.showGuidanceBox(); - }; - - /** - * Apply a Node Move Z Operation - * @param {operations.ot.NodeMoveZOperation} operation - */ - var processNodeMoveZOperation = function (operation) { - that.move(0, 0, operation.getOffsetZ()); - }; - - /** - * Propagate a Node Move Operation to the remote users and the local widgets - * @param {operations.ot.NodeMoveOperation} operation - */ - this.propagateNodeMoveOperation = function (operation) { - operation.setJabberId(_iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]); - processNodeMoveOperation(operation); - HistoryManagerInstance.add(operation); - EntityManagerInstance.storeDataYjs(); - - hideTraceAwareness(); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.ATTRIBUTE, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.HEATMAP, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.getOTOperation() - ); - const activityMap = y.getMap("activity"); - activityMap.set( - ActivityOperation.TYPE, - new ActivityOperation( - "NodeMoveActivity", - operation.getEntityId(), - operation.getJabberId(), - NodeMoveOperation.getOperationDescription( - that.getType(), - that.getLabel().getValue().getValue() - ), - { nodeType: that.getType() } - ).toJSON() - ); - - if (_ymap) { - _ymap.set(NodeMoveOperation.TYPE, operation.toJSON()); - } - }; - - /** - * Propagate a Node Move Z Operation to the remote users and the local widgets - * @param {operations.ot.NodeMoveZOperation} operation - */ - this.propagateNodeMoveZOperation = function (operation) { - var jabberId = _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]; - operation.setJabberId(jabberId); - processNodeMoveZOperation(operation); - HistoryManagerInstance.add(operation); - hideTraceAwareness(); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.ATTRIBUTE, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.getOTOperation() - ); - const activityMap = y.getMap("activity"); - activityMap.set( - ActivityOperation.TYPE, - new ActivityOperation( - "NodeMoveActivity", - operation.getEntityId(), - jabberId, - NodeMoveOperation.getOperationDescription( - that.getType(), - that.getLabel().getValue().getValue() - ), - { nodeType: that.getType() } - ).toJSON() - ); - - if (_ymap) _ymap.set(NodeMoveZOperation.TYPE, operation.toJSON()); - }; - - /** - * Apply a Node Resize Operation - * @param {operations.ot.NodeResizeOperation} operation - */ - var processNodeResizeOperation = function (operation) { - _canvas.hideGuidanceBox(); - that.resize(operation.getOffsetX(), operation.getOffsetY()); - _canvas.showGuidanceBox(); - }; - - /** - * Propagate a Node Resize Operation to the remote users and the local widgets - * @param {operations.ot.NodeResizeOperation} operation - */ - this.propagateNodeResizeOperation = function (operation) { - operation.setJabberId(_iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]); - processNodeResizeOperation(operation); - HistoryManagerInstance.add(operation); - EntityManagerInstance.storeDataYjs(); - hideTraceAwareness(); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.ATTRIBUTE, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.HEATMAP, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.getOTOperation() - ); - const activityMap = y.getMap("activity"); - activityMap.set( - ActivityOperation.TYPE, - new ActivityOperation( - "NodeResizeActivity", - operation.getEntityId(), - operation.getJabberId(), - NodeResizeOperation.getOperationDescription( - that.getType(), - that.getLabel().getValue().getValue() - ), - { nodeType: that.getType() } - ).toJSON() - ); - - if (_ymap) _ymap.set("NodeResizeOperation", operation.toJSON()); - }; - - /** - * Apply a Node Delete Operation - * @param {operations.ot.NodeDeleteOperation} operation - */ - var processNodeDeleteOperation = function (operation) { - var edges = that.getEdges(), - edgeId, - edge; - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - edge.remove(); - } - } - - for (var i = 0; i < _relatedGhostEdges.length; i++) { - if (typeof _relatedGhostEdges[i].remove == "function") - _relatedGhostEdges[i].remove(); - } - if (_ymap) { - _ymap = null; - } - that.remove(); - }; - - /** - * Propagate a Node Delete Operation to the remote users and the local widgets - * @param {operations.ot.NodeDeleteOperation} operation - */ - var propagateNodeDeleteOperation = function (operation) { - processNodeDeleteOperation(); - EntityManagerInstance.storeDataYjs(); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.ATTRIBUTE, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.HEATMAP, - operation.getOTOperation() - ); - const activityMap = y.getMap("activity"); - activityMap.set( - ActivityOperation.TYPE, - new ActivityOperation( - "NodeDeleteActivity", - operation.getEntityId(), - _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], - NodeDeleteOperation.getOperationDescription( - that.getType(), - that.getLabel().getValue().getValue() - ), - {} - ).toJSON() - ); - }; - - var refreshTraceAwareness = function (color) { - _$awarenessTrace.css({ - opacity: 1, - fill: color, - }); - }; - - var hideTraceAwareness = function () { - _$awarenessTrace.css({ - opacity: 0, - }); - }; - - /** - * Callback for a remote Node Move Operation - * @param {operations.ot.NodeMoveOperation} operation - */ - var remoteNodeMoveCallback = function (operation) { - if ( - operation instanceof NodeMoveOperation && - operation.getEntityId() === that.getEntityId() - ) { - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.ATTRIBUTE, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.HEATMAP, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.getOTOperation() - ); - const userMap = y.getMap("users"); - if (userMap.get(y.clientID) !== operation.getJabberId()) { - const userList = y.getMap("userList"); - var color = Util.getColor( - userList.get(operation.getJabberId()).globalId - ); - refreshTraceAwareness(color); - } - - processNodeMoveOperation(operation); - } - }; - - /** - * Callback for a remote Node Move Z Operation - * @param {operations.ot.NodeMoveZOperation} operation - */ - var remoteNodeMoveZCallback = function (operation) { - if ( - operation instanceof NodeMoveZOperation && - operation.getEntityId() === that.getEntityId() - ) { - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.ATTRIBUTE, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.getOTOperation() - ); - const userMap = y.getMap("users"); - if (userMap.get(y.clientID) !== operation.getJabberId()) { - const userList = y.getMap("userList"); - var color = Util.getColor( - userList.get(operation.getJabberId()).globalId - ); - refreshTraceAwareness(color); - } - processNodeMoveZOperation(operation); - } - }; - - /** - * Callback for a remote Node Resize Operation - * @param {operations.ot.NodeResizeOperation} operation - */ - var remoteNodeResizeCallback = function (operation) { - if ( - operation instanceof NodeResizeOperation && - operation.getEntityId() === that.getEntityId() - ) { - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.ATTRIBUTE, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.HEATMAP, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.getOTOperation() - ); - const userMap = y.getMap("users"); - if (userMap.get(y.clientID) !== operation.getJabberId()) { - const userList = y.getMap("userList"); - var color = Util.getColor( - userList.get(operation.getJabberId()).globalId - ); - refreshTraceAwareness(color); - } - processNodeResizeOperation(operation); - } - }; - - /** - * Callback for a remote Node Delete Operation - * @param {operations.ot.NodeDeleteOperation} operation - */ - this.remoteNodeDeleteCallback = function (operation) { - if ( - operation instanceof NodeDeleteOperation && - operation.getEntityId() === that.getEntityId() - ) { - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.ATTRIBUTE, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.getOTOperation() - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.HEATMAP, - operation.getOTOperation() - ); - processNodeDeleteOperation(); - HistoryManagerInstance.clean(operation.getEntityId()); - } - }; - - this.init = function () { - //Define Node Rightclick Menu - $.contextMenu({ - selector: "#" + id, - zIndex: AbstractEntity.CONTEXT_MENU_Z_INDEX, - build: function ($trigger, e) { - var menuItems; - var EntityManager = EntityManagerInstance; - - $(e.target).offset(); - that.getCanvas().get$node().offset(); - - if ( - _canvas.getSelectedEntity() === null || - _canvas.getSelectedEntity() === that - ) { - menuItems = lodash.extend(_contextMenuItemCallback(), { - connectTo: EntityManager.generateConnectToMenu(that), - sepMove: "---------", - moveToForeground: { - name: "Move to Foreground", - callback: function (/*key, opt*/) { - that.propagateNodeMoveZOperation( - new NodeMoveZOperation( - that.getEntityId(), - ++AbstractEntity.maxZIndex - _zIndex - ) - ); - }, - }, - moveToBackground: { - name: "Move to Background", - callback: function (/*key, opt*/) { - that.propagateNodeMoveZOperation( - new NodeMoveZOperation( - that.getEntityId(), - --AbstractEntity.minZIndex - _zIndex - ) - ); - }, - }, - sepDelete: "---------", - delete: { - name: "Delete", - callback: function (/*key, opt*/) { - that.triggerDeletion(); - }, - }, - quit: { - name: " ", - disabled: true, - }, - }); - - return { - items: menuItems, - events: { - show: function (/*opt*/) { - _canvas.select(that); - }, - }, - }; - } else { - _canvas.select(null); - return false; - } - }, - }); - }; - - /** - * Triggers jsPlumb's repaint function and adjusts the angle of the edge labels - */ - - /** - * Anchor options for new connections - * @type {object} - */ - var _anchorOptions = AnchorLocations.AutoDefault; - - /** - * Get options for new connections - * @returns {Object} - */ - this.getAnchorOptions = function () { - return _anchorOptions; - }; - - /** - * Send NodeDeleteOperation for node - */ - this.triggerDeletion = function (historyFlag) { - var edgeId, - edges = this.getEdges(), - edge; - _canvas.select(null); - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - edge.triggerDeletion(); - } - } - var operation = new NodeDeleteOperation( - id, - that.getType(), - _appearance.left, - _appearance.top, - _appearance.width, - _appearance.height, - _zIndex, - _appearance.containment, - that.toJSON() - ); - if (_ymap) { - propagateNodeDeleteOperation(operation); - const nodesMap = y.getMap("nodes"); - nodesMap.delete(that.getEntityId()); - } else { - propagateNodeDeleteOperation(operation); - } - if (!historyFlag) HistoryManagerInstance.add(operation); - }; - - //noinspection JSUnusedGlobalSymbols - /** - * Get callback to generate list of context menu items - * @returns {object} - */ - this.getContextMenuItemCallback = function () { - return _contextMenuItemCallback; - }; - - /** - * Set callback to generate list of context menu items - * @param {function} contextMenuItemCallback - */ - this.setContextMenuItemCallback = function (contextMenuItemCallback) { - if (typeof contextMenuItemCallback === "function") { - _contextMenuItemCallback = contextMenuItemCallback; - } - }; - - /** - * Get node appearance - * @returns {{left: number, top: number, width: number, height: number}} - */ - this.getAppearance = function () { - return _appearance; - }; - - /** - * Get position of node on z-axis - * @return {number} - */ - this.getZIndex = function () { - return _zIndex; - }; - - this.refreshTraceAwareness = function (color) { - refreshTraceAwareness(color); - }; - - /** - * Adds node to canvas - * @param {canvas_widget.AbstractCanvas} canvas - */ - this.addToCanvas = function (canvas) { - if (!canvas) throw new Error("Canvas is null"); - _canvas = canvas; - canvas.get$canvas().append(_$awarenessTrace); - canvas.get$canvas().append(this._$node); - }; - - /** - * Get associated canvas - * @returns {canvas_widget.AbstractCanvas} - */ - this.getCanvas = function () { - return _canvas; - }; - - /** - * Removes node from canvas - */ - this.removeFromCanvas = function () { - this._$node.remove(); - //destroy the context menu - $.contextMenu("destroy", "#" + that.getEntityId()); - _canvas = null; - _$awarenessTrace.remove(); - if (this.hasOwnProperty("unregisterCallbacks")) - this.unregisterCallbacks(); - }; - - /** - * Add attribute to node - * @param {canvas_widget.AbstractAttribute} attribute - */ - this.addAttribute = function (attribute) { - var id = attribute.getEntityId(); - if (!_attributes.hasOwnProperty(id)) { - _attributes[id] = attribute; - } - }; - - /** - * Get attribute by id - * @param {String} id Attribute's entity id - * @returns {canvas_widget.AbstractAttribute} - */ - this.getAttribute = function (id) { - if (_attributes.hasOwnProperty(id)) { - return _attributes[id]; - } - return null; - }; - - /** - * Delete attribute by id - * @param {String} id Attribute's entity id - */ - this.deleteAttribute = function (id) { - if (_attributes.hasOwnProperty(id)) { - delete _attributes[id]; - } - }; - - /** - * Set node's attributes - * @param {Object} attributes - */ - this.setAttributes = function (attributes) { - _attributes = attributes; - }; - - /** - * Get node's attributes - * @returns {Object} - */ - this.getAttributes = function () { - return _attributes; - }; - - /** - * Set edge label - * @param {canvas_widget.SingleValueAttribute} label - */ - this.setLabel = function (label) { - _label = label; - }; - - /** - * Get edge label - * @returns {canvas_widget.SingleValueAttribute} - */ - this.getLabel = function () { - return _label; - }; - - /** - * Get edge type - * @returns {string} - */ - this.getType = function () { - return _type; - }; - - /** - * Get edge type - * @returns {boolean} - */ - this.getContainment = function () { - return _containment; - }; - - /** - * Get jQuery object of DOM node representing the node - * @returns {jQuery} - * @private - */ - this._get$node = function () { - return this._$node; - }; - - /** - * Apply position and dimension attributes to the node - * @private - */ - this._draw = function () { - //noinspection JSAccessibilityCheck - _$awarenessTrace.css({ - left: _appearance.left + _appearance.width / 2, - top: _appearance.top + _appearance.height / 2, - width: _appearance.width * 1.2, - height: _appearance.height * 1.2, - zIndex: _zIndex - 1, - }); - this._$node.css({ - left: _appearance.left, - top: _appearance.top, - width: _appearance.width, - height: _appearance.height, - zIndex: _zIndex, - }); - }; - - /** - * Move the node - * @param {number} offsetX Offset in x-direction - * @param {number} offsetY Offset in y-direction - * @param {number} offsetZ Offset in z-direction - */ - this.move = function (offsetX, offsetY, offsetZ) { - const x = _appearance.left + offsetX; - const y = _appearance.top + offsetY; - if ( - x < 0 || - y < 0 || - x > _canvas.width - _appearance.width || - y > _canvas.height - _appearance.height - ) { - // reset the position - _$node.css({ - left: _appearance.left, - top: _appearance.top, - }); - console.error("Node cannot be moved outside of canvas"); - if (_ymap) { - window.y.transact(() => { - _ymap.set("left", _appearance.left); - _ymap.set("top", _appearance.top); - _ymap.set("zIndex", _zIndex); - }); - } - } else { - if (_ymap) { - window.y.transact(() => { - _ymap.set("left", (_appearance.left += offsetX)); - _ymap.set("top", (_appearance.top += offsetY)); - _ymap.set("zIndex", _zIndex); - }); - } - } - this._draw(); - this.repaint(); - }; - - this.moveAbs = function (left, top, zIndex) { - if (left < 0 || top < 0) { - console.error("Node cannot be moved outside of canvas"); - } - if ( - left > _canvas.width - _appearance.width || - top > _canvas.height - _appearance.height - ) { - console.error("Node cannot be moved outside of canvas"); - } - _appearance.left = left; - _appearance.top = top; - - if (zIndex) _zIndex = zIndex; - - if (_ymap) { - y.transact(() => { - _ymap.set("left", _appearance.left); - _ymap.set("top", _appearance.top); - if (zIndex) _ymap.set("zIndex", _zIndex); - }); - } - this._draw(); - this.repaint(); - }; - - /** - * Resize the node - * @param {number} offsetX Offset in x-direction - * @param {number} offsetY Offset in y-direction - */ - this.resize = function (offsetX, offsetY) { - _appearance.width += offsetX; - _appearance.height += offsetY; - if (_ymap) { - y.transact(() => { - _ymap.set("width", _appearance.width); - _ymap.set("height", _appearance.height); - }); - } - this._draw(); - this.repaint(); - }; - - /** - * Add ingoing edge - * @param {canvas_widget.AbstractEdge} edge - */ - this.addIngoingEdge = function (edge) { - var id = edge.getEntityId(); - var source = edge.getSource(); - var sourceEntityId = source.getEntityId(); - if (!_ingoingEdges.hasOwnProperty(id)) { - _ingoingEdges[id] = edge; - if (!_ingoingNeighbors.hasOwnProperty(sourceEntityId)) { - _ingoingNeighbors[sourceEntityId] = source; - } - } - }; - - /** - * Add outgoing edge - * @param {canvas_widget.AbstractEdge} edge - */ - this.addOutgoingEdge = function (edge) { - var id = edge.getEntityId(); - var target = edge.getTarget(); - var targetEntityId = target?.getEntityId(); - if (!_outgoingEdges.hasOwnProperty(id)) { - _outgoingEdges[id] = edge; - if (!_outgoingNeighbors.hasOwnProperty(targetEntityId)) { - _outgoingNeighbors[targetEntityId] = target; - } - } - }; - - /** - * Delete ingoing edge - * @param {canvas_widget.AbstractEdge} edge - */ - this.deleteIngoingEdge = function (edge) { - var id = edge.getEntityId(); - var source = edge.getSource(); - var sourceEntityId = source.getEntityId(); - var isMultiEdge = false; - if (_ingoingEdges.hasOwnProperty(id)) { - delete _ingoingEdges[id]; - for (var edgeId in _ingoingEdges) { - if ( - _ingoingEdges.hasOwnProperty(edgeId) && - _ingoingEdges[edgeId].getSource().getEntityId() === sourceEntityId - ) { - isMultiEdge = true; - } - } - if (!isMultiEdge) { - delete _ingoingNeighbors[sourceEntityId]; - } - } - }; - - /** - * Delete outgoing edge - * @param {canvas_widget.AbstractEdge} edge - */ - this.deleteOutgoingEdge = function (edge) { - var id = edge.getEntityId(); - var target = edge.getTarget(); - var targetEntityId = target?.getEntityId(); - var isMultiEdge = false; - if (_outgoingEdges.hasOwnProperty(id)) { - delete _outgoingEdges[id]; - for (var edgeId in _outgoingEdges) { - if ( - _outgoingEdges.hasOwnProperty(edgeId) && - _outgoingEdges[edgeId].getTarget().getEntityId() === targetEntityId - ) { - isMultiEdge = true; - } - } - if (!isMultiEdge) { - delete _outgoingNeighbors[targetEntityId]; - } - } - }; - - //noinspection JSUnusedGlobalSymbols - /** - * Get ingoing edges - * @returns {Object} - */ - this.getIngoingEdges = function () { - return _ingoingEdges; - }; - - /** - * Get outgoing edges - * @returns {Object} - */ - this.getOutgoingEdges = function () { - return _outgoingEdges; - }; - - /** - * Get all ingoing and outgoing edges - * @returns {Array} - */ - this.getEdges = function () { - return Util.union(_ingoingEdges, _outgoingEdges); - }; - - //noinspection JSUnusedGlobalSymbols - /** - * Get neighbors with an edge to the node - * @returns {Object} - */ - this.getIngoingNeighbors = function () { - return _ingoingNeighbors; - }; - - //noinspection JSUnusedGlobalSymbols - /** - * Get neighbors with an edge from the node - * @returns {Object} - */ - this.getOutgoingNeighbors = function () { - return _outgoingNeighbors; - }; - - //noinspection JSUnusedGlobalSymbols - /** - * Get neighbors with an edge to or from the node - * @returns {Object} - */ - this.getNeighbors = function () { - return Util.union(_ingoingNeighbors, _outgoingNeighbors); - }; - - /** - * Lowlight the node - */ - this.lowlight = function () { - this._$node.addClass("lowlighted"); - }; - - /** - * Unlowlight the node - */ - this.unlowlight = function () { - this._$node.removeClass("lowlighted"); - }; - - /** - * Select the node - */ - this.select = function () { - this.unhighlight(); - this._$node.addClass("selected"); - Util.delay(100).then(function () { - lodash.each(EntityManagerInstance.getEdges(), function (e) { - e.setZIndex(); - }); - }); - }; - - /** - * Unselect the node - */ - this.unselect = function () { - //this.highlight(_highlightColor,_highlightUsername); - this._$node.removeClass("selected"); - //trigger save when unselecting an entity - EntityManagerInstance.storeDataYjs(); - - Util.delay(100).then(function () { - lodash.each(EntityManagerInstance.getEdges(), function (e) { - e.setZIndex(); - }); - }); - }; - - /** - * Highlight the node by assigning it the passed color and label it with the passed username - * @param {String} color - * @param {String} username - */ - this.highlight = function (color, username) { - if (color && username) { - this._$node.css({ border: "2px solid " + color }); - this._$node.append( - $("
                          ") - .addClass("user_highlight") - .css("color", color) - .text(username) - ); - Util.delay(100).then(function () { - lodash.each(EntityManagerInstance.getEdges(), function (e) { - e.setZIndex(); - }); - }); - } - }; - - /** - * Unhighlight the node - */ - this.unhighlight = function () { - this._$node.css({ border: "" }); - this._$node.find(".user_highlight").remove(); - Util.delay(100).then(function () { - lodash.each(EntityManagerInstance.getEdges(), function (e) { - e.setZIndex(); - }); - }); - }; - - /** - * Remove the node - */ - this.remove = function () { - clearInterval(_awarenessTimer); - this.removeFromCanvas(); - jsPlumbInstance.removeAllEndpoints(_$node.get(0)); - jsPlumbInstance.unmanage(_$node.get(0)); - EntityManagerInstance.deleteNode(this.getEntityId()); - }; - - /** - * Get JSON representation of the node - * @returns {Object} - * @private - */ - this._toJSON = function () { - var attr = {}; - lodash.forEach(this.getAttributes(), function (val, key) { - attr[key] = val.toJSON(); - }); - //noinspection JSAccessibilityCheck - return { - label: _label.toJSON(), - left: _appearance.left, - top: _appearance.top, - width: _appearance.width, - height: _appearance.height, - zIndex: _zIndex, - type: _type, - attributes: attr, - }; - }; - - this.addGhostEdge = function (ghostEdge) { - _relatedGhostEdges.push(ghostEdge); - }; - - /** - * Bind events for move tool - */ - this.bindMoveToolEvents = () => { - this.enableDraggable(); - var originalPos = { - left: 0, - top: 0, - }; - - var $sizePreview = $('
                          ').hide(); - - this.makeResizable(that, _canvas, $sizePreview, id); - - this._$node - //Enable Node Rightclick menu - .contextMenu(true) - .find("input") - .prop("disabled", false) - .css("pointerEvents", ""); - - this.jsPlumbManagedElement = jsPlumbInstance.manage(this._$node.get(0)); - - jsPlumbInstance.bind(EVENT_DRAG_START, (params) => { - if (params.el.id !== this._$node.attr("id")) return true; - - originalPos.top = params.el.offsetTop; - originalPos.left = params.el.offsetLeft; - - _canvas.hideGuidanceBox(); - _$node.css({ opacity: 0.5 }); - - return true; - }); - - jsPlumbInstance.bind(EVENT_DRAG_STOP, (params) => { - if (params.el.id !== this._$node.attr("id")) return true; - - _$node.css({ opacity: "" }); - _canvas.bindMoveToolEvents(); - var offsetX = Math.round(params.el.offsetLeft - originalPos.left); - var offsetY = Math.round(params.el.offsetTop - originalPos.top); - // if offset is 0, no need to send the operation - if (offsetX === 0 && offsetY === 0) return; - // if offset bigger than canvas size, no need to send the operation - if ( - params.el.offsetLeft < 0 || - params.el.offsetTop < 0 || - params.el.offsetLeft > _canvas.width || - params.el.offsetTop > _canvas.height - ) { - console.error(" offset bigger than canvas size"); - return; - } - - var operation = new NodeMoveOperation( - that.getEntityId(), - offsetX, - offsetY - ); - that.propagateNodeMoveOperation(operation); - - //Avoid node selection on drag stop - _canvas.showGuidanceBox(); - }); - - // view_only is used by the CAE and allows to show a model in the Canvas which is not editable - // therefore, the nodes should not be draggable and their context menu should be disabled - const widgetConfigMap = y.getMap("widgetConfig"); - var viewOnly = widgetConfigMap.get("view_only"); - if (viewOnly) { - this.disableDraggable(); - _$node.on("click").contextMenu(false); - } - }; - - /** - * Unbind events for move tool - */ - this.unbindMoveToolEvents = () => { - //Disable Node Selection - // called for e.g. if we want to draw an edge - this._$node - .off("click") - .contextMenu(false) - .find("input") - .prop("disabled", true) - .css("pointerEvents", "none"); - - //Disable Node Dragging - this.disableDraggable(); - }; - - /** - * Bind source node events for edge tool - */ - this.makeSource = () => { - _$node.addClass("source"); - this.endPoint = window.jsPlumbInstance.addEndpoint(this._$node.get(0), { - connectorPaintStyle: { fill: "black", strokeWidth: 4 }, - source: true, - endpoint: { - type: "Rectangle", - options: { - width: _$node.width() + 50, - height: _$node.height() + 50, - }, - }, - paintStyle: { fill: "transparent" }, - anchor: AnchorLocations.Center, - deleteOnEmpty: true, - //maxConnections:1, - uniqueEndpoint: false, - deleteEndpointsOnDetach: true, - onMaxConnections: function (info /*, originalEvent*/) { - console.log( - "element is ", - info.element, - "maxConnections is", - info.maxConnections - ); - }, - }); - }; - - /** - * Bind target node events for edge tool - */ - this.makeTarget = () => { - _$node.addClass("target"); - this.endPoint = window.jsPlumbInstance.addEndpoint(this._$node.get(0), { - target: true, - endpoint: { - type: "Rectangle", - options: { - width: _$node.width() + 50, - height: _$node.height() + 50, - }, - }, - paintStyle: { fill: "transparent" }, - anchor: AnchorLocations.Center, - uniqueEndpoint: false, - //maxConnections:1, - deleteOnEmpty: true, - onMaxConnections: function (info /*, originalEvent*/) { - console.log( - "user tried to drop connection", - info.connection, - "on element", - info.element, - "with max connections", - info.maxConnections - ); - }, - }); - }; - - /** - * Unbind events for edge tool - */ - this.unbindEdgeToolEvents = function () { - try { - _$node.removeClass("source target"); - jsPlumbInstance.getEndpoints(_$node.get(0)).forEach((endpoint) => { - // We need to remove the endpoint that was created to enable node connection by dragging - // since we are not using the edge tool anymore - if (endpoint.connections.length === 0) { - jsPlumbInstance.deleteEndpoint(endpoint); - } - }); - } catch (error) { - console.error(error); - } - }; - - that.init(); - - this._registerYMap = function () { - _ymap.observe(function (event) { - const array = Array.from(event.changes.keys.entries()); - array.forEach(([key, change]) => { - if (event.value && event.value.historyFlag) { - var operation; - var data = event.value; - const userMap = y.getMap("users"); - var jabberId = userMap.get(yUserId); - switch (key) { - case NodeMoveOperation.TYPE: { - operation = new NodeMoveOperation( - data.id, - data.offsetX, - data.offsetY, - jabberId - ); - remoteNodeMoveCallback(operation); - break; - } - case NodeMoveZOperation.TYPE: { - operation = new NodeMoveZOperation( - data.id, - data.offsetZ, - jabberId - ); - remoteNodeMoveZCallback(operation); - break; - } - case NodeResizeOperation.TYPE: { - operation = new NodeResizeOperation( - data.id, - data.offsetX, - data.offsetY, - jabberId - ); - remoteNodeResizeCallback(operation); - break; - } - } - } - }); - }); - }; - - jsPlumbInstance.manage(this._$node.get(0)); - EntityManagerInstance.storeDataYjs(); - } - nodeSelector; - jsPlumbManagedElement; - endPoint; - - repaint() { - window.jsPlumbInstance.repaint(this._$node.get(0)); - - lodash.each(EntityManagerInstance.getEdges(), function (e) { - e.setZIndex(); - }); - } - - enableDraggable() { - jsPlumbInstance.setDraggable(this._$node.get(0), true); - } - - disableDraggable() { - jsPlumbInstance.setDraggable(this._$node.get(0), false); - } - - makeResizable(that, _canvas, $sizePreview, id) { - const initialSize = { - width: that._$node.width(), - height: that._$node.height(), - }; - interact(that.nodeSelector) - .resizable({ - // resize from all edges and corners - edges: { right: ".bi", bottom: ".bi" }, - square: true, - listeners: { - move(event) { - that.disableDraggable(); - let { x, y } = event.target.dataset; - - x = (parseFloat(x) || 0) + event.deltaRect.left; - y = (parseFloat(y) || 0) + event.deltaRect.top; - - Object.assign(event.target.style, { - width: `${event.rect.width}px`, - height: `${event.rect.height}px`, - transform: `translate(${x}px, ${y}px)`, - }); - - Object.assign(event.target.dataset, { x, y }); - - event.rect.width = Math.max(50, event.rect.width); - event.rect.height = Math.max(50, event.rect.height); - - $sizePreview.text( - Math.round(event.rect.width) + - "\u00D7" + - Math.round(event.rect.height) - ); - // that.repaint(); - }, - }, - modifiers: [ - // keep the edges inside the parent - interact.modifiers.restrictEdges({ - outer: "parent", - }), - // minimum size - interact.modifiers.restrictSize({ - min: { width: 40, height: 40 }, - }), - ], - inertia: { enabled: false }, - }) - .on(["resizestart"], (event) => { - // add resizing class - that._$node.addClass("resizing"); - that.disableDraggable(); - _canvas.hideGuidanceBox(); - $sizePreview.show(); - that._$node.css({ opacity: 0.5 }); - that._$node.append($sizePreview); - initialSize.width = that._$node.width(); - initialSize.height = that._$node.height(); - _canvas.unbindMoveToolEvents(); - }) - .on(["resizeend"], (event) => { - // remove resizing class - that._$node.removeClass("resizing"); - that.enableDraggable(); - const offsetX = event.rect.width - initialSize.width; - const offsetY = event.rect.height - initialSize.height; - $sizePreview.hide(); - that._$node.css({ opacity: "" }); - that.repaint(); - var operation = new NodeResizeOperation(id, offsetX, offsetY); - that.propagateNodeResizeOperation(operation); - _canvas.bindMoveToolEvents(); - }) - .draggable(); - } - - disableResizable() { - interact(this.nodeSelector).unset(); - } - - /** - * Apply position and dimension attributes to the node - */ - draw() { - return this._draw(); - } - /** - * Get jQuery object of DOM node representing the node - * @returns {jQuery} - */ - get$node() { - return this._get$node(); - } - /** - * Get JSON representation of the node - * @returns {{label: Object, left: number, top: number, width: number, height: number, type: string, attributes: Object}} - */ - toJSON() { - return this._toJSON(); - } - /** - * hide the node and all associated edges - */ - hide() { - this.get$node().hide(); - window.jsPlumbInstance.hide(this.get$node()); - } - /** - * show the node and all associated edges - */ - show() { - this.get$node().show(); - window.jsPlumbInstance.show(this.get$node()[0]); - window.jsPlumbInstance.repaint(this.get$node()[0]); - } - registerYMap() { - this._registerYMap(); - } -} - -/** - * Abstract Class Node - * @class canvas_widget.EnumNode - * @extends canvas_widget.AbstractNode - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {number} zIndex Position of node on z-axis - */ -class EnumNode extends AbstractNode { - static TYPE = "Enumeration"; - static DEFAULT_WIDTH = 150; - static DEFAULT_HEIGHT = 100; - constructor(id, left, top, width, height, zIndex, json) { - super(id, EnumNode.TYPE, left, top, width, height, zIndex, json); - var that = this; - - /** - * jQuery object of node template - * @type {jQuery} - * @private - */ - var _$template = $(lodash.template(enumNodeHtml)({ type: that.getType() })); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = AbstractNode.prototype.get$node - .call(this) - .append(_$template) - .addClass("class"); - - /** - * jQuery object of DOM node representing the attributes - * @type {jQuery} - * @private - */ - var _$attributeNode = _$node.find(".attributes"); - - /** - * Attributes of node - * @type {Object} - * @private - */ - var _attributes = this.getAttributes(); - - /** - * Get JSON representation of the node - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractNode.prototype.toJSON.call(this); - json.type = EnumNode.TYPE; - return json; - }; - var attr = new SingleValueListAttribute("[attributes]", "Attributes", this); - this.addAttribute(attr); - - this.registerYMap = function () { - AbstractNode.prototype.registerYMap.call(this); - that.getLabel().getValue().registerYType(); - attr.registerYMap(); - }; - this.unregisterCallbacks = function () { - that.getAttribute("[attributes]").unregisterCallbacks(); - }; - this.registerYTextAttributes = function (map) { - map.get(that.getLabel().getValue().getEntityId()).then(function (ytext) { - that.getLabel().getValue().registerYType(ytext); - }); - }; - - _$node.find(".label").append(this.getLabel().get$node()); - - for (var attributeKey in _attributes) { - if (_attributes.hasOwnProperty(attributeKey)) { - _$attributeNode.append(_attributes[attributeKey].get$node()); - } - } - } -} - -/** - * Abstract Class Node - * @class canvas_widget.NodeShapeNode - * @extends canvas_widget.AbstractNode - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {number} zIndex Position of node on z-axis - * @param {boolean} containment containment - */ -class NodeShapeNode extends AbstractNode { - static TYPE = "Node Shape"; - static DEFAULT_WIDTH = 150; - static DEFAULT_HEIGHT = 150; - constructor(id, left, top, width, height, zIndex, containment, json) { - super( - id, - "Node Shape", - left, - top, - width, - height, - zIndex, - containment, - json - ); - var that = this; - - /** - * jQuery object of node template - * @type {jQuery} - * @private - */ - var _$template = $(lodash.template(nodeShapeNodeHtml)({ type: that.getType() })); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = AbstractNode.prototype.get$node - .call(this) - .append(_$template) - .addClass("class"); - - /** - * jQuery object of DOM node representing the attributes - * @type {jQuery} - * @private - */ - var _$attributeNode = _$node.find(".attributes"); - - /** - * Attributes of node - * @type {Object} - * @private - */ - var _attributes = this.getAttributes(); - - /** - * Get JSON representation of the node - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractNode.prototype.toJSON.call(this); - json.type = NodeShapeNode.TYPE; - return json; - }; - - var attrShapeSelect = new SingleSelectionAttribute( - this.getEntityId() + "[shape]", - "Shape", - this, - { - circle: "Circle", - diamond: "Diamond", - rectangle: "Rectangle", - rounded_rectangle: "Rounded Rectangle", - triangle: "Triangle", - } - ); - var attrWidth = new IntegerAttribute( - this.getEntityId() + "[defaultWidth]", - "Default Width", - this - ); - var attrHeight = new IntegerAttribute( - this.getEntityId() + "[defaultHeight]", - "Default Height", - this - ); - var attrColor = new SingleColorValueAttribute( - this.getEntityId() + "[color]", - "Color", - this - ); - var attrContaintment = new BooleanAttribute( - this.getEntityId() + "[containment]", - "Containment", - this - ); - var attrCustomShape = new SingleMultiLineValueAttribute( - this.getEntityId() + "[customShape]", - "Custom Shape", - this - ); - var attrAnchors = new SingleValueAttribute( - this.getEntityId() + "[customAnchors]", - "Custom Anchors", - this - ); - - this.addAttribute(attrShapeSelect); - this.addAttribute(attrColor); - this.addAttribute(attrWidth); - this.addAttribute(attrHeight); - this.addAttribute(attrContaintment); - this.addAttribute(attrCustomShape); - this.addAttribute(attrAnchors); - - _$node.find(".label").append(this.getLabel().get$node()); - - for (var attributeKey in _attributes) { - if (_attributes.hasOwnProperty(attributeKey)) { - _$attributeNode.append(_attributes[attributeKey].get$node()); - } - } - - this.registerYMap = function () { - AbstractNode.prototype.registerYMap.call(this); - attrShapeSelect.getValue().registerYType(); - attrWidth.getValue().registerYType(); - attrHeight.getValue().registerYType(); - attrContaintment.getValue().registerYType(); - that.getLabel().getValue().registerYType(); - attrColor.getValue().registerYType(); - attrAnchors.getValue().registerYType(); - attrCustomShape.getValue().registerYType(); - }; - } -} - -/** - * EntityManager - * @class canvas_widget.EntityManager - * @memberof canvas_widget - * @constructor - */ -let EntityManager$1 = class EntityManager { - y = null; - setSharedDocument(y) { - this.y = y; - } - _nodes; - _edges; - - constructor() { - /** - * the view id indicates if the EntityManager should use View types for modeling or node types - * @type {string} - * @private - */ - var _viewId = undefined; - - /** - * Model attributes node - * @type {canvas_widget.ModelAttributesNode} - * @private - */ - var _modelAttributesNode = null; - /** - * Nodes of the graph - * @type {{}} - * @private - */ - var _nodes = {}; - this._nodes = _nodes; - /** - * Edges of the graph - * @type {{}} - * @private - */ - var _edges = {}; - this._edges = _edges; - - var metamodel = null; - - var guidancemodel = null; - - //noinspection JSUnusedGlobalSymbols - return { - /** - * Create a new node - * @memberof canvas_widget.EntityManager# - * @param {string} type Type of node - * @param {string} id Entity identifier of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {number} zIndex Position of node on z-axis - * @param {object} json the json representation - * @returns {canvas_widget.AbstractNode} - */ - createNode: function ( - type, - id, - left, - top, - width, - height, - zIndex, - containment, - json, - y - ) { - var node; - AbstractEntity.maxZIndex = Math.max(AbstractEntity.maxZIndex, zIndex); - AbstractEntity.minZIndex = Math.min(AbstractEntity.minZIndex, zIndex); - - if (_viewId && viewNodeTypes.hasOwnProperty(type)) { - node = viewNodeTypes[type]( - id, - left, - top, - width, - height, - zIndex, - containment, - json, - y - ); - } else if (nodeTypes.hasOwnProperty(type)) { - node = new nodeTypes[type]( - id, - left, - top, - width, - height, - zIndex, - containment, - json, - y - ); - } - _nodes[id] = node; - - EntityManagerInstance.storeDataYjs(); - return node; - }, - findObjectNodeByLabel(searchLabel) { - const re = new RegExp(searchLabel, "gi"); - for (const [id, node] of Object.entries(_nodes)) { - const currentNode = y.getMap("nodes").get(id).toJSON(); - for (const [key, property] of Object.entries(currentNode)) { - if (key.match(id)) { - if (property.match(re)) { - return node; - } - } - } - } - return null; - }, - /** - * Create model Attributes node - * @returns {canvas_widget.ModelAttributesNode} - */ - createModelAttributesNode: function (y) { - if (_modelAttributesNode === null) { - if (metamodel) - _modelAttributesNode = new ModelAttributesNode( - "modelAttributes", - metamodel.attributes, - y - ); - else - _modelAttributesNode = new ModelAttributesNode( - "modelAttributes", - null, - y - ); - return _modelAttributesNode; - } - return _modelAttributesNode; - }, - /** - * Find nodeby attr - * @memberof attribute_widget.EntityManager# - * @param {string} name Entity name - * @returns {canvas_widget.AbstractNode} - */ - findNodeByAttribute: function (attr, name) { - for (const key in _nodes) { - const node = _nodes[key]; - if (node.getAttribute(attr) === name) { - return node; - } - } - }, - - /** - * Find node by id - * @memberof canvas_widget.EntityManager# - * @param {string} id Entity id - * @returns {canvas_widget.AbstractNode} - */ - findNode: function (id) { - if (_nodes.hasOwnProperty(id)) { - return _nodes[id]; - } - return null; - }, - /** - * Find node or edge by id - * @memberof attribute_widget.EntityManager# - * @param {string} id Entity id - * @returns {*} - */ - find: function (id) { - return this.findNode(id) || this.findEdge(id); - }, - /** - * Delete node by id - * @memberof canvas_widget.EntityManager# - * @param {string} id Entity id - */ - deleteNode: function (id) { - if (_nodes.hasOwnProperty(id)) { - delete _nodes[id]; - } - EntityManagerInstance.storeDataYjs(); - }, - /** - * Get all nodes - * @memberof canvas_widget.EntityManager# - * @returns {object} - */ - getNodes: function () { - return _nodes; - }, - /** - * Get nodes by type - * @memberof canvas_widget.EntityManager# - * @param {string|string[]} type Entity type - * @returns {object} - */ - getNodesByType: function (type) { - var nodeId, - node, - nodesByType = {}; - - if (typeof type === "string") { - type = [type]; - } - - for (nodeId in _nodes) { - if (_nodes.hasOwnProperty(nodeId)) { - node = _nodes[nodeId]; - if (type.indexOf(node.getType()) !== -1) { - nodesByType[nodeId] = node; - } - } - } - return nodesByType; - }, - /** - * Create a new edge - * @memberof canvas_widget.EntityManager# - * @param {string} type Type of edge - * @param {string} id Entity identifier of edge - * @param {canvas_widget.AbstractNode} source Source node - * @param {canvas_widget.AbstractNode} target Target node - * @returns {canvas_widget.AbstractEdge} - */ - //TODO: switch id and type - createEdge: function (type, id, source, target) { - var edge; - - if (_viewId && viewEdgeTypes.hasOwnProperty(type)) { - edge = viewEdgeTypes[type](id, source, target); - } else if (edgeTypes.hasOwnProperty(type)) { - edge = new edgeTypes[type](id, source, target); - } else { - return undefined; - } - source.addOutgoingEdge(edge); - target?.addIngoingEdge(edge); - _edges[id] = edge; - EntityManagerInstance.storeDataYjs(); - return edge; - }, - /** - * Find edge by id - * @memberof canvas_widget.EntityManager# - * @param {string} id Entity id - * @returns {*} - */ - findEdge: function (id) { - if (_edges.hasOwnProperty(id)) { - return _edges[id]; - } - return null; - }, - /** - * Delete edge by id - * @memberof canvas_widget.EntityManager# - * @param {string} id Entity id - */ - deleteEdge: function (id) { - if (_edges.hasOwnProperty(id)) { - delete _edges[id]; - } - EntityManagerInstance.storeDataYjs(); - }, - /** - * Get all edges - * @memberof canvas_widget.EntityManager# - * @returns {object} - */ - getEdges: function () { - return _edges; - }, - /** - * Get edges by type - * @memberof canvas_widget.EntityManager# - * @param {string} type Entity type - * @returns {object} - */ - getEdgesByType: function (type) { - var edgeId, - edge, - edgesByType = {}; - - for (edgeId in _edges) { - if (_edges.hasOwnProperty(edgeId)) { - edge = _edges[edgeId]; - if (edge.getType() === type) { - edgesByType[edgeId] = edge; - } - } - } - return edgesByType; - }, - /** - * Get JSON representation of whole graph - * @memberof canvas_widget.EntityManager# - * @returns {object} - */ - graphToJSON: function () { - var attributesJSON; - var nodesJSON = {}; - var edgesJSON = {}; - attributesJSON = _modelAttributesNode - ? _modelAttributesNode.toJSON() - : {}; - lodash.forEach(_nodes, function (val, key) { - nodesJSON[key] = val.toJSON(); - }); - lodash.forEach(_edges, function (val, key) { - edgesJSON[key] = val.toJSON(); - }); - return { - attributes: attributesJSON, - nodes: nodesJSON, - edges: edgesJSON, - }; - }, - /** - * Create model attributes node by its JSON representation - * @memberof canvas_widget.EntityManager# - * @param {object} json JSON representation - * @returns {canvas_widget.AbstractNode} - */ - createModelAttributesNodeFromJSON: function (json) { - var node = this.createModelAttributesNode(); - if (node) { - node.getLabel().getValue().setValue(json.label.value.value); - for (var attrId in json.attributes) { - if (json.attributes.hasOwnProperty(attrId)) { - var attr = node.getAttribute(attrId); - if (attr) { - attr.setValueFromJSON(json.attributes[attrId]); - } - } - } - } - return node; - }, - /** - * Create a new node by its JSON representation - * @memberof canvas_widget.EntityManager# - * @param {string} type Type of node - * @param {string} id Entity identifier of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {object} json JSON representation - * @param {number} zIndex Position of node on z-axis - * @returns {canvas_widget.AbstractNode} - */ - createNodeFromJSON: function ( - type, - id, - left, - top, - width, - height, - zIndex, - containment, - json, - y - ) { - var node = this.createNode( - type, - id, - left, - top, - width, - height, - zIndex, - containment, - json, - y - ); - if (node) { - node.getLabel().getValue().setValue(json.label.value.value); - for (var attrId in json.attributes) { - if (json.attributes.hasOwnProperty(attrId)) { - var attr = node.getAttribute(attrId); - if (attr) { - attr.setValueFromJSON(json.attributes[attrId]); - } else { - var newId = attrId.replace(/[^\[\]]*/, id); - attr = node.getAttribute(newId); - if (attr) { - attr.setValueFromJSON(json.attributes[attrId]); - } - } - } - } - } - return node; - }, - /** - * Create a new node by its JSON representation - * @memberof canvas_widget.EntityManager# - * @param {string} type Type of edge - * @param {string} id Entity identifier of edge - * @param {canvas_widget.AbstractNode} source Source node entity id - * @param {canvas_widget.AbstractNode} target Target node entity id - * @param {object} json JSON representation - * @returns {canvas_widget.AbstractEdge} - */ - createEdgeFromJSON: function (type, id, source, target, json) { - const sourceNode = this.findNode(source); - const targetNode = this.findNode(target); - var edge = this.createEdge(type, id, sourceNode, targetNode); - if (edge) { - edge.getLabel().getValue().setValue(json.label.value.value); - for (var attrId in json.attributes) { - if (json.attributes.hasOwnProperty(attrId)) { - var attr = edge.getAttribute(attrId); - if (attr) { - attr.setValueFromJSON(json.attributes[attrId]); - } - } - } - } - return edge; - }, - /** - * Generate the 'Add node..' context menu options - * @param canvas Canvas to add node to - * @param left Position of node on x-axis - * @param top Position of node on <-axis - * @returns {object} Menu items - */ - generateAddNodeMenu: function (canvas, left, top) { - function makeAddNodeCallback(nodeType, width, height, containment) { - return function () { - canvas.createNode( - nodeType, - left, - top, - width, - height, - 32000, - containment - ); - }; - } - var items = {}, - nodeType, - _nodeTypes; - - if (_viewId && _layer === CONFIG.LAYER.MODEL) { - _nodeTypes = viewNodeTypes; - } else { - _nodeTypes = nodeTypes; - } - - for (nodeType in _nodeTypes) { - if (_nodeTypes.hasOwnProperty(nodeType)) { - if ( - _layer === CONFIG.LAYER.META && - !_viewId && - (nodeType === "ViewObject" || nodeType === "ViewRelationship") - ) - continue; - if ( - _layer === CONFIG.LAYER.META && - _viewId && - (nodeType === "Object" || - nodeType === "Relationship" || - nodeType === "Enumeration" || - nodeType === "Abstract Class") - ) - continue; - - items[nodeType] = { - name: ".." + nodeType, - callback: makeAddNodeCallback( - nodeType, - _nodeTypes[nodeType].DEFAULT_WIDTH, - _nodeTypes[nodeType].DEFAULT_HEIGHT, - _nodeTypes[nodeType].CONTAINMENT - ), - }; - } - } - return items; - }, - /** - * generates the context menu for the show and hide operations on node types - * @returns {object} - */ - generateVisibilityNodeMenu: function (visibility) { - var _applyVisibilityCallback = function (nodeType, vis) { - return function () { - if (vis !== "show" && vis !== "hide") return; - - var nodes; - if (_viewId && _layer === CONFIG.LAYER.MODEL) { - nodes = that.getNodesByViewType(nodeType); - } else { - nodes = that.getNodesByType(nodeType); - } - for (var nKey in nodes) { - if (nodes.hasOwnProperty(nKey)) { - nodes[nKey][vis](); - } - } - if (vis === "hide") { - this.data("show" + nodeType + "Disabled", true); - } else { - this.data("show" + nodeType + "Disabled", false); - } - - return false; - }; - }; - - var that = this; - var items = {}, - nodeType, - _nodeTypes; - - if (_viewId && _layer === CONFIG.LAYER.MODEL) { - _nodeTypes = viewNodeTypes; - } else { - _nodeTypes = nodeTypes; - } - - for (nodeType in _nodeTypes) { - if (_nodeTypes.hasOwnProperty(nodeType)) { - if ( - _layer === CONFIG.LAYER.META && - !_viewId && - (nodeType === "ViewObject" || nodeType === "ViewRelationship") - ) - continue; - if ( - _layer === CONFIG.LAYER.META && - _viewId && - (nodeType === "Object" || - nodeType === "Relationship" || - nodeType === "Enumeration" || - nodeType === "Abstract Class") - ) - continue; - - items[visibility + nodeType] = { - name: ".." + nodeType, - callback: _applyVisibilityCallback(nodeType, visibility), - disabled: (function (nodeType) { - return function () { - if (visibility === "hide") - return this.data(visibility + nodeType + "Disabled"); - else return !this.data(visibility + nodeType + "Disabled"); - }; - })(nodeType), - }; - } - } - return items; - }, - /** - * generates a the context menu for the show and hide operations on edge types - * @returns {object} - */ - generateVisibilityEdgeMenu: function (visibility) { - function _applyVisibilityCallback(edgeType, vis) { - return function () { - if (vis !== "show" && vis !== "hide") return; - var edges; - if (_viewId && _layer === CONFIG.LAYER.MODEL) { - edges = that.getEdgesByViewType(edgeType); - } else { - edges = that.getEdgesByType(edgeType); - } - for (var eKey in edges) { - if (edges.hasOwnProperty(eKey)) { - edges[eKey][vis](); - } - } - if (vis === "hide") { - this.data("show" + edgeType + "Disabled", true); - } else { - this.data("show" + edgeType + "Disabled", false); - } - }; - } - var that = this; - var items = {}, - edgeType, - _edgeTypes; - - if (_viewId && _layer === CONFIG.LAYER.MODEL) { - _edgeTypes = viewEdgeTypes; - } else { - _edgeTypes = edgeTypes; - } - - for (edgeType in _edgeTypes) { - if (_edgeTypes.hasOwnProperty(edgeType)) { - items[visibility + edgeType] = { - name: ".." + edgeType, - callback: _applyVisibilityCallback(edgeType, visibility), - disabled: (function (edgeType) { - return function () { - if (visibility === "hide") - return this.data(visibility + edgeType + "Disabled"); - else return !this.data(visibility + edgeType + "Disabled"); - }; - })(edgeType), - }; - } - } - return items; - }, - /** - * Generate the 'Connect to..' context menu options for the passed node - * @param {canvas_widget.AbstractNode} node - */ - generateConnectToMenu: function (node) { - function makeTargetNodeCallback(connectionType, targetNodeId) { - return function (/*key, opt*/) { - node - .getCanvas() - .createEdge(connectionType, node.getEntityId(), targetNodeId); - }; - } - - var connectionType, - sourceNodeTypes, - targetNodeTypes, - targetNodeType, - connectionItems, - targetNodeTypeItems, - targetNodeItems, - i, - numOfRelations, - j, - numOfTargetTypes, - targetNodes, - targetNodeId, - targetNode, - targetAppearance, - sourceAppearance = node.getAppearance(); - - connectionItems = {}; - for (connectionType in relations) { - if (relations.hasOwnProperty(connectionType)) { - targetNodeTypeItems = {}; - for ( - i = 0, numOfRelations = relations[connectionType].length; - i < numOfRelations; - i++ - ) { - sourceNodeTypes = relations[connectionType][i].sourceTypes; - targetNodeTypes = relations[connectionType][i].targetTypes; - if ( - sourceNodeTypes.indexOf(node.getType()) !== -1 || - (_layer === CONFIG.LAYER.MODEL && - _viewId && - sourceNodeTypes.indexOf(node.getCurrentViewType()) !== -1) - ) { - for ( - j = 0, numOfTargetTypes = targetNodeTypes.length; - j < numOfTargetTypes; - j++ - ) { - targetNodeType = targetNodeTypes[j]; - targetNodeItems = {}; - if (_viewId && _layer === CONFIG.LAYER.MODEL) { - targetNodes = this.getNodesByViewType(targetNodeType); - } else { - targetNodes = this.getNodesByType(targetNodeType); - } - for (targetNodeId in targetNodes) { - if (targetNodes.hasOwnProperty(targetNodeId)) { - targetNode = targetNodes[targetNodeId]; - if (targetNode === node) continue; - if ( - _layer === CONFIG.LAYER.MODEL && - _viewId && - targetNode.getCurrentViewType() === null - ) - continue; - targetAppearance = targetNode.getAppearance(); - if ( - !targetNode - .getNeighbors() - .hasOwnProperty(node.getEntityId()) - ) { - targetNodeItems[ - connectionType + targetNodeType + i + targetNodeId - ] = { - name: - ".." + - (targetNode.getLabel().getValue().getValue() || - targetNode.getType()), - callback: makeTargetNodeCallback( - connectionType, - targetNodeId - ), - distanceSquare: - Math.pow( - targetAppearance.left - sourceAppearance.left, - 2 - ) + - Math.pow( - targetAppearance.top - sourceAppearance.top, - 2 - ), - targetNodeId: - connectionType + targetNodeType + i + targetNodeId, - }; - } - } - } - if (lodash.size(targetNodeItems) > 0) { - var targetNodeItemsTmp = lodash.sortBy( - targetNodeItems, - "distanceSquare" - ); - targetNodeItems = {}; - for ( - var k = 0, numOfItems = targetNodeItemsTmp.length; - k < numOfItems; - k++ - ) { - targetNodeItems[k + targetNodeItemsTmp[k].targetNodeId] = - targetNodeItemsTmp[k]; - } - targetNodeTypeItems[connectionType + targetNodeType + i] = { - name: "..to " + targetNodeType + "..", - items: targetNodeItems, - }; - } - } - } - } - if (lodash.size(targetNodeTypeItems) > 0) { - connectionItems[connectionType] = { - name: "..with " + connectionType + "..", - items: targetNodeTypeItems, - }; - } - } - } - - return { - name: "Connect..", - items: connectionItems, - disabled: (function (connectionItems) { - return lodash.size(connectionItems) === 0; - })(connectionItems), - }; - }, - generateGuidanceMetamodel: function () { - var metamodel = this.generateMetaModel(); - var actionNodeLabels = []; - var createEntityNodeLabels = []; - //Create guidance metamodel - var guidanceMetamodel = { - attributes: {}, - nodes: {}, - edges: {}, - }; - - //Create initial node - var initialNode = { - label: guidancemodel.INITIAL_NODE_LABEL, - shape: { - shape: "", - color: "", - defaultWidth: 200, - defaultHeight: 60, - containment: false, - customShape: startActivityNodeHtml, - customAnchors: "", - }, - attributes: {}, - }; - - //Add a label attribute to the initial node - initialNode.attributes[Util.generateRandomId()] = { - key: "label", - value: "string", - }; - - guidanceMetamodel.nodes[Util.generateRandomId()] = initialNode; - - //Create final node - var finalNode = { - label: guidancemodel.ACTIVITY_FINAL_NODE_LABEL, - shape: { - shape: "circle", - color: "", - defaultWidth: 50, - defaultHeight: 50, - containment: false, - customShape: activityFinalNodeHtml, - customAnchors: ["Perimeter", { shape: "Circle", anchorCount: 60 }], - }, - attributes: {}, - }; - - guidanceMetamodel.nodes[Util.generateRandomId()] = finalNode; - - //Create merge node - var mergeNode = { - label: guidancemodel.MERGE_NODE_LABEL, - shape: { - shape: "diamond", - color: "yellow", - defaultWidth: 0, - defaultHeight: 0, - containment: false, - customShape: "", - customAnchors: "", - }, - attributes: {}, - }; - - guidanceMetamodel.nodes[Util.generateRandomId()] = mergeNode; - - //Create 'call activity node' - var callActivityNode = { - label: guidancemodel.CALL_ACTIVITY_NODE_LABEL, - shape: { - shape: "rounded_rectangle", - color: "", - defaultWidth: 100, - defaultHeight: 50, - containment: false, - customShape: callActivityNodeHtml, - customAnchors: "", - }, - attributes: {}, - }; - - actionNodeLabels.push(guidancemodel.CALL_ACTIVITY_NODE_LABEL); - - //Add a label attribute to the call activity node - callActivityNode.attributes[Util.generateRandomId()] = { - key: "label", - value: "string", - }; - - guidanceMetamodel.nodes[Util.generateRandomId()] = callActivityNode; - - //Create concurrency node - var concurrencyNode = { - label: guidancemodel.CONCURRENCY_NODE_LABEL, - shape: { - shape: "rectangle", - color: "black", - defaultWidth: 10, - defaultHeight: 200, - containment: false, - customShape: "", - customAnchors: "", - }, - attributes: {}, - }; - - guidanceMetamodel.nodes[Util.generateRandomId()] = concurrencyNode; - - var flowEdgeRelations = []; - var dataFlowEdgeRelations = []; - - var nodes = metamodel.nodes; - for (var nodeId in nodes) { - if (nodes.hasOwnProperty(nodeId)) { - var node = nodes[nodeId]; - - var createObjectNodeToEntityNodeRelation = { - sourceTypes: [], - targetTypes: [], - }; - //Generate the 'create object node' - var label = guidancemodel.getCreateObjectNodeLabelForType( - node.label - ); - createObjectNodeToEntityNodeRelation.sourceTypes.push(label); - actionNodeLabels.push(label); - createEntityNodeLabels.push(label); - var id = Util.generateRandomId(); - guidanceMetamodel.nodes[id] = { - label: label, - attributes: {}, - shape: { - shape: "rounded_rectangle", - color: "", - defaultWidth: 100, - defaultHeight: 50, - containment: false, - customShape: lodash.template(actionNodeHtml)({ - label: node.label, - icon: "plus", - }), - customAnchors: "", - }, - }; - - //Generate the 'entity node' - var entityLabel = guidancemodel.getEntityNodeLabelForType( - node.label - ); - createObjectNodeToEntityNodeRelation.targetTypes.push(label); - id = Util.generateRandomId(); - guidanceMetamodel.nodes[id] = { - label: entityLabel, - attributes: {}, - shape: { - shape: "rectangle", - color: "", - defaultWidth: 100, - defaultHeight: 50, - containment: false, - customShape: lodash.template(entityNodeHtml)({ - icon: "square", - label: node.label, - }), - customAnchors: "", - }, - }; - - //Generate the 'set property node' - setPropertyLabel = guidancemodel.getSetPropertyNodeLabelForType( - node.label - ); - actionNodeLabels.push(setPropertyLabel); - id = Util.generateRandomId(); - guidanceMetamodel.nodes[id] = { - label: setPropertyLabel, - attributes: {}, - shape: { - shape: "", - defaultWidth: 130, - defaultHeight: 50, - containment: false, - customShape: lodash.template(setPropertyNodeHtml)(), - customAnchors: "", - }, - }; - - var options = {}; - for (var attributeId in node.attributes) { - var attribute = node.attributes[attributeId]; - options[attribute.key] = attribute.key; - } - - guidanceMetamodel.nodes[id].attributes[Util.generateRandomId()] = { - key: "Property", - value: "Value", - options: options, - }; - - //Define the 'create object node' to 'entity node' relation - dataFlowEdgeRelations.push({ - sourceTypes: [label], - targetTypes: [entityLabel], - }); - - //Define the 'entity node' to 'set property node' relation - dataFlowEdgeRelations.push({ - sourceTypes: [entityLabel], - targetTypes: [setPropertyLabel], - }); - - //Define the 'entity node' to 'create relationship node' relation - for (var edgeId in metamodel.edges) { - var edge = metamodel.edges[edgeId]; - for (var relationId in edge.relations) { - var relation = edge.relations[relationId]; - if ( - relation.sourceTypes.indexOf(node.label) > -1 || - relation.targetTypes.indexOf(node.label) > -1 - ) { - dataFlowEdgeRelations.push({ - sourceTypes: [entityLabel], - targetTypes: - guidancemodel.getCreateRelationshipNodeLabelForType( - edge.label - ), - }); - break; - } - } - } - } - } - var edgesByLabel = {}; - - var edges = metamodel.edges; - for (var edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - var edge = edges[edgeId]; - //Generate 'create relationship node' - var label = guidancemodel.getCreateRelationshipNodeLabelForType( - edge.label - ); - actionNodeLabels.push(label); - createEntityNodeLabels.push(label); - edgesByLabel[edge.label] = edge; - - var id = Util.generateRandomId(); - guidanceMetamodel.nodes[id] = { - label: label, - attributes: {}, - shape: { - shape: "rounded_rectangle", - color: "", - defaultWidth: 100, - defaultHeight: 50, - containment: false, - customShape: lodash.template(actionNodeHtml)({ - label: edge.label, - icon: "plus", - }), - customAnchors: "", - }, - }; - - //Generate 'entity node' - var entityLabel = guidancemodel.getEntityNodeLabelForType( - edge.label - ); - - var id = Util.generateRandomId(); - guidanceMetamodel.nodes[id] = { - label: entityLabel, - attributes: {}, - shape: { - shape: "rectangle", - color: "black", - defaultWidth: 100, - defaultHeight: 50, - containment: false, - customShape: lodash.template(entityNodeHtml)({ - icon: "exchange", - label: edge.label, - }), - customAnchors: "", - }, - }; - - //Generate the 'set property node' - if (Object.keys(edge.attributes).length > 0) { - var setPropertyLabel = - guidancemodel.getSetPropertyNodeLabelForType(edge.label); - actionNodeLabels.push(setPropertyLabel); - id = Util.generateRandomId(); - guidanceMetamodel.nodes[id] = { - label: setPropertyLabel, - attributes: {}, - shape: { - shape: "", - defaultWidth: 0, - defaultHeight: 0, - containment: false, - customShape: lodash.template(setPropertyNodeHtml)({ - type: setPropertyLabel, - color: "white", - }), - customAnchors: "", - }, - }; - - var options = {}; - for (var attributeId in edge.attributes) { - var attribute = edge.attributes[attributeId]; - options[attribute.key] = attribute.key; - } - - guidanceMetamodel.nodes[id].attributes[Util.generateRandomId()] = - { - key: "Property", - value: "Value", - options: options, - }; - } - - //Define the 'create relationship node' to 'entity node' relation - dataFlowEdgeRelations.push({ - sourceTypes: [label], - targetTypes: [entityLabel], - }); - - //Define the 'entity node' to 'set property node' relation - dataFlowEdgeRelations.push({ - sourceTypes: [entityLabel], - targetTypes: [setPropertyLabel], - }); - } - } - - //Create the flow edge - - //Relations between all action nodes - flowEdgeRelations = flowEdgeRelations.concat({ - sourceTypes: actionNodeLabels, - targetTypes: actionNodeLabels.concat([ - guidancemodel.MERGE_NODE_LABEL, - guidancemodel.ACTIVITY_FINAL_NODE_LABEL, - guidancemodel.CONCURRENCY_NODE_LABEL, - ]), - }); - - //Relations for the initial node - flowEdgeRelations = flowEdgeRelations.concat({ - sourceTypes: [guidancemodel.INITIAL_NODE_LABEL], - targetTypes: [ - guidancemodel.CALL_ACTIVITY_NODE_LABEL, - guidancemodel.MERGE_NODE_LABEL, - guidancemodel.CONCURRENCY_NODE_LABEL, - ].concat(createEntityNodeLabels), - }); - - //Relations for the merge node - flowEdgeRelations = flowEdgeRelations.concat({ - sourceTypes: [guidancemodel.MERGE_NODE_LABEL], - targetTypes: [ - guidancemodel.ACTIVITY_FINAL_NODE_LABEL, - guidancemodel.MERGE_NODE_LABEL, - guidancemodel.CONCURRENCY_NODE_LABEL, - ].concat(actionNodeLabels), - }); - - //Relations for the concurrency node - flowEdgeRelations = flowEdgeRelations.concat({ - sourceTypes: [guidancemodel.CONCURRENCY_NODE_LABEL], - targetTypes: [ - guidancemodel.ACTIVITY_FINAL_NODE_LABEL, - guidancemodel.CONCURRENCY_NODE_LABEL, - guidancemodel.MERGE_NODE_LABEL, - ].concat(actionNodeLabels), - }); - - //Create the action flow edge - guidanceMetamodel.edges[Util.generateRandomId()] = { - label: "Action flow edge", - shape: { - arrow: "unidirassociation", - shape: "curved", - color: "black", - overlay: "", - overlayPosition: "top", - overlayRotate: true, - }, - relations: flowEdgeRelations, - }; - - //Create the data flow edge - var dataFlowEdge = { - label: "Data flow edge", - shape: { - arrow: "unidirassociation", - shape: "curved", - color: "black", - overlay: "", - overlayPosition: "top", - overlayRotate: true, - }, - attributes: {}, - relations: dataFlowEdgeRelations, - }; - - dataFlowEdge.attributes[Util.generateRandomId()] = { - key: "Destination", - value: "Value", - options: { - Source: "Source", - Target: "Target", - }, - }; - guidanceMetamodel.edges[Util.generateRandomId()] = dataFlowEdge; - - //Create the association edge - guidanceMetamodel.edges[Util.generateRandomId()] = { - label: "Association edge", - shape: { - arrow: "unidirassociation", - shape: "curved", - color: "", - dashstyle: "4 2", - overlay: "", - overlayPosition: "hidden", - overlayRotate: true, - }, - relations: [ - { - sourceTypes: [guidancemodel.CALL_ACTIVITY_NODE_LABEL], - targetTypes: [guidancemodel.INITIAL_NODE_LABEL], - }, - ], - }; - - return guidanceMetamodel; - }, - generateLogicalGuidanceRepresentation: function (m) { - const dataMap = y.getMap("data"); - var graph = new graphlib.Graph(); - var model; - if (m) model = m; - else model = dataMap.get("guidancemodel"); - if (!model) return null; - var nodes = model.nodes; - var edges = model.edges; - //Returns successor node which belong to the action flow (everything except entity nodes) - var getFlowSuccessors = function (nodeId) { - var targets = []; - var labels = []; - for (var edgeId in edges) { - var edge = edges[edgeId]; - if (edge.source == nodeId) { - //var targetType = nodes[edge.target].type - if (edge.type == "Action flow edge") { - targets.push(edge.target); - labels.push(edge.label.value.value); - } - } - } - return { - targets: targets, - labels: labels, - }; - }; - - var getEntitySuccessor = function (nodeId) { - for (var edgeId in edges) { - var edge = edges[edgeId]; - if (edge.source == nodeId) { - var targetType = nodes[edge.target].type; - if ((targetType = guidancemodel.isEntityNodeLabel(targetType))) - return edge.target; - } - } - return ""; - }; - - var getEntityPredecessorsForCreateRelationshipAction = function ( - nodeId - ) { - var entities = { - Source: "", - Target: "", - }; - for (var edgeId in edges) { - var edge = edges[edgeId]; - if (edge.target == nodeId) { - var sourceType = nodes[edge.source].type; - if ((sourceType = guidancemodel.isEntityNodeLabel(sourceType))) { - var destination = getAttributeValue(edge, "Destination"); - entities[destination] = edge.source; - } - } - } - return entities; - }; - - var getEntityPredecessorForSetPropertyAction = function (nodeId) { - for (var edgeId in edges) { - var edge = edges[edgeId]; - if (edge.target == nodeId) { - var sourceType = nodes[edge.source].type; - if ((sourceType = guidancemodel.isEntityNodeLabel(sourceType))) { - return edge.source; - } - } - } - return ""; - }; - - var getInitialNodeForCallActivityAction = function (nodeId) { - for (var edgeId in edges) { - var edge = edges[edgeId]; - if (edge.source == nodeId && edge.type == "Association edge") { - return edge.target; - } - } - return ""; - }; - - var getAttributeValue = function (node, attributeName) { - for (var attributeId in node.attributes) { - var attribute = node.attributes[attributeId]; - if (attribute.name == attributeName) return attribute.value.value; - } - return ""; - }; - - for (var nodeId in nodes) { - var node = nodes[nodeId]; - var type = node.type; - var subType = ""; - - if (type == guidancemodel.INITIAL_NODE_LABEL) { - var successors = getFlowSuccessors(nodeId); - graph.setNode(nodeId, { - type: "INITIAL_NODE", - name: getAttributeValue(node, "label"), - }); - for (var i = 0; i < successors.targets.length; i++) { - graph.setEdge( - nodeId, - successors.targets[i], - successors.labels[i] - ); - } - } else if (type == guidancemodel.MERGE_NODE_LABEL) { - var successors = getFlowSuccessors(nodeId); - graph.setNode(nodeId, { - type: "MERGE_NODE", - }); - for (var i = 0; i < successors.targets.length; i++) { - graph.setEdge( - nodeId, - successors.targets[i], - successors.labels[i] - ); - } - } else if (type == guidancemodel.CONCURRENCY_NODE_LABEL) { - var successors = getFlowSuccessors(nodeId); - graph.setNode(nodeId, { - type: "CONCURRENCY_NODE", - }); - for (var i = 0; i < successors.targets.length; i++) { - graph.setEdge( - nodeId, - successors.targets[i], - successors.labels[i] - ); - } - } else if (type == guidancemodel.ACTIVITY_FINAL_NODE_LABEL) { - graph.setNode(nodeId, { - type: "ACTIVITY_FINAL_NODE", - }); - } else if ((subType = guidancemodel.isCreateObjectNodeLabel(type))) { - var successors = getFlowSuccessors(nodeId); - graph.setNode(nodeId, { - type: "CREATE_OBJECT_ACTION", - objectType: subType, - createdObjectId: getEntitySuccessor(nodeId), - }); - for (var i = 0; i < successors.targets.length; i++) { - graph.setEdge( - nodeId, - successors.targets[i], - successors.labels[i] - ); - } - } else if ( - (subType = guidancemodel.isCreateRelationshipNodeLabel(type)) - ) { - var entities = - getEntityPredecessorsForCreateRelationshipAction(nodeId); - var successors = getFlowSuccessors(nodeId); - graph.setNode(nodeId, { - type: "CREATE_RELATIONSHIP_ACTION", - relationshipType: subType, - createdRelationshipId: getEntitySuccessor(nodeId), - sourceObjectId: entities["Source"], - targetObjectId: entities["Target"], - }); - for (var i = 0; i < successors.targets.length; i++) { - graph.setEdge( - nodeId, - successors.targets[i], - successors.labels[i] - ); - } - } else if ((subType = guidancemodel.isSetPropertyNodeLabel(type))) { - var successors = getFlowSuccessors(nodeId); - graph.setNode(nodeId, { - type: "SET_PROPERTY_ACTION", - entityType: subType, - propertyName: getAttributeValue(node, "Property"), - sourceObjectId: getEntityPredecessorForSetPropertyAction(nodeId), - }); - for (var i = 0; i < successors.targets.length; i++) { - graph.setEdge( - nodeId, - successors.targets[i], - successors.labels[i] - ); - } - } else if (type == guidancemodel.CALL_ACTIVITY_NODE_LABEL) { - var successors = getFlowSuccessors(nodeId); - graph.setNode(nodeId, { - type: "CALL_ACTIVITY_ACTION", - initialNodeId: getInitialNodeForCallActivityAction(nodeId), - }); - for (var i = 0; i < successors.targets.length; i++) { - graph.setEdge( - nodeId, - successors.targets[i], - successors.labels[i] - ); - } - } - } - return graphlib.json.write(graph); - }, - generateGuidanceRules: function () { - var guidanceRules = { objectToolRules: [] }; - var nodes = guidancemodel.guidancemodel.nodes; - var edges = guidancemodel.guidancemodel.edges; - for (var nodeId in nodes) { - var node = nodes[nodeId]; - var type = node.type; - - if (guidancemodel.isObjectToolType(type)) { - var srcObjectType = - guidancemodel.getObjectTypeForObjectToolType(type); - var destObjectType = null; - var relationshipType = null; - var relevantEdges = []; - var label = ""; - //Get the label attribute - for (var attributeId in node.attributes) { - if (node.attributes[attributeId].name == "label") - label = node.attributes[attributeId].value.value; - } - var edgeId; - for (edgeId in edges) { - if (edges[edgeId].source == nodeId) - relevantEdges.push(edges[edgeId]); - } - for (var i = 0; i < relevantEdges.length; i++) { - var edge = relevantEdges[i]; - var target = nodes[edge.target]; - if (guidancemodel.isObjectContextType(target.type)) { - destObjectType = - guidancemodel.getObjectTypeForObjectContextType(target.type); - } else if (guidancemodel.isRelationshipContextType(target.type)) { - relationshipType = - guidancemodel.getRelationshipTypeForRelationshipContextType( - target.type - ); - } - } - if (destObjectType !== null && relationshipType !== null) { - var objectToolRule = { - srcObjectType: srcObjectType, - destObjectType: destObjectType, - relationshipType: relationshipType, - label: label, - }; - guidanceRules.objectToolRules.push(objectToolRule); - } - } - } - return guidanceRules; - }, - /** - * Generate the JSON Representation of the meta-model for a new editor instance based on the current graph - * @returns {{nodes: {}, edges: {}}} JSON representation of meta model - */ - generateMetaModel: function () { - /** - * Determine the type of the concrete classes (ObjectNodes) of the class diagram contained in the sub graph rooted by the passed node - * @param node Node to start with - * @param [visitedNodes] List of node that already have been visited - * @returns {object} - */ - function getConcreteObjectNodeTypes(node, visitedNodes) { - var edgeId, - edge, - ingoingEdges, - source, - type, - classTypes = []; - - if (!visitedNodes) visitedNodes = []; - - if (visitedNodes.indexOf(node) !== -1) return []; - - visitedNodes.push(node); - - type = node.getLabel().getValue().getValue(); - if (node instanceof ObjectNode && classTypes.indexOf(type) === -1) { - classTypes.push(type); - } - - ingoingEdges = node.getIngoingEdges(); - for (edgeId in ingoingEdges) { - if (ingoingEdges.hasOwnProperty(edgeId)) { - edge = ingoingEdges[edgeId]; - source = edge.getSource(); - if ( - (edge instanceof GeneralisationEdge && - source instanceof ObjectNode) || - (edge instanceof GeneralisationEdge && - source instanceof AbstractClassNode) - ) { - classTypes = classTypes.concat( - getConcreteObjectNodeTypes(source, visitedNodes) - ); - } - } - } - return classTypes; - } - - /** - * Determine the attributes of the passed node by traversing the underlying class diagram - * @param node Node to start with - * @param [visitedNodes] List of node that already have been visited - * @returns {object} - */ - function getNodeAttributes(node, visitedNodes) { - var nodeAttributes, attributeId, attribute; - var edgeId, edge, edges; - var source, target; - var neighbor, options; - var attributes = {}; - var obj = {}; - - if (!visitedNodes) visitedNodes = []; - - if (visitedNodes.indexOf(node) !== -1) return {}; - - visitedNodes.push(node); - - //Traverse edges to check for inheritance and linked enums - edges = node.getOutgoingEdges(); - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - source = edge.getSource(); - target = edge.getTarget(); - - //Does the node inherit attributes from a parent node? - if ( - (edge instanceof GeneralisationEdge && - target instanceof AbstractClassNode) || - (edge instanceof GeneralisationEdge && - node instanceof ObjectNode && - target instanceof ObjectNode) || - (edge instanceof GeneralisationEdge && - node instanceof RelationshipNode && - target instanceof RelationshipNode) || - (edge instanceof GeneralisationEdge && - node instanceof EnumNode && - target instanceof EnumNode) - ) { - Util.merge(attributes, getNodeAttributes(target, visitedNodes)); - - //Is there an enum linked to the node - } else if ( - (edge instanceof BiDirAssociationEdge && - ((target === node && - (neighbor = source) instanceof EnumNode) || - (source === node && - (neighbor = target) instanceof EnumNode))) || - (edge instanceof UniDirAssociationEdge && - (neighbor = target) instanceof EnumNode) - ) { - options = {}; - nodeAttributes = {}; - Util.merge(nodeAttributes, getNodeAttributes(neighbor, [])); - for (attributeId in nodeAttributes) { - if (nodeAttributes.hasOwnProperty(attributeId)) { - attribute = nodeAttributes[attributeId]; - options[attribute.value] = attribute.value; - } - } - obj = {}; - obj[neighbor.getEntityId()] = { - key: edge.getLabel().getValue().getValue(), - value: neighbor.getLabel().getValue().getValue(), - options: options, - }; - Util.merge(attributes, obj); - } - } - } - //Compute node attributes - nodeAttributes = node.getAttribute("[attributes]").getAttributes(); - for (attributeId in nodeAttributes) { - if (nodeAttributes.hasOwnProperty(attributeId)) { - attribute = nodeAttributes[attributeId]; - if (node instanceof RelationshipNode) { - obj = {}; - obj[attributeId] = { - key: attribute.getKey().getValue(), - value: attribute.getValue().getValue(), - position: attribute.getValue2().getValue(), - }; - Util.merge(attributes, obj); - } else if (node instanceof EnumNode) { - obj = {}; - obj[attributeId] = { - value: attribute.getValue().getValue(), - }; - Util.merge(attributes, obj); - } else { - obj = {}; - obj[attributeId] = { - key: attribute.getKey().getValue(), - value: attribute.getValue().getValue(), - }; - Util.merge(attributes, obj); - } - } - } - return attributes; - } - - var metamodel = { - attributes: {}, - nodes: {}, - edges: {}, - }; - - var nodeId, node; - var attributes; - var edge, edgeId, edges; - var source, target; - var neighbor; - var groupSource, groupTarget; - var groupNeighbor; - var shape; - var sourceTypes, targetTypes, concreteTypes; - var groupSourceTypes, groupTargetTypes, groupConcreteTypes; - var relations; - var groupEdge, groupEdgeId, groupEdges; - - for (nodeId in _nodes) { - if (_nodes.hasOwnProperty(nodeId)) { - node = _nodes[nodeId]; - if (node instanceof ObjectNode) { - if ( - node.getLabel().getValue().getValue() === "Model Attributes" - ) { - attributes = getNodeAttributes(node); - metamodel.attributes = attributes; - } else { - attributes = getNodeAttributes(node); - edges = node.getEdges(); - shape = null; - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - source = edge.getSource(); - target = edge.getTarget(); - if ( - (edge instanceof BiDirAssociationEdge && - ((target === node && - (neighbor = source) instanceof NodeShapeNode) || - (source === node && - (neighbor = target) instanceof NodeShapeNode))) || - (edge instanceof UniDirAssociationEdge && - (neighbor = target) instanceof NodeShapeNode) - ) { - shape = { - shape: neighbor - .getAttribute(neighbor.getEntityId() + "[shape]") - .getValue() - .getValue(), - color: neighbor - .getAttribute(neighbor.getEntityId() + "[color]") - .getValue() - .getValue(), - defaultWidth: parseInt( - neighbor - .getAttribute( - neighbor.getEntityId() + "[defaultWidth]" - ) - .getValue() - .getValue() - ), - defaultHeight: parseInt( - neighbor - .getAttribute( - neighbor.getEntityId() + "[defaultHeight]" - ) - .getValue() - .getValue() - ), - containment: neighbor - .getAttribute( - neighbor.getEntityId() + "[containment]" - ) - .getValue() - .getValue(), - customShape: neighbor - .getAttribute( - neighbor.getEntityId() + "[customShape]" - ) - .getValue() - .getValue(), - customAnchors: neighbor - .getAttribute( - neighbor.getEntityId() + "[customAnchors]" - ) - .getValue() - .getValue(), - }; - } - } - } - metamodel.nodes[nodeId] = { - label: node.getLabel().getValue().getValue(), - attributes: attributes, - shape: shape || { - shape: "rectangle", - color: "white", - containment: false, - customShape: "", - customAnchors: "", - defaultWidth: 0, - defaultHeight: 0, - }, - }; - } - } else if (node instanceof RelationshipNode) { - attributes = getNodeAttributes(node); - edges = node.getEdges(); - sourceTypes = []; - targetTypes = []; - relations = []; - shape = null; - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - source = edge.getSource(); - target = edge.getTarget(); - if ( - edge instanceof BiDirAssociationEdge && - ((target === node && - (neighbor = source) instanceof ObjectNode) || - (source === node && - (neighbor = target) instanceof ObjectNode)) - ) { - concreteTypes = getConcreteObjectNodeTypes(neighbor); - sourceTypes = sourceTypes.concat(concreteTypes); - targetTypes = targetTypes.concat(concreteTypes); - } else if ( - edge instanceof UniDirAssociationEdge && - source === node && - target instanceof ObjectNode - ) { - targetTypes = targetTypes.concat( - getConcreteObjectNodeTypes(target) - ); - } else if ( - edge instanceof UniDirAssociationEdge && - target === node && - source instanceof ObjectNode - ) { - sourceTypes = sourceTypes.concat( - getConcreteObjectNodeTypes(source) - ); - } else if ( - edge instanceof BiDirAssociationEdge && - ((target === node && - (neighbor = source) instanceof AbstractClassNode) || - (source === node && - (neighbor = target) instanceof AbstractClassNode)) - ) { - concreteTypes = getConcreteObjectNodeTypes(neighbor); - sourceTypes = sourceTypes.concat(concreteTypes); - targetTypes = targetTypes.concat(concreteTypes); - } else if ( - edge instanceof UniDirAssociationEdge && - source === node && - target instanceof AbstractClassNode - ) { - targetTypes = targetTypes.concat( - getConcreteObjectNodeTypes(target) - ); - } else if ( - edge instanceof UniDirAssociationEdge && - target === node && - source instanceof AbstractClassNode - ) { - sourceTypes = sourceTypes.concat( - getConcreteObjectNodeTypes(source) - ); - } else if ( - (edge instanceof BiDirAssociationEdge && - ((target === node && - (neighbor = source) instanceof EdgeShapeNode) || - (source === node && - (neighbor = target) instanceof EdgeShapeNode))) || - (edge instanceof UniDirAssociationEdge && - source === node && - (neighbor = target) instanceof EdgeShapeNode) - ) { - shape = { - arrow: neighbor - .getAttribute(neighbor.getEntityId() + "[arrow]") - .getValue() - .getValue(), - shape: neighbor - .getAttribute(neighbor.getEntityId() + "[shape]") - .getValue() - .getValue(), - color: neighbor - .getAttribute(neighbor.getEntityId() + "[color]") - .getValue() - .getValue(), - overlay: neighbor - .getAttribute(neighbor.getEntityId() + "[overlay]") - .getValue() - .getValue(), - overlayPosition: neighbor - .getAttribute( - neighbor.getEntityId() + "[overlayPosition]" - ) - .getValue() - .getValue(), - overlayRotate: neighbor - .getAttribute( - neighbor.getEntityId() + "[overlayRotate]" - ) - .getValue() - .getValue(), - }; - } else if ( - edge instanceof GeneralisationEdge && - target === node && - (neighbor = source) instanceof RelationshipGroupNode - ) { - groupEdges = neighbor.getEdges(); - groupSourceTypes = []; - groupTargetTypes = []; - for (groupEdgeId in groupEdges) { - if (groupEdges.hasOwnProperty(groupEdgeId)) { - groupEdge = groupEdges[groupEdgeId]; - groupSource = groupEdge.getSource(); - groupTarget = groupEdge.getTarget(); - if ( - groupEdge instanceof BiDirAssociationEdge && - ((groupTarget === neighbor && - (groupNeighbor = groupSource) instanceof - ObjectNode) || - (groupSource === neighbor && - (groupNeighbor = groupTarget) instanceof - ObjectNode)) - ) { - groupConcreteTypes = - getConcreteObjectNodeTypes(groupNeighbor); - groupSourceTypes = - groupSourceTypes.concat(groupConcreteTypes); - groupTargetTypes = - groupTargetTypes.concat(groupConcreteTypes); - } else if ( - groupEdge instanceof UniDirAssociationEdge && - groupSource === neighbor && - groupTarget instanceof ObjectNode - ) { - groupTargetTypes = groupTargetTypes.concat( - getConcreteObjectNodeTypes(groupTarget) - ); - } else if ( - groupEdge instanceof UniDirAssociationEdge && - groupTarget === neighbor && - groupSource instanceof ObjectNode - ) { - groupSourceTypes = groupSourceTypes.concat( - getConcreteObjectNodeTypes(groupSource) - ); - } else if ( - groupEdge instanceof BiDirAssociationEdge && - ((groupTarget === neighbor && - (groupNeighbor = groupSource) instanceof - AbstractClassNode) || - (groupSource === neighbor && - (groupNeighbor = groupTarget) instanceof - AbstractClassNode)) - ) { - groupConcreteTypes = - getConcreteObjectNodeTypes(groupNeighbor); - groupSourceTypes = - groupSourceTypes.concat(groupConcreteTypes); - groupTargetTypes = - groupTargetTypes.concat(groupConcreteTypes); - } else if ( - groupEdge instanceof UniDirAssociationEdge && - groupSource === neighbor && - groupTarget instanceof AbstractClassNode - ) { - groupTargetTypes = groupTargetTypes.concat( - getConcreteObjectNodeTypes(groupTarget) - ); - } else if ( - groupEdge instanceof UniDirAssociationEdge && - groupTarget === neighbor && - groupSource instanceof AbstractClassNode - ) { - groupSourceTypes = groupSourceTypes.concat( - getConcreteObjectNodeTypes(groupSource) - ); - } - } - } - - if ( - groupSourceTypes.length > 0 && - groupTargetTypes.length > 0 - ) { - relations.push({ - sourceTypes: groupSourceTypes, - targetTypes: groupTargetTypes, - }); - } - } - } - } - - if (sourceTypes.length > 0 && targetTypes.length > 0) { - relations.push({ - sourceTypes: sourceTypes, - targetTypes: targetTypes, - }); - } - - metamodel.edges[nodeId] = { - label: node.getLabel().getValue().getValue(), - shape: shape || { - arrow: "bidirassociation", - shape: "straight", - color: "black", - overlay: "", - overlayPosition: "top", - overlayRotate: true, - }, - relations: relations, - attributes: attributes, - }; - } - } - } - return metamodel; - }, - /** - * Store current graph representation in the ROLE space - * @returns {Deferred} - */ - storeData: function () { - var resourceSpace = new openapp.oo.Resource(openapp.param.space()); - - var data = this.graphToJSON(); - - var resourcesToSave = []; - var promises = []; - - //In the guidance model editor update the guidance model - if (guidancemodel.isGuidanceEditor()) { - resourcesToSave.push({ - typeName: CONFIG.NS.MY.GUIDANCEMODEL, - representation: data, - }); - } - //In the metamodel editor create the guidance metamodel needed for the guidance editor - else if (!metamodel.hasOwnProperty("nodes")) { - resourcesToSave.push({ - typeName: CONFIG.NS.MY.METAMODELPREVIEW, - representation: this.generateMetaModel(), - }); - resourcesToSave.push({ - typeName: CONFIG.NS.MY.GUIDANCEMETAMODEL, - representation: this.generateGuidanceMetamodel(), - }); - resourcesToSave.push({ - typeName: CONFIG.NS.MY.MODEL, - representation: data, - }); - } - //In the model editor just update the model - else { - resourcesToSave.push({ - typeName: CONFIG.NS.MY.MODEL, - representation: data, - }); - } - - var recreateResource = function (type, representation) { - var deferred = $.Deferred(); - var innerDeferred = $.Deferred(); - //noinspection JSUnusedGlobalSymbols - resourceSpace.getSubResources({ - relation: openapp.ns.role + "data", - type: type, - onEach: function (doc) { - doc.del(); - }, - onAll: function () { - innerDeferred.resolve(); - }, - }); - innerDeferred.then(function () { - resourceSpace.create({ - relation: openapp.ns.role + "data", - type: type, - representation: representation, - callback: function () { - deferred.resolve(); - }, - }); - }); - return deferred.promise(); - }; - - for (var i = 0; i < resourcesToSave.length; i++) { - var item = resourcesToSave[i]; - promises.push(recreateResource(item.typeName, item.representation)); - } - - return $.when.apply($, promises); - }, - storeDataYjs: function () { - var data = this.graphToJSON(); - const dataMap = y.getMap("data"); - if (guidancemodel.isGuidanceEditor()) { - dataMap.set("guidancemodel", data); - } else if (!metamodel) { - dataMap.set("metamodelpreview", this.generateMetaModel()); - dataMap.set("guidancemetamodel", this.generateGuidanceMetamodel()); - dataMap.set("model", data); - } else { - dataMap.set("model", data); - } - }, - /** - * Delete the Model Attribute Node - */ - deleteModelAttribute: function () { - _modelAttributesNode = null; - }, - /** - * resets the EntityManager - */ - reset: function () { - _nodes = {}; - _edges = {}; - this.deleteModelAttribute(); - }, - /** - * initializes the node types - * @param vls the vvs - */ - initNodeTypes: function (vls) { - nodeTypes = _initNodeTypes(vls); - }, - /** - * initializes the view edge types - * @param vls the vvs - */ - initEdgeTypes: function (vls) { - var res = _initEdgeTypes(vls); - edgeTypes = res.edgeTypes; - relations = res.relations; - }, - /** - * initializes both the node types- and the edge types Object - * @param vls the vvs - */ - initModelTypes: function (vls) { - this.initNodeTypes(vls); - this.initEdgeTypes(vls); - }, - /** - * Get the node type by its name - * @param type the name of the node type - * @returns {object} - */ - getNodeType: function (type) { - return nodeTypes.hasOwnProperty(type) ? nodeTypes[type] : null; - }, - /** - * Get the edge type bt its name - * @param {string} type the name of the edge type - * @returns {*} - */ - getEdgeType: function (type) { - return edgeTypes.hasOwnProperty(type) ? edgeTypes[type] : null; - }, - /** - * initializes the node types of a view - * @param vvs - */ - initViewNodeTypes: function (vvs) { - //delete the old view type references - for (var nodeTypeName in nodeTypes) { - if (nodeTypes.hasOwnProperty(nodeTypeName)) { - delete nodeTypes[nodeTypeName].VIEWTYPE; - } - } - viewNodeTypes = _initNodeTypes(vvs); - }, - /** - * initializes the edge types of a view - * @param vvs - */ - initViewEdgeTypes: function (vvs) { - //delete the old view type references - for (var edgeTypeName in edgeTypes) { - if (edgeTypes.hasOwnProperty(edgeTypeName)) { - delete edgeTypes[edgeTypeName].VIEWTYPE; - } - } - var res = _initEdgeTypes(vvs); - viewEdgeTypes = res.edgeTypes; - relations = res.relations; - }, - /** - * initializes the node and edge types of view - * @param vvs - */ - initViewTypes: function (vvs) { - this.setViewId(vvs.id); - this.initViewNodeTypes(vvs); - this.initViewEdgeTypes(vvs); - }, - /** - * get a view node type - * @param {string} type the name of the view type - * @returns {*} - */ - getViewNodeType: function (type) { - return viewNodeTypes.hasOwnProperty(type) ? viewNodeTypes[type] : null; - }, - /** - * get a view edge type - * @param {string} type the name of the view edge type - * @returns {*} - */ - getViewEdgeType: function (type) { - return viewEdgeTypes.hasOwnProperty(type) ? viewEdgeTypes[type] : null; - }, - /** - * set the identifier of the view - * @param {string} viewId - */ - setViewId: function (viewId) { - _viewId = viewId; - }, - /** - * get the identifier of the view - * @returns {*} - */ - getViewId: function () { - return _viewId; - }, - /** - * get nodes by view type - * @param {string} type the name of the view type - * @returns {object} a map of objects with key as identifier and value as Node - */ - getNodesByViewType: function (type) { - if (viewNodeTypes.hasOwnProperty(type)) { - return this.getNodesByType( - viewNodeTypes[type].getTargetNodeType().TYPE - ); - } - return null; - }, - /** - * get edges by view type - * @param {string}type the view type - * @returns {*} - */ - getEdgesByViewType: function (type) { - if (viewEdgeTypes.hasOwnProperty(type)) { - return this.getEdgesByType( - viewEdgeTypes[type].getTargetEdgeType().TYPE - ); - } - return null; - }, - /** - * Get the current layer you are operating on - * @returns {string} CONFIG.LAYER.META or CONFIG.LAYER.MODEL - */ - getLayer: function () { - return _layer; - }, - /** - * Get the relations between nodes and edges types - * @returns {{}} - */ - getRelations: function () { - return relations; - }, - setGuidance: function (guidance) { - guidancemodel = guidance; - }, - init: function (mm) { - metamodel = mm; - if (metamodel && metamodel.hasOwnProperty("nodes")) { - nodeTypes = _initNodeTypes(metamodel); - _layer = CONFIG.LAYER.MODEL; - } else { - _layer = CONFIG.LAYER.META; - - nodeTypes[ObjectNode.TYPE] = ObjectNode; - nodeTypes[AbstractClassNode.TYPE] = AbstractClassNode; - nodeTypes[RelationshipNode.TYPE] = RelationshipNode; - nodeTypes[RelationshipGroupNode.TYPE] = RelationshipGroupNode; - nodeTypes[EnumNode.TYPE] = EnumNode; - nodeTypes[NodeShapeNode.TYPE] = NodeShapeNode; - nodeTypes[EdgeShapeNode.TYPE] = EdgeShapeNode; - - //add view types - nodeTypes[ViewObjectNode.TYPE] = ViewObjectNode; - nodeTypes[ViewRelationshipNode$1.TYPE] = ViewRelationshipNode$1; - } - - if (metamodel && metamodel.hasOwnProperty("edges")) { - var res = _initEdgeTypes(metamodel); - edgeTypes = res.edgeTypes; - relations = res.relations; - } else { - edgeTypes[GeneralisationEdge.TYPE] = GeneralisationEdge; - edgeTypes[BiDirAssociationEdge.TYPE] = BiDirAssociationEdge; - edgeTypes[UniDirAssociationEdge.TYPE] = UniDirAssociationEdge; - - relations[BiDirAssociationEdge.TYPE] = BiDirAssociationEdge.RELATIONS; - relations[UniDirAssociationEdge.TYPE] = - UniDirAssociationEdge.RELATIONS; - relations[GeneralisationEdge.TYPE] = GeneralisationEdge.RELATIONS; - } - }, - }; - } -}; - -const EntityManagerInstance = new EntityManager$1(); - -/** - * Node - * @class canvas_widget.makeNode - * @memberof canvas_widget - * @constructor - * @param type Type of node - * @param $shape - * @param anchors - * @param attributes - * @returns {Node} - */ -function makeNode(type, $shape, anchors, attributes) { - /** - * Node - * @class canvas_widget.Node - * @extends canvas_widget.AbstractNode - * @constructor - * @param {string} id Entity identifier of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {number} zIndex Position of node on z-axis - * @param {boolean} containment containment - */ - class Node extends AbstractNode { - constructor(id, left, top, width, height, zIndex, containment) { - super(id, type, left, top, width, height, zIndex, containment); - var that = this; - - var currentViewType = null; - - this.setCurrentViewType = function (type) { - currentViewType = type; - }; - - this.getCurrentViewType = function () { - return currentViewType; - }; - - /** - * jQuery object of node template - * @type {jQuery} - * @private - */ - var _$template = $shape.clone(); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = AbstractNode.prototype.get$node - .call(this) - .append(_$template); - - /** - * Options for new connections - * @type {object} - */ - var _anchorOptions = anchors; - - this.nodeSelector = getQuerySelectorFromNode(_$node); - - var init = function () { - var attribute, attributeId, attrObj; - attrObj = {}; - for (attributeId in attributes) { - if (attributes.hasOwnProperty(attributeId)) { - attribute = attributes[attributeId]; - var key = attribute.key.toLowerCase(); - switch (attribute.value) { - case "boolean": - attrObj[attributeId] = new BooleanAttribute( - id + "[" + attribute.key.toLowerCase() + "]", - attribute.key, - that - ); - break; - case "string": - attrObj[attributeId] = new SingleValueAttribute( - id + "[" + attribute.key.toLowerCase() + "]", - attribute.key, - that - ); - if ( - attribute.key.toLowerCase() === "label" || - attribute.key.toLowerCase() === "title" || - attribute.key.toLowerCase() === "name" - ) { - that.setLabel(attrObj[attributeId]); - } - break; - case "integer": - attrObj[attributeId] = new IntegerAttribute( - id + "[" + attribute.key.toLowerCase() + "]", - attribute.key, - that - ); - break; - case "file": - attrObj[attributeId] = new FileAttribute( - id + "[" + attribute.key.toLowerCase() + "]", - attribute.key, - that - ); - break; - case "quiz": - attrObj[attributeId] = new QuizAttribute( - id + "[" + attribute.key.toLowerCase() + "]", - attribute.key, - that - ); - if ( - attribute.key.toLowerCase() === "label" || - attribute.key.toLowerCase() === "title" || - attribute.key.toLowerCase() === "name" - ) { - that.setLabel(attrObj[attributeId]); - } - default: - if (attribute.options) { - attrObj[attributeId] = new SingleSelectionAttribute( - id + "[" + attribute.key.toLowerCase() + "]", - attribute.key, - that, - attribute.options - ); - } - } - _$node.find("." + key).append(attrObj[attributeId].get$node()); - } - } - that.setAttributes(attrObj); - }; - - /** - * Get anchor options for new connections - * @returns {Object} - */ - this.getAnchorOptions = function () { - return _anchorOptions; - }; - - /** Set anchor options for new connections - * - */ - this.setAnchorOptions = function (anchors) { - _anchorOptions = anchors; - }; - - /** - * Bind source node events for edge tool - */ - this.makeSource = () => { - _$node.addClass("source"); - window.jsPlumbInstance.addEndpoint(_$node.get(0), { - connectorPaintStyle: { fill: "black", strokeWidth: 4 }, - source: true, - endpoint: { - type: "Rectangle", - options: { - width: _$node.width() + 50, - height: _$node.height() + 50, - }, - }, - paintStyle: { fill: "transparent" }, - anchor: AnchorLocations.Center, - deleteOnEmpty: true, - uuid: id + "_eps1", - //maxConnections:1, - uniqueEndpoint: false, - deleteEndpointsOnDetach: true, - onMaxConnections: function (info /*, originalEvent*/) { - console.log( - "element is ", - info.element, - "maxConnections is", - info.maxConnections - ); - }, - }); - }; - - /** - * Bind target node events for edge tool - */ - this.makeTarget = () => { - _$node.addClass("target"); - window.jsPlumbInstance.addEndpoint(_$node.get(0), { - target: true, - endpoint: { - type: "Rectangle", - options: { - width: _$node.width() + 50, - height: _$node.height() + 50, - }, - }, - uuid: id + "_ept1", - paintStyle: { fill: "transparent" }, - anchor: AnchorLocations.Center, - uniqueEndpoint: false, - //maxConnections:1, - deleteOnEmpty: true, - onMaxConnections: function (info /*, originalEvent*/) { - console.log( - "user tried to drop connection", - info.connection, - "on element", - info.element, - "with max connections", - info.maxConnections - ); - }, - }); - - //local user wants to create an edge selected from the pallette - window.jsPlumbInstance.bind("beforeDrop", function (info) { - var allConn = window.jsPlumbInstance.getConnections({ - target: info.targetId, - source: info.sourceId, - }); - var length = allConn.length; - //if true => Detected a duplicated edge - if (length > 0) return false; //don't create the edge - else return true; //no duplicate create the edge - }); - }; - - /** - * Unbind events for edge tool - */ - this.unbindEdgeToolEvents = function () { - try { - _$node.removeClass("source target"); - jsPlumbInstance.getEndpoints(_$node.get(0)).forEach((endpoint) => { - // We need to remove the endpoint that was created to enable node connection by dragging - // since we are not using the edge tool anymore - if (endpoint.connections.length === 0) { - jsPlumbInstance.deleteEndpoint(endpoint); - } - }); - } catch (error) { - console.error(error); - } - }; - - /** - * Get JSON representation of the node - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractNode.prototype.toJSON.call(this); - json.type = type; - return json; - }; - - /** - * set a new shape for the node - * @param $shape - */ - this.set$shape = function ($shape) { - _$template.remove(); - var _$shape = $shape.clone(); - - var attributes = that.getAttributes(); - for (var attrKey in attributes) { - if (attributes.hasOwnProperty(attrKey)) { - var attribute = attributes[attrKey]; - var $tmp = _$shape.find("." + attribute.getName().toLowerCase()); - if ($tmp.length > 0) { - //initialize the value again - if (attribute.getValue().hasOwnProperty("init")) - attribute.getValue().init(); - $tmp.append(attribute.get$node()); - break; - } - } - } - _$template = _$shape; - _$node.append(_$shape); - }; - - this.get$node = function () { - return _$node; - }; - - init(); - - this.registerYMap = function () { - AbstractNode.prototype.registerYMap.call(this); - var labelAttr = that.getLabel(); - if (labelAttr) labelAttr.registerYType(); - var attr = that.getAttributes(); - for (var key in attr) { - if (attr.hasOwnProperty(key)) { - var val = attr[key].getValue(); - if (val.hasOwnProperty("registerYType")) { - val.registerYType(); - } - } - } - }; - } - nodeSelector; - /** - * Get the jquery shape object from the node type - * @static - * @returns {*} - */ - static get$shape() { - return $shape; - } - /** - * Get the anchors of the node type - * @static - * @returns {*} - */ - static getAnchors() { - return anchors; - } - static getAttributes() { - return attributes; - } - } - - return Node; -} - -/** - * AbstractNode - * @class canvas_widget.AbstractNode - * @extends canvas_widget.AbstractEntity - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of node - * @param {string} type Type of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {boolean} containment containment - * @param {number} zIndex Position of node on z-axis - */ - -/** - * ObjectNode - * @class canvas_widget.ObjectNode - * @extends canvas_widget.AbstractNode - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {number} zIndex Position of node on z-axis - */ -class ObjectNode extends AbstractNode { - static TYPE = "Object"; - static DEFAULT_WIDTH = 150; - static DEFAULT_HEIGHT = 100; - constructor(id, left, top, width, height, zIndex, json, y) { - super(id, ObjectNode.TYPE, left, top, width, height, zIndex, json, y); - var that = this; - - /** - * jQuery object of node template - * @type {jQuery} - * @private - */ - var _$template = $(lodash.template(objectNodeHtml)({ type: that.getType() })); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = AbstractNode.prototype.get$node - .call(this) - .append(_$template) - .addClass("object"); - - /** - * jQuery object of DOM node representing the attributes - * @type {jQuery} - * @private - */ - var _$attributeNode = _$node.find(".attributes"); - - /** - * Attributes of node - * @type {Object} - * @private - */ - var _attributes = this.getAttributes(); - - /** - * Get JSON representation of the node - * @returns {Object} - */ - this.toJSON = function () { - return AbstractNode.prototype.toJSON.call(this); - }; - var attr = new KeySelectionValueListAttribute( - "[attributes]", - "Attributes", - this, - { - string: "String", - boolean: "Boolean", - integer: "Integer", - file: "File", - quiz: "Questions", - } - ); - this.addAttribute(attr); - - this.registerYMap = function () { - AbstractNode.prototype.registerYMap.call(this); - that.getLabel().getValue().registerYType(); - attr.registerYMap(); - }; - - _$node.find(".label").append(this.getLabel().get$node()); - - for (var attributeKey in _attributes) { - if (_attributes.hasOwnProperty(attributeKey)) { - _$attributeNode.append(_attributes[attributeKey].get$node()); - } - } - - this.unregisterCallbacks = function () { - that.getAttribute("[attributes]").unregisterCallbacks(); - }; - - this.setContextMenuItemCallback(function () { - return { - addShape: { - name: "Add Node Shape", - callback: function () { - var canvas = that.getCanvas(), - appearance = that.getAppearance(); - - //noinspection JSAccessibilityCheck - const id = canvas.createNode( - NodeShapeNode.TYPE, - appearance.left + appearance.width + 50, - appearance.top, - 150, - 100 - ); - canvas.createEdge( - BiDirAssociationEdge.TYPE, - that.getEntityId(), - id - ); - }, - disabled: function () { - var edges = that.getEdges(), - edge, - edgeId; - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if ( - (edge instanceof BiDirAssociationEdge && - ((edge.getTarget() === that && - edge.getSource() instanceof NodeShapeNode) || - (edge.getSource() === that && - edge.getTarget() instanceof NodeShapeNode))) || - (edge instanceof UniDirAssociationEdge && - edge.getTarget() instanceof NodeShapeNode) - ) { - return true; - } - } - } - return false; - }, - }, - sepConvertTo: "---------", - convertTo: { - name: "Convert to..", - items: { - abstractClassNode: { - name: "..Abstract Class", - callback: function () { - var canvas = that.getCanvas(), - appearance = that.getAppearance(), - nodeId; - - //noinspection JSAccessibilityCheck - nodeId = canvas.createNode( - AbstractClassNode.TYPE, - appearance.left, - appearance.top, - appearance.width, - appearance.height, - that.getZIndex(), - that.toJSON() - ); - var edges = that.getOutgoingEdges(), - edge, - edgeId; - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - canvas.createEdge( - edge.getType(), - nodeId, - edge.getTarget().getEntityId(), - edge.toJSON() - ); - } - } - - edges = that.getIngoingEdges(); - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if (edge.getSource() !== edge.getTarget()) { - canvas.createEdge( - edge.getType(), - edge.getSource().getEntityId(), - nodeId, - edge.toJSON() - ); - } - } - } - - that.triggerDeletion(); - }, - }, - relationshipNode: { - name: "..Relationship", - callback: function () { - var canvas = that.getCanvas(), - appearance = that.getAppearance(), - nodeId; - - //noinspection JSAccessibilityCheck - nodeId = canvas.createNode( - RelationshipNode.TYPE, - appearance.left, - appearance.top, - appearance.width, - appearance.height, - that.getZIndex(), - that.toJSON() - ); - var edges = that.getOutgoingEdges(), - edge, - edgeId; - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - canvas.createEdge( - edge.getType(), - nodeId, - edge.getTarget().getEntityId(), - edge.toJSON() - ); - } - } - - edges = that.getIngoingEdges(); - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if (edge.getSource() !== edge.getTarget()) { - canvas.createEdge( - edge.getType(), - edge.getSource().getEntityId(), - nodeId, - edge.toJSON() - ); - } - } - } - - that.triggerDeletion(); - }, - }, - relationshipGroupNode: { - name: "..Relationship Group", - callback: function () { - var canvas = that.getCanvas(), - appearance = that.getAppearance(), - nodeId; - - //noinspection JSAccessibilityCheck - nodeId = canvas.createNode( - RelationshipGroupNode.TYPE, - appearance.left, - appearance.top, - appearance.width, - appearance.height, - that.getZIndex(), - that.toJSON() - ); - var edges = that.getOutgoingEdges(), - edge, - edgeId; - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - canvas.createEdge( - edge.getType(), - nodeId, - edge.getTarget().getEntityId(), - edge.toJSON() - ); - } - } - - edges = that.getIngoingEdges(); - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if (edge.getSource() !== edge.getTarget()) { - canvas.createEdge( - edge.getType(), - edge.getSource().getEntityId(), - nodeId, - edge.toJSON() - ); - } - } - } - - that.triggerDeletion(); - }, - }, - }, - }, - sep: "---------", - }; - }); - } -} - -/** - * Abstract Class Node - * @class canvas_widget.AbstractClassNode - * @extends canvas_widget.AbstractNode - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {number} zIndex Position of node on z-axis - */ -class AbstractClassNode extends AbstractNode { - static TYPE = "Abstract Class"; - static DEFAULT_WIDTH = 150; - static DEFAULT_HEIGHT = 100; - - constructor(id, left, top, width, height, zIndex, json) { - super(id, AbstractClassNode.TYPE, left, top, width, height, zIndex, json); - - var that = this; - - /** - * jQuery object of node template - * @type {jQuery} - * @private - */ - var _$template = $( - lodash.template(abstractClassNodeHtml)({ type: that.getType() }) - ); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = AbstractNode.prototype.get$node - .call(this) - .append(_$template) - .addClass("class"); - - /** - * jQuery object of DOM node representing the attributes - * @type {jQuery} - * @private - */ - var _$attributeNode = _$node.find(".attributes"); - - /** - * Attributes of node - * @type {Object} - * @private - */ - var _attributes = this.getAttributes(); - - /** - * Get JSON representation of the node - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractNode.prototype.toJSON.call(this); - json.type = AbstractClassNode.TYPE; - return json; - }; - - var attr = new KeySelectionValueListAttribute( - "[attributes]", - "Attributes", - this, - { - string: "String", - boolean: "Boolean", - integer: "Integer", - file: "File", - quiz: "Questions", - } - ); - this.addAttribute(attr); - - this.registerYMap = function () { - AbstractNode.prototype.registerYMap.call(this); - that.getLabel().getValue().registerYType(); - attr.registerYMap(); - }; - - this.unregisterCallbacks = function () { - that.getAttribute("[attributes]").unregisterCallbacks(); - }; - - _$node.find(".label").append(this.getLabel().get$node()); - - for (var attributeKey in _attributes) { - if (_attributes.hasOwnProperty(attributeKey)) { - _$attributeNode.append(_attributes[attributeKey].get$node()); - } - } - - this.setContextMenuItemCallback(function () { - return { - convertTo: { - name: "Convert to..", - items: { - objectNode: { - name: "..Object", - callback: function () { - var canvas = that.getCanvas(), - appearance = that.getAppearance(), - nodeId; - - //noinspection JSAccessibilityCheck - nodeId = canvas.createNode( - ObjectNode.TYPE, - appearance.left, - appearance.top, - appearance.width, - appearance.height, - that.getZIndex(), - that.getContainment(), - that.toJSON() - ); - var edges = that.getOutgoingEdges(), - edge, - edgeId; - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - canvas.createEdge( - edge.getType(), - nodeId, - edge.getTarget().getEntityId(), - edge.toJSON() - ); - } - } - - edges = that.getIngoingEdges(); - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if (edge.getSource() !== edge.getTarget()) { - canvas.createEdge( - edge.getType(), - edge.getSource().getEntityId(), - nodeId, - edge.toJSON() - ); - } - } - } - - that.triggerDeletion(); - }, - }, - relationshipNode: { - name: "..Relationship", - callback: function () { - var canvas = that.getCanvas(), - appearance = that.getAppearance(), - nodeId; - - //noinspection JSAccessibilityCheck - nodeId = canvas.createNode( - RelationshipNode.TYPE, - appearance.left, - appearance.top, - appearance.width, - appearance.height, - that.getZIndex(), - that.getContainment(), - that.toJSON() - ); - var edges = that.getOutgoingEdges(), - edge, - edgeId; - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - canvas.createEdge( - edge.getType(), - nodeId, - edge.getTarget().getEntityId(), - edge.toJSON() - ); - } - } - - edges = that.getIngoingEdges(); - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if (edge.getSource() !== edge.getTarget()) { - canvas.createEdge( - edge.getType(), - edge.getSource().getEntityId(), - nodeId, - edge.toJSON() - ); - } - } - } - - that.triggerDeletion(); - }, - }, - relationshipGroupNode: { - name: "..Relationship Group", - callback: function () { - var canvas = that.getCanvas(), - appearance = that.getAppearance(), - nodeId; - - //noinspection JSAccessibilityCheck - nodeId = canvas.createNode( - RelationshipGroupNode.TYPE, - appearance.left, - appearance.top, - appearance.width, - appearance.height, - that.getZIndex(), - that.getContainment(), - that.toJSON() - ); - var edges = that.getOutgoingEdges(), - edge, - edgeId; - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - canvas.createEdge( - edge.getType(), - nodeId, - edge.getTarget().getEntityId(), - edge.toJSON() - ); - } - } - - edges = that.getIngoingEdges(); - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if (edge.getSource() !== edge.getTarget()) { - canvas.createEdge( - edge.getType(), - edge.getSource().getEntityId(), - nodeId, - edge.toJSON() - ); - } - } - } - - that.triggerDeletion(); - }, - }, - }, - }, - sep: "---------", - }; - }); - } -} - -/** - * RelationshipNode - * @class canvas_widget.RelationshipNode - * @extends canvas_widget.AbstractNode - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {number} zIndex Position of node on z-axis - */ -class RelationshipNode extends AbstractNode { - static TYPE = "Relationship"; - static DEFAULT_WIDTH = 150; - static DEFAULT_HEIGHT = 100; - - constructor(id, left, top, width, height, zIndex, json) { - super(id, "Relationship", left, top, width, height, zIndex, json); - var that = this; - - /** - * jQuery object of node template - * @type {jQuery} - * @private - */ - var _$template = $( - lodash.template(relationshipNodeHtml)({ type: that.getType() }) - ); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var $node = AbstractNode.prototype.get$node - .call(this) - .append(_$template) - .addClass("relation"); - - /** - * jQuery object of DOM node representing the attributes - * @type {jQuery} - * @private - */ - var _$attributeNode = $node.find(".attributes"); - - /** - * Attributes of node - * @type {Object} - * @private - */ - var _attributes = this.getAttributes(); - - /** - * Get JSON representation of the node - * @returns {Object} - */ - this.toJSON = function () { - return AbstractNode.prototype.toJSON.call(this); - }; - - var attr = new KeySelectionValueSelectionValueListAttribute( - "[attributes]", - "Attributes", - this, - { - string: "String", - boolean: "Boolean", - integer: "Integer", - file: "File", - }, - { hidden: "Hide", top: "Top", center: "Center", bottom: "Bottom" } - ); - this.addAttribute(attr); - - this.registerYMap = function () { - AbstractNode.prototype.registerYMap.call(this); - that.getLabel().getValue().registerYType(); - attr.registerYMap(); - }; - - this.unregisterCallbacks = function () { - that.getAttribute("[attributes]").unregisterCallbacks(); - }; - - $node.find(".label").append(this.getLabel().get$node()); - - for (var attributeKey in _attributes) { - if (_attributes.hasOwnProperty(attributeKey)) { - _$attributeNode.append(_attributes[attributeKey].get$node()); - } - } - - this.setContextMenuItemCallback(function () { - return { - addShape: { - name: "Add Edge Shape", - callback: function () { - var canvas = that.getCanvas(), - appearance = that.getAppearance(); - - //noinspection JSAccessibilityCheck - canvas - .createNode( - EdgeShapeNode.TYPE, - appearance.left + appearance.width + 50, - appearance.top, - 150, - 100 - ) - .done(function (nodeId) { - canvas.createEdge( - BiDirAssociationEdge.TYPE, - that.getEntityId(), - nodeId - ); - }); - }, - disabled: function () { - var edges = that.getEdges(), - edge, - edgeId; - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if ( - (edge instanceof BiDirAssociationEdge && - ((edge.getTarget() === that && - edge.getSource() instanceof EdgeShapeNode) || - (edge.getSource() === that && - edge.getTarget() instanceof EdgeShapeNode))) || - (edge instanceof UniDirAssociationEdge && - edge.getTarget() instanceof EdgeShapeNode) - ) { - return true; - } - } - } - return false; - }, - }, - sepConvertTo: "---------", - convertTo: { - name: "Convert to..", - items: { - abstractNode: { - name: "..Abstract Class Node", - callback: function () { - var canvas = that.getCanvas(), - appearance = that.getAppearance(), - nodeId; - - //noinspection JSAccessibilityCheck - nodeId = canvas.createNode( - AbstractClassNode.TYPE, - appearance.left, - appearance.top, - appearance.width, - appearance.height, - that.getZIndex(), - that.toJSON() - ); - var edges = that.getOutgoingEdges(), - edge, - edgeId; - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - canvas.createEdge( - edge.getType(), - nodeId, - edge.getTarget().getEntityId(), - edge.toJSON() - ); - } - } - - edges = that.getIngoingEdges(); - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if (edge.getSource() !== edge.getTarget()) { - canvas.createEdge( - edge.getType(), - edge.getSource().getEntityId(), - nodeId, - edge.toJSON() - ); - } - } - } - - that.triggerDeletion(); - }, - }, - objectNode: { - name: "..Object Node", - callback: function () { - var canvas = that.getCanvas(), - appearance = that.getAppearance(), - nodeId; - - //noinspection JSAccessibilityCheck - nodeId = canvas.createNode( - ObjectNode.TYPE, - appearance.left, - appearance.top, - appearance.width, - appearance.height, - that.getZIndex(), - that.toJSON() - ); - var edges = that.getOutgoingEdges(), - edge, - edgeId; - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - canvas.createEdge( - edge.getType(), - nodeId, - edge.getTarget().getEntityId(), - edge.toJSON() - ); - } - } - - edges = that.getIngoingEdges(); - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if (edge.getSource() !== edge.getTarget()) { - canvas.createEdge( - edge.getType(), - edge.getSource().getEntityId(), - nodeId, - edge.toJSON() - ); - } - } - } - - that.triggerDeletion(); - }, - }, - relationshipGroupNode: { - name: "..Relationship Group", - callback: function () { - var canvas = that.getCanvas(), - appearance = that.getAppearance(), - nodeId; - - //noinspection JSAccessibilityCheck - nodeId = canvas.createNode( - RelationshipGroupNode.TYPE, - appearance.left, - appearance.top, - appearance.width, - appearance.height, - that.getZIndex(), - that.toJSON() - ); - var edges = that.getOutgoingEdges(), - edge, - edgeId; - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - canvas.createEdge( - edge.getType(), - nodeId, - edge.getTarget().getEntityId(), - edge.toJSON() - ); - } - } - - edges = that.getIngoingEdges(); - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if (edge.getSource() !== edge.getTarget()) { - canvas.createEdge( - edge.getType(), - edge.getSource().getEntityId(), - nodeId, - edge.toJSON() - ); - } - } - } - - that.triggerDeletion(); - }, - }, - }, - }, - sep: "---------", - }; - }); - } -} - -/** - * Abstract Class Node - * @class canvas_widget.EdgeShapeNode - * @extends canvas_widget.AbstractNode - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {number} zIndex Position of node on z-axis - */ -class EdgeShapeNode extends AbstractNode { - static TYPE = "Edge Shape"; - static DEFAULT_WIDTH = 150; - static DEFAULT_HEIGHT = 150; - - constructor(id, left, top, width, height, zIndex, json) { - super(id, EdgeShapeNode.TYPE, left, top, width, height, zIndex, json); - var that = this; - - /** - * jQuery object of node template - * @type {jQuery} - * @private - */ - var _$template = $(lodash.template(edgeShapeNodeHtml)({ type: that.getType() })); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = AbstractNode.prototype.get$node - .call(this) - .append(_$template) - .addClass("class"); - - /** - * jQuery object of DOM node representing the attributes - * @type {jQuery} - * @private - */ - var _$attributeNode = _$node.find(".attributes"); - - /** - * Attributes of node - * @type {Object} - * @private - */ - var _attributes = this.getAttributes(); - - /** - * Get JSON representation of the node - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractNode.prototype.toJSON.call(this); - json.type = EdgeShapeNode.TYPE; - return json; - }; - - var attrArrow = new SingleSelectionAttribute( - this.getEntityId() + "[arrow]", - "Arrow", - this, - { - bidirassociation: "---", - unidirassociation: "-->", - generalisation: "--▷", - diamond: "-◁▷", - } - ); - var attrShape = new SingleSelectionAttribute( - this.getEntityId() + "[shape]", - "Shape", - this, - { straight: "Straight", curved: "Curved", segmented: "Segmented" } - ); - var attrColor = new SingleColorValueAttribute( - this.getEntityId() + "[color]", - "Color", - this - ); - var attrOverlay = new SingleValueAttribute( - this.getEntityId() + "[overlay]", - "Overlay Text", - this - ); - var attrOverlayPos = new SingleSelectionAttribute( - this.getEntityId() + "[overlayPosition]", - "Overlay Position", - this, - { hidden: "Hide", top: "Top", center: "Center", bottom: "Bottom" } - ); - var attrOverlayRotate = new BooleanAttribute( - this.getEntityId() + "[overlayRotate]", - "Autoflip Overlay", - this - ); - - this.addAttribute(attrArrow); - this.addAttribute(attrShape); - this.addAttribute(attrColor); - this.addAttribute(attrOverlay); - this.addAttribute(attrOverlayPos); - this.addAttribute(attrOverlayRotate); - - this.registerYMap = function (map, disableYText) { - AbstractNode.prototype.registerYMap.call(this, map); - attrArrow.getValue().registerYType(); - attrShape.getValue().registerYType(); - attrOverlayPos.getValue().registerYType(); - attrOverlayRotate.getValue().registerYType(); - that.getLabel().getValue().registerYType(); - attrColor.getValue().registerYType(); - attrOverlay.getValue().registerYType(); - }; - - _$node.find(".label").append(this.getLabel().get$node()); - - for (var attributeKey in _attributes) { - if (_attributes.hasOwnProperty(attributeKey)) { - _$attributeNode.append(_attributes[attributeKey].get$node()); - } - } - } -} - -/** - * makeEdge - * @class canvas_widget.makeEdge - * @memberof canvas_widget - * @constructor - * @param {string} type Type of edge - * @param arrowType - * @param shapeType - * @param color - * @param dashstyle - * @param overlay - * @param overlayPosition - * @param overlayRotate - * @param attributes - * @returns {Edge} - */ -function makeEdge( - type, - arrowType, - shapeType, - color, - dashstyle, - overlay, - overlayPosition, - overlayRotate, - attributes -) { - var shape = shapes.hasOwnProperty(shapeType) - ? shapes[shapeType] - : lodash.values(shapes)[0]; - color = color - ? $colorTestElement.css("color", "#000000").css("color", color).css("color") - : "#000000"; - - /** - * Edge - * @class canvas_widget.Edge - * @extends canvas_widget.AbstractEdge - * @constructor - * @param {string} id Entity identifier of edge - * @param {canvas_widget.AbstractNode} source Source node - * @param {canvas_widget.AbstractNode} target Target node - */ - class Edge extends AbstractEdge { - constructor(id, source, target) { - super(id, type, source, target, overlayRotate); - var that = this; - - var currentViewType = null; - - /** - * Set the currently applied view type - * @param {string} type - */ - this.setCurrentViewType = function (type) { - currentViewType = type; - }; - - /** - * Get the currently applied view type - * @returns {string} the view type - */ - this.getCurrentViewType = function () { - return currentViewType; - }; - - /** - * Stores jsPlumb overlays for the edge - * @type {Array} - */ - var overlays = []; - - /** - * make jsPlumb overlay - * @param text - * @returns {Function} - */ - var makeOverlayFunction = function (text) { - return function () { - return $("
                          ").append( - $("
                          ") - .addClass("edge_label fixed") - .css("color", color) - .text(text) - ); - }; - }; - - /** - * make a jsPlumb overlay for a attribute - * @param attribute - * @returns {Function} - */ - var makeAttributeOverlayFunction = function (attribute) { - return function () { - const $node = $("
                          ").append( - $("
                          ").addClass("edge_label").append(attribute.get$node()) - ); - return $node.get(0); - }; - }; - var init = function () { - var attribute, attributeId, attrObj; - - if (Arrows().hasOwnProperty(arrowType)) { - overlays.push(Arrows(color)[arrowType]); - } - - if (overlay) { - switch (overlayPosition) { - case "top": - overlays.push({ - type: "Custom", - options: { - create: makeOverlayFunction(overlay), - location: 0.9, - id: "label", - }, - }); - break; - case "bottom": - overlays.push({ - type: "Custom", - options: { - create: makeOverlayFunction(overlay), - location: 0.1, - id: "label", - }, - }); - break; - default: - case "center": - overlays.push({ - type: "Custom", - options: { - create: makeOverlayFunction(overlay), - location: 0.5, - id: "label", - }, - }); - break; - } - } - - attrObj = {}; - for (attributeId in attributes) { - if (attributes.hasOwnProperty(attributeId)) { - attribute = attributes[attributeId]; - switch (attribute.value) { - case "boolean": - attrObj[attributeId] = new BooleanAttribute( - id + "[" + attribute.key.toLowerCase() + "]", - attribute.key, - that - ); - break; - case "string": - attrObj[attributeId] = new SingleValueAttribute( - id + "[" + attribute.key.toLowerCase() + "]", - attribute.key, - that - ); - break; - case "integer": - attrObj[attributeId] = new IntegerAttribute( - id + "[" + attribute.key.toLowerCase() + "]", - attribute.key, - that - ); - break; - case "file": - attrObj[attributeId] = new FileAttribute( - id + "[" + attribute.key.toLowerCase() + "]", - attribute.key, - that - ); - break; - default: - if (attribute.options) { - attrObj[attributeId] = new SingleSelectionAttribute( - id + "[" + attribute.key.toLowerCase() + "]", - attribute.key, - that, - attribute.options - ); - } - } - - switch (attribute.position) { - case "top": - overlays.push({ - type: "Custom", - options: { - create: makeAttributeOverlayFunction(attrObj[attributeId]), - location: 1, - id: "label " + attributeId, - }, - }); - break; - case "center": - overlays.push({ - type: "Custom", - options: { - create: makeAttributeOverlayFunction(attrObj[attributeId]), - location: 0.5, - id: "label " + attributeId, - }, - }); - break; - case "bottom": - overlays.push({ - type: "Custom", - options: { - create: makeAttributeOverlayFunction(attrObj[attributeId]), - location: 0, - id: "label " + attributeId, - }, - }); - break; - } - } - } - that.setAttributes(attrObj); - - overlays.push({ - type: "Custom", - options: { - create: function () { - that.get$overlay().hide().find(".type").addClass(shapeType); - return that.get$overlay().get(0); - }, - location: 0.5, - id: "label", - }, - }); - - if (overlay) { - that - .get$overlay() - .find("input[name='Label']") - .css("visibility", "hidden"); - } - - that.setDefaultPaintStyle({ - stroke: color, - strokeWidth: 4, - }); - }; - - /** - * Connect source and target node and draw the edge on canvas - */ - this.connect = function () { - var source = this.getSource(); - var target = this.getTarget(); - var connectOptions = { - source: source.get$node().get(0), - target: target.get$node().get(0), - paintStyle: that.getDefaultPaintStyle(), - endpoint: "Dot", - anchors: [source.getAnchorOptions(), target.getAnchorOptions()], - connector: shape, - overlays: overlays, - cssClass: this.getEntityId(), - }; - - if (source === target) { - connectOptions.anchors = ["TopCenter", "LeftMiddle"]; - } - - source.addOutgoingEdge(this); - target.addIngoingEdge(this); - this.setJsPlumbConnection( - window.jsPlumbInstance.connect(connectOptions) - ); - - this.repaintOverlays(); - lodash.each(EntityManagerInstance.getEdges(), function (e) { - e.setZIndex(); - }); - }; - - /** - * Get JSON representation of the edge - * @returns {object} - */ - this.toJSON = function () { - var json = AbstractEdge.prototype.toJSON.call(this); - json.type = type; - return json; - }; - - /** - * restyles the edge - * @param arrowType - * @param color - * @param shapeType - * @param dashstyle - * @param overlay - * @param overlayPosition - * @param overlayRotate - * @param attributes - */ - this.restyle = function ( - arrowType, - color, - shapeType, - dashstyle, - overlay, - overlayPosition, - overlayRotate, - attributes - ) { - overlays = []; - - color = color - ? $colorTestElement - .css("color", "black") - .css("color", color) - .css("color") - : "black"; - - if (Arrows().hasOwnProperty(arrowType)) { - overlays.push(Arrows(color)[arrowType]); - } - - if (overlay) { - switch (overlayPosition) { - case "top": - overlays.push({ - type: "Custom", - options: { - create: makeOverlayFunction(overlay), - location: 0.9, - id: "label", - }, - }); - break; - case "bottom": - overlays.push({ - type: "Custom", - options: { - create: makeOverlayFunction(overlay), - location: 0.1, - id: "label", - }, - }); - break; - default: - case "center": - overlays.push({ - type: "Custom", - options: { - create: makeOverlayFunction(overlay), - location: 0.5, - id: "label", - }, - }); - break; - } - } - - overlays.push({ - type: "Custom", - options: { - create: function () { - that.get$overlay().hide().find(".type").addClass(shapeType); - return that.get$overlay().get(0); - }, - location: 0.5, - id: "label", - }, - }); - - if (overlay) { - that - .get$overlay() - .find("input[name='Label']") - .css("visibility", "hidden"); - } - - for (var attributeId in attributes) { - if (attributes.hasOwnProperty(attributeId)) { - var attribute = attributes[attributeId]; - switch (attribute.position) { - case "top": - overlays.push({ - type: "Custom", - options: { - create: makeAttributeOverlayFunction( - that.getAttribute(attributeId) - ), - location: 1, - id: "label " + attributeId, - }, - }); - break; - case "center": - overlays.push({ - type: "Custom", - options: { - create: makeAttributeOverlayFunction( - that.getAttribute(attributeId) - ), - location: 0.5, - id: "label " + attributeId, - }, - }); - break; - case "bottom": - overlays.push({ - type: "Custom", - options: { - create: makeAttributeOverlayFunction( - that.getAttribute(attributeId) - ), - location: 0, - id: "label " + attributeId, - }, - }); - break; - } - } - } - - var paintStyle = { - strokeStyle: color, - lineWidth: 2, - dashstyle: dashstyle, - }; - - that.setDefaultPaintStyle(paintStyle); - that.setRotateOverlay(overlayRotate); - - if (that.getJsPlumbConnection()) { - //if the edge is drawn on the canvas - that.getJsPlumbConnection().removeAllOverlays(); - for (var i = 0; i < overlays.length; i++) { - that.getJsPlumbConnection().addOverlay(overlays[i]); - } - that.getJsPlumbConnection().setPaintStyle(paintStyle); - that.repaintOverlays(); - } - }; - - this.registerYMap = function () { - AbstractEdge.prototype.registerYMap.call(this); - - var attr = that.getAttributes(); - for (var key in attr) { - if (attr.hasOwnProperty(key)) { - var val = attr[key].getValue(); - if (val.hasOwnProperty("registerYType")) { - val.registerYType(); - } - } - } - }; - - init(); - } - /** - * Get the arrow type of the edge type - * @static - * @returns {*} - */ - static getArrowType() { - return arrowType; - } - /** - * Get the shape type of the edge type - * @static - * @returns {*} - */ - static getShapeType() { - return shapeType; - } - /** - * Get the color of the edge type - * @static - * @returns {*} - */ - static getShape() { - return shape; - } - static getColor() { - return color; - } - /** - * Get the overlay of the edge type - * @static - * @returns {*} - */ - static getOverlay() { - return overlay; - } - /** - * Get the overlay position of the edge type - * @static - * @returns {*} - */ - static getOverlayPosition() { - return overlayPosition; - } - /** - * Get the overlay rotate of the edge type - * @static - * @returns {*} - */ - static getOverlayRotate() { - return overlayRotate; - } - /** - * Get the attribute definition of the edge type - * @static - * @returns {*} - */ - static getAttributes() { - return attributes; - } - static getType() { - return type; - } - static getArrowOverlays() { - var overlays = []; - if (Arrows().hasOwnProperty(arrowType)) { - overlays.push(Arrows(color)[arrowType]); - } - return overlays; - } - } - - return Edge; -} - -/** - * AbstractNode - * @class canvas_widget.AbstractNode - * @extends canvas_widget.AbstractEntity - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of node - * @param {string} type Type of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {boolean} containment containment - * @param {number} zIndex Position of node on z-axis - */ - -/** - * Abstract Class Node - * @class canvas_widget.RelationshipGroupNode - * @extends canvas_widget.AbstractNode - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {number} zIndex Position of node on z-axis - */ -class RelationshipGroupNode extends AbstractNode { - static TYPE = "Relation"; - static DEFAULT_WIDTH = 150; - static DEFAULT_HEIGHT = 100; - constructor(id, left, top, width, height, zIndex) { - super(id, RelationshipGroupNode.TYPE, left, top, width, height, zIndex); - var that = this; - - /** - * jQuery object of node template - * @type {jQuery} - * @private - */ - var _$template = $( - lodash.template(relationshipGroupNodeHtml)({ type: that.getType() }) - ); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = AbstractNode.prototype.get$node - .call(this) - .append(_$template) - .addClass("class"); - - /** - * jQuery object of DOM node representing the attributes - * @type {jQuery} - * @private - */ - var _$attributeNode = _$node.find(".attributes"); - - /** - * Attributes of node - * @type {Object} - * @private - */ - var _attributes = this.getAttributes(); - - /** - * Get JSON representation of the node - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractNode.prototype.toJSON.call(this); - json.type = RelationshipGroupNode.TYPE; - return json; - }; - - this.registerYMap = function () { - AbstractNode.prototype.registerYMap.call(this); - that.getLabel().getValue().registerYType(); - }; - - _$node.find(".label").append(this.getLabel().get$node()); - - for (var attributeKey in _attributes) { - if (_attributes.hasOwnProperty(attributeKey)) { - _$attributeNode.append(_attributes[attributeKey].get$node()); - } - } - } -} - -/** - * SelectionValue - * @class canvas_widget.SelectionValue - * @extends canvas_widget.AbstractValue - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier - * @param {string} name Name of attribute - * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {canvas_widget.AbstractNode|canvas_widget.AbstractEdge} rootSubjectEntity Topmost entity in the chain of entity the attribute is assigned to - * @param {Object} options Selection options - */ -class SelectionValue extends AbstractValue { - constructor( - id, - name, - subjectEntity, - rootSubjectEntity, - options, - useAttributeHtml - ) { - super(id, name, subjectEntity, rootSubjectEntity); - - var that = this; - - useAttributeHtml = - typeof useAttributeHtml !== "undefinded" ? useAttributeHtml : false; - - /** - * Value - * @type {string} - * @private - */ - var _value = lodash.keys(options)[0]; - - if (useAttributeHtml) { - selectionValueHtml = attributeSelectionValueHtml; - } - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = $( - lodash.template(selectionValueHtml)({ - name: name, - options: options, - }) - ); - - if (useAttributeHtml) { - _$node.off(); - } - - /** - * Inter widget communication wrapper - * @type {Object} - * @private - */ - y = y || window.y; - var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); - - /** - * Apply a Value Change Operation - * @param {operations.ot.ValueChangeOperation} operation - */ - var processValueChangeOperation = function (operation) { - that.setValue(operation.getValue()); - }; - - /** - * Set value - * @param {string} value - */ - this.setValue = function (value) { - _value = value; - if (useAttributeHtml) { - _$node.val(value); - if (value == "Quiz") { - Object.values(rootSubjectEntity.getAttributes()).forEach((value) => { - if (value instanceof QuizAttribute) { - value.showTable(); - } - }); - } else - Object.values(rootSubjectEntity.getAttributes()).forEach((value) => { - if (value instanceof QuizAttribute) { - value.hideTable(); - } - }); - } else _$node.text(options[value]); - }; - - /** - * Get value - * @returns {string} - */ - this.getValue = function () { - return _value; - }; - - /** - * Get jQuery object of DOM node representing the value - * @returns {jQuery} - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the edge - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractValue.prototype.toJSON.call(this); - json.value = _value; - return json; - }; - - /** - * Set value by its JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - this.setValue(json.value); - }; - - this.registerYType = function () { - //observer - that - .getRootSubjectEntity() - .getYMap() - .observeDeep(function ([event]) { - const array = Array.from(event.changes.keys.entries()); - array.forEach(([key, change]) => { - const updated = event.currentTarget.get(key); - if ( - updated?.type !== "update" || - !(updated?.entityId === that.getEntityId()) - ) - return; - var operation = new ValueChangeOperation( - updated.entityId, - updated.value, - updated.type, - updated.position, - updated.jabberId - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.getOTOperation() - ); - processValueChangeOperation(operation); - - //Only the local user Propagates the activity and saves the state of the model - if ( - _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID] === - operation.getJabberId() - ) { - const activityMap = y.getMap("activity"); - - activityMap.set( - ActivityOperation.TYPE, - new ActivityOperation( - "ValueChangeActivity", - that.getEntityId(), - _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], - ValueChangeOperation.getOperationDescription( - that.getSubjectEntity().getName(), - that.getRootSubjectEntity().getType(), - that.getRootSubjectEntity().getLabel().getValue().getValue() - ), - { - value: operation.getValue(), - subjectEntityName: that.getSubjectEntity().getName(), - rootSubjectEntityType: that - .getRootSubjectEntity() - .getType(), - rootSubjectEntityId: that - .getRootSubjectEntity() - .getEntityId(), - } - ).toJSON() - ); - - //its a view type and create a reference to the origin - if (updated.entityId.indexOf("[target]") != -1) { - ViewTypesUtil.createReferenceToOrigin( - that.getRootSubjectEntity() - ); - //CVG - Promise.resolve().then(function () { return ClosedViewGeneration; }).then(function (CVG) { - CVG(rootSubjectEntity); - }); - } - //trigger the save - EntityManagerInstance.storeDataYjs(); - } else { - //the remote users propagtes the change to their local attribute widget - //TODO(PENDING): can be replaced with yjs as well - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.ATTRIBUTE, - operation.getOTOperation() - ); - } - }); - }); - }; - } -} - -/** - * IntegerAttribute - * @class canvas_widget.IntegerAttribute - * @extends canvas_widget.AbstractAttribute - * @memberof canvas_widget - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to - */ -class IntegerAttribute extends AbstractAttribute { - constructor(id, name, subjectEntity, useAttributeHtml) { - super(id, name, subjectEntity); - useAttributeHtml = - typeof useAttributeHtml !== "undefined" ? useAttributeHtml : false; - - /*** - * Value object of value - * @type {canvas_widget.IntegerValue} - * @private - */ - var _value = new IntegerValue( - id, - name, - this, - this.getRootSubjectEntity(), - useAttributeHtml - ); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(integerAttributeHtml)()); - - /** - * Set Value object of value - * @param {canvas_widget.IntegerValue} value - */ - this.setValue = function (value) { - _value = value; - _$node.val(value); - }; - - /** - * Get Value object of value - * @return {canvas_widget.IntegerValue} value - */ - this.getValue = function () { - return _value; - }; - - /** - * jQuery object of DOM node representing the attribute - * @type {jQuery} - * @private - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the attribute - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.value = _value.toJSON(); - return json; - }; - - /** - * Set attribute value by its JSON representation - * @param {Object} json - */ - this.setValueFromJSON = function (json) { - _value.setValueFromJSON(json.value); - }; - - _$node.find(".name").text(this.getName()); - _$node.find(".value").append(_value.get$node()); - } -} - -/** - * SingleSelectionAttribute - * @class canvas_widget.SingleSelectionAttribute - * @extends canvas_widget.AbstractAttribute - * @memberof canvas_widget - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {Object} options Selection options as key value object - */ - -class SingleSelectionAttribute extends AbstractAttribute { - constructor(id, name, subjectEntity, options, useAttributeHtml) { - super(id, name, subjectEntity); - useAttributeHtml = - typeof useAttributeHtml !== "undefinded" ? useAttributeHtml : false; - var that = this; - /*** - * Value object of value - * @type {canvas_widget.SelectionValue} - * @private - */ - var _value = new SelectionValue( - id, - name, - this, - this.getRootSubjectEntity(), - options, - useAttributeHtml - ); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(singleSelectionAttributeHtml)()); - - /** - * Set Value object of value - * @param {canvas_widget.SelectionValue} value - */ - this.setValue = function (value) { - _value = value; - _$node.val(value); - }; - - /** - * Get Value object of value - * @return {canvas_widget.SelectionValue} value - */ - this.getValue = function () { - return _value; - }; - - /** - * jQuery object of DOM node representing the attribute - * @type {jQuery} - * @private - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get the options object for the Attribute - * @returns {Object} - */ - this.getOptionValue = function () { - return options.hasOwnProperty(_value.getValue()) - ? options[_value.getValue()] - : null; - }; - - /** - * Get JSON representation of the attribute - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.value = _value.toJSON(); - json.option = that.getOptionValue(); - return json; - }; - - this.getOptions = function () { - return options; - }; - - /** - * Set attribute value by its JSON representation - * @param {Object} json - */ - this.setValueFromJSON = function (json) { - _value.setValueFromJSON(json.value); - }; - - _$node.find(".name").text(this.getName()); - _$node.find(".value").append(_value.get$node()); - } -} - -/** - * IntegerValue - * @class canvas_widget.IntegerValue - * @extends canvas_widget.AbstractValue - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier - * @param {string} name Name of attribute - * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {canvas_widget.AbstractNode|canvas_widget.AbstractEdge} rootSubjectEntity Topmost entity in the chain of entity the attribute is assigned to - */ -class IntegerValue extends AbstractValue { - constructor(id, name, subjectEntity, rootSubjectEntity, useAttributeHtml) { - super(id, name, subjectEntity, rootSubjectEntity); - var that = this; - - if (useAttributeHtml) integerValueHtml = attributeIntegerValueHtml; - - /** - * Value - * @type {number} - * @private - */ - var _value = 0; - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(integerValueHtml)({ value: _value })); - - /** - * Inter widget communication wrapper - * @type {Object} - * @private - */ - y = y || window.y; - var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); - - /** - * Apply a Value Change Operation - * @param {operations.ot.ValueChangeOperation} operation - */ - var processValueChangeOperation = function (operation) { - that.setValue(operation.getValue()); - }; - - var init = function () { - _$node.off(); - }; - - /** - * Set value - * @param {number} value - */ - this.setValue = function (value) { - _value = value; - if (useAttributeHtml) _$node.val(value); - else _$node.text(value); - }; - - /** - * Get value - * @returns {number} - */ - this.getValue = function () { - return _value; - }; - - /** - * Get jQuery object of DOM node representing the value - * @returns {jQuery} - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the edge - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractValue.prototype.toJSON.call(this); - json.value = _value; - return json; - }; - - /** - * Set value by its JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - this.setValue(json?.value); - }; - - this.registerYType = function () { - //observer - that - .getRootSubjectEntity() - .getYMap() - .observe(function (event) { - const array = Array.from(event.changes.keys.entries()); - array.forEach(([key, change]) => { - if (change.action !== "update") return; - // check if key is the entity id - if (key !== that.getEntityId()) return; - const data = event.target.get(key); - var operation = new ValueChangeOperation( - data.entityId, - data.value, - data.type, - data.position, - data.jabberId - ); - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.GUIDANCE, - operation.getOTOperation() - ); - processValueChangeOperation(operation); - - //Only the local user Propagates the activity - if ( - _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID] === - operation.getJabberId() - ) { - EntityManagerInstance.storeDataYjs(); - const activityMap = y.getMap("activity"); - - activityMap.set( - ActivityOperation.TYPE, - new ActivityOperation( - "ValueChangeActivity", - that.getEntityId(), - _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], - ValueChangeOperation.getOperationDescription( - that.getSubjectEntity().getName(), - that.getRootSubjectEntity().getType(), - that.getRootSubjectEntity().getLabel().getValue().getValue() - ), - { - value: operation.getValue(), - subjectEntityName: that.getSubjectEntity().getName(), - rootSubjectEntityType: that - .getRootSubjectEntity() - .getType(), - rootSubjectEntityId: that - .getRootSubjectEntity() - .getEntityId(), - } - ).toJSON() - ); - } else { - //the remote users propagtes the change to their local attribute widget - //TODO(PENDING): can be replaced with yjs as well - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.ATTRIBUTE, - operation.getOTOperation() - ); - } - }); - }); - }; - - init(); - } -} - -/** - * SingleValueAttribute - * @class canvas_widget.SingleValueAttribute - * @extends canvas_widget.AbstractAttribute - * @memberof canvas_widget - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to - */ -class SingleValueAttribute extends AbstractAttribute { - value; - constructor(id, name, subjectEntity, y) { - y = y || window.y; - if (!y) { - throw new Error("y is undefined"); - } - super(id, name, subjectEntity); - - /*** - * Value object of value - * @type {canvas_widget.Value} - * @private - */ - var _value = new Value(id, name, this, this.getRootSubjectEntity(), y); - this.value = _value; - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(canvasSingleValueAttributeHtml)()); - - /** - * Set Value object of value - * @param {canvas_widget.Value} value - */ - this.setValue = function (value) { - _value = value; - this.value = value; - }; - - /** - * Get Value object of value - * @returns {canvas_widget.Value} - */ - this.getValue = function () { - return _value; - }; - - /** - * jQuery object of DOM node representing the attribute - * @type {jQuery} - * @private - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the attribute - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.value = _value.toJSON(); - return json; - }; - - /** - * Set attribute value by its JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - _value.setValueFromJSON(json.value); - }; - - this.registerYType = function () { - _value.registerYType(); - }; - - _$node.find(".name").text(this.getName()); - _$node.find(".value").append(_value.get$node()); - } -} - -/** - * SingleValueListAttribute - * @class canvas_widget.SingleValueListAttribute - * @extends canvas_widget.AbstractAttribute - * @memberof canvas_widget - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to - */ -class SingleValueListAttribute extends AbstractAttribute { - static TYPE = "SingleValueListAttribute"; - constructor(id, name, subjectEntity) { - super(id, name, subjectEntity); - var that = this; - - /** - * List of attributes - * @type {Object} - * @private - */ - var _list = {}; - - /** - * jQuery object of DOM node representing the attribute - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(singleValueListAttributeHtml)()); - y = y || window.y; - /** - * Inter widget communication wrapper - * @type {Object} - */ - var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); - - /** - * Apply an Attribute Add Operation - * @param {operations.ot.AttributeAddOperation} operation - */ - var processAttributeAddOperation = function (operation) { - var attribute = new SingleValueAttribute( - operation.getEntityId() + "[value]", - "Attribute", - that - ); - attribute.registerYType(); - that.addAttribute(attribute); - _$node.find(".list").append(attribute.get$node()); - }; - - /** - * Apply an Attribute Delete Operation - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var processAttributeDeleteOperation = function (operation) { - var attribute = that.getAttribute(operation.getEntityId()); - if (attribute) { - that.deleteAttribute(attribute.getEntityId()); - attribute.get$node().remove(); - } - }; - /** - * Propagate an Attribute Add Operation to the remote users and the local widgets - * @param {operations.ot.AttributeAddOperation} operation - */ - var propagateAttributeAddOperation = function (operation) { - processAttributeAddOperation(operation); - EntityManagerInstance.storeDataYjs(); - }; - - /** - * Propagate an Attribute Delete Operation to the remote users and the local widgets - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var propagateAttributeDeleteOperation = function (operation) { - processAttributeDeleteOperation(operation); - var ynode = that.getRootSubjectEntity().getYMap(); - ynode.delete(operation.getEntityId()); - EntityManagerInstance.storeDataYjs(); - }; - - /** - * Callback for a remote Attrbute Add Operation - * @param {operations.ot.AttributeAddOperation} operation - */ - var remoteAttributeAddCallback = function (operation) { - if ( - operation instanceof AttributeAddOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - processAttributeAddOperation(operation); - } - }; - - /** - * Callback for a remote Attribute Delete Operation - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var remoteAttributeDeleteCallback = function (operation) { - if ( - operation instanceof AttributeDeleteOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - processAttributeDeleteOperation(operation); - } - }; - - var localAttributeAddCallback = function (operation) { - if ( - operation instanceof AttributeAddOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - propagateAttributeAddOperation(operation); - } - }; - - /** - * Callback for a local Attribute Delete Operation - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var localAttributeDeleteCallback = function (operation) { - if ( - operation instanceof AttributeDeleteOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - propagateAttributeDeleteOperation(operation); - } - }; - - /** - * Add attribute to attribute list - * @param {canvas_widget.AbstractAttribute} attribute - */ - this.addAttribute = function (attribute) { - var id = attribute.getEntityId(); - if (!_list.hasOwnProperty(id)) { - _list[id] = attribute; - } - }; - - /** - * Get attribute of attribute list by its entity id - * @param id - * @returns {canvas_widget.AbstractAttribute} - */ - this.getAttribute = function (id) { - if (_list.hasOwnProperty(id)) { - return _list[id]; - } - return null; - }; - - /** - * Delete attribute from attribute list by its entity id - * @param {string} id - */ - this.deleteAttribute = function (id) { - if (_list.hasOwnProperty(id)) { - delete _list[id]; - } - }; - - /** - * Get attribute list - * @returns {Object} - */ - this.getAttributes = function () { - return _list; - }; - - /** - * Set attribute list - * @param {Object} list - */ - this.setAttributes = function (list) { - _list = list; - }; - - /** - * Get jQuery object of the DOM node representing the attribute (list) - * @returns {jQuery} - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the attribute (list) - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.type = SingleValueListAttribute.TYPE; - var attr = {}; - lodash.forEach(this.getAttributes(), function (val, key) { - attr[key] = val.toJSON(); - }); - json.list = attr; - return json; - }; - - /** - * Set attribute list by its JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - lodash.forEach(json.list, function (val, key) { - var attribute = new SingleValueAttribute(key, key, that, y); - attribute.setValueFromJSON(json.list[key]); - that.addAttribute(attribute); - _$node.find(".list").append(attribute.get$node()); - }); - }; - - /** - * Register inter widget communication callbacks - */ - this.registerCallbacks = function () { - _iwcw.registerOnDataReceivedCallback(localAttributeAddCallback); - _iwcw.registerOnDataReceivedCallback(localAttributeDeleteCallback); - }; - - /** - * Unregister inter widget communication callbacks - */ - this.unregisterCallbacks = function () { - _iwcw.unregisterOnDataReceivedCallback(localAttributeAddCallback); - _iwcw.unregisterOnDataReceivedCallback(localAttributeDeleteCallback); - }; - - _$node.find(".name").text(this.getName()); - - for (var attributeId in _list) { - if (_list.hasOwnProperty(attributeId)) { - _$node.find(".list").append(_list[attributeId].get$node()); - } - } - - if (_iwcw) { - that.registerCallbacks(); - } - this.registerYMap = function (disableYText) { - var ymap = that.getRootSubjectEntity().getYMap(); - - var attrs = that.getAttributes(); - for (var key in attrs) { - if (attrs.hasOwnProperty(key)) { - var attr = attrs[key]; - attr.getValue().registerYType(); - } - } - - ymap.observe(function (event) { - var operation; - - const array = Array.from(event.changes.keys.entries()); - array.forEach(([key, change]) => { - if (key.indexOf("[value]") != -1) { - switch (change.action) { - case "add": { - if (event.currentTarget.get("modifiedBy") === window.y.clientID) - return; - - operation = new AttributeAddOperation( - key.replace(/\[\w*\]/g, ""), - that.getEntityId(), - that.getRootSubjectEntity().getEntityId(), - that.constructor.name - ); - remoteAttributeAddCallback(operation); - break; - } - case "delete": { - operation = new AttributeDeleteOperation( - key, - that.getEntityId(), - that.getRootSubjectEntity().getEntityId(), - that.constructor.name - ); - remoteAttributeDeleteCallback(operation); - } - } - } - }); - }); - }; - } -} - -/** - * Value - * @class canvas_widget.Value - * @extends canvas_widget.AbstractValue - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier - * @param {string} name Name of attribute - * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {canvas_widget.AbstractNode|canvas_widget.AbstractEdge} rootSubjectEntity Topmost entity in the chain of entity the attribute is assigned to - */ -class Value extends AbstractValue { - value = ""; - constructor(id, name, subjectEntity, rootSubjectEntity, y) { - super(id, name, subjectEntity, rootSubjectEntity); - y = y || window.y; - if (!y) throw new Error("y is undefined"); - IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); - var _ytext = null; - - const yMap = rootSubjectEntity.getYMap(); - if (!yMap) { - throw new Error("yMap is undefined"); - } - y.transact(() => { - if (yMap?.has(id)) { - _ytext = rootSubjectEntity.getYMap().get(id); - if (!(_ytext instanceof Text)) { - _ytext = new Text(); - rootSubjectEntity.getYMap().set(id, _ytext); - } - } else { - _ytext = new Text(); - rootSubjectEntity.getYMap().set(id, _ytext); - } - rootSubjectEntity.getYMap().set("modifiedBy", window.y.clientID); - }); - - var that = this; - /** - * Value - * @type {string} - * @private - */ - var _value = ""; - this.value = _value; - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(valueHtml)({ name: name })); - - /** - * Set value - * @param {string} value - */ - this.setValue = function (value) { - _value = value; - _$node.val(value).trigger("blur"); - - this.value = _ytext.toString(); - }; - - /** - * Get value - * @returns {string} - */ - this.getValue = function () { - return _value; - }; - - /** - * Get jQuery object of DOM node representing the value - * @returns {jQuery} - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the edge - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractValue.prototype.toJSON.call(this); - json.value = _value; - return json; - }; - - /** - * Set value by its JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - this.setValue(json.value); - }; - - this.registerYType = function () { - _ytext.observe( - lodash.debounce(function (event) { - _value = _ytext.toString().replace(/\n/g, ""); - that.setValue(_value); - if (event.currentTarget.get("modifiedBy") === window.y.clientID) { - EntityManagerInstance.storeDataYjs(); - const userMap = y.getMap("users"); - const jabberId = userMap.get(event.currentTarget.doc.clientID); - - const activityMap = y.getMap("activity"); - activityMap.set( - ActivityOperation.TYPE, - new ActivityOperation( - "ValueChangeActivity", - that.getEntityId(), - jabberId, - ValueChangeOperation.getOperationDescription( - that.getSubjectEntity().getName(), - that.getRootSubjectEntity().getType(), - that.getRootSubjectEntity().getLabel().getValue().getValue() - ), - { - value: _value, - subjectEntityName: that.getSubjectEntity().getName(), - rootSubjectEntityType: that.getRootSubjectEntity().getType(), - rootSubjectEntityId: that - .getRootSubjectEntity() - .getEntityId(), - } - ).toJSON() - ); - } - }, 500) - ); - }; - - this.getYText = function () { - return _ytext; - }; - - //automatically determines the size of input - _$node - .autoGrowInput({ - comfortZone: 10, - minWidth: 40, - maxWidth: 1000, - }) - .trigger("blur"); - } -} - -/** - * QuizAttribute - * @class attribute_widget.SingleValueAttribute - * @memberof attribute_widget - * @extends attribute_widget.AbstractAttribute - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {attribute_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to - */ -class QuizAttribute extends AbstractAttribute { - constructor(id, name, subjectEntity) { - super(id, name, subjectEntity); - /*** - * Value object of value - * @type {attribute_widget.Value} - * @private - */ - var _value = new Value(id, name, this, this.getRootSubjectEntity()); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(singleQuizAttributeHtml)({ id: id })); - - /** - * Set Value object of value - * @param {attribute_widget.Value} value - */ - this.setValue = function (value) { - _value = value; - }; - - /** - * Get Value object of value - * @returns {attribute_widget.Value} - */ - this.getValue = function () { - return _value; - }; - - /** - * jQuery object of DOM node representing the attribute - * @type {jQuery} - * @public - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the attribute - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.value = _value.toJSON(); - return json; - }; - - /** - * Set attribute value by its JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - _value.setValueFromJSON(json.value); - }; - - this.registerYType = function () { - _value.registerYType(); - }; - - _$node.find(".name").text(this.getName()); - _$node.find(".value").append(_value.get$node()); - - function addRow() { - var table = _$node.find("#table")[0]; - var rows = table.rows.length; - var row = table.insertRow(table.rows.length); - var cell0 = row.insertCell(0); - var cell1 = row.insertCell(1); - var cell2 = row.insertCell(2); - var cell3 = row.insertCell(3); - var input0 = document.createElement("input"); - var input1 = document.createElement("input"); - var input2 = document.createElement("input"); - var input3 = document.createElement("input"); - input0.id = rows + "0"; - input1.id = rows + "1"; - input2.id = rows + "2"; - input3.id = rows + "3"; - input1.type = "text"; - input2.type = "text"; - input3.type = "text"; - cell0.appendChild(input0); - cell1.appendChild(input1); - cell2.appendChild(input2); - cell3.appendChild(input3); - } - - this.showTable = function () { - _$node.find("#table")[0].style.visibility = "visible"; - _$node.find("#b")[0].style.visibility = "visible"; - _$node.find("#c")[0].style.visibility = "visible"; - _$node.find("#submit")[0].style.visibility = "visible"; - _$node.find("#display")[0].style.visibility = "visible"; - }; - - this.hideTable = function () { - _$node.find("#table")[0].style.visibility = "hidden"; - _$node.find("#b")[0].style.visibility = "hidden"; - _$node.find("#c")[0].style.visibility = "hidden"; - _$node.find("#submit")[0].style.visibility = "hidden"; - _$node.find("#display")[0].style.visibility = "hidden"; - }; - - _$node.find("#b").click(function () { - addRow(); - }); - - // remove rows from table - _$node.find("#c").click(function () { - var table = _$node.find("#table")[0]; - var rows = table.rows.length; - table.deleteRow(rows - 1); - }); - - // write table input into attribute field - _$node.find("#submit").click(function () { - var table = _$node.find("#table")[0]; - var Json = {}; - Json["topic"] = _$node.find("#topic")[0].value; - var Sequence = []; - var Questions = []; - var Intents = []; - var Hints = []; - var row = table.rows.length; - for (var i = 2; i < row; i++) { - if ( - _$node.find("#" + i.toString() + "1")[0].value == "" || - _$node.find("#" + i.toString() + "2")[0].value == "" - ) { - continue; - } - Sequence.push(_$node.find("#" + i.toString() + "0")[0].value); - Questions.push(_$node.find("#" + i.toString() + "1")[0].value); - Intents.push(_$node.find("#" + i.toString() + "2")[0].value); - if (_$node.find("#" + i.toString() + "3")[0].value == "") { - Hints.push("No Hint Available for this Question"); - } else Hints.push(_$node.find("#" + i.toString() + "3")[0].value); - } - Json["Questions"] = Questions; - Json["Sequence"] = Sequence; - Json["Intents"] = Intents; - Json["Hints"] = Hints; - console.log(JSON.stringify(Json)); - _$node.find(".val")[0].value = JSON.stringify(Json); - var field = _$node.find(".val")[0]; - field.dispatchEvent(new Event("input")); - }); - - // take content from attribute field and display as table - _$node.find("#display").click(function () { - var table = _$node.find("#table")[0]; - var Json = _$node.find(".val")[0].value; - console.log(Json); - var content = JSON.parse(Json); - _$node.find("#topic")[0].value = content.topic; - var rowNumb = content.Questions.length; - console.log(rowNumb); - var currRows = table.rows.length - 2; - console.log(currRows); - if (currRows < rowNumb) { - for (currRows; currRows < rowNumb; currRows++) { - addRow(); - } - } - for (var i = 2; i < rowNumb + 2; i++) { - if (_$node.find("#" + i.toString() + "0")[0].value == null) { - break; - } - _$node.find("#" + i.toString() + "0")[0].value = - content.Sequence[i - 2]; - _$node.find("#" + i.toString() + "1")[0].value = - content.Questions[i - 2]; - _$node.find("#" + i.toString() + "2")[0].value = content.Intents[i - 2]; - _$node.find("#" + i.toString() + "3")[0].value = content.Hints[i - 2]; - } - }); - } -} - -/** - * KeySelectionValueAttribute - * @class canvas_widget.KeySelectionValueAttribute - * @extends canvas_widget.AbstractAttribute - * @memberof canvas_widget - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {Object} options Selection options - */ -class KeySelectionValueAttribute extends AbstractAttribute { - constructor(id, name, subjectEntity, options) { - super(id, name, subjectEntity); - - var _ymap = null; - - //noinspection UnnecessaryLocalVariableJS - /** - * Selection options - * @type {Object} - * @private - */ - var _options = options; - - /** - * Value object of key - * @type {canvas_widget.Value} - * @private - */ - var _key = new Value(id + "[key]", "", this, this.getRootSubjectEntity()); - - /*** - * Value object of value - * @type {canvas_widget.Value} - * @private - */ - var _value = new SelectionValue( - id + "[value]", - "", - this, - this.getRootSubjectEntity(), - _options - ); - - /** - * jQuery object of the DOM node representing the attribute - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(keySelectionValueAttributeHtml)({ id: id })); - - //noinspection JSUnusedGlobalSymbols - /** - * Set Value object of key - * @param {canvas_widget.Value} key - */ - this.setKey = function (key) { - _key = key; - }; - - /** - * Get Value object of key - * @returns {canvas_widget.Value} - */ - this.getKey = function () { - return _key; - }; - - /** - * Set Value object of value - * @param {canvas_widget.Value} value - */ - this.setValue = function (value) { - _value = value; - }; - - /** - * Get Value object of value - * @returns {canvas_widget.Value} - */ - this.getValue = function () { - return _value; - }; - - /** - * Get jQuery object of the DOM node representing the attribute - * @returns {jQuery} - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the attribute - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.key = _key.toJSON(); - json.value = _value.toJSON(); - return json; - }; - - /** - * Set value of key and value by their JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - _key.setValueFromJSON(json.key); - _value.setValueFromJSON(json.value); - }; - - this.registerYMap = function () { - _key.registerYType(); - _value.registerYType(); - }; - - this.getYMap = function () { - return _ymap; - }; - - _$node.find(".key").append(_key.get$node()); - _$node.find(".value").append(_value.get$node()); - } -} - -/** - * ConditionListAttribute - * @class canvas_widget.ConditionListAttribute - * @extends canvas_widget.AbstractAttribute - * @memberof canvas_widget - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {Object} options Selection options - * @param {Object} options2 Selection options - */ -class ConditionListAttribute extends AbstractAttribute { - static TYPE = "ConditionListAttribute"; - constructor(id, name, subjectEntity, options, options2, y) { - y = y || window.y; - super(id, name, subjectEntity); - var that = this; - - /** - * Selection options - * @type {Object} - * @private - */ - var _options = options; - - /** - * Selection options - * @type {Object} - * @private - */ - var _options2 = options2; - - /** - * List of attributes - * @type {Object} - * @private - */ - var _list = {}; - - /** - * jQuery object of DOM node representing the attribute - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(listHtml)()); - - /** - * Inter widget communication wrapper - * @type {Object} - */ - var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); - - /** - * Apply an Attribute Add Operation - * @param {operations.ot.AttributeAddOperation} operation - * @param {YText} ytext - */ - var processAttributeAddOperation = function (operation) { - var attribute = new ConditionPredicateAttribute( - operation.getEntityId(), - "Attribute", - that, - _options, - _options2 - ); - attribute.registerYMap(); - that.addAttribute(attribute); - _$node.find(".list").append(attribute.get$node()); - }; - - /** - * Propagate an Attribute Add Operation to the remote users and the local widgets - * @param {operations.ot.AttributeAddOperation} operation - */ - var propagateAttributeAddOperation = function (operation) { - processAttributeAddOperation(operation); - EntityManagerInstance.storeDataYjs(); - }; - - /** - * Apply an Attribute Delete Operation - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var processAttributeDeleteOperation = function (operation) { - var attribute = that.getAttribute(operation.getEntityId()); - if (attribute) { - that.deleteAttribute(attribute.getEntityId()); - attribute.get$node().remove(); - } - EntityManagerInstance.storeDataYjs(); - }; - - /** - * Propagate an Attribute Delete Operation to the remote users and the local widgets - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var propagateAttributeDeleteOperation = function (operation) { - processAttributeDeleteOperation(operation); - var ymap = that.getRootSubjectEntity().getYMap(); - ymap.delete(operation.getEntityId() + "[val]"); - }; - - /** - * Callback for a remote Attrbute Add Operation - * @param {operations.ot.AttributeAddOperation} operation - */ - var remoteAttributeAddCallback = function (operation) { - if ( - operation instanceof AttributeAddOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - processAttributeAddOperation(operation); - } - }; - - /** - * Callback for a remote Attribute Delete Operation - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var remoteAttributeDeleteCallback = function (operation) { - if ( - operation instanceof AttributeDeleteOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - processAttributeDeleteOperation(operation); - } - }; - - /** - * Callback for a local Attribute Add Operation - * @param {operations.ot.AttributeAddOperation} operation - */ - var localAttributeAddCallback = function (operation) { - if ( - operation instanceof AttributeAddOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - propagateAttributeAddOperation(operation); - } - }; - - /** - * Callback for a local Attribute Delete Operation - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var localAttributeDeleteCallback = function (operation) { - if ( - operation instanceof AttributeDeleteOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - propagateAttributeDeleteOperation(operation); - } - }; - - /** - * Add attribute to attribute list - * @param {canvas_widget.AbstractAttribute} attribute - */ - this.addAttribute = function (attribute) { - var id = attribute.getEntityId(); - if (!_list.hasOwnProperty(id)) { - _list[id] = attribute; - } - }; - - /** - * Get attribute of attribute list by its entity id - * @param id - * @returns {canvas_widget.AbstractAttribute} - */ - this.getAttribute = function (id) { - if (_list.hasOwnProperty(id)) { - return _list[id]; - } - return null; - }; - - /** - * Delete attribute from attribute list by its entity id - * @param {string} id - */ - this.deleteAttribute = function (id) { - if (_list.hasOwnProperty(id)) { - delete _list[id]; - } - }; - - /** - * Get attribute list - * @returns {Object} - */ - this.getAttributes = function () { - return _list; - }; - - /** - * Set attribute list - * @param {Object} list - */ - this.setAttributes = function (list) { - _list = list; - }; - - /** - * Get jQuery object of the DOM node representing the attribute (list) - * @returns {jQuery} - */ - this.get$node = function () { - return _$node; - }; - - this.setOptions = function (options) { - _options = options; - }; - - /** - * Get JSON representation of the attribute (list) - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.type = ConditionListAttribute.TYPE; - var attr = {}; - lodash.forEach(this.getAttributes(), function (val, key) { - attr[key] = val.toJSON(); - }); - json.list = attr; - return json; - }; - - /** - * Set attribute list by its JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - lodash.forEach(json.list, function (val, key) { - var attribute = new ConditionPredicateAttribute( - key, - key, - that, - _options, - _options2 - ); - attribute.setValueFromJSON(json.list[key]); - that.addAttribute(attribute); - _$node.find(".list").append(attribute.get$node()); - }); - }; - - /** - * Register inter widget communication callbacks - */ - this.registerCallbacks = function () { - _iwcw.registerOnDataReceivedCallback(localAttributeAddCallback); - _iwcw.registerOnDataReceivedCallback(localAttributeDeleteCallback); - }; - - /** - * Unregister inter widget communication callbacks - */ - this.unregisterCallbacks = function () { - _iwcw.unregisterOnDataReceivedCallback(localAttributeAddCallback); - _iwcw.unregisterOnDataReceivedCallback(localAttributeDeleteCallback); - }; - - _$node.find(".name").text(this.getName()); - - for (var attributeId in _list) { - if (_list.hasOwnProperty(attributeId)) { - _$node.find(".list").append(_list[attributeId].get$node()); - } - } - - this.registerYMap = function () { - var ymap = that.getRootSubjectEntity().getYMap(); - var attrs = that.getAttributes(); - for (var key in attrs) { - if (attrs.hasOwnProperty(key)) { - attrs[key].registerYMap(); - } - } - - ymap.observe(function (event) { - const array = Array.from(event.changes.keys.entries()); - array.forEach(([key, change]) => { - if (key.indexOf("[value]") != -1) { - var operation; - event.currentTarget.get(key); - switch (change.action) { - case "add": { - if (eventWasTriggeredByMe(event)) return; - const jabberId = event.currentTarget.get("jabberId"); - if (jabberId === _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]) - return; - operation = new AttributeAddOperation( - key.replace(/\[\w*\]/g, ""), - that.getEntityId(), - that.getRootSubjectEntity().getEntityId(), - that.constructor.name - ); - remoteAttributeAddCallback(operation); - - break; - } - case "delete": { - operation = new AttributeDeleteOperation( - key.replace(/\[\w*\]/g, ""), - that.getEntityId(), - that.getRootSubjectEntity().getEntityId(), - that.constructor.name - ); - remoteAttributeDeleteCallback(operation); - break; - } - } - } else if (key.indexOf("updateConditionOption") != -1) { - that.setOptions(event.value); - } - }); - }); - }; - - if (_iwcw) { - that.registerCallbacks(); - } - } -} - -/** - * RenamingAttribute - * @class canvas_widget.ConditionPredicateAttribute - * @memberof canvas_widget - * @extends canvas_widget.AbstractAttribute - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {Object} options Selection options - * @constructor - */ -class RenamingAttribute extends AbstractAttribute { - static TYPE = "RenamingAttribute"; - constructor(id, name, subjectEntity, options) { - super(id, name, subjectEntity); - - //noinspection UnnecessaryLocalVariableJS - /** - * Selection options - * @type {Object} - * @private - */ - var _options = options; - - /** - * Value object of key - * @type {canvas_widget.Value} - * @private - */ - var _key = new Value( - id + "[val]", - "Attribute Name", - this, - this.getRootSubjectEntity() - ); - - /*** - * Value object of ref - * @type {canvas_widget.Value} - * @private - */ - var _ref = new Value( - id + "[ref]", - "Attribute Reference", - this, - this.getRootSubjectEntity() - ); - - /*** - * Value object of vis - * @type {canvas_widget.Value} - * @private - */ - var _vis = new SelectionValue( - id + "[vis]", - "Attribute Visibility", - this, - this.getRootSubjectEntity(), - _options - ); - - /** - * jQuery object of the DOM node representing the attribute - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(renamingAttrHTML)()); - - //noinspection JSUnusedGlobalSymbols - /** - * Set Value object of key - * @param {canvas_widget.Value} key - */ - this.setKey = function (key) { - _key = key; - }; - - /** - * Get Value object of key - * @returns {canvas_widget.Value} - */ - this.getKey = function () { - return _key; - }; - - /** - * Get Value object of value - * @returns {canvas_widget.Value} - */ - this.getRef = function () { - return _ref; - }; - - /** - * Get Visibility object of value - * @returns {canvas_widget.Value} - */ - this.getVis = function () { - return _vis; - }; - - //noinspection JSUnusedGlobalSymbols - /** - * Set Value object of value - * @param {canvas_widget.Value} value - */ - this.setVis = function (value) { - _vis = value; - }; - - /** - * Get jQuery object of the DOM node representing the attribute - * @returns {jQuery} - */ - this.get$node = function () { - return _$node; - }; - - /** - * Set value of key and value by their JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - _key.setValueFromJSON(json.val); - _ref.setValueFromJSON(json.ref); - _vis.setValueFromJSON(json.vis || { value: "" }); - }; - - /** - * Get JSON representation of the attribute - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.val = _key.toJSON(); - json.ref = _ref.toJSON(); - json.vis = _vis.toJSON(); - return json; - }; - _$node.find(".val").append(_key.get$node()); - _$node.find(".ref").append(_ref.get$node()).hide(); - _$node.find(".vis").append(_vis.get$node()); - - this.registerYMap = function () { - _key.registerYType(); - _ref.registerYType(); - _vis.registerYType(); - }; - } -} - -/** - * KeySelectionValueSelectionValueListAttribute - * @class canvas_widget.KeySelectionValueSelectionValueListAttribute - * @extends canvas_widget.AbstractAttribute - * @memberof canvas_widget - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {Object} options Selection options - * @param {Object} options2 Selection options - */ -class KeySelectionValueSelectionValueListAttribute extends AbstractAttribute { - static TYPE = "KeySelectionValueSelectionValueListAttribute"; - - constructor(id, name, subjectEntity, options, options2) { - super(id, name, subjectEntity); - var that = this; - - /** - * Selection options - * @type {Object} - * @private - */ - var _options = options; - - /** - * Selection options - * @type {Object} - * @private - */ - var _options2 = options2; - - /** - * List of attributes - * @type {Object} - * @private - */ - var _list = {}; - - /** - * jQuery object of DOM node representing the attribute - * @type {jQuery} - * @private - */ - var _$node = $( - lodash.template(keySelectionValueSelectionValueListAttributeHtml)() - ); - - /** - * Inter widget communication wrapper - * @type {Object} - */ - y = y || window.y; - var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); - - /** - * Apply an Attribute Add Operation - * @param {operations.ot.AttributeAddOperation} operation - */ - var processAttributeAddOperation = function (operation) { - var attribute = new KeySelectionValueSelectionValueAttribute( - operation.getEntityId(), - "Attribute", - that, - _options, - _options2 - ); - attribute.registerYType(); - that.addAttribute(attribute); - if (_$node.find(".list").find("#" + attribute.getEntityId()).length == 0) - _$node.find(".list").append(attribute.get$node()); - EntityManagerInstance.storeDataYjs(); - }; - - /** - * Apply an Attribute Delete Operation - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var processAttributeDeleteOperation = function (operation) { - var attribute = that.getAttribute(operation.getEntityId()); - if (attribute) { - that.deleteAttribute(attribute.getEntityId()); - attribute.get$node().remove(); - } - EntityManagerInstance.storeDataYjs(); - }; - - /** - * Propagate an Attribute Add Operation to the remote users and the local widgets - * @param {operations.ot.AttributeAddOperation} operation - */ - var propagateAttributeAddOperation = function (operation) { - processAttributeAddOperation(operation); - }; - - /** - * Propagate an Attribute Delete Operation to the remote users and the local widgets - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var propagateAttributeDeleteOperation = function (operation) { - processAttributeDeleteOperation(operation); - var ynode = that.getRootSubjectEntity().getYMap(); - ynode.delete(operation.getEntityId() + "[key]"); - }; - - /** - * Callback for a remote Attrbute Add Operation - * @param {operations.ot.AttributeAddOperation} operation - */ - var remoteAttributeAddCallback = function (operation) { - if ( - operation instanceof AttributeAddOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - processAttributeAddOperation(operation); - } - }; - - /** - * Callback for a remote Attribute Delete Operation - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var remoteAttributeDeleteCallback = function (operation) { - if ( - operation instanceof AttributeDeleteOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - _iwcw.sendLocalOTOperation( - CONFIG.WIDGET.NAME.ATTRIBUTE, - operation.getOTOperation() - ); - processAttributeDeleteOperation(operation); - } - }; - - var localAttributeAddCallback = function (operation) { - if ( - operation instanceof AttributeAddOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - propagateAttributeAddOperation(operation); - } - }; - - /** - * Callback for a local Attribute Delete Operation - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var localAttributeDeleteCallback = function (operation) { - if ( - operation instanceof AttributeDeleteOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - propagateAttributeDeleteOperation(operation); - } - }; - - /** - * Add attribute to attribute list - * @param {canvas_widget.AbstractAttribute} attribute - */ - this.addAttribute = function (attribute) { - var id = attribute.getEntityId(); - if (!_list.hasOwnProperty(id)) { - _list[id] = attribute; - } - }; - - /** - * Get attribute of attribute list by its entity id - * @param id - * @returns {canvas_widget.AbstractAttribute} - */ - this.getAttribute = function (id) { - if (_list.hasOwnProperty(id)) { - return _list[id]; - } - return null; - }; - - /** - * Delete attribute from attribute list by its entity id - * @param {string} id - */ - this.deleteAttribute = function (id) { - if (_list.hasOwnProperty(id)) { - _list[id]; - - delete _list[id]; - } - }; - - /** - * Get attribute list - * @returns {Object} - */ - this.getAttributes = function () { - return _list; - }; - - /** - * Set attribute list - * @param {Object} list - */ - this.setAttributes = function (list) { - _list = list; - }; - - /** - * Get jQuery object of the DOM node representing the attribute (list) - * @returns {jQuery} - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the attribute (list) - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.type = KeySelectionValueSelectionValueListAttribute.TYPE; - var attr = {}; - lodash.forEach(this.getAttributes(), function (val, key) { - attr[key] = val.toJSON(); - }); - json.list = attr; - return json; - }; - - /** - * Set attribute list by its JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - lodash.forEach(json.list, function (val, key) { - var attribute = new KeySelectionValueSelectionValueAttribute( - key, - key, - that, - _options, - _options2 - ); - attribute.setValueFromJSON(json.list[key]); - that.addAttribute(attribute); - if ( - _$node.find(".list").find("#" + attribute.getEntityId()).length == 0 - ) - _$node.find(".list").append(attribute.get$node()); - }); - }; - - /** - * Register inter widget communication callbacks - */ - this.registerCallbacks = function () { - _iwcw.registerOnDataReceivedCallback(localAttributeAddCallback); - _iwcw.registerOnDataReceivedCallback(localAttributeDeleteCallback); - }; - - /** - * Unregister inter widget communication callbacks - */ - this.unregisterCallbacks = function () { - _iwcw.unregisterOnDataReceivedCallback(localAttributeAddCallback); - _iwcw.unregisterOnDataReceivedCallback(localAttributeDeleteCallback); - }; - - _$node.find(".name").text(this.getName()); - - for (var attributeId in _list) { - if (_list.hasOwnProperty(attributeId)) { - _$node.find(".list").append(_list[attributeId].get$node()); - } - } - - if (_iwcw) { - that.registerCallbacks(); - } - - this.registerYMap = function () { - var ymap = that.getRootSubjectEntity().getYMap(); - var attrs = that.getAttributes(); - for (var key in attrs) { - if (attrs.hasOwnProperty(key)) { - var attr = attrs[key]; - attr.registerYType(); - } - } - - ymap.observe(function (event) { - const array = Array.from(event.changes.keys.entries()); - array.forEach(([key, change]) => { - if (key.indexOf("[key]") != -1) { - var operation; - event.currentTarget.get(key); - switch (change.action) { - case "add": { - const jabberId = event.currentTarget.get("jabberId"); - if (jabberId === _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]) - return; - operation = new AttributeAddOperation( - key.replace(/\[\w*\]/g, ""), - that.getEntityId(), - that.getRootSubjectEntity().getEntityId(), - that.constructor.name - ); - remoteAttributeAddCallback(operation); - break; - } - case "delete": { - operation = new AttributeDeleteOperation( - key.replace(/\[\w*\]/g, ""), - that.getEntityId(), - that.getRootSubjectEntity().getEntityId(), - that.constructor.name - ); - remoteAttributeDeleteCallback(operation); - break; - } - } - } - }); - }); - }; - } -} - -/** - * RenamingListAttribute - * @class canvas_widget.RenamingListAttribute - * @extends canvas_widget.AbstractAttribute - * @memberof canvas_widget - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {Object} options Selection options - */ -class RenamingListAttribute extends AbstractAttribute { - static TYPE = "RenamingListAttribute"; - constructor(id, name, subjectEntity, options, y) { - y = y || window.y; - super(id, name, subjectEntity); - var that = this; - - /** - * Selection options - * @type {Object} - * @private - */ - var _options = options; - - /** - * List of attributes - * @type {Object} - * @private - */ - var _list = {}; - - /** - * jQuery object of DOM node representing the attribute - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(listHtml)()); - - /** - * Inter widget communication wrapper - * @type {Object} - */ - var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); - - /** - * Apply an Attribute Add Operation - * @param {operations.ot.AttributeAddOperation} operation - * @param { YText} ytext - */ - var processAttributeAddOperation = function (operation) { - var attribute = new RenamingAttribute( - operation.getEntityId(), - "Attribute", - that, - _options - ); - that.addAttribute(attribute); - attribute.registerYMap(); - _$node.find(".list").append(attribute.get$node()); - EntityManagerInstance.storeDataYjs(); - return attribute; - }; - - /** - * Propagate an Attribute Add Operation to the remote users and the local widgets - * @param {operations.ot.AttributeAddOperation} operation - */ - this.propagateAttributeAddOperation = function (operation) { - return processAttributeAddOperation(operation); - }; - - /** - * Apply an Attribute Delete Operation - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var processAttributeDeleteOperation = function (operation) { - var attribute = that.getAttribute(operation.getEntityId()); - if (attribute) { - that.deleteAttribute(attribute.getEntityId()); - attribute.get$node().remove(); - } - }; - - /** - * Propagate an Attribute Delete Operation to the remote users and the local widgets - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var propagateAttributeDeleteOperation = function (operation) { - processAttributeDeleteOperation(operation); - var ymap = that.getRootSubjectEntity().getYMap(); - ymap.delete(operation.getEntityId() + "[val]"); - EntityManagerInstance.storeDataYjs(); - }; - - /** - * Callback for a remote Attrbute Add Operation - * @param {operations.ot.AttributeAddOperation} operation - */ - var remoteAttributeAddCallback = function (operation) { - if ( - operation instanceof AttributeAddOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - processAttributeAddOperation(operation); - subjectEntity.showAttributes(); - } - }; - - /** - * Callback for a remote Attribute Delete Operation - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var remoteAttributeDeleteCallback = function (operation) { - if ( - operation instanceof AttributeDeleteOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - processAttributeDeleteOperation(operation); - } - }; - - /** - * Callback for a local Attribute Add Operation - * @param {operations.ot.AttributeAddOperation} operation - */ - var localAttributeAddCallback = function (operation) { - if ( - operation instanceof AttributeAddOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - propagateAttributeAddOperation(operation); - } - }; - - /** - * Callback for a local Attribute Delete Operation - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var localAttributeDeleteCallback = function (operation) { - if ( - operation instanceof AttributeDeleteOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - propagateAttributeDeleteOperation(operation); - } - }; - - /** - * Add attribute to attribute list - * @param {canvas_widget.AbstractAttribute} attribute - */ - this.addAttribute = function (attribute) { - var id = attribute.getEntityId(); - if (!_list.hasOwnProperty(id)) { - _list[id] = attribute; - } - }; - - /** - * Get attribute of attribute list by its entity id - * @param id - * @returns {canvas_widget.AbstractAttribute} - */ - this.getAttribute = function (id) { - if (_list.hasOwnProperty(id)) { - return _list[id]; - } - return null; - }; - - /** - * Delete attribute from attribute list by its entity id - * @param {string} id - */ - this.deleteAttribute = function (id) { - if (_list.hasOwnProperty(id)) { - delete _list[id]; - } - }; - - /** - * Get attribute list - * @returns {Object} - */ - this.getAttributes = function () { - return _list; - }; - - /** - * Set attribute list - * @param {Object} list - */ - this.setAttributes = function (list) { - _list = list; - }; - - /** - * Get jQuery object of the DOM node representing the attribute (list) - * @returns {jQuery} - */ - this.get$node = function () { - return _$node; - }; - - this.setOptions = function (options) { - _options = options; - }; - - /** - * Get JSON representation of the attribute (list) - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.type = RenamingListAttribute.TYPE; - var attr = {}; - lodash.forEach(this.getAttributes(), function (val, key) { - attr[key] = val.toJSON(); - }); - json.list = attr; - return json; - }; - - /** - * Set attribute list by its JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - lodash.forEach(json.list, function (val, key) { - var attribute = new RenamingAttribute(key, key, that, _options); - attribute.setValueFromJSON(json.list[key]); - that.addAttribute(attribute); - _$node.find(".list").append(attribute.get$node()); - }); - }; - - /** - * Register inter widget communication callbacks - */ - this.registerCallbacks = function () { - _iwcw.registerOnDataReceivedCallback(localAttributeAddCallback); - _iwcw.registerOnDataReceivedCallback(localAttributeDeleteCallback); - }; - - /** - * Unregister inter widget communication callbacks - */ - this.unregisterCallbacks = function () { - _iwcw.unregisterOnDataReceivedCallback(localAttributeAddCallback); - _iwcw.unregisterOnDataReceivedCallback(localAttributeDeleteCallback); - }; - - _$node.find(".name").text(this.getName()); - - for (var attributeId in _list) { - if (_list.hasOwnProperty(attributeId)) { - _$node.find(".list").append(_list[attributeId].get$node()); - } - } - - if (_iwcw) { - that.registerCallbacks(); - } - this.registerYMap = function () { - var ymap = that.getRootSubjectEntity().getYMap(); - var attrs = that.getAttributes(); - for (var key in attrs) { - if (attrs.hasOwnProperty(key)) { - var attr = attrs[key]; - attr.registerYMap(); - } - } - - ymap.observe(function (event) { - const array = Array.from(event.changes.keys.entries()); - array.forEach(([key, change]) => { - if (key.indexOf("[val]") != -1) { - event.currentTarget.get(key); - switch (change.action) { - case "add": { - // var yUserId = event.object.map[key][0]; - // if (yUserId === y.clientID) return; - const operation = new AttributeAddOperation( - key.replace(/\[\w*\]/g, ""), - that.getEntityId(), - that.getRootSubjectEntity().getEntityId(), - that.constructor.name - ); - remoteAttributeAddCallback(operation); - - break; - } - case "delete": { - const operation = new AttributeDeleteOperation( - key.replace(/\[\w*\]/g, ""), - that.getEntityId(), - that.getRootSubjectEntity().getEntityId(), - that.constructor.name - ); - remoteAttributeDeleteCallback(operation); - break; - } - } - } - }); - }); - }; - } -} - -/** - * ConditionPredicateAttribute - * @class attribute_widget.ConditionPredicateAttribute - * @memberof attribute_widget - * @extends attribute_widget.AbstractAttribute - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {Object} options Selection options - * @param {Object} options2 Selection options - * @constructor - */ -class ConditionPredicateAttribute extends AbstractAttribute { - static TYPE = "ConditionPredicateAttribute"; - constructor(id, name, subjectEntity, options, options2) { - super(id, name, subjectEntity); - - //noinspection UnnecessaryLocalVariableJS - /** - * Selection options - * @type {Object} - * @private - */ - var _options = options; - - //noinspection UnnecessaryLocalVariableJS - /** - * Selection options - * @type {Object} - * @private - */ - var _options2 = options2; - - //var _options3 = options3; - /** - * Value object of key - * @type {attribute_widget.Value} - * @private - */ - var _key = new Value( - id + "[value]", - "Attribute Value", - this, - this.getRootSubjectEntity() - ); - - /*** - * Value object of value - * @type {attribute_widget.Value} - * @private - */ - var _value = new SelectionValue( - id + "[property]", - "Attribute Name", - this, - this.getRootSubjectEntity(), - _options - ); - - /*** - * Value object of value - * @type {attribute_widget.Value} - * @private - */ - var _value2 = new SelectionValue( - id + "[operator]", - "Logical Operator", - this, - this.getRootSubjectEntity(), - _options2 - ); - - /** - * jQuery object of the DOM node representing the attribute - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(condition_predicateHtml)()); - - //noinspection JSUnusedGlobalSymbols - /** - * Set Value object of key - * @param {attribute_widget.Value} key - */ - this.setKey = function (key) { - _key = key; - }; - - /** - * Get Value object of key - * @returns {attribute_widget.Value} - */ - this.getKey = function () { - return _key; - }; - - /** - * Set Value object of value - * @param {attribute_widget.Value} value - */ - this.setValue = function (value) { - _value = value; - }; - - /** - * Get Value object of value - * @returns {attribute_widget.Value} - */ - this.getValue = function () { - return _value; - }; - - //noinspection JSUnusedGlobalSymbols - /** - * Set Value object of value - * @param {attribute_widget.Value} value - */ - this.setValue2 = function (value) { - _value2 = value; - }; - - /** - * Get Value object of value - * @returns {attribute_widget.Value} - */ - this.getValue2 = function () { - return _value2; - }; - - /** - * Get jQuery object of the DOM node representing the attribute - * @returns {jQuery} - */ - this.get$node = function () { - return _$node; - }; - - /** - * Set value of key and value by their JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - _key.setValueFromJSON(json.val); - _value.setValueFromJSON(json.property); - _value2.setValueFromJSON(json.operator || { value: "" }); - }; - /** - * Get JSON representation of the attribute - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.val = _key.toJSON(); - json.property = _value.toJSON(); - json.operator = _value2.toJSON(); - return json; - }; - _$node.find(".val").append(_key.get$node()); - _$node.find(".property").append(_value.get$node()); - _$node.find(".operator").append(_value2.get$node()); - //_$node.find(".operator2").append(_value3.get$node()); - this.registerYMap = function () { - _key.registerYType(); - _value.registerYType(); - _value2.registerYType(); - }; - } -} - -/** - * SingleColorValueAttribute - * @class canvas_widget.SingleColorValueAttribute - * @extends canvas_widget.AbstractAttribute - * @memberof canvas_widget - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to - */ -class SingleColorValueAttribute extends AbstractAttribute { - constructor(id, name, subjectEntity) { - super(id, name, subjectEntity); - - /*** - * Value object of value - * @type {canvas_widget.Value} - * @private - */ - var _value = new Value(id, name, this, this.getRootSubjectEntity()); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(singleColorValueAttributeHtml)()); - - /** - * Set Value object of value - * @param {canvas_widget.Value} value - */ - this.setValue = function (value) { - _value = value; - }; - - /** - * Get Value object of value - * @returns {canvas_widget.Value} - */ - this.getValue = function () { - return _value; - }; - - /** - * jQuery object of DOM node representing the attribute - * @type {jQuery} - * @private - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the attribute - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.value = _value.toJSON(); - return json; - }; - - /** - * Set attribute value by its JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - _value.setValueFromJSON(json.value); - }; - - _$node.find(".name").text(this.getName()); - _$node.find(".value").append(_value.get$node()); - } -} - -/** - * KeySelectionValueSelectionValueAttribute - * @class canvas_widget.KeySelectionValueSelectionValueAttribute - * @extends canvas_widget.AbstractAttribute - * @memberof canvas_widget - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {Object} options Selection options - * @param {Object} options2 Selection options - */ -class KeySelectionValueSelectionValueAttribute extends AbstractAttribute { - constructor(id, name, subjectEntity, options, options2) { - super(id, name, subjectEntity); - - //noinspection UnnecessaryLocalVariableJS - /** - * Selection options - * @type {Object} - * @private - */ - var _options = options; - - //noinspection UnnecessaryLocalVariableJS - /** - * Selection options - * @type {Object} - * @private - */ - var _options2 = options2; - - /** - * Value object of key - * @type {canvas_widget.Value} - * @private - */ - var _key = new Value(id + "[key]", "", this, this.getRootSubjectEntity()); - - /*** - * Value object of value - * @type {canvas_widget.Value} - * @private - */ - var _value = new SelectionValue( - id + "[value]", - "", - this, - this.getRootSubjectEntity(), - _options - ); - - /*** - * Value object of value - * @type {canvas_widget.Value} - * @private - */ - var _value2 = new SelectionValue( - id + "[value2]", - "", - this, - this.getRootSubjectEntity(), - _options2 - ); - - /** - * jQuery object of the DOM node representing the attribute - * @type {jQuery} - * @private - */ - var _$node = $( - lodash.template(keySelectionValueSelectionValueAttributeHtml)({ id: id }) - ); - - //noinspection JSUnusedGlobalSymbols - /** - * Set Value object of key - * @param {canvas_widget.Value} key - */ - this.setKey = function (key) { - _key = key; - }; - - /** - * Get Value object of key - * @returns {canvas_widget.Value} - */ - this.getKey = function () { - return _key; - }; - - /** - * Set Value object of value - * @param {canvas_widget.Value} value - */ - this.setValue = function (value) { - _value = value; - }; - - /** - * Get Value object of value - * @returns {canvas_widget.Value} - */ - this.getValue = function () { - return _value; - }; - - /** - * Set Value object of value - * @param {canvas_widget.Value} value - */ - this.setValue2 = function (value) { - _value2 = value; - }; - - /** - * Get Value object of value - * @returns {canvas_widget.Value} - */ - this.getValue2 = function () { - return _value2; - }; - - /** - * Get jQuery object of the DOM node representing the attribute - * @returns {jQuery} - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the attribute - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.key = _key.toJSON(); - json.value = _value.toJSON(); - json.value2 = _value2.toJSON(); - return json; - }; - - /** - * Set value of key and value by their JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - _key.setValueFromJSON(json.key); - _value.setValueFromJSON(json.value); - _value2.setValueFromJSON(json.value2 || { value: "" }); - }; - - this.registerYType = function () { - _key.registerYType(); - _value.registerYType(); - _value2.registerYType(); - }; - - _$node.find(".key").append(_key.get$node()); - _$node.find(".value").append(_value.get$node()); - } -} - -/** - * KeySelectionValueListAttribute - * @class canvas_widget.KeySelectionValueListAttribute - * @extends canvas_widget.AbstractAttribute - * @memberof canvas_widget - * @constructor - * @param {string} id Entity id - * @param {string} name Name of attribute - * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to - * @param {Object} options Selection options - */ -class KeySelectionValueListAttribute extends AbstractAttribute { - static TYPE = "KeySelectionValueListAttribute"; - constructor(id, name, subjectEntity, options) { - super(id, name, subjectEntity); - var that = this; - - /** - * Selection options - * @type {Object} - * @private - */ - var _options = options; - - /** - * List of attributes - * @type {Object} - * @private - */ - var _list = {}; - - /** - * jQuery object of DOM node representing the attribute - * @type {jQuery} - * @private - */ - var _$node = $(lodash.template(keySelectionValueListAttributeHtml)()); - - /** - * Inter widget communication wrapper - * @type {Object} - */ - y = y || window.y; - var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); - - /** - * Apply an Attribute Add Operation - * @param {operations.ot.AttributeAddOperation} operation - */ - var processAttributeAddOperation = function (operation) { - var attribute = new KeySelectionValueAttribute( - operation.getEntityId(), - "Attribute", - that, - _options - ); - attribute.registerYMap(); - that.addAttribute(attribute); - if (_$node.find(".list").find("#" + attribute.getEntityId()).length == 0) - _$node.find(".list").append(attribute.get$node()); - }; - - /** - * Apply an Attribute Delete Operation - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var processAttributeDeleteOperation = function (operation) { - var attribute = that.getAttribute(operation.getEntityId()); - if (attribute) { - that.deleteAttribute(attribute.getEntityId()); - attribute.get$node().remove(); - } - }; - - /** - * Propagate an Attribute Add Operation to the remote users and the local widgets - * @param {operations.ot.AttributeAddOperation} operation - */ - var propagateAttributeAddOperation = function (operation) { - processAttributeAddOperation(operation); - EntityManagerInstance.storeDataYjs(); - }; - - /** - * Propagate an Attribute Delete Operation to the remote users and the local widgets - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var propagateAttributeDeleteOperation = function (operation) { - processAttributeDeleteOperation(operation); - var ymap = that.getRootSubjectEntity().getYMap(); - ymap.delete(operation.getEntityId() + "[key]"); - EntityManagerInstance.storeDataYjs(); - }; - - /** - * Callback for a remote Attrbute Add Operation - * @param {operations.ot.AttributeAddOperation} operation - */ - var remoteAttributeAddCallback = function (operation) { - if ( - operation instanceof AttributeAddOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - processAttributeAddOperation(operation); - } - }; - - /** - * Callback for a remote Attribute Delete Operation - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var remoteAttributeDeleteCallback = function (operation) { - if ( - operation instanceof AttributeDeleteOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - processAttributeDeleteOperation(operation); - } - }; - - var localAttributeAddCallback = function (operation) { - if ( - operation instanceof AttributeAddOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - propagateAttributeAddOperation(operation); - } - }; - /** - * Callback for a local Attribute Delete Operation - * @param {operations.ot.AttributeDeleteOperation} operation - */ - var localAttributeDeleteCallback = function (operation) { - if ( - operation instanceof AttributeDeleteOperation && - operation.getRootSubjectEntityId() === - that.getRootSubjectEntity().getEntityId() && - operation.getSubjectEntityId() === that.getEntityId() - ) { - propagateAttributeDeleteOperation(operation); - } - }; - - /** - * Add attribute to attribute list - * @param {canvas_widget.AbstractAttribute} attribute - */ - this.addAttribute = function (attribute) { - var id = attribute.getEntityId(); - if (!_list.hasOwnProperty(id)) { - _list[id] = attribute; - } - }; - - /** - * Get attribute of attribute list by its entity id - * @param id - * @returns {canvas_widget.AbstractAttribute} - */ - this.getAttribute = function (id) { - if (_list.hasOwnProperty(id)) { - return _list[id]; - } - return null; - }; - - /** - * Delete attribute from attribute list by its entity id - * @param {string} id - */ - this.deleteAttribute = function (id) { - if (_list.hasOwnProperty(id)) { - delete _list[id]; - } - }; - - /** - * Get attribute list - * @returns {Object} - */ - this.getAttributes = function () { - return _list; - }; - - /** - * Set attribute list - * @param {Object} list - */ - this.setAttributes = function (list) { - _list = list; - }; - - /** - * Get jQuery object of the DOM node representing the attribute (list) - * @returns {jQuery} - */ - this.get$node = function () { - return _$node; - }; - - /** - * Get JSON representation of the attribute (list) - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractAttribute.prototype.toJSON.call(this); - json.type = KeySelectionValueListAttribute.TYPE; - var attr = {}; - lodash.forEach(this.getAttributes(), function (val, key) { - attr[key] = val.toJSON(); - }); - json.list = attr; - return json; - }; - - /** - * Set attribute list by its JSON representation - * @param json - */ - this.setValueFromJSON = function (json) { - lodash.forEach(json.list, function (val, key) { - var attribute = new KeySelectionValueAttribute( - key, - key, - that, - _options - ); - attribute.setValueFromJSON(json.list[key]); - that.addAttribute(attribute); - if ( - _$node.find(".list").find("#" + attribute.getEntityId()).length == 0 - ) - _$node.find(".list").append(attribute.get$node()); - }); - }; - - /** - * Register inter widget communication callbacks - */ - this.registerCallbacks = function () { - _iwcw.registerOnDataReceivedCallback(localAttributeAddCallback); - _iwcw.registerOnDataReceivedCallback(localAttributeDeleteCallback); - }; - - /** - * Unregister inter widget communication callbacks - */ - this.unregisterCallbacks = function () { - _iwcw.unregisterOnDataReceivedCallback(localAttributeAddCallback); - _iwcw.unregisterOnDataReceivedCallback(localAttributeDeleteCallback); - }; - - _$node.find(".name").text(this.getName()); - - for (var attributeId in _list) { - if (_list.hasOwnProperty(attributeId)) { - _$node.find(".list").append(_list[attributeId].get$node()); - } - } - - if (_iwcw) { - that.registerCallbacks(); - } - - this.registerYMap = function () { - var ymap = that.getRootSubjectEntity().getYMap(); - var attrs = that.getAttributes(); - for (var key in attrs) { - if (attrs.hasOwnProperty(key)) { - var attr = attrs[key]; - attr.getKey().registerYType(); - attr.getValue().registerYType(); - } - } - - ymap.observe(function (event) { - const array = Array.from(event.changes.keys.entries()); - array.forEach(([key, change]) => { - if (key.indexOf("[key]") != -1) { - var operation; - switch (change.action) { - case "add": { - // var yUserId = event.object.map[key][0]; - // if (yUserId === y.clientID) return; - operation = new AttributeAddOperation( - key.replace(/\[\w*\]/g, ""), - that.getEntityId(), - that.getRootSubjectEntity().getEntityId(), - that.constructor.name - ); - remoteAttributeAddCallback(operation); - - break; - } - case "delete": { - operation = new AttributeDeleteOperation( - key.replace(/\[\w*\]/g, ""), - that.getEntityId(), - that.getRootSubjectEntity().getEntityId(), - that.constructor.name - ); - remoteAttributeDeleteCallback(operation); - break; - } - } - } - }); - }); - }; - } -} - -/** - * Abstract Class Node - * @class canvas_widget.ModelAttributesNode - * @extends canvas_widget.AbstractNode - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of node - * @param {object} [attr] model attributes - */ -class ModelAttributesNode extends AbstractNode { - static TYPE = "ModelAttributesNode"; - - constructor(id, attr, y) { - super(id, ModelAttributesNode.TYPE, 0, 0, 0, 0, 0, null, null, y); - y = y || window.y; - if (!y) { - throw new Error("y is not defined"); - } - /** - * jQuery object of node template - * @type {jQuery} - * @private - */ - var _$template = $(lodash.template(modelAttributesNodeHtml)()); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = AbstractNode.prototype.get$node - .call(this) - .append(_$template) - .addClass("class"); - - /** - * jQuery object of DOM node representing the attributes - * @type {jQuery} - * @private - */ - var _$attributeNode = _$node.find(".attributes"); - - /** - * Attributes of node - * @type {Object} - * @private - */ - var _attributes = this.getAttributes(); - - /** - * Get JSON representation of the node - * @returns {Object} - */ - this.toJSON = function () { - var json = AbstractNode.prototype.toJSON.call(this); - json.type = ModelAttributesNode.TYPE; - return json; - }; - - if (attr) { - for (var attrKey in attr) { - if (attr.hasOwnProperty(attrKey)) { - switch (attr[attrKey].value) { - case "boolean": - this.addAttribute( - new BooleanAttribute( - this.getEntityId() + - "[" + - attr[attrKey].key.toLowerCase() + - "]", - attr[attrKey].key, - this - ) - ); - break; - case "string": - this.addAttribute( - new SingleValueAttribute( - this.getEntityId() + - "[" + - attr[attrKey].key.toLowerCase() + - "]", - attr[attrKey].key, - this - ) - ); - break; - case "integer": - this.addAttribute( - new IntegerAttribute( - this.getEntityId() + - "[" + - attr[attrKey].key.toLowerCase() + - "]", - attr[attrKey].key, - this - ) - ); - break; - case "file": - this.addAttribute( - new FileAttribute( - this.getEntityId() + - "[" + - attr[attrKey].key.toLowerCase() + - "]", - attr[attrKey].key, - this - ) - ); - break; - default: - if (attr[attrKey].options) { - this.addAttribute( - new SingleSelectionAttribute( - this.getEntityId() + - "[" + - attr[attrKey].key.toLowerCase() + - "]", - attr[attrKey].key, - this, - attr[attrKey].options - ) - ); - } - break; - } - } - } - } else { - this.addAttribute( - new SingleValueAttribute(this.getEntityId() + "[name]", "Name", this, y) - ); - this.addAttribute( - new SingleMultiLineValueAttribute( - this.getEntityId() + "[description]", - "Description", - this, - y - ) - ); - } - - this.getLabel().getValue().setValue("Model Attributes"); - - _$node.find(".label").text("Model Attributes"); - _$node.hide(); - - for (var attributeKey in _attributes) { - if (_attributes.hasOwnProperty(attributeKey)) { - _$attributeNode.append(_attributes[attributeKey].get$node()); - } - } - - this.registerYMap = function () { - AbstractNode.prototype.registerYMap.call(this); - var attrs = this.getAttributes(); - for (var key in attrs) { - if (attrs.hasOwnProperty(key)) { - var attr = attrs[key]; - if ( - attr instanceof SingleValueAttribute || - attr instanceof SingleMultiLineValueAttribute - ) { - attr.getValue().registerYType(); - } else if ( - !(attr instanceof FileAttribute) && - !(attr instanceof SingleValueAttribute) && - !(attr instanceof SingleMultiLineValueAttribute) - ) { - attr.getValue().registerYType(); - } - } - } - }; - } -} - -/** - * ViewObjectNode - * @class canvas_widget.ViewObjectNode - * @extends canvas_widget.AbstractNode - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {number} zIndex Position of node on z-axis - * @param {object} jsonFromResource the ViewObjectNode is created from a json - */ -class ViewObjectNode extends AbstractNode { - static TYPE = "ViewObject"; - static DEFAULT_WIDTH = 150; - static DEFAULT_HEIGHT = 100; - constructor(id, left, top, width, height, zIndex, json) { - var that = this; - - super(id, "ViewObject", left, top, width, height, zIndex, json); - - /** - * jQuery object of node template - * @type {jQuery} - * @private - */ - var _$template = $( - lodash.template(viewobjectNodeHtml)({ type: that.getType() }) - ); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = AbstractNode.prototype.get$node - .call(this) - .append(_$template) - .addClass("viewobject"); - - /** - * jQuery object of DOM node representing the attributes - * @type {jQuery} - * @private - */ - var _$attributeNode = _$node.find(".attributes"); - - /** - * Attributes of node - * @type {Object} - * @private - */ - this.getAttributes(); - - /** - * Get JSON representation of the node - * @returns {Object} - */ - this.toJSON = function () { - return AbstractNode.prototype.toJSON.call(this); - }; - - this.createConditionListAttribute = function (refAttrs) { - var targetAttrList = {}; - if (refAttrs && refAttrs.constructor.name === "RenamingListAttribute") { - var attrs = refAttrs.getAttributes(); - for (var key in attrs) { - if (attrs.hasOwnProperty(key)) { - targetAttrList[key] = attrs[key].getKey().getValue(); - } - } - } else { - for (var key in refAttrs) { - if (refAttrs.hasOwnProperty(key)) { - targetAttrList[key] = refAttrs[key].val.value; - } - } - } - var conditionListAttr = new ConditionListAttribute( - "[condition]", - "Conditions", - that, - targetAttrList, - LogicalOperator - ); - that.addAttribute(conditionListAttr); - _$attributeNode.append(conditionListAttr.get$node()); - conditionListAttr.get$node().hide(); - return conditionListAttr; - }; - - this.registerYMap = function () { - AbstractNode.prototype.registerYMap.call(this); - that.getLabel().getValue().registerYType(); - renamingList.registerYMap(); - if (cla) cla.registerYMap(); - targetAttribute.getValue().registerYType(); - conjSelection.getValue().registerYType(); - }; - - this.showAttributes = function () { - if (renamingList.get$node().is(":hidden")) renamingList.get$node().show(); - if (conjSelection.get$node().is(":hidden")) - conjSelection.get$node().show(); - if (cla.get$node().is(":hidden")) cla.get$node().show(); - if (!targetAttribute.get$node().is(":hidden")) - targetAttribute.get$node().hide(); - }; - - var targetAttribute, renamingList, conjSelection, cla; - _$node.find(".label").append(this.getLabel().get$node()); - if (window.hasOwnProperty("y")) { - const dataMap = y.getMap("data"); - var model = dataMap.get("model"); - if (model) { - var selectionValues = - ViewTypesUtil.GetAllNodesOfBaseModelAsSelectionList2(model.nodes, [ - "Object", - ]); - targetAttribute = new SingleSelectionAttribute( - id + "[target]", - "Target", - that, - selectionValues - ); - that.addAttribute(targetAttribute); - _$attributeNode.prepend(targetAttribute.get$node()); - } - if (json) - cla = that.createConditionListAttribute( - json.attributes["[attributes]"].list - ); - else cla = that.createConditionListAttribute(); - } - - renamingList = new RenamingListAttribute( - "[attributes]", - "Attributes", - that, - { - show: "Visible", - hide: "Hidden", - } - ); - that.addAttribute(renamingList); - _$attributeNode.append(renamingList.get$node()); - renamingList.get$node().hide(); - - conjSelection = new SingleSelectionAttribute( - id + "[conjunction]", - "Conjunction", - that, - LogicalConjunctions - ); - that.addAttribute(conjSelection); - _$attributeNode.append(conjSelection.get$node()); - conjSelection.get$node().hide(); - - if (json && conjSelection && cla && renamingList && targetAttribute) - that.showAttributes(); - - this.setContextMenuItemCallback(function () { - var viewId = $("#lblCurrentView").text(); - return { - addShape: { - name: "Add Node Shape", - callback: function () { - var canvas = that.getCanvas(), - appearance = that.getAppearance(); - - //noinspection JSAccessibilityCheck - canvas - .createNode( - NodeShapeNode.TYPE, - appearance.left + appearance.width + 50, - appearance.top, - 150, - 100 - ) - .done(function (nodeId) { - canvas.createEdge( - BiDirAssociationEdge.TYPE, - that.getEntityId(), - nodeId, - null, - null, - viewId - ); - }); - }, - disabled: function () { - var edges = that.getEdges(), - edge, - edgeId; - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if ( - (edge instanceof BiDirAssociationEdge && - ((edge.getTarget() === that && - edge.getSource() instanceof NodeShapeNode) || - (edge.getSource() === that && - edge.getTarget() instanceof NodeShapeNode))) || - (edge instanceof UniDirAssociationEdge && - edge.getTarget() instanceof NodeShapeNode) - ) { - return true; - } - } - } - return false; - }, - }, - sep: "---------", - }; - }); - } -} - -/** - * ViewRelationshipNode - * @class canvas_widget.ViewRelationshipNode - * @extends canvas_widget.AbstractNode - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {number} zIndex Position of node on z-axis - * @param {object} json indicates if the ViewObjectNode is created from a json - - */ -let ViewRelationshipNode$1 = class ViewRelationshipNode extends AbstractNode { - static TYPE = "ViewRelationship"; - static DEFAULT_WIDTH = 150; - static DEFAULT_HEIGHT = 100; - constructor(id, left, top, width, height, zIndex, json) { - super(id, "ViewRelationship", left, top, width, height, zIndex, json); - var that = this; - - /** - * jQuery object of node template - * @type {jQuery} - * @private - */ - var _$template = $( - lodash.template(viewrelationshipNodeHtml$1)({ - type: that.getType(), - }) - ); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = AbstractNode.prototype.get$node - .call(this) - .append(_$template) - .addClass("viewrelationship"); - - /** - * jQuery object of DOM node representing the attributes - * @type {jQuery} - * @private - */ - var _$attributeNode = _$node.find(".attributes"); - - /** - * Attributes of node - * @type {Object} - * @private - */ - this.getAttributes(); - - /** - * Get JSON representation of the node - * @returns {Object} - */ - this.toJSON = function () { - return AbstractNode.prototype.toJSON.call(this); - }; - - this.registerYMap = function () { - AbstractNode.prototype.registerYMap.call(this); - that.getLabel().getValue().registerYType(); - attributeList.registerYMap(); - if (cla) cla.registerYMap(); - attribute.getValue().registerYType(); - conjSelection.getValue().registerYType(); - }; - - this.showAttributes = function () { - if (renamingList.get$node().is(":hidden")) renamingList.get$node().show(); - if (conjSelection.get$node().is(":hidden")) - conjSelection.get$node().show(); - if (cla.get$node().is(":hidden")) cla.get$node().show(); - if (!targetAttribute.get$node().is(":hidden")) - targetAttribute.get$node().hide(); - }; - - this.createConditionListAttribute = function (refAttrs) { - var targetAttrList = {}; - if (refAttrs && refAttrs.constructor.name === "RenamingListAttribute") { - var attrs = refAttrs.getAttributes(); - for (var key in attrs) { - if (attrs.hasOwnProperty(key)) { - targetAttrList[key] = attrs[key].getKey().getValue(); - } - } - } else { - for (var key in refAttrs) { - if (refAttrs.hasOwnProperty(key)) { - targetAttrList[key] = refAttrs[key].val.value; - } - } - } - var conditionListAttr = new ConditionListAttribute( - "[condition]", - "Conditions", - that, - targetAttrList, - LogicalOperator - ); - that.addAttribute(conditionListAttr); - _$attributeNode.append(conditionListAttr.get$node()); - conditionListAttr.get$node().hide(); - return conditionListAttr; - }; - - this.registerYMap = function () { - AbstractNode.prototype.registerYMap.call(this); - that.getLabel().getValue().registerYType(); - renamingList.registerYMap(); - if (cla) cla.registerYMap(); - targetAttribute.getValue().registerYType(); - conjSelection.getValue().registerYType(); - }; - - var targetAttribute, renamingList, conjSelection, cla; - _$node.find(".label").append(this.getLabel().get$node()); - if (window.hasOwnProperty("y")) { - const dataMap = y.getMap("data"); - var model = dataMap.get("model"); - if (model) { - var selectionValues = - ViewTypesUtil.GetAllNodesOfBaseModelAsSelectionList2(model.nodes, [ - "Relationship", - ]); - targetAttribute = new SingleSelectionAttribute( - id + "[target]", - "Reference", - that, - selectionValues - ); - that.addAttribute(targetAttribute); - _$attributeNode.prepend(targetAttribute.get$node()); - - if (json) - cla = that.createConditionListAttribute( - json.attributes["[attributes]"].list - ); - else cla = that.createConditionListAttribute(); - } - } - - renamingList = new RenamingListAttribute( - "[attributes]", - "Attributes", - that, - { - hidden: "Show", - top: "Show Top", - center: "Show Center", - bottom: "Show Bottom", - hide: "Hide", - } - ); - that.addAttribute(renamingList); - _$attributeNode.append(renamingList.get$node()); - renamingList.get$node().hide(); - - conjSelection = new SingleSelectionAttribute( - id + "[conjunction]", - "Conjunction", - that, - LogicalConjunctions - ); - that.addAttribute(conjSelection); - _$attributeNode.append(conjSelection.get$node()); - conjSelection.get$node().hide(); - - if (json && conjSelection && cla && renamingList && targetAttribute) - that.showAttributes(); - - this.setContextMenuItemCallback(function () { - var viewId = $("#lblCurrentView").text(); - return { - addShape: { - name: "Add Edge Shape", - callback: function () { - var canvas = that.getCanvas(), - appearance = that.getAppearance(), - nodeId; - - canvas.createNode( - EdgeShapeNode.TYPE, - appearance.left + appearance.width + 50, - appearance.top, - 150, - 100 - ); - canvas.createEdge( - BiDirAssociationEdge.TYPE, - that.getEntityId(), - nodeId, - null, - null, - viewId - ); - }, - disabled: function () { - var edges = that.getEdges(), - edge, - edgeId; - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if ( - (edge instanceof BiDirAssociationEdge && - ((edge.getTarget() === that && - edge.getSource() instanceof EdgeShapeNode) || - (edge.getSource() === that && - edge.getTarget() instanceof EdgeShapeNode))) || - (edge instanceof UniDirAssociationEdge && - edge.getTarget() instanceof EdgeShapeNode) - ) { - return true; - } - } - } - return false; - }, - }, - sep: "---------", - }; - }); - } -}; - -/** - * BiDirAssociationEdge - * @class canvas_widget.BiDirAssociationEdge - * @extends canvas_widget.AbstractEdge - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of edge - * @param {canvas_widget.AbstractNode} source Source node - * @param {canvas_widget.AbstractNode} target Target node - */ - -/** - * GeneralisationEdge - * @class GeneralisationEdge - * @extends AbstractEdge - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of edge - * @param {canvas_widget.AbstractNode} source Source node - * @param {canvas_widget.AbstractNode} target Target node - */ -class GeneralisationEdge extends AbstractEdge { - static TYPE = "Generalisation"; - static RELATIONS = [ - { - sourceTypes: [ObjectNode.TYPE], - targetTypes: [ObjectNode.TYPE, AbstractClassNode.TYPE], - }, - { - sourceTypes: [RelationshipNode.TYPE], - targetTypes: [RelationshipNode.TYPE, AbstractClassNode.TYPE], - }, - { - sourceTypes: [RelationshipGroupNode.TYPE], - targetTypes: [RelationshipNode.TYPE, ViewRelationshipNode$1.TYPE], - }, - { - sourceTypes: [AbstractClassNode.TYPE], - targetTypes: [AbstractClassNode.TYPE], - }, - { - sourceTypes: [EnumNode.TYPE], - targetTypes: [EnumNode.TYPE], - }, - ]; - - constructor(id, source, target) { - super(id, GeneralisationEdge.TYPE, source, target); - var that = this; - - /** - * Connect source and target node and draw the edge on canvas - */ - this.connect = function () { - var source = this.getSource(); - var target = this.getTarget(); - var connectOptions = { - source: source.get$node().get(0), - target: target.get$node().get(0), - paintStyle: { - stroke: "black", - strokeWidth: 4, - }, - endpoint: "Dot", - anchors: [source.getAnchorOptions(), target.getAnchorOptions()], - connector: { - type: StraightConnector.type, - options: { gap: 0 }, - }, - overlays: [ - { - type: "Arrow", - options: { - width: 20, - length: 25, - location: 1, - foldback: 1, - paintStyle: { - fill: "#ffffff", - outlineWidth: 2, - dashstyle: "black", - }, - }, - }, - { - type: "Custom", - options: { - create: function () { - return that.get$overlay().get(0); - }, - location: 0.5, - id: "label", - }, - }, - ], - cssClass: this.getEntityId(), - }; - - if (source === target) { - connectOptions.anchor = ["TopCenter", "LeftMiddle"]; - } - - source.addOutgoingEdge(this); - target.addIngoingEdge(this); - this.setJsPlumbConnection(window.jsPlumbInstance.connect(connectOptions)); - - this.repaintOverlays(); - lodash.each(EntityManagerInstance.getEdges(), function (e) { - e.setZIndex(); - }); - }; - - this.get$overlay().find(".type").addClass("segmented"); - } -} - -/** - * UniDirAssociationEdge - * @class canvas_widget.UniDirAssociationEdge - * @extends canvas_widget.AbstractEdge - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of edge - * @param {canvas_widget.AbstractNode} source Source node - * @param {canvas_widget.AbstractNode} target Target node - */ -class UniDirAssociationEdge extends AbstractEdge { - static TYPE = "Uni-Dir-Association"; - static RELATIONS = [ - { - sourceTypes: [ObjectNode.TYPE], - targetTypes: [ - EnumNode.TYPE, - NodeShapeNode.TYPE, - RelationshipNode.TYPE, - RelationshipGroupNode.TYPE, - ViewRelationshipNode$1.TYPE, - ], - }, - { - sourceTypes: [RelationshipNode.TYPE], - targetTypes: [ - EnumNode.TYPE, - EdgeShapeNode.TYPE, - ObjectNode.TYPE, - AbstractClassNode.TYPE, - ViewObjectNode.TYPE, - ], - }, - { - sourceTypes: [RelationshipGroupNode.TYPE], - targetTypes: [ObjectNode.TYPE, AbstractClassNode.TYPE], - }, - { - sourceTypes: [AbstractClassNode.TYPE], - targetTypes: [ - EnumNode.TYPE, - RelationshipNode.TYPE, - RelationshipGroupNode.TYPE, - ], - }, - { - sourceTypes: [ViewObjectNode.TYPE], - targetTypes: [ - EnumNode.TYPE, - NodeShapeNode.TYPE, - RelationshipNode.TYPE, - RelationshipGroupNode.TYPE, - ViewRelationshipNode$1.TYPE, - ], - }, - { - sourceTypes: [ViewRelationshipNode$1.TYPE], - targetTypes: [ - EnumNode.TYPE, - EdgeShapeNode.TYPE, - ObjectNode.TYPE, - AbstractClassNode.TYPE, - ViewObjectNode.TYPE, - ], - }, - ]; - - constructor(id, source, target) { - super(id, UniDirAssociationEdge.TYPE, source, target); - var that = this; - - /** - * Connect source and target node and draw the edge on canvas - */ - this.connect = function () { - var source = this.getSource(); - var target = this.getTarget(); - var connectOptions = { - source: source.get$node().get(0), - target: target.get$node().get(0), - paintStyle: { - stroke: "black", - strokeWidth: 4, - }, - endpoint: "Dot", - anchors: [source.getAnchorOptions(), target.getAnchorOptions()], - connector: { - type: StraightConnector.type, - options: { gap: 0 }, - }, - overlays: [ - { - type: "Arrow", - options: { - width: 20, - length: 30, - location: 1, - foldback: 0.5, - paintStyle: { - fill: "#ffffff", - outlineWidth: 2, - outlineStroke: "black", - }, - }, - }, - { - type: "Custom", - options: { - create: function () { - return that.get$overlay().get(0); - }, - location: 0.5, - id: "label", - }, - }, - ], - cssClass: this.getEntityId(), - }; - - if (source === target) { - connectOptions.anchors = ["TopCenter", "LeftMiddle"]; - } - - source.addOutgoingEdge(this); - target.addIngoingEdge(this); - this.setJsPlumbConnection(window.jsPlumbInstance.connect(connectOptions)); - - this.repaintOverlays(); - lodash.each(EntityManagerInstance.getEdges(), function (e) { - e.setZIndex(); - }); - }; - - this.get$overlay().find(".type").addClass("segmented"); - - /*this.setContextMenuItems({ - sep0: "---------", - convertToBiDirAssociationEdge: { - name: "Convert to Bi-Dir. Assoc. Edge", - callback: function(){ - var canvas = that.getCanvas(); - - //noinspection JSAccessibilityCheck - canvas.createEdge(require('canvas_widget/BiDirAssociationEdge').TYPE,that.getSource().getEntityId(),that.getTarget().getEntityId(),that.toJSON()); - - that.triggerDeletion(); - - } - } - });*/ - } -} - -class BiDirAssociationEdge extends AbstractEdge { - static TYPE = "Bi-Dir-Association"; - static RELATIONS = [ - { - sourceTypes: [ObjectNode.TYPE], - targetTypes: [ - EnumNode.TYPE, - NodeShapeNode.TYPE, - RelationshipNode.TYPE, - RelationshipGroupNode.TYPE, - ViewRelationshipNode$1.TYPE, - ], - }, - { - sourceTypes: [RelationshipNode.TYPE], - targetTypes: [ - EnumNode.TYPE, - EdgeShapeNode.TYPE, - ObjectNode.TYPE, - AbstractClassNode.TYPE, - ViewObjectNode.TYPE, - ], - }, - { - sourceTypes: [RelationshipGroupNode.TYPE], - targetTypes: [ObjectNode.TYPE, AbstractClassNode.TYPE], - }, - { - sourceTypes: [AbstractClassNode.TYPE], - targetTypes: [ - EnumNode.TYPE, - RelationshipNode.TYPE, - RelationshipGroupNode.TYPE, - ], - }, - { - sourceTypes: [EnumNode.TYPE], - targetTypes: [ - ObjectNode.TYPE, - RelationshipNode.TYPE, - AbstractClassNode.TYPE, - ], - }, - { - sourceTypes: [NodeShapeNode.TYPE], - targetTypes: [ObjectNode.TYPE], - }, - { - sourceTypes: [EdgeShapeNode.TYPE], - targetTypes: [RelationshipNode.TYPE], - }, - { - sourceTypes: [ViewObjectNode.TYPE], - targetTypes: [ - EnumNode.TYPE, - NodeShapeNode.TYPE, - RelationshipNode.TYPE, - RelationshipGroupNode.TYPE, - ViewRelationshipNode$1.TYPE, - ], - }, - { - sourceTypes: [ViewRelationshipNode$1.TYPE], - targetTypes: [ - EnumNode.TYPE, - EdgeShapeNode.TYPE, - ObjectNode.TYPE, - AbstractClassNode.TYPE, - ViewObjectNode.TYPE, - ], - }, - ]; - constructor(id, source, target) { - super(id, BiDirAssociationEdge.TYPE, source, target); - var that = this; - - /** - * Connect source and target node and draw the edge on canvas - */ - this.connect = function () { - var source = this.getSource(); - var target = this.getTarget(); - var connectOptions = { - source: source.get$node().get(0), - target: target.get$node().get(0), - paintStyle: { - stroke: "black", - strokeWidth: 4, - }, - endpoint: "Dot", - anchors: [source.getAnchorOptions(), target.getAnchorOptions()], - connector: { - type: StraightConnector.type, - options: { gap: 0 }, - }, - overlays: [ - { - type: "Custom", - options: { - create: function () { - return that.get$overlay().get(0); - }, - location: 0.5, - id: "label", - }, - }, - ], - cssClass: this.getEntityId(), - }; - - if (source === target) { - connectOptions.anchors = ["TopCenter", "LeftMiddle"]; - } - - source.addOutgoingEdge(this); - target.addIngoingEdge(this); - this.setJsPlumbConnection(window.jsPlumbInstance.connect(connectOptions)); - - this.repaintOverlays(); - lodash.each(EntityManagerInstance.getEdges(), function (e) { - e.setZIndex(); - }); - }; - - this.get$overlay().find(".type").addClass("segmented"); - } + /** + * Get type of Operation + * @returns {string} + */ + this.getType = function(){ + //noinspection JSAccessibilityCheck + return _operation.type; + }; + + /** + * Get additional data for operation + * @returns {string} + */ + this.getData = function(){ + return _operation.data; + }; + + /** + * Get JSON Representation of operation + * @returns {{type: string, data: string}} + */ + this.getOperationObject = function(){ + return _operation; + }; + } + +/** + * EntityOperation + * @class operations.ot.EntityOperation + * @memberof operations.ot + * @param {string} operationType Type of operation + * @param {string} entityId Entity id of the entity this activity works on + * @param {string} entityType Type of the entity this activity works on + * @constructor + */ +class EntityOperation { + static TYPES = { + AttributeAddOperation: "AttributeAddOperation", + AttributeDeleteOperation: "AttributeDeleteOperation", + EdgeAddOperation: "EdgeAddOperation", + EdgeDeleteOperation: "EdgeDeleteOperation", + NodeAddOperation: "NodeAddOperation", + NodeDeleteOperation: "NodeDeleteOperation", + NodeMoveOperation: "NodeMoveOperation", + NodeMoveZOperation: "NodeMoveZOperation", + NodeResizeOperation: "NodeResizeOperation", + ValueChangeOperation: "ValueChangeOperation", + }; + getOperationType; + setOTOperation; + _getOTOperation; + getEntityId; + getEntityType; + adjust; + inverse; + toJSON; + + triggeredBy; + constructor(operationType, entityId, entityType) { + this.triggeredBy = window.y.clientID; + + /** + * Type of operation + * @type {string} + * @private + */ + var _operationType = operationType; + + /** + * Corresponding OtOperation + * @type {operations.ot.OTOperation} + * @private + */ + var _otOperation = null; + + /** + * Entity id of the entity this activity works on + * @type {string} + * @private + */ + var _entityId = entityId; + + /** + * Type of the entity this activity works on + * @type {string} + * @private + */ + var _entityType = entityType; + + /** + * Get type of operation + * @returns {string} + */ + this.getOperationType = function () { + return _operationType; + }; + + /** + * Set corresponding ot operation + * @param {operations.ot.OTOperation} otOperation + */ + this.setOTOperation = function (otOperation) { + _otOperation = otOperation; + }; + + /** + * Get corresponding ot operation + * @returns {operations.ot.OTOperation} + * @private + */ + this._getOTOperation = function () { + return _otOperation; + }; + + /** + * Get entity id of the entity this activity works onf + * @returns {string} + */ + this.getEntityId = function () { + return _entityId; + }; + + //noinspection JSUnusedGlobalSymbols + /** + * Get type of the entity this activity works on + * @returns {string} + */ + this.getEntityType = function () { + return _entityType; + }; + + /** + * Adjust the passed operation in the history of operation + * when this operation is applied remotely after the passed operation + * on an graph instance stored in the passed EntityManager + * @param {canvas_widget.EntityManager} EntityManager + * @param {EntityOperation} operation Remote operation + * @returns {EntityOperation} + */ + this.adjust = function (EntityManager, operation) { + return operation; + }; + + /** + * Compute the inverse of the operation + * @returns {operations.ot.EntityOperation} + */ + this.inverse = function () { + return this; + }; + } + //noinspection JSAccessibilityCheck + /** + * Get corresponding ot operation + * @returns {operations.ot.OTOperation} + */ + getOTOperation() { + return this._getOTOperation(); + } +} + +/** + * NodeDeleteOperation + * @class operations.ot.NodeDeleteOperation + * @memberof operations.ot + * @extends operations.ot.EntityOperation + * @param {String} entityId Entity id of the entity this activity works on + * @param {String} type Type of node to delete + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {number} zIndex Position of node on z-axis + * @param {boolean} containment containment + * @param {object} json JSON representation of node + * @constructor + */ +class NodeDeleteOperation extends EntityOperation { + static TYPE = "NodeDeleteOperation"; + getType; + getLeft; + getTop; + getWidth; + getHeight; + getZIndex; + getContainment; + getJSON; + constructor( + entityId, + type, + left, + top, + width, + height, + zIndex, + containment, + json + ) { + super( + EntityOperation.TYPES.NodeDeleteOperation, + entityId, + CONFIG.ENTITY.NODE + ); + var that = this; + + /** + * Type of node to add + * @type {String} + * @private + */ + var _type = type; + + /** + * x-coordinate of node position + * @type {number} + * @private + */ + var _left = left; + + /** + * y-coordinate of node position + * @type {number} + * @private + */ + var _top = top; + + /** + * Width of node + * @type {number} + * @private + */ + var _width = width; + + /** + * Height of node + * @type {number} + * @private + */ + var _height = height; + + /** + * Position of node on z-axis + * @type {number} + * @private + */ + var _zIndex = zIndex; + + /** + * is containment type + * @type {boolean} + * @private + */ + var _containment = containment; + + /** + * JSON representation of node + * @type {Object} + * @private + */ + var _json = json; + + /** + * Create OTOperation for operation + * @returns {operations.ot.OTOperation} + */ + var createOTOperation = function () { + return new OTOperation( + CONFIG.ENTITY.NODE + ":" + that.getEntityId(), + JSON.stringify({ + type: _type, + left: _left, + top: _top, + width: _width, + height: _height, + zIndex: _zIndex, + containment: _containment, + json: _json, + }), + CONFIG.OPERATION.TYPE.UPDATE, + CONFIG.IWC.POSITION.NODE.DEL + ); + }; + + /** + * Get type of node to add + * @returns {String} + */ + this.getType = function () { + return _type; + }; + + /** + * Get x-coordinate of node position + * @returns {number} + */ + this.getLeft = function () { + return _left; + }; + + /** + * Get y-coordinate of node position + * @returns {number} + */ + this.getTop = function () { + return _top; + }; + + /** + * Get width of node + * @returns {number} + */ + this.getWidth = function () { + return _width; + }; + + /** + * Get height of node + * @returns {number} + */ + this.getHeight = function () { + return _height; + }; + + /** + * Get position of node on z-axis + * @returns {number} + */ + this.getZIndex = function () { + return _zIndex; + }; + + /** + * is containment type + * @returns {boolean} + */ + this.getContainment = function () { + return _containment; + }; + + /** + * Get JSON representation of node + * @return {Object} + */ + this.getJSON = function () { + return _json; + }; + + /** + * Get corresponding ot operation + * @returns {operations.ot.OTOperation} + * @private + */ + this.getOTOperation = function () { + var otOperation = EntityOperation.prototype.getOTOperation.call(this); + if (otOperation === null) { + otOperation = createOTOperation(); + this.setOTOperation(otOperation); + } + return otOperation; + }; + + /** + * Adjust the passed operation in the history of operation + * when this operation is applied remotely after the passed operation + * on an graph instance stored in the passed EntityManager + * @param {canvas_widget.EntityManager} EntityManager + * @param {EntityOperation} operation Remote operation + * @returns {EntityOperation} + */ + this.adjust = function (EntityManager, operation) { + var edge; + switch (operation.getOperationType()) { + case EntityOperation.TYPES.AttributeAddOperation: + case EntityOperation.TYPES.AttributeDeleteOperation: + edge = EntityManager.findEdge(operation.getRootSubjectEntityId()); + if ( + edge && + (edge.getSource().getEntityId() === this.getEntityId() || + edge.getTarget().getEntityId() === this.getEntityId()) + ) { + return null; + } + if (this.getEntityId() === operation.getRootSubjectEntityId()) { + return null; + } + break; + case EntityOperation.TYPES.EdgeAddOperation: + case EntityOperation.TYPES.EdgeDeleteOperation: + edge = EntityManager.findEdge(operation.getEntityId()); + if ( + edge && + (edge.getSource().getEntityId() === this.getEntityId() || + edge.getTarget().getEntityId() === this.getEntityId()) + ) { + return null; + } + break; + case EntityOperation.TYPES.NodeAddOperation: + case EntityOperation.TYPES.NodeDeleteOperation: + case EntityOperation.TYPES.NodeMoveOperation: + case EntityOperation.TYPES.NodeResizeOperation: + if (this.getEntityId() === operation.getEntityId()) { + return null; + } + break; + case EntityOperation.TYPES.ValueChangeOperation: + edge = EntityManager.findEdge(operation.getRootSubjectEntityId()); + if ( + edge && + (edge.getSource().getEntityId() === this.getEntityId() || + edge.getTarget().getEntityId() === this.getEntityId()) + ) { + return null; + } + if (operation.getRootSubjectEntityId() === this.getEntityId()) { + return null; + } + break; + } + + return operation; + }; + + /** + * Compute the inverse of the operation + * @returns {operations.ot.NodeAddOperation} + */ + this.inverse = function () { + return new NodeAddOperation( + this.getEntityId(), + this.getType(), + this.getLeft(), + this.getTop(), + this.getWidth(), + this.getHeight(), + this.getZIndex(), + this.getContainment(), + this.getContainment(), + json + ); + }; + } + static getOperationDescription(nodeType, nodeLabel, viewId) { + if (!nodeLabel && !viewId) { + return "..deleted " + nodeType; + } else if (!viewId) { + return "..deleted " + nodeType + " " + nodeLabel; + } else + return "..deleted " + nodeType + " " + nodeLabel + " in View " + viewId; + } + toJSON = function () { + return { + id: this.getEntityId(), + type: this.getType(), + left: this.getLeft(), + top: this.getTop(), + width: this.getWidth(), + height: this.getHeight(), + zIndex: this.getZIndex(), + containment: this.getContainment(), + json: this.getJSON(), + }; + }; +} + +class NodeAddOperation extends EntityOperation { + static TYPE = "NodeAddOperation"; + getType; + getOriginType; + getLeft; + getTop; + getWidth; + getHeight; + getZIndex; + getContainment; + getJSON; + getViewId; + getJabberId; + getDefaultLabel; + getDefaultAttributeValues; + toJSON; + + constructor( + entityId, + type, + left, + top, + width, + height, + zIndex, + containment, + json = null, + viewId = null, + oType = null, + jabberId = null, + defaultLabel = null, + defaultAttributeValues = null + ) { + super(EntityOperation.TYPES.NodeAddOperation, entityId, CONFIG.ENTITY.NODE); + var that = this; + + /** + * the identifier of the view + * @type {string} + * @private + */ + var _viewId = viewId; + + /** + * the jabberId of the user + * @type {string} + * @private + */ + var _jabberId = jabberId; + + var _oType = oType; + + /** + * Type of node to add + * @type {String} + * @private + */ + var _type = type; + + /** + * x-coordinate of node position + * @type {number} + * @private + */ + var _left = left; + + /** + * y-coordinate of node position + * @type {number} + * @private + */ + var _top = top; + + /** + * Width of node + * @type {number} + * @private + */ + var _width = width; + + /** + * Height of node + * @type {number} + * @private + */ + var _height = height; + + /** + * Position of node on z-axis + * @type {number} + * @private + */ + var _zIndex = zIndex; + + /** + * is containment type + * @type {boolean} + * @private + */ + var _containment = containment; + + /** + * JSON representation of node + * @type {Object} + * @private + */ + var _json = json; + + /** + * Default label of node + * @type {String} + * @private + */ + var _defaultLabel = defaultLabel; + + /** + * May be used to set default values for node attributes. + */ + var _defaultAttributeValues = defaultAttributeValues; + + /** + * Create OTOperation for operation + * @returns {operations.ot.OTOperation} + */ + var createOTOperation = function () { + return new OTOperation( + CONFIG.ENTITY.NODE + ":" + that.getEntityId(), + JSON.stringify({ + type: _type, + left: _left, + top: _top, + width: _width, + height: _height, + zIndex: _zIndex, + containment: _containment, + json: _json, + viewId: _viewId, + oType: _oType, + jabberId: _jabberId, + }), + CONFIG.OPERATION.TYPE.INSERT, + CONFIG.IWC.POSITION.NODE.ADD + ); + }; + + /** + * Get type of node to add + * @returns {String} + */ + this.getType = function () { + return _type; + }; + + this.getOriginType = function () { + return _oType; + }; + + /** + * Get x-coordinate of node position + * @returns {number} + */ + this.getLeft = function () { + return _left; + }; + + /** + * Get y-coordinate of node position + * @returns {number} + */ + this.getTop = function () { + return _top; + }; + + /** + * Get width of node + * @returns {number} + */ + this.getWidth = function () { + return _width; + }; + + /** + * Get height of node + * @returns {number} + */ + this.getHeight = function () { + return _height; + }; + + /** + * Get position of node on z-axis + * @returns {number} + */ + this.getZIndex = function () { + return _zIndex; + }; + + /** + * Get containment + * @returns {boolean} + */ + this.getContainment = function () { + return _containment; + }; + + /** + * Get JSON representation of node + * @return {Object} + */ + this.getJSON = function () { + return _json; + }; + + /** + * the identifier of the view + * @returns {string} + */ + this.getViewId = function () { + return _viewId; + }; + + /** + * Get the jabberid + * @returns {string} + */ + this.getJabberId = function () { + return _jabberId; + }; + + /** + * Get default label of node + * @returns {string} + */ + this.getDefaultLabel = function () { + return _defaultLabel; + }; + + /** + * Get default values for node attributes. + * @returns {*} + */ + this.getDefaultAttributeValues = function () { + return _defaultAttributeValues; + }; + + /** + * Get corresponding ot operation + * @returns {operations.ot.OTOperation} + * @private + */ + this.getOTOperation = function () { + var otOperation = EntityOperation.prototype.getOTOperation.call(this); + if (otOperation === null) { + otOperation = createOTOperation(); + this.setOTOperation(otOperation); + } + return otOperation; + }; + + /** + * Adjust the passed operation in the history of operation + * when this operation is applied remotely after the passed operation + * on an graph instance stored in the passed EntityManager + * @param {canvas_widget.EntityManager} EntityManager + * @param {EntityOperation} operation Remote operation + * @returns {EntityOperation} + */ + this.adjust = function (EntityManager, operation) { + return operation; + }; + + /** + * Compute the inverse of the operation + * @returns {NodeDeleteOperation} + */ + this.inverse = function () { + return new NodeDeleteOperation( + this.getEntityId(), + this.getType(), + this.getLeft(), + this.getTop(), + this.getWidth(), + this.getHeight(), + this.getZIndex(), + this.getContainment(), + json + ); + }; + + this.toJSON = function () { + return { + id: this.getEntityId(), + type: this.getType(), + left: this.getLeft(), + top: this.getTop(), + width: this.getWidth(), + height: this.getHeight(), + zIndex: this.getZIndex(), + containment: this.getContainment(), + json: this.getJSON(), + viewId: this.getViewId(), + oType: this.getOriginType(), + jabberId: this.getJabberId(), + defaultLabel: this.getDefaultLabel(), + defaultAttributeValues: this.getDefaultAttributeValues(), + triggeredBy: this.triggeredBy, + }; + }; + } + static getOperationDescription(nodeType, nodeLabel, viewId) { + if (!nodeLabel && !viewId) { + return "..created a new " + nodeType; + } else if (!viewId) { + return "..created " + nodeType + " " + nodeLabel; + } else + return ".. created " + nodeType + " " + nodeLabel + " in View " + viewId; + } +} + +/** + * EdgeDeleteOperation + * @class operations.ot.EdgeDeleteOperation + * @memberof operations.ot + * @extends operations.ot.EntityOperation + * @param entityId Entity id of the entity this activity works on + * @param {String} type Type of edge to delete + * @param {String} source Entity id of source node + * @param {String} target Entity id of target node + * @param {object} json JSON representation of edge + * @constructor + */ +class EdgeDeleteOperation extends EntityOperation { + static TYPE = "EdgeDeleteOperation"; + getType; + getSource; + getTarget; + getJSON; + constructor(entityId, type, source, target, json = null) { + super( + EntityOperation.TYPES.EdgeDeleteOperation, + entityId, + CONFIG.ENTITY.EDGE + ); + var that = this; + + /** + * Type of edge to delte + * @type {String} + * @private + */ + var _type = type; + + /** + * Entity id of source node + * @type {String} + * @private + */ + var _source = source; + + /** + * Entity id of target node + * @type {String} + * @private + */ + var _target = target; + + /** + * JSON representation of node + * @type {Object} + * @private + */ + var _json = json; + + /** + * Create OTOperation for operation + * @returns {operations.ot.OTOperation} + */ + var createOTOperation = function () { + return new OTOperation( + CONFIG.ENTITY.EDGE + ":" + that.getEntityId(), + JSON.stringify({ + type: _type, + source: _source, + target: _target, + json: _json, + }), + CONFIG.OPERATION.TYPE.UPDATE, + CONFIG.IWC.POSITION.EDGE.DEL + ); + }; + + /** + * Get type of edge to delete + * @returns {String} + */ + this.getType = function () { + return _type; + }; + + /** + * Get entity id of source node + * @returns {String} + */ + this.getSource = function () { + return _source; + }; + + /** + * Get entity id of target node + * @returns {String} + */ + this.getTarget = function () { + return _target; + }; + + /** + * Get JSON representation of edge + * @return {Object} + */ + this.getJSON = function () { + return _json; + }; + + /** + * Get corresponding ot operation + * @returns {operations.ot.OTOperation} + * @private + */ + this.getOTOperation = function () { + var otOperation = EntityOperation.prototype.getOTOperation.call(this); + if (otOperation === null) { + otOperation = createOTOperation(); + this.setOTOperation(otOperation); + } + return otOperation; + }; + + /** + * Adjust the passed operation in the history of operation + * when this operation is applied remotely after the passed operation + * on an graph instance stored in the passed EntityManager + * @param {canvas_widget.EntityManager} EntityManager + * @param {EntityOperation} operation Remote operation + * @returns {EntityOperation} + */ + this.adjust = function (EntityManager, operation) { + switch (operation.getOperationType()) { + case EntityOperation.TYPES.AttributeAddOperation: + case EntityOperation.TYPES.AttributeDeleteOperation: + if (this.getEntityId() === operation.getRootSubjectEntityId()) { + return null; + } + break; + case EntityOperation.TYPES.EdgeAddOperation: + case EntityOperation.TYPES.EdgeDeleteOperation: + if (this.getEntityId() === operation.getEntityId()) { + return null; + } + break; + case EntityOperation.TYPES.ValueChangeOperation: + if (this.getEntityId() === operation.getRootSubjectEntityId()) { + return null; + } + break; + } + + return operation; + }; + + /** + * Compute the inverse of the operation + * @returns {EdgeAddOperation} + */ + this.inverse = function () { + return new EdgeAddOperation( + this.getEntityId(), + this.getType(), + this.getSource(), + this.getTarget() + ); + }; + } + static getOperationDescription(edgeType, edgeLabel, viewId) { + if (!edgeLabel && !viewId) { + return "..deleted " + edgeType; + } else if (!viewId) { + return "..deleted " + edgeType + " " + edgeLabel; + } else { + return "..deleted " + edgeType + " " + edgeLabel + "in View " + viewId; + } + } + toJSON = function () { + return { + id: this.getEntityId(), + type: this.getType(), + source: this.getSource(), + target: this.getTarget(), + json: this.getJSON(), + }; + }; +} + +/** + * EdgeAddOperation + * @class operations.ot.EdgeAddOperation + * @memberof operations.ot + * @extends operations.ot.EntityOperation + * @param {String} entityId Entity id of the entity this activity works on + * @param {String} type Type of edge to add + * @param {String} source Entity id of source node + * @param {String} target Entity id of target node + * @param {object} json JSON representation of edge + * @param {string} viewId the identifier of the view + * @param {string} oType oType the original Type, only set in views + * @param {string} jabberId the jabberId of the user + * @constructor + */ +class EdgeAddOperation extends EntityOperation { + static TYPE = "EdgeAddOperation"; + getOriginType; + getType; + getSource; + getTarget; + getViewId; + getJabberId; + getJSON; + constructor( + entityId, + type, + source, + target, + json = null, + viewId = null, + oType = null, + jabberId = null + ) { + super(EntityOperation.TYPES.EdgeAddOperation, entityId, CONFIG.ENTITY.EDGE); + var that = this; + + var _oType = oType; + + var _jabberId = jabberId; + + this.getOriginType = function () { + return _oType; + }; + + /** + * the identifier of the view + * @type {string} + * @private + */ + var _viewId = viewId; + + /** + * Type of edge to add + * @type {String} + * @private + */ + var _type = type; + + /** + * Entity id of source node + * @type {String} + * @private + */ + var _source = source; + + /** + * Entity id of target node + * @type {String} + * @private + */ + var _target = target; + + /** + * JSON representation of edge + * @type {Object} + * @private + */ + var _json = json; + + /** + * Create OTOperation for operation + * @returns {operations.ot.OTOperation} + */ + var createOTOperation = function () { + return new OTOperation( + CONFIG.ENTITY.EDGE + ":" + that.getEntityId(), + JSON.stringify({ + type: _type, + source: _source, + target: _target, + json: _json, + viewId: _viewId, + oType: _oType, + jabberId: _jabberId, + }), + CONFIG.OPERATION.TYPE.INSERT, + CONFIG.IWC.POSITION.EDGE.ADD + ); + }; + + /** + * Get type of edge to add + * @returns {String} + */ + this.getType = function () { + return _type; + }; + + /** + * Get entity id of source node + * @returns {String} + */ + this.getSource = function () { + return _source; + }; + + /** + * Get entity id of target node + * @returns {String} + */ + this.getTarget = function () { + return _target; + }; + + /** + * get the identifier of the view + * @returns {string} + */ + this.getViewId = function () { + return _viewId; + }; + + /** + * Get the jabber id + * @returns {string} + */ + this.getJabberId = function () { + return _jabberId; + }; + + /** + * Get JSON representation of edge + * @return {Object} + */ + this.getJSON = function () { + return _json; + }; + + /** + * Get corresponding ot operation + * @returns {operations.ot.OTOperation} + * @private + */ + this.getOTOperation = function () { + var otOperation = EntityOperation.prototype.getOTOperation.call(this); + if (otOperation === null) { + otOperation = createOTOperation(); + this.setOTOperation(otOperation); + } + return otOperation; + }; + + /** + * Adjust the passed operation in the history of operation + * when this operation is applied remotely after the passed operation + * on an graph instance stored in the passed EntityManager + * @param {canvas_widget.EntityManager} EntityManager + * @param {EntityOperation} operation Remote operation + * @returns {EntityOperation} + */ + this.adjust = function (EntityManager, operation) { + return operation; + }; + + /** + * Compute the inverse of the operation + * @returns {EdgeDeleteOperation} + */ + this.inverse = function () { + return new EdgeDeleteOperation( + this.getEntityId(), + this.getType(), + this.getSource(), + this.getTarget() + ); + }; + } + static getOperationDescription( + edgeType, + edgeLabel, + sourceNodeType, + sourceNodeLabel, + targetNodeType, + targetNodeLabel, + viewId + ) { + if (!edgeLabel && !viewId) { + return ( + "..created a new " + + edgeType + + " between " + + sourceNodeType + + " " + + sourceNodeLabel + + " and " + + targetNodeType + + " " + + targetNodeLabel + ); + } else if (!viewId) { + return ( + "..created " + + edgeType + + " " + + edgeLabel + + " between " + + sourceNodeType + + " " + + sourceNodeLabel + + " and " + + targetNodeType + + " " + + targetNodeLabel + ); + } else { + return ( + "..created " + + edgeType + + " " + + edgeLabel + + " between " + + sourceNodeType + + " " + + sourceNodeLabel + + " and " + + targetNodeType + + " " + + targetNodeLabel + + " in View " + + viewId + ); + } + } + toJSON = function () { + return { + id: this.getEntityId(), + type: this.getType(), + source: this.getSource(), + target: this.getTarget(), + json: this.getJSON(), + viewId: this.getViewId(), + oType: this.getOriginType(), + jabberId: this.getJabberId(), + }; + }; +} + +/** + * AttributeAddOperation + * @class operations.ot.AttributeAddOperation + * @memberof operations.ot + * @extends operations.ot.EntityOperation + * @param {String} entityId Entity id of the entity this activity works on + * @param {String} subjectEntityId Id of the entity the attribute is assigned to + * @param {String} rootSubjectEntityId Id of topmost entity in the chain of entities the attribute is assigned to + * @param {String} type Type of attribute to add + * @constructor + */ +class AttributeAddOperation extends EntityOperation { + static TYPE = "AttributeAddOperation"; + getSubjectEntityId; + getRootSubjectEntityId; + getType; + getData; + toJSON; + constructor( + entityId, + subjectEntityId, + rootSubjectEntityId, + type, + data = null + ) { + super( + EntityOperation.TYPES.AttributeAddOperation, + entityId, + CONFIG.ENTITY.ATTR + ); + var that = this; + + /** + * Id of the entity the attribute is assigned to + * @type {String} + * @private + */ + var _subjectEntityId = subjectEntityId; + + /** + * Id of topmost entity in the chain of entities the attribute is assigned to + * @type {String} + * @private + */ + var _rootSubjectEntityId = rootSubjectEntityId; + + /** + * Type of attribute to add + * @type {String} + * @private + */ + var _type = type; + + var _data = data; + + /** + * Create OTOperation for operation + * @returns {operations.ot.OTOperation} + */ + var createOTOperation = function () { + return new OTOperation( + CONFIG.ENTITY.ATTR + ":" + that.getEntityId(), + JSON.stringify({ + type: _type, + subjectEntityId: _subjectEntityId, + rootSubjectEntityId: _rootSubjectEntityId, + data: _data, + }), + CONFIG.OPERATION.TYPE.INSERT, + CONFIG.IWC.POSITION.ATTR.ADD + ); + }; + + /** + * Get id of the entity the attribute is assigned to + * @returns {*} + */ + this.getSubjectEntityId = function () { + return _subjectEntityId; + }; + + /** + * Get id of topmost entity in the chain of entities the attribute is assigned to + * @returns {*} + */ + this.getRootSubjectEntityId = function () { + return _rootSubjectEntityId; + }; + + /** + * Get type of attribute to add + * @returns {*} + */ + this.getType = function () { + return _type; + }; + + /** + * Get corresponding ot operation + * @returns {operations.ot.OTOperation} + * @private + */ + this.getOTOperation = function () { + var otOperation = EntityOperation.prototype.getOTOperation.call(this); + if (otOperation === null) { + otOperation = createOTOperation(); + that.setOTOperation(otOperation); + } + return otOperation; + }; + + this.getData = function () { + return _data; + }; + + /** + * Adjust the passed operation in the history of operation + * when this operation is applied remotely after the passed operation + * on an graph instance stored in the passed EntityManager + * @param {canvas_widget.EntityManager} EntityManager + * @param {EntityOperation} operation Remote operation + * @returns {EntityOperation} + */ + this.adjust = function (EntityManager, operation) { + return operation; + }; + + /** + * Compute the inverse of the operation + * @returns {AttributeDeleteOperation} + */ + this.inverse = function () { + return new AttributeDeleteOperation( + that.getEntityId(), + that.getSubjectEntityId(), + that.getRootSubjectEntityId(), + that.getType() + ); + }; + + this.toJSON = function () { + return { + entityId: this.getEntityId(), + type: this.getType(), + subjectEntityId: this.getSubjectEntityId(), + rootSubjectEntityId: this.getRootSubjectEntityId(), + data: this.getData(), + }; + }; + } +} + +/** + * AttributeDeleteOperation + * @class operations.ot.AttributeDeleteOperation + * @memberof operations.ot + * @extends operations.ot.EntityOperation + * @param {String} entityId Entity id of the entity this activity works on + * @param {String} subjectEntityId Id of the entity the attribute is assigned to + * @param {String} rootSubjectEntityId Id of topmost entity in the chain of entities the attribute is assigned to + * @param {String} type Type of attribute to delete + * @constructor + */ +class AttributeDeleteOperation extends EntityOperation { + static TYPE = "AttributeDeleteOperation"; + getSubjectEntityId; + getRootSubjectEntityId; + getType; + toJSON; + constructor(entityId, subjectEntityId, rootSubjectEntityId, type) { + super( + EntityOperation.TYPES.AttributeDeleteOperation, + entityId, + CONFIG.ENTITY.ATTR + ); + var that = this; + + /** + * Id of the entity the attribute is assigned to + * @type {String} + * @private + */ + var _subjectEntityId = subjectEntityId; + + /** + * Id of topmost entity in the chain of entities the attribute is assigned to + * @type {String} + * @private + */ + var _rootSubjectEntityId = rootSubjectEntityId; + + /** + * Type of attribute to add + * @type {String} + * @private + */ + var _type = type; + + /** + * Create OTOperation for operation + * @returns {operations.ot.OTOperation} + */ + var createOTOperation = function () { + return new OTOperation( + CONFIG.ENTITY.ATTR + ":" + that.getEntityId(), + JSON.stringify({ + type: _type, + subjectEntityId: _subjectEntityId, + rootSubjectEntityId: _rootSubjectEntityId, + }), + CONFIG.OPERATION.TYPE.UPDATE, + CONFIG.IWC.POSITION.ATTR.DEL + ); + }; + + /** + * Get id of the entity the attribute is assigned to + * @returns {*} + */ + this.getSubjectEntityId = function () { + return _subjectEntityId; + }; + + /** + * Get id of topmost entity in the chain of entities the attribute is assigned to + * @returns {*} + */ + this.getRootSubjectEntityId = function () { + return _rootSubjectEntityId; + }; + + /** + * Get type of attribute to add + * @returns {*} + */ + this.getType = function () { + return _type; + }; + + /** + * Get corresponding ot operation + * @returns {operations.ot.OTOperation} + * @private + */ + this.getOTOperation = function () { + var otOperation = EntityOperation.prototype.getOTOperation.call(this); + if (otOperation === null) { + otOperation = createOTOperation(); + that.setOTOperation(otOperation); + } + return otOperation; + }; + + /** + * Adjust the passed operation in the history of operation + * when this operation is applied remotely after the passed operation + * on an graph instance stored in the passed EntityManager + * @param {canvas_widget.EntityManager} EntityManager + * @param {operations.ot.EntityOperation} operation Remote operation + * @returns {operations.ot.EntityOperation} + */ + this.adjust = function (EntityManager, operation) { + switch (operation.getOperationType()) { + case EntityOperation.TYPES.AttributeAddOperation: + case EntityOperation.TYPES.AttributeDeleteOperation: + if ( + that.getRootSubjectEntityId() === operation.getRootSubjectEntityId() + ) { + return null; + } + break; + case EntityOperation.TYPES.ValueChangeOperation: + if (operation.getEntityIdChain().indexOf(this.getEntityId()) !== -1) { + return null; + } + break; + } + + return operation; + }; + + /** + * Compute the inverse of the operation + * @returns {operations.ot.AttributeAddOperation} + */ + this.inverse = function () { + return new AttributeAddOperation( + this.getEntityId(), + this.getSubjectEntityId(), + this.getRootSubjectEntityId(), + this.getType() + ); + }; + this.toJSON = function () { + return { + entityId: this.getEntityId(), + type: this.getType(), + subjectEntityId: this.getSubjectEntityId(), + rootSubjectEntityId: this.getRootSubjectEntityId(), + }; + }; + } +} + +/** + * NodeMoveOperation + * @class operations.ot.NodeMoveOperation + * @memberof operations.ot + * @extends operations.ot.EntityOperation + * @param {String} entityId Entity id of the entity this activity works on + * @param {number} offsetX Offset in x-direction + * @param {number} offsetY Offset in y-direction + * @param {string} optional: jabberId the jabberId of the user (is automatically set by propagateNodeMoveOperation) + * @constructor + */ +class NodeMoveOperation extends EntityOperation { + static TYPE = "NodeMoveOperation"; + getOffsetX; + getOffsetY; + getJabberId; + setJabberId; + constructor(entityId, offsetX, offsetY, jabberId) { + super( + EntityOperation.TYPES.NodeMoveOperation, + entityId, + CONFIG.ENTITY.NODE + ); + var that = this; + + /** + * Offset in x-direction + * @type {number} + * @private + */ + var _offsetX = offsetX; + + /** + * Offset in y-direction + * @type {number} + * @private + */ + var _offsetY = offsetY; + + /** + * jabber id of the user + * @type {string} + * @private + */ + var _jabberId = jabberId; + + /** + * Create OTOperation for operation + * @returns {operations.ot.OTOperation} + */ + var createOTOperation = function () { + return new OTOperation( + CONFIG.ENTITY.NODE + ":" + that.getEntityId(), + JSON.stringify({ + offsetX: _offsetX, + offsetY: _offsetY, + jabberId: _jabberId, + }), + CONFIG.OPERATION.TYPE.UPDATE, + CONFIG.IWC.POSITION.NODE.POS + ); + }; + + /** + * Get offset in x-direction + * @returns {number} + */ + this.getOffsetX = function () { + return _offsetX; + }; + + /** + * Get offset in y-direction + * @returns {number} + */ + this.getOffsetY = function () { + return _offsetY; + }; + + /** + * Get the JabberId + * @returns {string} + */ + this.getJabberId = function () { + return _jabberId; + }; + /** + * Set the JabberId + * @param {string} jabberId + */ + this.setJabberId = function (jabberId) { + _jabberId = jabberId; + }; + + /** + * Get corresponding ot operation + * @returns {operations.ot.OTOperation} + * @private + */ + this.getOTOperation = function () { + var otOperation = EntityOperation.prototype.getOTOperation.call(this); + if (otOperation === null) { + otOperation = createOTOperation(); + this.setOTOperation(otOperation); + } + return otOperation; + }; + + /** + * Adjust the passed operation in the history of operation + * when this operation is applied remotely after the passed operation + * on an graph instance stored in the passed EntityManager + * @param {canvas_widget.EntityManager} EntityManager + * @param {EntityOperation} operation Remote operation + * @returns {EntityOperation} + */ + this.adjust = function (EntityManager, operation) { + return operation; + }; + + /** + * Compute the inverse of the operation + * @returns {NodeMoveOperation} + */ + this.inverse = function () { + return new NodeMoveOperation( + this.getEntityId(), + -this.getOffsetX(), + -this.getOffsetY(), + this.getJabberId() + ); + }; + } + static getOperationDescription(nodeType, nodeLabel, viewId) { + if (!nodeLabel && !viewId) { + return "..moved " + nodeType; + } else if (!viewId) { + return "..moved " + nodeType + " " + nodeLabel; + } else { + return "..moved " + nodeType + " " + nodeLabel + " in View " + viewId; + } + } + toJSON = function () { + return { + id: this.getEntityId(), + offsetX: this.getOffsetX(), + offsetY: this.getOffsetY(), + jabberId: this.getJabberId(), + }; + }; +} + +/** + * NodeMoveZOperation + * @class operations.ot.NodeMoveZOperation + * @memberof operations.ot + * @extends operations.ot.EntityOperation + * @param {String} entityId Entity id of the entity this activity works on + * @param {number} offsetZ Offset in z-direction + * @param {string} optional: jabberId the jabberId of the user (is automatically set by propagateNodeMoveOperation) + * @constructor + */ +class NodeMoveZOperation extends EntityOperation { + static TYPE = "NodeMoveZOperation"; + getOffsetZ; + getJabberId; + setJabberId; + constructor(entityId, offsetZ, jabberId) { + super( + EntityOperation.TYPES.NodeMoveZOperation, + entityId, + CONFIG.ENTITY.NODE + ); + var that = this; + + /** + * Offset in y-direction + * @type {number} + * @private + */ + var _offsetZ = offsetZ; + + /** + * the jabberId + * @type {string} + * @private + */ + var _jabberId = jabberId; + + /** + * Create OTOperation for operation + * @returns {operations.ot.OTOperation} + */ + var createOTOperation = function () { + return new OTOperation( + CONFIG.ENTITY.NODE + ":" + that.getEntityId(), + JSON.stringify({ + offsetZ: _offsetZ, + jabberId: _jabberId, + }), + CONFIG.OPERATION.TYPE.UPDATE, + CONFIG.IWC.POSITION.NODE.Z + ); + }; + + /** + * Get offset in z-direction + * @returns {number} + */ + this.getOffsetZ = function () { + return _offsetZ; + }; + + this.getJabberId = function () { + return _jabberId; + }; + + this.setJabberId = function (jabberId) { + _jabberId = jabberId; + }; + + /** + * Get corresponding ot operation + * @returns {operations.ot.OTOperation} + * @private + */ + this.getOTOperation = function () { + var otOperation = EntityOperation.prototype.getOTOperation.call(this); + if (otOperation === null) { + otOperation = createOTOperation(); + this.setOTOperation(otOperation); + } + return otOperation; + }; + + /** + * Adjust the passed operation in the history of operation + * when this operation is applied remotely after the passed operation + * on an graph instance stored in the passed EntityManager + * @param {canvas_widget.EntityManager} EntityManager + * @param {EntityOperation} operation Remote operation + * @returns {EntityOperation} + */ + this.adjust = function (EntityManager, operation) { + return operation; + }; + + /** + * Compute the inverse of the operation + * @returns {NodeMoveZOperation} + */ + this.inverse = function () { + return new NodeMoveZOperation( + this.getEntityId(), + -this.getOffsetZ(), + this.getJabberId() + ); + }; + } + static getOperationDescription(nodeType, nodeLabel, viewId) { + if (!nodeLabel && !viewId) { + return "..moved " + nodeType + " on on Z-Axis"; + } else if (!viewId) { + return "..moved " + nodeType + " " + nodeLabel + " on Z-Axis"; + } else { + return ( + "..moved " + + nodeType + + " " + + nodeLabel + + " in View " + + viewId + + " on Z-Axis" + ); + } + } + toJSON = function () { + return { + id: this.getEntityId(), + offsetZ: this.getOffsetZ(), + jabberId: this.getJabberId(), + }; + }; +} + +/** + * NodeResizeOperation + * @class operations.ot.NodeResizeOperation + * @memberof operations.ot + * @extends operations.ot.EntityOperation + * @param {String} entityId Entity id of the entity this activity works on + * @param {number} offsetX Offset in x-direction + * @param {number} offsetY Offset in y-direction + * @param {string} optional: jabberId the jabberId of the user (is automatically set by propagateNodeMoveOperation) + * @constructor + */ +class NodeResizeOperation extends EntityOperation { + static TYPE = "NodeResizeOperation"; + getOffsetX + getOffsetY + getJabberId + setJabberId + constructor(entityId, offsetX, offsetY, jabberId) { + super( + EntityOperation.TYPES.NodeResizeOperation, + entityId, + CONFIG.ENTITY.NODE + ); + var that = this; + + var _jabberId = jabberId; + + /** + * Offset in x-direction + * @type {number} + * @private + */ + var _offsetX = offsetX; + + /** + * Offset in y-direction + * @type {number} + * @private + */ + var _offsetY = offsetY; + + /** + * Create OTOperation for operation + * @returns {operations.ot.OTOperation} + */ + var createOTOperation = function () { + return new OTOperation( + CONFIG.ENTITY.NODE + ":" + that.getEntityId(), + JSON.stringify({ + offsetX: _offsetX, + offsetY: _offsetY, + jabberId: _jabberId, + }), + CONFIG.OPERATION.TYPE.UPDATE, + CONFIG.IWC.POSITION.NODE.DIM + ); + }; + + /** + * Get offset in x-direction + * @returns {number} + */ + this.getOffsetX = function () { + return _offsetX; + }; + + /** + * Get offset in y-direction + * @returns {number} + */ + this.getOffsetY = function () { + return _offsetY; + }; + + this.getJabberId = function () { + return _jabberId; + }; + + this.setJabberId = function (jabberId) { + _jabberId = jabberId; + }; + + /** + * Get corresponding ot operation + * @returns {operations.ot.OTOperation} + * @private + */ + this.getOTOperation = function () { + var otOperation = EntityOperation.prototype.getOTOperation.call(this); + if (otOperation === null) { + otOperation = createOTOperation(); + this.setOTOperation(otOperation); + } + return otOperation; + }; + + /** + * Adjust the passed operation in the history of operation + * when this operation is applied remotely after the passed operation + * on an graph instance stored in the passed EntityManager + * @param {canvas_widget.EntityManager} EntityManager + * @param {EntityOperation} operation Remote operation + * @returns {EntityOperation} + */ + this.adjust = function (EntityManager, operation) { + return operation; + }; + + /** + * Compute the inverse of the operation + * @returns {NodeResizeOperation} + */ + this.inverse = function () { + return new NodeResizeOperation( + this.getEntityId(), + -this.getOffsetX(), + -this.getOffsetY(), + this.getJabberId() + ); + }; + } + static getOperationDescription(nodeType, nodeLabel, viewId) { + if (!nodeLabel && !viewId) { + return "..resized " + nodeType; + } else if (!viewId) { + return "..resized " + nodeType + " " + nodeLabel; + } else { + return "..resized " + nodeType + " " + nodeLabel + " in View " + viewId; + } + } + toJSON=function() { + return { + id: this.getEntityId(), + offsetX: this.getOffsetX(), + offsetY: this.getOffsetY(), + jabberId: this.getJabberId(), + }; + } +} + +/** + * ValueChangeOperation + * @class operations.ot.ValueChangeOperation + * @memberof operations.ot + * @extends operations.ot.EntityOperation + * @param entityId Entity id of the entity this activity works on + * @param {string} value Char that has been added resp. deleted + * @param {string} type Type of operation (insertion resp. deletion) + * @param {number} position Position where the char has been added resp. deleted + * @constructor + */ +class ValueChangeOperation extends EntityOperation { + static TYPE = "ValueChangeOperation"; + getJabberId; + setJabberId; + getFromView; + setFromView; + getValue; + getType; + setPosition; + getPosition; + setRemote; + getRemote; + setEntityIdChain; + getEntityIdChain; + getRootSubjectEntityId; + constructor( + entityId, + value, + type, + position, + jabberId = null, + fromView = null + ) { + if (!entityId) throw new Error("Entity id is required"); + super( + EntityOperation.TYPES.ValueChangeOperation, + entityId, + CONFIG.ENTITY.VAL + ); + var that = this; + + var _fromView = fromView; + + var _jabberId = jabberId; + + /** + * Char that has been added resp. deleted + * @type {string} + * @private + */ + var _value = value; + + /** + * Type of operation (insertion resp. deletion) + * @type {string} + * @private + */ + var _type = type; + + /** + * Position where the char has been added resp. deleted + * @type {number} + * @private + */ + var _position = position; + + /** + * Is the change issued by a remote user + * @type {boolean} + * @private + */ + var _remote = true; + + /** + * Chain of entities the value is assigned to + * @type {string[]} + * @private + */ + var _entityIdChain = []; + + /** + * Create OTOperation for operation + * @returns {operations.ot.OTOperation} + */ + var createOTOperation = function () { + return new OTOperation( + CONFIG.ENTITY.VAL + ":" + that.getEntityId(), + _value, + _type, + _position, + _jabberId, + _fromView + ); + }; + + this.getJabberId = function () { + return _jabberId; + }; + this.setJabberId = function (jabberId) { + _jabberId = jabberId; + }; + + this.getFromView = function () { + return _fromView; + }; + + this.setFromView = function (fromView) { + _fromView = fromView; + }; + /** + * Get char that has been added resp. deleted + * @returns {string} + */ + this.getValue = function () { + return _value; + }; + + /** + * Get type of operation (insertion resp. deletion) + * @returns {string} + */ + this.getType = function () { + return _type; + }; + + /** + * Set type of operation (insertion resp. deletion) + * @param position + */ + this.setPosition = function (position) { + _position = position; + }; + + /** + * Get position where the char has been added resp. deleted + * @returns {number} + */ + this.getPosition = function () { + return _position; + }; + + /** + * Set if the change is issued by a remote user + * @param remote + */ + this.setRemote = function (remote) { + _remote = remote; + }; + + /** + * Get if the change is issued by a remote user + * @returns {boolean} + */ + this.getRemote = function () { + return _remote; + }; + + /** + * Set chain of entities the value is assigned to + * @param {string[]} entityIdChain + */ + this.setEntityIdChain = function (entityIdChain) { + _entityIdChain = entityIdChain; + }; + + /** + * Get chain of entities the value is assigned to + * @returns {string[]} + */ + this.getEntityIdChain = function () { + return _entityIdChain; + }; + + /** + * Get topmost entity in the chain of entity the value is assigned to + * @returns {string} + */ + this.getRootSubjectEntityId = function () { + return _entityIdChain[0]; + }; + + /** + * Get corresponding ot operation + * @returns {operations.ot.OTOperation} + * @private + */ + this.getOTOperation = function () { + var otOperation = EntityOperation.prototype.getOTOperation.call(this); + if (otOperation === null) { + otOperation = createOTOperation(); + this.setOTOperation(otOperation); + } + return otOperation; + }; + + /** + * Adjust the passed operation in the history of operation + * when this operation is applied remotely after the passed operation + * on an graph instance stored in the passed EntityManager + * @param {canvas_widget.EntityManager} EntityManager + * @param {operations.ot.EntityOperation} operation Remote operation + * @returns {operations.ot.EntityOperation} + */ + this.adjust = function (EntityManager, operation) { + switch (operation.getOperationType()) { + case EntityOperation.TYPES.ValueChangeOperation: + if (this.getEntityId() === operation.getEntityId()) { + if ( + (this.getPosition() === operation.getPosition && + this.getValue() === operation.getValue && + this.getType() === CONFIG.OPERATION.TYPE.INSERT && + operation.getType() === CONFIG.OPERATION.TYPE.DELETE) || + (this.getType() === CONFIG.OPERATION.TYPE.DELETE && + operation.getType() === CONFIG.OPERATION.TYPE.INSERT) + ) { + return null; + } + if (this.getPosition() <= operation.getPosition()) { + switch (this.getType()) { + case CONFIG.OPERATION.TYPE.INSERT: + operation.setPosition(operation.getPosition() + 1); + break; + case CONFIG.OPERATION.TYPE.DELETE: + operation.setPosition(operation.getPosition() - 1); + break; + } + } + } + break; + } + + return operation; + }; + + /** + * Compute the inverse of the operation + * @returns {ValueChangeOperation} + */ + this.inverse = function () { + var newType, + ValueChangeOperation = ValueChangeOperation; + + switch (this.getType()) { + case CONFIG.OPERATION.TYPE.INSERT: + newType = CONFIG.OPERATION.TYPE.DELETE; + break; + case CONFIG.OPERATION.TYPE.DELETE: + newType = CONFIG.OPERATION.TYPE.INSERT; + break; + case CONFIG.OPERATION.TYPE.UPDATE: + newType = CONFIG.OPERATION.TYPE.UPDATE; + break; + } + return new ValueChangeOperation( + this.getEntityId(), + this.getValue(), + newType, + this.getPosition() + ); + }; + this.toJSON = function () { + return { + entityId: this.getEntityId(), + value: this.getValue(), + position: this.getPosition(), + type: this.getType(), + jabberId: this.getJabberId(), + }; + }; + } + + static getOperationDescription(valueKey, entityType, entityName, viewId) { + if (!viewId) + return ( + ".. changed " + + valueKey + + " of " + + entityType + + (entityName ? " " : "") + + entityName + ); + else + return ( + ".. changed " + + valueKey + + " of " + + entityType + + (entityName ? " " : "") + + entityName + + " in View " + + viewId + ); + } +} + +EntitySelectOperation.TYPE = "EntitySelectOperation"; + +/** + * Entity Select Operation + * @class operations.non_ot.EntitySelectOperation + * @memberof operations.non_ot + * @constructor + * @param {string} selectedEntityId Entity id of the selected entity + * @param {string} selectedEntityType + * @param {string} jabberId + */ + +function EntitySelectOperation(selectedEntityId, selectedEntityType, jabberId) { + /** + * Entity id of the selected entity + * @type {string} + * @private + */ + var _selectedEntityId = selectedEntityId; + + var _jabberId = jabberId; + + var _selectedEntityType = selectedEntityType; + + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var _nonOTOperation = null; + + /** + * Get entity id of the selected entity + * @returns {string} + */ + this.getSelectedEntityId = function () { + return _selectedEntityId; + }; + + this.getSelectedEntityType = function () { + return _selectedEntityType; + }; + + this.getJabberId = function () { + return _jabberId; + }; + + /** + * Set corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + */ + this.setNonOTOperation = function (nonOTOperation) { + _nonOTOperation = nonOTOperation; + }; + + /** + * Get corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + */ + this.getNonOTOperation = function () { + return _nonOTOperation; + }; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (_nonOTOperation === null) { + _nonOTOperation = new NonOTOperation( + EntitySelectOperation.TYPE, + JSON.stringify({ + selectedEntityId: _selectedEntityId, + selectedEntityType: _selectedEntityType, + }) + ); + } + return _nonOTOperation; + }; +} + +EntitySelectOperation.prototype.toJSON = function () { + return { + selectedEntityId: this.getSelectedEntityId(), + selectedEntityType: this.getSelectedEntityType(), + jabberId: this.getJabberId(), + }; +}; + +/** + * ToolSelectOperation + * @class operations.non_ot.ToolSelectOperation.non_ot.ToolSelectOperation + * @memberof operations.non_ot + * @constructor + * @param {string} toolName Name of selected tool + * @param label + * @param {map} defaultAttributeValues Map containing default values for the attributes of a node. + */ +class ToolSelectOperation { + static TYPE = "ToolSelectOperation"; + /** + * Name of selected tool + * @type {string} + */ + selectedToolName; + + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + nonOTOperation; + + /** + * Default label of selected tool + * @type {string} + */ + defaultLabel; + + /** + * May be used to set default values for node attributes. + * @type {map} + */ + defaultAttributeValues; + + /** + * Get name of selected tool + * @returns {string} + */ + getSelectedToolName; + + /** + * Get default label of selected tool + * @returns {string} + */ + getDefaultLabel; + + /** + * Get default values for node attributes. + * @returns {map} + */ + getDefaultAttributeValues; + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + toNonOTOperation; + constructor(toolName, label, defaultAttributeValues = {}) { + /** + * Name of selected tool + * @type {string} + */ + var selectedToolName = toolName; + + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var nonOTOperation = null; + + /** + * Default label of selected tool + * @type {string} + */ + var defaultLabel = label; + + /** + * May be used to set default values for node attributes. + * @type {map} + */ + var defaultAttributeValues = defaultAttributeValues; + + /** + * Get name of selected tool + * @returns {string} + */ + this.getSelectedToolName = function () { + return selectedToolName; + }; + + /** + * Get default label of selected tool + * @returns {string} + */ + this.getDefaultLabel = function () { + return defaultLabel; + }; + + /** + * Get default values for node attributes. + * @returns {map} + */ + this.getDefaultAttributeValues = function () { + return defaultAttributeValues; + }; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (nonOTOperation === null) { + nonOTOperation = new NonOTOperation( + ToolSelectOperation.TYPE, + JSON.stringify({ selectedToolName: selectedToolName }) + ); + } + return nonOTOperation; + }; + } +} + +/** + * ActivityOperation + * @class operations.non_ot.ActivityOperation + * @memberof operations.non_ot + * @constructor + * @param {string} type Type of activity + * @param {string} entityId Entity id of the entity this activity works on + * @param {string} sender JabberId of the user who issued this activity + * @param {string} text Text of this activity which is displayed in the activity widget + * @param {object} data Additional data for the activity + */ +class ActivityOperation { + static TYPE = "ActivityOperation"; + constructor(type, entityId, sender, text, data) { + /** + * Type of activity + * @type {string} + * @private + */ + var _type = type; + + /** + * Entity id of the entity this activity works on + * @type {string} + * @private + */ + var _entityId = entityId; + + /** + * JabberId of the user who issued this activity + * @type {string} + * @private + */ + var _sender = sender; + + /** + * Text of this activity which is displayed in the activity widget + * @type {string} + * @private + */ + var _text = text; + + /** + * Additional data for the activity + * @type {Object} + * @private + */ + var _data = data; + + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var _nonOTOperation = null; + + /** + * Get type of activity + * @returns {string} + */ + this.getType = function () { + return _type; + }; + + /** + * Get entity id of the entity this activity works on + * @returns {string} + */ + this.getEntityId = function () { + return _entityId; + }; + + /** + * Get JabberId of the user who issued this activity + * @returns {string} + */ + this.getSender = function () { + return _sender; + }; + + /** + * Get text of this activity which is displayed in the activity widget + * @returns {string} + */ + this.getText = function () { + return _text; + }; + + /** + * Get additional data for the activity + * @returns {Object} + */ + this.getData = function () { + return _data; + }; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (_nonOTOperation === null) { + _nonOTOperation = new NonOTOperation( + ActivityOperation.TYPE, + JSON.stringify({ + type: _type, + entityId: _entityId, + sender: _sender, + text: _text, + data: _data, + }) + ); + } + return _nonOTOperation; + }; + } + toJSON() { + return { + type: this.getType(), + entityId: this.getEntityId(), + sender: this.getSender(), + text: this.getText(), + data: this.getData(), + }; + } +} + +ExportMetaModelOperation.TYPE = "ExportMetaModelOperation"; + +/** + * Export Image Operation + * @class operations.non_ot.ExportMetaModelOperation + * @memberof operations.non_ot + * @constructor + * @param {string} requestingComponent Name of requesting Component + * @param {string} data Meta model + */ +function ExportMetaModelOperation(requestingComponent, data) { + /** + * Name of requesting Component + * @type {string} + * @private + */ + var _requestingComponent = requestingComponent; + /** + * Meta model + * @type {object} + * @private + */ + var _data = data; + + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var _nonOTOperation = null; + + /** + * Get name of requesting Component + * @returns {string} + */ + this.getRequestingComponent = function () { + return _requestingComponent; + }; + + /** + * Get data URL of image + * @returns {object} + */ + this.getData = function () { + return _data; + }; + + /** + * Get exported JSON representation of the graph + * @param {object} data + */ + this.setData = function (data) { + _data = data; + }; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (_nonOTOperation === null) { + _nonOTOperation = new NonOTOperation( + ExportMetaModelOperation.TYPE, + JSON.stringify({ + requestingComponent: _requestingComponent, + data: _data, + }) + ); + } + return _nonOTOperation; + }; +} + +ExportLogicalGuidanceRepresentationOperation.TYPE = + "ExportLogicalGuidanceRepresentationOperation"; + +/** + * Export Image Operation + * @class operations.non_ot.ExportLogicalGuidanceRepresentationOperation + * @memberof operations.non_ot + * @constructor + * @param {string} requestingComponent Name of requesting Component + * @param {string} data Meta model + */ +function ExportLogicalGuidanceRepresentationOperation( + requestingComponent, + data +) { + /** + * Name of requesting Component + * @type {string} + * @private + */ + var _requestingComponent = requestingComponent; + /** + * Guidance rules + * @type {object} + * @private + */ + var _data = data; + + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var _nonOTOperation = null; + + /** + * Get name of requesting Component + * @returns {string} + */ + this.getRequestingComponent = function () { + return _requestingComponent; + }; + + /** + * Get data URL of image + * @returns {object} + */ + this.getData = function () { + return _data; + }; + + /** + * Get exported JSON representation of the graph + * @param {object} data + */ + this.setData = function (data) { + _data = data; + }; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (_nonOTOperation === null) { + _nonOTOperation = new NonOTOperation( + ExportLogicalGuidanceRepresentationOperation.TYPE, + JSON.stringify({ + requestingComponent: _requestingComponent, + data: _data, + }) + ); + } + return _nonOTOperation; + }; +} + +ExportImageOperation.TYPE = "ExportImageOperation"; + +/** + * Export Image Operation + * @class operations.non_ot.ExportImageOperation + * @memberof operations.non_ot + * @constructor + * @param {string} requestingComponent Name of requesting Component + * @param {string} data Data URL of image + */ +function ExportImageOperation(requestingComponent, data) { + /** + * Name of requesting Component + * @type {string} + * @private + */ + var _requestingComponent = requestingComponent; + /** + * Data URL of image + * @type {object} + * @private + */ + var _data = data; + + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var _nonOTOperation = null; + + /** + * Get name of requesting Component + * @returns {string} + */ + this.getRequestingComponent = function () { + return _requestingComponent; + }; + + /** + * Get data URL of image + * @returns {object} + */ + this.getData = function () { + return _data; + }; + + /** + * Get exported JSON representation of the graph + * @param {object} data + */ + this.setData = function (data) { + _data = data; + }; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (_nonOTOperation === null) { + _nonOTOperation = new NonOTOperation( + ExportImageOperation.TYPE, + JSON.stringify({ + requestingComponent: _requestingComponent, + data: _data, + }) + ); + } + return _nonOTOperation; + }; +} + +/** + * SetViewTypesOperation + * @class operations.non_ot.WidgetEnterOperation + * @memberof operations.non_ot + * @constructor + * @param {boolean} flag enable (true)/disable(false) the view types of the vml in the palette widget + */ +class SetViewTypesOperation { + static TYPE = "SetViewTypesOperation"; + _flag; + nonOTOperation; + /** + * Get name of selected tool + * @returns {string} + */ + getFlag = function () { + return this._flag; + }; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + toNonOTOperation = function () { + if (this.nonOTOperation === null) { + this.nonOTOperation = new NonOTOperation( + SetViewTypesOperation.TYPE, + JSON.stringify({ flag: this._flag }) + ); + } + return this.nonOTOperation; + }; + + constructor(flag) { + /** + * Enable or disable the view types of the vml + * @type {boolean} + * @private + */ + this._flag = flag; + + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + this.nonOTOperation = null; + } +} + +/** + * InitModelTypesOperation + * @class operations.non_ot.InitModelTypesOperation + * @memberof operations.non_ot + * @constructor + * @param {string} vls the visual language specification + * @param {bool} startViewGeneration + */ +class InitModelTypesOperation { + static TYPE = "InitModelTypesOperation"; + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + nonOTOperation = null; + _vls; + _startViewGeneration; + getVLS = function () { + return this._vls; + }; + + /** + * Get name of selected tool + * @returns {string} + */ + getViewGenerationFlag = function () { + return this._startViewGeneration; + }; + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + toNonOTOperation = function () { + if (this.nonOTOperation === null) { + this.nonOTOperation = new NonOTOperation( + InitModelTypesOperation.TYPE, + JSON.stringify({ + vls: this._vls, + startViewGeneration: this._startViewGeneration, + }) + ); + } + return this.nonOTOperation; + }; + constructor(vls, startViewGeneration) { + /** + * Name of selected tool + * @type {string} + */ + this._vls = vls; + + this._startViewGeneration = startViewGeneration; + } +} + +ViewInitOperation.TYPE = "ViewInitOperation"; + +/** + * ViewInitOperation + * @class operations.non_ot.ViewInitOperation + * @memberof operations.non_ot + * @constructor + * @param {object} data the view as json + * @param {object} viewpoint the viewpoint vls as json + */ +function ViewInitOperation(data, viewpoint) { + /** + * Name of selected tool + * @type {string} + */ + var _data = data; + + var _viewpoint = viewpoint; + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var nonOTOperation = null; + + /** + * Get name of selected tool + * @returns {string} + */ + this.getData = function () { + return _data; + }; + + this.getViewpoint = function () { + return _viewpoint; + }; + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (nonOTOperation === null) { + nonOTOperation = new NonOTOperation( + ViewInitOperation.TYPE, + JSON.stringify({ data: _data, viewpoint: _viewpoint }) + ); + } + return nonOTOperation; + }; +} + +/** + * DeleteViewOperation + * @class operations.non_ot.DeleteViewOperation + * @memberof operations.non_ot + * @constructor + * @param {string} viewId identifier of the view + */ +class DeleteViewOperation { + static TYPE = "DeleteViewOperation"; + constructor(viewId) { + /** + * Name of selected tool + * @type {string} + */ + var _viewId = viewId; + + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var nonOTOperation = null; + + /** + * Get the list with node ids to delete + * @returns {string} + */ + this.getViewId = function () { + return _viewId; + }; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (nonOTOperation === null) { + nonOTOperation = new NonOTOperation( + DeleteViewOperation.TYPE, + JSON.stringify({ viewId: _viewId }) + ); + } + return nonOTOperation; + }; + } +} + +SetModelAttributeNodeOperation.TYPE = "SetModelAttributeNodeOperation"; + +/** + * SetModelAttributeNodeOperation + * @class operations.non_ot.SetModelAttributeNodeOperation + * @memberof operations.non_ot + * @constructor + */ +function SetModelAttributeNodeOperation() { + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var nonOTOperation = null; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (nonOTOperation === null) { + nonOTOperation = new NonOTOperation( + SetModelAttributeNodeOperation.TYPE, + JSON.stringify({ empty: "empty" }) + ); + } + return nonOTOperation; + }; +} + +UpdateViewListOperation.TYPE = "UpdateViewListOperation"; + +/** + * UpdateViewListOperation + * @class operations.non_ot.UpdateViewListOperation + * @memberof operations.non_ot + * @constructor + */ +function UpdateViewListOperation() { + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var nonOTOperation = null; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (nonOTOperation === null) { + nonOTOperation = new NonOTOperation( + UpdateViewListOperation.TYPE, + JSON.stringify({}) + ); + } + return nonOTOperation; + }; +} + +ShowGuidanceBoxOperation.TYPE = "ShowGuidanceBoxOperation"; + +/** + * ToolGuidanceOperation + * @class operations.non_ot.ToolGuidanceOperation + * @memberof operations.non_ot + * @constructor + * @param {string} toolName Name of selected tool + */ +function ShowGuidanceBoxOperation(label, guidance, entityId) { + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var nonOTOperation = null; + var _label = label; + var _guidance = guidance; + var _entityId = entityId; + + this.getLabel = function () { + return _label; + }; + + this.getGuidance = function () { + return _guidance; + }; + + this.getEntityId = function () { + return _entityId; + }; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (nonOTOperation === null) { + nonOTOperation = new NonOTOperation( + ShowGuidanceBoxOperation.TYPE, + JSON.stringify({ + label: _label, + guidance: _guidance, + entityId: _entityId, + }) + ); + } + return nonOTOperation; + }; +} + +CanvasViewChangeOperation.TYPE = "CanvasViewChangeOperation"; + +/** + * Entity Select Operation + * @class operations.non_ot.EntitySelectOperation + * @memberof operations.non_ot + * @constructor + * @param {string} selectedEntityId Entity id of the selected entity + */ +function CanvasViewChangeOperation(left, top, width, height, zoom) { + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var _nonOTOperation = null; + + this.getLeft = function () { + return left; + }; + + this.getTop = function () { + return top; + }; + + this.getWidth = function () { + return width; + }; + + this.getHeight = function () { + return height; + }; + + this.getZoom = function () { + return zoom; + }; + + /** + * Set corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + */ + this.setNonOTOperation = function (nonOTOperation) { + _nonOTOperation = nonOTOperation; + }; + + /** + * Get corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + */ + this.getNonOTOperation = function () { + return _nonOTOperation; + }; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (_nonOTOperation === null) { + _nonOTOperation = new NonOTOperation( + CanvasViewChangeOperation.TYPE, + JSON.stringify({ + left: left, + top: top, + width: width, + height: height, + zoom: zoom, + }) + ); + } + return _nonOTOperation; + }; +} + +RevokeSharedActivityOperation.TYPE = "RevokeSharedActivityOperation"; + +/** + * Entity Select Operation + * @class operations.non_ot.EntitySelectOperation + * @memberof operations.non_ot + * @constructor + * @param {string} selectedEntityId Entity id of the selected entity + */ +function RevokeSharedActivityOperation(id) { + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var _nonOTOperation = null; + + this.getId = function () { + return id; + }; + + /** + * Set corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + */ + this.setNonOTOperation = function (nonOTOperation) { + _nonOTOperation = nonOTOperation; + }; + + /** + * Get corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + */ + this.getNonOTOperation = function () { + return _nonOTOperation; + }; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (_nonOTOperation === null) { + _nonOTOperation = new NonOTOperation( + RevokeSharedActivityOperation.TYPE, + JSON.stringify({ + id: id, + }) + ); + } + return _nonOTOperation; + }; +} + +RevokeSharedActivityOperation.prototype.toJSON = function () { + return { id: this.getId() }; +}; + +CollaborateInActivityOperation.TYPE = "CollaborateInActivityOperation"; + +/** + * Entity Select Operation + * @class operations.non_ot.EntitySelectOperation + * @memberof operations.non_ot + * @constructor + * @param {string} selectedEntityId Entity id of the selected entity + */ +function CollaborateInActivityOperation(id) { + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var _nonOTOperation = null; + + this.getId = function () { + return id; + }; + + /** + * Set corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + */ + this.setNonOTOperation = function (nonOTOperation) { + _nonOTOperation = nonOTOperation; + }; + + /** + * Get corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + */ + this.getNonOTOperation = function () { + return _nonOTOperation; + }; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (_nonOTOperation === null) { + _nonOTOperation = new NonOTOperation( + CollaborateInActivityOperation.TYPE, + JSON.stringify({ + id: id, + }) + ); + } + return _nonOTOperation; + }; +} + +MoveCanvasOperation.TYPE = "MoveCanvasOperation"; + +/** + * Entity Select Operation + * @class operations.non_ot.EntitySelectOperation + * @memberof operations.non_ot + * @constructor + * @param {string} selectedEntityId Entity id of the selected entity + */ +function MoveCanvasOperation(objectId, transition) { + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var _nonOTOperation = null; + + this.getObjectId = function () { + return objectId; + }; + + this.getTransition = function () { + return transition; + }; + + /** + * Set corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + */ + this.setNonOTOperation = function (nonOTOperation) { + _nonOTOperation = nonOTOperation; + }; + + /** + * Get corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + */ + this.getNonOTOperation = function () { + return _nonOTOperation; + }; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (_nonOTOperation === null) { + _nonOTOperation = new NonOTOperation( + MoveCanvasOperation.TYPE, + JSON.stringify({ + objectId: objectId, + transition: transition, + }) + ); + } + return _nonOTOperation; + }; +} + +/** + * Entity Select Operation + * @class operations.non_ot.EntitySelectOperation + * @memberof operations.non_ot + * @constructor + * @param {string} data + */ +class GuidanceStrategyOperation { + static TYPE = "GuidanceStrategyOperation"; + constructor(data) { + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var _nonOTOperation = null; + + this.getData = function () { + return data; + }; + + /** + * Set corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + */ + this.setNonOTOperation = function (nonOTOperation) { + _nonOTOperation = nonOTOperation; + }; + + /** + * Get corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + */ + this.getNonOTOperation = function () { + return _nonOTOperation; + }; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (_nonOTOperation === null) { + _nonOTOperation = new NonOTOperation( + GuidanceStrategyOperation.TYPE, + JSON.stringify({ + data: data, + }) + ); + } + return _nonOTOperation; + }; + } + toJSON() { + return { data: this.getData() }; + } +} + +UpdateMetamodelOperation.TYPE = "UpdateMetamodelOperation"; + +/** + * UpdateMetamodelOperation + * @class operations.non_ot.UpdateMetamodelOperation + * @memberof operations.non_ot + * @constructor + */ +function UpdateMetamodelOperation(metaModelingRoomName, modelingRoomName) { + /** + * Room name of metamodel is created + * @type {string} + */ + var _metaModelingRoomName = metaModelingRoomName; + + /** + * Room name to upload created metamodel + * @type {string} + */ + var _modelingRoomName = modelingRoomName; + + /** + * Corresponding NonOtOperation + * @type {operations.non_ot.NonOTOperation} + * @private + */ + var _nonOTOperation = null; + + /** + * Get metamodeling room name + * @returns {string} + */ + this.getMetaModelingRoomName = function () { + return _metaModelingRoomName; + }; + + /** + * Get modeling room name + * @returns {string} + */ + this.getModelingRoomName = function () { + return _modelingRoomName; + }; + + /** + * Convert operation to NonOTOperation + * @returns {operations.non_ot.NonOTOperation} + */ + this.toNonOTOperation = function () { + if (_nonOTOperation === null) { + _nonOTOperation = new NonOTOperation( + UpdateMetamodelOperation.TYPE, + JSON.stringify({ empty: "empty" }) + ); + } + return _nonOTOperation; + }; +} +UpdateMetamodelOperation.prototype.toJSON = function () { + return {}; +}; + +/** + * OperationFactory + * @class operations.OperationFactory + * @memberof operations.ot + * @constructor + */ +function OperationFactory() { + return { + /** + * Creates an Operation from a received NonOTOperation + * @memberof operations.OperationFactory# + * @param operation + * @returns {operations.non_ot.ToolSelectOperation|EntitySelectOperation|ToolSelectOperation} + */ + createOperationFromNonOTOperation: function (operation) { + var type = operation.getType(), + data, + resOperation; + + try { + data = JSON.parse(operation.getData()); + } catch (e) { + console.error( + "Not able to parse data to JSON. Check the corresponding operation" + ); + return null; + } + + switch (type) { + case EntitySelectOperation.TYPE: + resOperation = new EntitySelectOperation( + data.selectedEntityId, + data.selectedEntityType, + data.jabberId + ); + resOperation.setNonOTOperation(operation); + break; + case ToolSelectOperation.TYPE: + resOperation = new ToolSelectOperation( + data.selectedToolName, + data.name, + data.defaultAttributeValues + ); + break; + case ActivityOperation.TYPE: + resOperation = new ActivityOperation( + data.type, + data.entityId, + data.sender, + data.text, + data.data + ); + break; + case ExportMetaModelOperation.TYPE: + resOperation = new ExportMetaModelOperation( + data.requestingComponent, + data.data + ); + break; + case ExportLogicalGuidanceRepresentationOperation.TYPE: + resOperation = new ExportLogicalGuidanceRepresentationOperation( + data.requestingComponent, + data.data + ); + break; + case ExportImageOperation.TYPE: + resOperation = new ExportImageOperation( + data.requestingComponent, + data.data + ); + break; + case SetViewTypesOperation.TYPE: + resOperation = new SetViewTypesOperation(data.flag); + break; + case InitModelTypesOperation.TYPE: + resOperation = new InitModelTypesOperation( + data.vls, + data.startViewGeneration + ); + break; + case ViewInitOperation.TYPE: + resOperation = new ViewInitOperation(data.data, data.viewpoint); + break; + case DeleteViewOperation.TYPE: + resOperation = new DeleteViewOperation(data.viewId); + break; + case ShowGuidanceBoxOperation.TYPE: + resOperation = new ShowGuidanceBoxOperation( + data.label, + data.guidance, + data.entityId + ); + break; + case SetModelAttributeNodeOperation.TYPE: + resOperation = new SetModelAttributeNodeOperation(); + break; + case UpdateViewListOperation.TYPE: + resOperation = new UpdateViewListOperation(); + break; + case CanvasViewChangeOperation.TYPE: + resOperation = new CanvasViewChangeOperation( + data.left, + data.top, + data.width, + data.height, + data.zoom + ); + resOperation.setNonOTOperation(operation); + break; + case RevokeSharedActivityOperation.TYPE: + resOperation = new RevokeSharedActivityOperation(data.id); + break; + case CollaborateInActivityOperation.TYPE: + resOperation = new CollaborateInActivityOperation(data.id); + break; + case MoveCanvasOperation.TYPE: + resOperation = new MoveCanvasOperation( + data.objectId, + data.transition + ); + break; + case GuidanceStrategyOperation.TYPE: + resOperation = new GuidanceStrategyOperation(data.data); + resOperation.setNonOTOperation(operation); + break; + case UpdateMetamodelOperation.TYPE: + resOperation = new UpdateMetamodelOperation( + data.metamodelingRoomName, + data.modelingRoomName + ); + break; + default: + resOperation = new NonOTOperation(type, data); + break; + } + return resOperation; + }, + /** + * Creates an entity operation from a received OTOperation + * @memberof operations.OperationFactory# + * @param operation + * @returns {EntityOperation} + */ + createOperationFromOTOperation: function (operation) { + var value; + var entityType; + var entityId; + var components = operation.getName().split(":"); + + var resOperation; + + if (components.length === 2) { + entityType = components[0]; + entityId = components[1]; + + switch (entityType) { + case CONFIG.ENTITY.NODE: + try { + value = JSON.parse(operation.getValue()); + } catch (e) { + return null; + } + switch (operation.getPosition()) { + case CONFIG.IWC.POSITION.NODE.ADD: + switch (operation.getType()) { + case CONFIG.OPERATION.TYPE.INSERT: + resOperation = new NodeAddOperation( + entityId, + value.type, + value.left, + value.top, + value.width, + value.height, + value.zIndex, + value.containment, + value.json, + value.viewId, + value.oType, + value.jabberId + ); + break; + case CONFIG.OPERATION.TYPE.UPDATE: + resOperation = new NodeDeleteOperation( + entityId, + value.type, + value.left, + value.top, + value.width, + value.height, + value.zIndex, + value.containment, + value.json + ); + break; + } + break; + case CONFIG.IWC.POSITION.NODE.POS: + resOperation = new NodeMoveOperation( + entityId, + value.offsetX, + value.offsetY, + value.jabberId + ); + break; + case CONFIG.IWC.POSITION.NODE.Z: + resOperation = new NodeMoveZOperation( + entityId, + value.offsetZ, + value.jabberId + ); + break; + case CONFIG.IWC.POSITION.NODE.DIM: + resOperation = new NodeResizeOperation( + entityId, + value.offsetX, + value.offsetY, + value.jabberId + ); + break; + } + break; + case CONFIG.ENTITY.EDGE: + try { + value = JSON.parse(operation.getValue()); + } catch (e) { + return null; + } + switch (operation.getType()) { + case CONFIG.OPERATION.TYPE.INSERT: + resOperation = new EdgeAddOperation( + entityId, + value.type, + value.source, + value.target, + value.json, + value.viewId, + value.oType, + value.jabberId + ); + break; + case CONFIG.OPERATION.TYPE.UPDATE: + resOperation = new EdgeDeleteOperation( + entityId, + value.type, + value.source, + value.target, + value.json + ); + break; + } + break; + case CONFIG.ENTITY.ATTR: + try { + value = JSON.parse(operation.getValue()); + } catch (e) { + return null; + } + switch (operation.getType()) { + case CONFIG.OPERATION.TYPE.INSERT: + resOperation = new AttributeAddOperation( + entityId, + value.subjectEntityId, + value.rootSubjectEntityId, + value.type, + value.data + ); + break; + case CONFIG.OPERATION.TYPE.UPDATE: + resOperation = new AttributeDeleteOperation( + entityId, + value.subjectEntityId, + value.rootSubjectEntityId, + value.type + ); + break; + } + break; + case CONFIG.ENTITY.VAL: + resOperation = new ValueChangeOperation( + entityId, + operation.getValue(), + operation.getType(), + operation.getPosition(), + null + ); + break; + } + } + if (resOperation !== null) { + resOperation.setOTOperation(operation); + } + return resOperation; + }, + }; +} + +var OperationFactory$1 = OperationFactory(); + +/** + * Provides messaging functionality. + * @param {Array} categories - (currently not implemented) categories of widgets that shall process the intent (e.g. ["editor","proxy" ]) + * @param {String} origin - The origin (i.e. the url where your application script lives) is needed for messaging + * @param {} y - A reference to yjs' Y object for global messaging + */ +class Client { + //console.log(y); + _y; + _componentName = "unknown"; + + //private variables + _connected = false; + _categories; + _callback; + + // Needed for HTML5 messaging + _origin; + + constructor(componentName, categories, origin, y) { + //console.log(y); + this._y = y; + + this._componentName = componentName; + this._categories = categories; + // Needed for HTML5 messaging + this._origin = origin; + } + + /** + * Connect widget to messaging. This sets up the callback function and creates + * an event listener for HTML5 messaging and a yjs observer for global messaging. + * If yjs is not available only local messaging is set up. + * @param {function} callback - The callback function used for receiving messages. + */ + connect(callback) { + this._callback = callback; + var handler = this.receiveMessage.bind(this); + //Todo + const widgetTageName = getWidgetTagName(this._componentName); + try { + const _node = document.querySelector(widgetTageName); + + if (!_node) { + throw new Error( + "html tag not found in document. Please make sure that you added the " + + widgetTageName + + " to the document. Hint: do not use the shadow dom." + ); + } + _node.addEventListener("syncmeta-message", handler); + } catch (error) { + console.error(error); + } + + + if (this._y) { + // If yjs is available also connect a global listener + const intents = this._y.getMap("intents"); + if (intents) intents.observe(handler); + } + } + + /** + * Disconnect the widget from messaging. This removes the event listener + * and the callback for both local and global messaging. If yjs is not available, + * only local messaging will be available. + */ + disconnect() { + //THISELEMENT.removeEventListener("syncmeta-message", this.receiveMessage, false); + this._callback = null; + + if (!(this._y === null || this._y === undefined)) { + this._y.getMap("intents").unobserve(this.receiveMessage); + } + } + + /** + * Publishes an intent, + * @param {intent} - The intent about to be published, this object contains all information. + */ + publish(intent) { + if (util.validateIntent(intent)) { + if (intent.flags[0] === util.FLAGS.PUBLISH_GLOBAL) { + this.publishGlobal(intent, this._y); + } else if (intent.flags[0] === util.FLAGS.PUBLISH_LOCAL) { + this.publishLocal(intent, this._origin); + } + } + } + + publishLocal(intent, origin) { + //Find iframe and post message + const widgets = []; + for (const el of document.querySelectorAll("*")) { + if (el.tagName.match(/-widget$/i)) { + widgets.push(el); + } + } + + widgets.forEach(function (widget) { + const receiverTagName = getWidgetTagName(intent.receiver.toLowerCase()); + if (widget.tagName.toLowerCase() === receiverTagName.toLowerCase()) { + const event = new CustomEvent("syncmeta-message", { + detail: { + intent, + origin, + }, + }); + widget.dispatchEvent(event); + } + }); + } + + publishGlobal(intent, y) { + //y.share.intents.push(intent); + y.getMap("intents").set(intent.receiver, intent); + } + + /** + * Unpack events and pre process them. This unwraps HTML5 messages and manages the yjs map + * used for global messaging. + * @param {Event} event - The event that activated the callback + */ + receiveMessage(event) { + // Local messaging events + if (event.type === "syncmeta-message") { + //Unpack message events + if (event instanceof CustomEvent) { + this._callback(event.detail.intent); + } + } else if (event.type === "add" || event.type == "update") { + //Unpack yjs event and remove from map + var intent = event.object.get(event.name); + event.object.delete(event.name); + console.log(intent); + this._callback(intent); + } + } +} + +//======================= IWC.util ============================== + +class util { + /** + * Used to determine whether global or local messaging should be used. + * Local messaging uses HTML5 messaging, global messaging uses yjs. + */ + static FLAGS = { + PUBLISH_LOCAL: "PUBLISH_LOCAL", + PUBLISH_GLOBAL: "PUBLISH_GLOBAL", + }; + + /** + * Check intent for correctness. + */ + static validateIntent(intent) { + if (typeof intent.sender != "string") { + throw new Error( + "Intent object must possess property 'component' of type 'String'" + ); + } + if (typeof intent.data != "string") { + throw new Error( + "Intent object must possess property 'data' of type 'String'" + ); + } + if (typeof intent.dataType != "string") { + throw new Error( + "Intent object must possess property 'dataType' of type 'String'" + ); + } + return true; + } +} + +var PAYLOAD_DATA_TYPE = { + OT_OPERATION: "OTOperation", + NON_OT_OPERATION: "NonOTOperation", +}; + +class IWCWrapper { + /** + * Inter-widget communication wrapper + * @class IWCWrapper + * @constructor + * @param componentName Name of component (widget) using the wrapper + */ + + /** + * Set if local messages should be buffered + * @type {boolean} + */ + BUFFER_ENABLED = false; + + /** + * Interval for sending buffered local messages + * @type {number} + */ + INTERVAL_SEND = 25; + + Space = null; + + //noinspection JSMismatchedCollectionQueryUpdate + /** + * Buffer for local messages + * @type {Array} + * @private + */ + _messageBuffer = []; + + //noinspection JSMismatchedCollectionQueryUpdate + /** + * Set of registered Callbacks for local data receive events + * @type {Array} + * @private + */ + _onDataReceivedCallbacks = []; + + _onDataReceivedCallers = []; + + /** + * Stores (for each user) the times an inocming messages has been received to drop duplicate (same time) messages + * @type {object} + * @private + */ + _times = {}; + + /** + * Inter widget communication client + * @type {iwc.Client} + * @private + */ + _iwc; + /** + * Disconnect the iwc client + * @memberof IWCWrapper# + */ + disconnect; + /** + * Connect the iwc client + * @memberof IWCWrapper# + */ + connect; + sendLocalMessage; + sendLocalOTOperation; + sendLocalNonOTOperation; + getUserColor; + registerOnDataReceivedCallback; + unregisterOnDataReceivedCallback; + getUser; + getMembers; + getSpaceTitle; + setSpace; + componentName; + + /** + * Encapsulates the passed message information into the Android Intent-like format required by the iwc client + * @param {string} receiver Component name of the receiving component (widget), empty string for remote messages + * @param {string|string[]} flags Single flag or array of flags to indicate if the messages should be propagate locally or remotely + * @param {string} action Type of data (DATA, DATA_ARRAY, SYNC) + * @param {object} payload Message Payload + * @returns {Object} + */ + encapsulateMessage(receiver, flags, action, payload) { + var i, numOfFlags, flag; + // @ts-ignore + var validatedFlags = []; + + if (flags instanceof Array) { + for (i = 0, numOfFlags = flags.length; i < numOfFlags; i++) { + flag = flags[i]; + if ( + flag === CONFIG.IWC.FLAG.PUBLISH_LOCAL || + flag === CONFIG.IWC.FLAG.PUBLISH_GLOBAL + ) { + // @ts-ignore + validatedFlags.push(flag); + } + } + } else if (typeof flags === "string") { + if ( + flags === CONFIG.IWC.FLAG.PUBLISH_LOCAL || + flags === CONFIG.IWC.FLAG.PUBLISH_GLOBAL + ) { + // @ts-ignore + validatedFlags.push(flags); + } + } else { + throw "Parameter flags has wrong type. Array or String expected."; + } + + if (typeof action !== "string") { + throw "Parameter action has wrong type. String expected."; + } + + receiver = receiver || ""; + + return { + receiver: receiver, + sender: this.componentName, + data: "", + dataType: "", + action: action, + flags: validatedFlags, + extras: { + payload: payload, + time: new Date().getTime(), + }, + }; + } + + /** + * Send all buffered local messages encapsulated in one message + */ + sendBufferedMessages() { + var intent; + var data = null; + + for (var receiver in this._messageBuffer) { + if (this._messageBuffer.hasOwnProperty(receiver)) { + data = this._messageBuffer[receiver].splice( + 0, + this._messageBuffer[receiver].length + ); + //sendBufferTimer.pause(); + if (data.length == 1) { + intent = this.encapsulateMessage( + receiver, + CONFIG.IWC.FLAG.PUBLISH_LOCAL, + CONFIG.IWC.ACTION.DATA, + data[0] + ); + if (util.validateIntent(intent)) { + //console.log("=== " + intent.flags.toString().replace(/PUBLISH_/g, "") + " INTENT TRANSMITTED AT COMPONENT " + componentName + " ==="); + //console.log(intent); + + this._iwc.publish(intent); + } + } else if (data.length > 1) { + intent = this.encapsulateMessage( + receiver, + CONFIG.IWC.FLAG.PUBLISH_LOCAL, + CONFIG.IWC.ACTION.DATA_ARRAY, + data + ); + if (util.validateIntent(intent)) { + //console.log("=== " + intent.flags.toString().replace(/PUBLISH_/g, "") + " INTENT TRANSMITTED AT COMPONENT " + componentName + " ==="); + //console.log(intent); + + this._iwc.publish(intent); + } + } + } + } + //sendBufferTimer.resume(); + } + + /** + * Callback for received local messages + * @param {object} intent Message content in Android Intent-like format required by the iwc client + */ + onIntentReceivedCallback(_self, intent) { + //some CAE widgets still use the old iwc.js library + //then it happens that intent are not parsed and processes correctly by the new iwc and then + //the complete message as string is returned + //this workaround should help for now to make it work with syncmeta + if (typeof intent === "string") { + try { + intent = JSON.parse(intent); + if (intent.hasOwnProperty("OpenApplicationEvent")) { + intent = intent["OpenApplicationEvent"]; + if (intent.hasOwnProperty("message")) intent = intent.message; + } + } catch (e) { + return; + } + } + + if ( + !intent.hasOwnProperty("extras") || + !intent.extras.hasOwnProperty("payload") + ) { + return; + } + + var payload = intent.extras.payload, + senderTime = intent.extras.time, + senderTimes = _self._times[intent.sender]; + + var i, numOfSenderTimes, numOfMessages; + + function handleMessage(payload) { + var type, data, sender, operation, resOperation, i, numOfCallbacks; + + if ( + !payload || + !payload.hasOwnProperty("type") || + !payload.hasOwnProperty("data") + ) { + return; + } + type = payload.type; + data = payload.data; + sender = payload.sender; + switch (type) { + case PAYLOAD_DATA_TYPE.OT_OPERATION: + operation = new OTOperation( + data.name, + data.value, + data.type, + data.position + ); + operation.setSender(sender); + resOperation = + OperationFactory$1.createOperationFromOTOperation(operation); + //adjustHistory(remoteOp); + for ( + i = 0, numOfCallbacks = _self._onDataReceivedCallbacks.length; + i < numOfCallbacks; + i++ + ) { + if (typeof _self._onDataReceivedCallbacks[i] === "function") { + var caller = _self._onDataReceivedCallers[i] || _self; + _self._onDataReceivedCallbacks[i].call(caller, resOperation); + } + } + break; + case PAYLOAD_DATA_TYPE.NON_OT_OPERATION: + operation = new NonOTOperation(data.type, data.data); + operation.setSender(sender); + resOperation = + OperationFactory$1.createOperationFromNonOTOperation(operation); + //adjustHistory(remoteOp); + for ( + i = 0, numOfCallbacks = _self._onDataReceivedCallbacks.length; + i < numOfCallbacks; + i++ + ) { + if (typeof _self._onDataReceivedCallbacks[i] === "function") { + var caller = _self._onDataReceivedCallers[i] || _self; + _self._onDataReceivedCallbacks[i].call(caller, resOperation); + } + } + break; + } + } + + if (intent.flags.indexOf(CONFIG.IWC.FLAG.PUBLISH_GLOBAL) !== -1) return; + + if (typeof senderTimes === "undefined") { + senderTimes = _self._times[intent.sender] = []; + } else { + for ( + i = 0, numOfSenderTimes = senderTimes.length; + i < numOfSenderTimes; + i++ + ) { + if (senderTime === senderTimes[i]) { + return; + } + } + } + + senderTimes.push(senderTime); + + //console.log("=== " + intent.flags.toString().replace(/PUBLISH_/g,"") + " INTENT RECEIVED AT COMPONENT " + componentName + " ==="); + //console.log(intent); + + switch (intent.action) { + case CONFIG.IWC.ACTION.DATA: + handleMessage(payload); + break; + case CONFIG.IWC.ACTION.DATA_ARRAY: + for (i = 0, numOfMessages = payload.length; i < numOfMessages; i++) { + handleMessage(payload[i]); + } + break; + } + } + + constructor(componentName, y) { + this.componentName = componentName; + this._iwc = new Client(componentName, "*", null, y); + window._iwc_instance_ = this._iwc; + + //var sendBufferTimer; + //if(BUFFER_ENABLED) sendBufferTimer = new IWCWrapper.PausableInterval(sendBufferedMessages, INTERVAL_SEND); + if (this.BUFFER_ENABLED) + setInterval(this.sendBufferedMessages, this.INTERVAL_SEND); + + this.connect = () => + this._iwc.connect((intent) => + this.onIntentReceivedCallback(this, intent) + ); + this.disconnect = () => this._iwc.disconnect; + + /** + * Send data locally to an other component + * @memberof IWCWrapper# + * @param {string} receiver Component name of receiving component, empty string for broadcast + * @param {object} data Data to send + */ + this.sendLocalMessage = function (receiver, data) { + var intent; + + if (!receiver || receiver === "") return; + + if (this.BUFFER_ENABLED) { + //sendBufferTimer.pause(); + if (this._messageBuffer.hasOwnProperty(receiver)) { + this._messageBuffer[receiver].push(data); + } else { + this._messageBuffer[receiver] = [data]; + } + //sendBufferTimer.resume(); + } else { + intent = this.encapsulateMessage( + receiver, + CONFIG.IWC.FLAG.PUBLISH_LOCAL, + CONFIG.IWC.ACTION.DATA, + data + ); + if (util.validateIntent(intent)) { + //console.log("=== " + intent.flags.toString().replace(/PUBLISH_/g,"") + " INTENT TRANSMITTED AT COMPONENT " + componentName + " ==="); + //console.log(intent); + + this._iwc.publish(intent); + } + } + }; + /** + * Send OTOperation locally to an other component + * @memberof IWCWrapper# + * @param {string} receiver Component name of receiving component, empty string for broadcast + * @param {operations.ot.OTOperation} operation Operation to send + */ + this.sendLocalOTOperation = function (receiver, operation) { + this.sendLocalMessage(receiver, { + type: PAYLOAD_DATA_TYPE.OT_OPERATION, + data: operation.getOperationObject(), + sender: operation.getSender(), + }); + }; + /** + * Send NonOTOperation locally to an other component + * @memberof IWCWrapper# + * @param {string} receiver Component name of receiving component, empty string for broadcast + * @param {operations.non_ot.NonOTOperation} operation Operation to send + */ + this.sendLocalNonOTOperation = function (receiver, operation) { + this.sendLocalMessage(receiver, { + type: PAYLOAD_DATA_TYPE.NON_OT_OPERATION, + data: operation.getOperationObject(), + sender: operation.getSender(), + }); + }; + this.getUserColor = function (jabberId) { + return Util.getColor(this.Space.members[jabberId].globalId); + }; + /** + * Register callback for local data receive events + * @memberof IWCWrapper# + * @param {function} callback + */ + this.registerOnDataReceivedCallback = function (callback, caller) { + if (typeof callback === "function") { + this.unregisterOnDataReceivedCallback(callback); + this._onDataReceivedCallbacks.push(callback); + this._onDataReceivedCallers.push(caller); + } + }; + /** + * Unregister callback for local data receive events + * @memberof IWCWrapper# + * @param {function} callback + */ + this.unregisterOnDataReceivedCallback = function (callback) { + var i, numOfCallbacks; + + if (typeof callback === "function") { + for ( + i = 0, numOfCallbacks = this._onDataReceivedCallbacks.length; + i < numOfCallbacks; + i++ + ) { + if (callback === this._onDataReceivedCallbacks[i]) { + this._onDataReceivedCallbacks.splice(i, 1); + this._onDataReceivedCallers.splice(i, 1); + } + } + } + }; + this.getUser = function () { + if (!this.Space) { + console.error("Space is null"); + this.Space = { user: {} }; + } else if (!this.Space.user) { + console.error("User in space is null, generating new anonymous user"); + this.Space.user = Util.generateAnonymousUser(); + } + return this.Space.user; + }; + this.getMembers = function () { + return this.Space.members; + }; + this.getSpaceTitle = function () { + return this.Space.title; + }; + this.setSpace = function (s) { + this.Space = s; + }; + + return this; + } +} + +/** + * Inter widget communication and OT client module + * @exports IWCW + */ +class IWCW { + static instances = {}; //static variable to store instances of IWCWrapper. One for each widget + constructor() {} + /** + * Instance of IWCWrapper + * @type {IWCWrapper} + */ + + static hasInstance(componentName) { + return componentName in IWCW.instances; + } + + /** + * Get instance of IWCOTWrapper + * @param {string} componentName Name of component (widget) using the wrapper + * @returns {IWCWrapper} + */ + static getInstance(componentName, y) { + if (!this.hasInstance(componentName)) { + y = y || window.y; + if (!y) { + console.error( + "y is null, y is the shared y document that should be passed along when calling getInstance, proceed with caution" + ); + } + IWCW.instances[componentName] = new IWCWrapper(componentName, y); + IWCW.instances[componentName].connect(); + } + return IWCW.instances[componentName]; + } +} + +$.fn.autoGrowInput = function (o) { + o = $.extend( + { + maxWidth: 1000, + minWidth: 0, + comfortZone: 70, + }, + o + ); + + this.filter("input:text").each(function () { + var minWidth = o.minWidth || $(this).width(), + val = "", + input = $(this), + testSubject = $("").css({ + position: "absolute", + top: -9999, + left: -9999, + width: "auto", + fontSize: input.css("fontSize"), + fontFamily: input.css("fontFamily"), + fontWeight: input.css("fontWeight"), + letterSpacing: input.css("letterSpacing"), + whiteSpace: "nowrap", + }), + check = function () { + val = input.val(); + + // Enter new content into testSubject + var escaped = val + .replace(/&/g, "&") + .replace(/\s/g, " ") + .replace(//g, ">"); + testSubject.html(escaped); + + // Calculate new width + whether to change + var testerWidth = testSubject.width(), + newWidth = + testerWidth + o.comfortZone >= minWidth + ? testerWidth + o.comfortZone + : minWidth, + currentWidth = input.width(), + isValidWidthChange = + (newWidth < currentWidth && newWidth >= minWidth) || + (newWidth > minWidth && newWidth < o.maxWidth); + + // Animate width + if (isValidWidthChange) { + input.width(newWidth); + } + }; + + $("body").append(testSubject); + + $(this).bind("keyup keydown blur update", check); + }); + + return this; +}; + +/** + * AbstractEntity + * @class canvas_widget.AbstractEntity + * @memberof canvas_widget + * @constructor + * @param {string} id Identifier of this entity + */ + class AbstractEntity { + static MAX_Z_INDEX = 32000; + static MIN_Z_INDEX = 1; + static CONTEXT_MENU_Z_INDEX = 32000 + 1; + + static maxZIndex = 16000; + static minZIndex = 16000; + constructor(id) { + /** + * Entity identifier + * @type {string} + * @private + */ + var _id = id; + + /** + * Get the entity identifier + * @returns {string} entity id + */ + this.getEntityId = function () { + return _id; + }; + } + } + +const abstractAttributeHtml = "
                          "; // replaced by importmap.plugin.js + +/** + * AbstractAttribute + * @class canvas_widget.AbstractAttribute + * @extends canvas_widget.AbstractEntity + * @memberof canvas_widget + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to + */ +class AbstractAttribute extends AbstractEntity { + constructor(id, name, subjectEntity) { + super(id); + + /** + * Entity id + * @type {string} + * @private + */ + var _id = id; + + /** + * Name of Attribute + * @type {string} + * @private + */ + var _name = name; + + /** + * jQuery object of DOM node representing the attribute + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(abstractAttributeHtml)()); + + /** + * Entity the attribute is assigned to + * @type {canvas_widget.AbstractEntity} + * @private + */ + var _subjectEntity = subjectEntity; + + /** + * Set name of the attribute + * @param {string} name + */ + this.setName = function (name) { + _name = name; + }; + + /** + * Get name of the attribute + * @returns {String} + */ + this.getName = function () { + return _name; + }; + + /** + * Get entity the attribute is assigned to + * @returns {canvas_widget.AbstractEntity} + */ + this.getSubjectEntity = function () { + return _subjectEntity; + }; + + /** + * Get topmost entity in the chain of entities the attribute is assigned to + * @returns {canvas_widget.AbstractEdge|canvas_widget.AbstractNode} + */ + this.getRootSubjectEntity = function () { + var rootSubjectEntity = this.getSubjectEntity(); + while (rootSubjectEntity instanceof AbstractAttribute) { + rootSubjectEntity = rootSubjectEntity.getSubjectEntity(); + } + return rootSubjectEntity; + }; + + /** + * Get id of the entity the attribute is assigned to + * @returns {String} + */ + this.getSubjectEntityId = function () { + return _subjectEntity.getEntityId(); + }; + + /** + * Get jQuery object of the DOM node representing the attribute + * @returns {jQuery} + * @private + */ + this._get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the attribute + * @returns {Object} + * @private + */ + this._toJSON = function () { + return { + id: _id, + name: _name, + }; + }; + } + /** + * Get jQuery object of the DOM node representing the attribute + * @returns {jQuery} + */ + get$node() { + return this._get$node(); + } + /** + * Get JSON representation of the attribute + * @returns {Object} + */ + toJSON() { + return this._toJSON(); + } + registerYTypeForValue(map, value) { + var deferred = $.Deferred(); + map.get(value.getEntityId()).then(function (type) { + value.registerYType(type); + deferred.resolve(); + }); + return deferred.promise(); + } +} + +/** + * AbstractValue + * @class canvas_widget.AbstractValue + * @member of canvas_widget + * @constructor + * @param {string} id Entity identifier + * @param {string} name Name of attribute + * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {canvas_widget.AbstractNode|canvas_widget.AbstractEdge} rootSubjectEntity Topmost entity in the chain of entity the attribute is assigned to + */ + class AbstractValue { + constructor(id, name, subjectEntity, rootSubjectEntity) { + var that = this; + + /** + * The entity identifier + * @returns {string} entity id + */ + var _id = id; + + /** + * Name of Attribute + * @type {string} + * @private + */ + var _name = name; + + /** + * Entity the attribute is assigned to + * @type {canvas_widget.AbstractEntity} + * @private + */ + var _subjectEntity = subjectEntity; + + /** + * Topmost entity in the chain of entity the attribute is assigned to + * @type {canvas_widget.AbstractEdge|canvas_widget.AbstractNode} + * @private + */ + var _rootSubjectEntity = rootSubjectEntity; + + /** + * Get the entity identifier + * @returns {string} entity id + */ + this.getEntityId = function () { + return _id; + }; + + /** + * Get name of value + * @returns {string} + */ + this.getName = function () { + return _name; + }; + + /** + * Get entity the attribute is assigned to + * @returns {canvas_widget.AbstractEntity} + */ + this.getSubjectEntity = function () { + return _subjectEntity; + }; + + /** + * Get topmost entity in the chain of entity the attribute is assigned to + * @returns {canvas_widget.AbstractEdge|canvas_widget.AbstractNode} + */ + this.getRootSubjectEntity = function () { + return _rootSubjectEntity; + }; + + /** + * Get JSON representation of the edge + * @returns {Object} + */ + this._toJSON = function () { + return { + id: that.getEntityId(), + name: _name, + }; + }; + } + //noinspection JSAccessibilityCheck + toJSON() { + return this._toJSON(); + } + } + +function Arrows(color){ + return { + //"bidirassociation": {}, //No overlays for bi-dir-association + unidirassociation: { + type: "Arrow", + options: { + width: 20, + length: 30, + location: 1, + foldback: 0.1, + paintStyle: { + fill: "#ffffff", + outlineWidth: 2, + outlineStroke: color, + }, + }, + }, + generalisation: { + type: "Arrow", + options: { + width: 20, + length: 30, + location: 1, + foldback: 1, + paintStyle: { + fill: "#ffffff", + outlineWidth: 2, + outlineStroke: color, + }, + }, + }, + diamond: { + type: "Arrow", + options: { + width: 20, + length: 20, + location: 1, + foldback: 2, + paintStyle: { + fill: "#ffffff", + outlineWidth: 2, + outlineStroke: color, + }, + }, + }, + }; + } + +let booleanValueHtml = "
                          <%= value %>
                          "; // replaced by importmap.plugin.js +const attributeBooleanValueHtml = "\"\n <% if (value) { %> checked=\"checked\" <% } %> />\n"; // replaced by importmap.plugin.js + +/** + * BooleanValue + * @class canvas_widget.BooleanValue + * @extends canvas_widget.AbstractValue + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier + * @param {string} name Name of attribute + * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {canvas_widget.AbstractNode|canvas_widget.AbstractEdge} rootSubjectEntity Topmost entity in the chain of entity the attribute is assigned to + */ +class BooleanValue extends AbstractValue { + constructor(id, name, subjectEntity, rootSubjectEntity, useAttributeHtml) { + if (useAttributeHtml) booleanValueHtml = attributeBooleanValueHtml; + + super(id, name, subjectEntity, rootSubjectEntity); + var that = this; + /** + * Value + * @type {boolean} + * @private + */ + var _value = false; + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(booleanValueHtml)({ value: _value })); + + /** + * Inter widget communication wrapper + * @type {Object} + * @private + */ + y = y || window.y; + var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); + + /** + * Apply a Value Change Operation + * @param {operations.ot.ValueChangeOperation} operation + */ + var processValueChangeOperation = function (operation) { + that.setValue(operation.getValue()); + }; + + var init = function () { + _$node.off(); + }; + + /** + * Set value + * @param {boolean} value + */ + this.setValue = function (value) { + _value = value; + if (useAttributeHtml) _$node.prop("checked", value); + else _$node.text(value); + }; + + /** + * Get value + * @returns {boolean} + */ + this.getValue = function () { + return _value; + }; + + /** + * Get jQuery object of DOM node representing the value + * @returns {jQuery} + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the edge + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractValue.prototype.toJSON.call(this); + json.value = _value; + return json; + }; + + /** + * Set value by its JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + this.setValue(json.value); + }; + + this.registerYType = function () { + that + .getRootSubjectEntity() + .getYMap() + .observe(function (event) { + const array = Array.from(event.changes.keys.entries()); + array.forEach(function ([key, change]) { + if (change.action !== "update" || key !== that.getEntityId()) { + return; + } + const map = event.currentTarget.get(key); + const json = map; + + var operation = new ValueChangeOperation( + json.entityId, + json.value, + json.type, + json.position, + json.jabberId + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.getOTOperation() + ); + processValueChangeOperation(operation); + + //Only the local user Propagates the activity + if ( + _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID] === + operation.getJabberId() + ) { + const activityMap = y.getMap("activity"); + activityMap.set( + ActivityOperation.TYPE, + new ActivityOperation( + "ValueChangeActivity", + that.getEntityId(), + _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], + ValueChangeOperation.getOperationDescription( + that.getSubjectEntity().getName(), + that.getRootSubjectEntity().getType(), + that.getRootSubjectEntity().getLabel().getValue().getValue() + ), + { + value: operation.getValue(), + subjectEntityName: that.getSubjectEntity().getName(), + rootSubjectEntityType: that + .getRootSubjectEntity() + .getType(), + rootSubjectEntityId: that + .getRootSubjectEntity() + .getEntityId(), + } + ).toJSON() + ); + } else { + //the remote users propagtes the change to their local attribute widget + //TODO(PENDING): can be replace with yjs as well + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.ATTRIBUTE, + operation.getOTOperation() + ); + } + }); + }); + + //Debounce the save function + that + .getRootSubjectEntity() + .getYMap() + .observe( + lodash.debounce(function (event) { + event.keysChanged.forEach(function (key) { + if ( + key == "jabberId" && + key === _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID] + ) + EntityManager.saveState(); + }); + }, 500) + ); + }; + + init(); + } +} + +const booleanAttributeHtml = "
                          \n
                          \n
                          \n
                          "; // replaced by importmap.plugin.js + +/** + * BooleanAttribute + * @class canvas_widget.BooleanAttribute + * @extends canvas_widget.AbstractAttribute + * @memberof canvas_widget + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to + */ +class BooleanAttribute extends AbstractAttribute { + constructor(id, name, subjectEntity, useAttributeHtml) { + useAttributeHtml = + typeof useAttributeHtml !== "undefined" ? useAttributeHtml : false; + super(id, name, subjectEntity); + + /*** + * Value object of value + * @type {canvas_widget.BooleanValue} + * @private + */ + var _value = new BooleanValue( + id, + name, + this, + this.getRootSubjectEntity(), + useAttributeHtml + ); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(booleanAttributeHtml)()); + + /** + * Set Value object of value + * @param {canvas_widget.BooleanValue} value + */ + this.setValue = function (value) { + _value = value; + _$node.val(value); + }; + + /** + * Get Value object of value + * @return {canvas_widget.BooleanValue} value + */ + this.getValue = function () { + return _value; + }; + + /** + * jQuery object of DOM node representing the attribute + * @type {jQuery} + * @private + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the attribute + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.value = _value.toJSON(); + return json; + }; + + /** + * Set attribute value by its JSON representation + * @param {Object} json + */ + this.setValueFromJSON = function (json) { + _value.setValueFromJSON(json.value); + }; + + _$node.find(".name").text(this.getName()); + _$node.find(".value").append(_value.get$node()); + } +} + +const openapp$1 = new OpenAppProvider().openapp; + +let fileValueHtml = "
                          <%= value %>
                          "; // replaced by importmap.plugin.js +const attributeFileValueHtml = "
                          \n
                          \n \n \n
                          \n
                          \n \n \n \n \n
                          \n
                          \n"; // replaced by importmap.plugin.js + +FileValue.prototype = new AbstractValue(); +FileValue.prototype.constructor = FileValue; +/** + * FileValue + * @class canvas_widget.FileValue + * @extends canvas_widget.AbstractValue + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier + * @param {string} name Name of attribute + * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {canvas_widget.AbstractNode|canvas_widget.AbstractEdge} rootSubjectEntity Topmost entity in the chain of entity the attribute is assigned to + */ +function FileValue( + id, + name, + subjectEntity, + rootSubjectEntity, + useAttributeHtml +) { + var that = this; + + if (useAttributeHtml) fileValueHtml = attributeFileValueHtml; + + AbstractValue.call(this, id, name, subjectEntity, rootSubjectEntity); + + /** + * Value + * @type {string} + * @private + */ + var _value = ""; + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node; + + if (useAttributeHtml) _$node = $(lodash.template(fileValueHtml)({ name: name })); + else _$node = $(lodash.template(fileValueHtml)({ value: _value })); + + var _$selectFile = _$node.find(".select_file"); + + var _$manageFile = _$node.find(".manage_file"); + + /** + * Inter widget communication wrapper + * @type {Object} + * @private + */ + y = y || window.y; + var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); + + /** + * Get chain of entities the attribute is assigned to + * @returns {string[]} + */ + var getEntityIdChain = function () { + var chain = [that.getEntityId()], + entity = that; + while (entity instanceof AbstractAttribute) { + chain.unshift(entity.getSubjectEntity().getEntityId()); + entity = entity.getSubjectEntity(); + } + return chain; + }; + + var uploadFile = function (name, type, data) { + var resourceSpace = new openapp$1.oo.Resource(openapp$1.param.space()); + + resourceSpace.create({ + relation: openapp$1.ns.role + "data", + type: "my:ns:file", + representation: { + name: name, + type: type, + data: data, + }, + callback: function (d) { + if (d.uri) { + propagateValueChange(CONFIG.OPERATION.TYPE.UPDATE, d.uri, 0); + } + }, + }); + }; + + /** + * Apply a Value Change Operation + * @param {operations.ot.ValueChangeOperation} operation + */ + var processValueChangeOperation = function (operation) { + that.setValue(operation.getValue()); + }; + + var propagateValueChange = function (type, value, position) { + var operation = new ValueChangeOperation( + that.getEntityId(), + value, + type, + position + ); + propagateValueChangeOperation(operation); + }; + + /** + * Propagate a Value Change Operation to the remote users and the local widgets + * @param {operations.ot.ValueChangeOperation} operation + */ + var propagateValueChangeOperation = function (operation) { + operation.setEntityIdChain(getEntityIdChain()); + processValueChangeOperation(operation); + if (_iwcw.sendRemoteOTOperation(operation)) { + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.ATTRIBUTE, + operation.getOTOperation() + ); + const activityMap = y.getMap("activity"); + + activityMap.set( + ActivityOperation.TYPE, + new ActivityOperation( + "ValueChangeActivity", + that.getEntityId(), + _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], + ValueChangeOperation.getOperationDescription( + that.getSubjectEntity().getName(), + that.getRootSubjectEntity().getType(), + that.getRootSubjectEntity().getLabel().getValue().getValue() + ), + { + value: operation.getValue(), + subjectEntityName: that.getSubjectEntity().getName(), + rootSubjectEntityType: that.getRootSubjectEntity().getType(), + rootSubjectEntityId: that.getRootSubjectEntity().getEntityId(), + } + ).toJSON() + ); + } + }; + + /** + * Callback for a local Value Change Operation + * @param {operations.ot.ValueChangeOperation} operation + */ + var localValueChangeCallback = function (operation) { + if ( + operation instanceof ValueChangeOperation && + operation.getEntityId() === that.getEntityId() + ) { + propagateValueChangeOperation(operation); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.getOTOperation() + ); + } + }; + + var init = function () { + if (!useAttributeHtml) return; + + _$selectFile.find("#file_object").change(function () { + var files = $(this)[0].files, + file; + + if (!files || files.length === 0) return; + file = files[0]; + if (file.size > 1048576) { + alert("Chosen file is too large. Maximum size: 1MB"); + } + }); + + _$selectFile.find("#file_submit").click(function () { + var fileReader, + files = _$selectFile.find("#file_object")[0].files, + file; + + if (!files || files.length === 0) return; + file = files[0]; + + fileReader = new FileReader(); + fileReader.onload = function (e) { + uploadFile(file.name, file.type, e.target.result); + }; + fileReader.readAsDataURL(file); + }); + + _$manageFile.find("#file_delete").click(function () { + //openapp.resource.del(_value); + propagateValueChange(CONFIG.OPERATION.TYPE.UPDATE, "", 0); + }); + + _$selectFile.show(); + _$manageFile.hide(); + }; + + /** + * Set value + * @param {string} value + */ + this.setValue = function (value) { + _value = value; + if (_value === "") { + _$node.text(""); + } else { + $.get(_value + "/:representation").done(function (data) { + _$node.text(data.name); + }); + } + }; + + /** + * Get value + * @returns {string} + */ + this.getValue = function () { + return _value; + }; + + /** + * Get jQuery object of DOM node representing the value + * @returns {jQuery} + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the edge + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractValue.prototype.toJSON.call(this); + json.value = _value; + return json; + }; + + /** + * Set value by its JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + this.setValue(json.value); + }; + + /** + * Register inter widget communication callbacks + */ + this.registerCallbacks = function () { + //_iwcw.registerOnRemoteDataReceivedCallback(remoteValueChangeCallback); + _iwcw.registerOnDataReceivedCallback(localValueChangeCallback); + //_iwcw.registerOnHistoryChangedCallback(historyValueChangeCallback); + }; + + /** + * Unregister inter widget communication callbacks + */ + this.unregisterCallbacks = function () { + //_iwcw.unregisterOnRemoteDataReceivedCallback(remoteValueChangeCallback); + _iwcw.unregisterOnDataReceivedCallback(localValueChangeCallback); + //_iwcw.unregisterOnHistoryChangedCallback(historyValueChangeCallback); + }; + + if (_iwcw) { + that.registerCallbacks(); + } + + init(); +} + +const fileAttributeHtml = "
                          \n
                          \n
                          \n
                          "; // replaced by importmap.plugin.js + +/** + * FileAttribute + * @class canvas_widget.FileAttribute + * @extends canvas_widget.AbstractAttribute + * @memberof canvas_widget + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to + */ +class FileAttribute extends AbstractAttribute { + constructor(id, name, subjectEntity, useAttributeHtml) { + useAttributeHtml = + typeof useAttributeHtml !== "undefined" ? useAttributeHtml : false; + super(id, name, subjectEntity); + + /*** + * Value object of value + * @type {canvas_widget.FileValue} + * @private + */ + var _value = new FileValue( + id, + name, + this, + this.getRootSubjectEntity(), + useAttributeHtml + ); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(fileAttributeHtml)()); + + /** + * Set Value object of value + * @param {canvas_widget.FileValue} value + */ + this.setValue = function (value) { + _value = value; + _$node.val(value); + }; + + /** + * Get Value object of value + * @return {canvas_widget.FileValue} value + */ + this.getValue = function () { + return _value; + }; + + /** + * jQuery object of DOM node representing the attribute + * @type {jQuery} + * @private + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the attribute + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.value = _value.toJSON(); + return json; + }; + + /** + * Set attribute value by its JSON representation + * @param {Object} json + */ + this.setValueFromJSON = function (json) { + _value.setValueFromJSON(json.value); + }; + + _$node.find(".name").text(this.getName()); + _$node.find(".value").append(_value.get$node()); + } +} + +const multiLineValueHtml = "
                          <%= value %>
                          "; // replaced by importmap.plugin.js + +/** + * MultiLineValue + * @class canvas_widget.MultiLineValue + * @extends canvas_widget.AbstractValue + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier + * @param {string} name Name of attribute + * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {canvas_widget.AbstractNode|canvas_widget.AbstractEdge} rootSubjectEntity Topmost entity in the chain of entity the attribute is assigned to + */ +class MultiLineValue extends AbstractValue { + constructor(id, name, subjectEntity, rootSubjectEntity, y) { + super(id, name, subjectEntity, rootSubjectEntity); + var that = this; + + var _ytext = null; + y = y || window.y; + if (y) { + const yMap = rootSubjectEntity.getYMap(); + if (!yMap) { + rootSubjectEntity.registerYMap(); + } + + if (rootSubjectEntity.getYMap()?.has(id)) + _ytext = rootSubjectEntity.getYMap().get(id); + else { + _ytext = new Text(); + rootSubjectEntity.getYMap().set(id, _ytext); + } + } + + /** + * MultiLineValue + * @type {string} + * @private + */ + var _value = ""; + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(multiLineValueHtml)({ value: _value })); + + /** + * Inter widget communication wrapper + * @type {Object} + * @private + */ + y = y || window.y; + var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); + + /** + * Get chain of entities the attribute is assigned to + * @returns {string[]} + */ + var getEntityIdChain = function () { + var chain = [that.getEntityId()], + entity = that; + while (entity instanceof AbstractAttribute) { + chain.unshift(entity.getSubjectEntity().getEntityId()); + entity = entity.getSubjectEntity(); + } + return chain; + }; + + /** + * Propagate a Value Change Operation to the remote users and the local widgets + * @param {operations.ot.ValueChangeOperation} operation + */ + var propagateValueChangeOperation = function (operation) { + operation.setEntityIdChain(getEntityIdChain()); + operation.setRemote(false); + that.setValue(operation.getValue()); + operation.setRemote(true); + const activityMap = y.getMap("activity"); + + activityMap.set( + ActivityOperation.TYPE, + new ActivityOperation( + "ValueChangeActivity", + that.getEntityId(), + _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], + ValueChangeOperation.getOperationDescription( + that.getSubjectEntity().getName(), + that.getRootSubjectEntity().getType(), + that.getRootSubjectEntity().getLabel().getValue().getValue() + ), + { + value: _value, + subjectEntityName: that.getSubjectEntity().getName(), + rootSubjectEntityType: that.getRootSubjectEntity().getType(), + rootSubjectEntityId: that.getRootSubjectEntity().getEntityId(), + } + ) + .toNonOTOperation() + .toJSON() + ); + + /*if(that.getRootSubjectEntity().getYMap()){ + that.getRootSubjectEntity().getYMap().set(that.getEntityId(),operation.toJSON()); + }*/ + }; + + /** + * Callback for a local Value Change Operation + * @param {operations.ot.ValueChangeOperation} operation + */ + var localValueChangeCallback = function (operation) { + if ( + operation instanceof ValueChangeOperation && + operation.getEntityId() === that.getEntityId() + ) { + propagateValueChangeOperation(operation); + } + }; + + /** + * Set value + * @param {string} value + */ + this.setValue = function (value) { + _value = value; + _$node.text(value); + }; + + /** + * Get value + * @returns {string} + */ + this.getValue = function () { + return _value; + }; + + /** + * Get jQuery object of DOM node representing the value + * @returns {jQuery} + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the edge + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractValue.prototype.toJSON.call(this); + json.value = _value; + return json; + }; + + /** + * Set value by its JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + this.setValue(json.value); + }; + + /** + * Register inter widget communication callbacks + */ + this.registerCallbacks = function () { + _iwcw.registerOnDataReceivedCallback(localValueChangeCallback); + //_iwcw.registerOnHistoryChangedCallback(historyValueChangeCallback); + }; + + /** + * Unregister inter widget communication callbacks + */ + this.unregisterCallbacks = function () { + _iwcw.unregisterOnDataReceivedCallback(localValueChangeCallback); + //_iwcw.unregisterOnHistoryChangedCallback(historyValueChangeCallback); + }; + + this.registerYType = function () { + if (!_ytext) throw new Error("_ytext is undefined"); + // _ytext.bind(_$node[0]); + + if (that.getValue() !== _ytext.toString()) { + if (_ytext.toString().length > 0) + _ytext.delete(0, _ytext.toString().length - 1); + _ytext.insert(0, that.getValue()); + } + + _ytext.observe(function (event) { + _value = _ytext.toString(); + + //TODO i can not find out who triggered the delete :-(. Therefore do this only for non delete event types + if (event.type !== "delete") { + y.getMap("users"); + var jabberId = "User"; + const activityMap = y.getMap("activity"); + + activityMap.set( + ActivityOperation.TYPE, + new ActivityOperation( + "ValueChangeActivity", + that.getEntityId(), + jabberId, + ValueChangeOperation.getOperationDescription( + that.getSubjectEntity().getName(), + that.getRootSubjectEntity().getType(), + that.getRootSubjectEntity().getLabel().getValue().getValue() + ), + { + value: "", + subjectEntityName: that.getSubjectEntity().getName(), + rootSubjectEntityType: that.getRootSubjectEntity().getType(), + rootSubjectEntityId: that.getRootSubjectEntity().getEntityId(), + } + ).toJSON() + ); + } + }); + }; + + if (_iwcw) { + that.registerCallbacks(); + } + } +} + +const singleMultiLineValueAttributeHtml = "
                          \n
                          \n
                          \n
                          "; // replaced by importmap.plugin.js + +/** + * SingleMultiLineValueAttribute + * @class canvas_widget.SingleMultiLineValueAttribute + * @extends canvas_widget.AbstractAttribute + * @memberof canvas_widget + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to + */ +class SingleMultiLineValueAttribute extends AbstractAttribute { + constructor(id, name, subjectEntity, y) { + super(id, name, subjectEntity); + + /*** + * Value object of value + * @type {canvas_widget.MultiLineValue} + * @private + */ + var _value = new MultiLineValue( + id, + name, + this, + this.getRootSubjectEntity(), + y + ); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(singleMultiLineValueAttributeHtml)()); + + /** + * Set Value object of value + * @param {canvas_widget.MultiLineValue} value + */ + this.setValue = function (value) { + _value = value; + }; + + /** + * Get Value object of value + * @returns {canvas_widget.MultiLineValue} + */ + this.getValue = function () { + return _value; + }; + + /** + * jQuery object of DOM node representing the attribute + * @type {jQuery} + * @private + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the attribute + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.value = _value.toJSON(); + return json; + }; + + /** + * Set attribute value by its JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + _value.setValueFromJSON(json.value); + }; + + _$node.find(".name").text(this.getName()); + _$node.find(".value").append(_value.get$node()); + } +} + +function makeViewEdge( + type, + arrowType, + shapeType, + color, + dashstyle, + overlay, + overlayPosition, + overlayRotate, + attributes, + edgeType, + conditions, + conj +) { + function ViewEdge(id, source, target) { + var viewEdge = new edgeType(id, source, target); + viewEdge.restyle( + arrowType, + color, + shapeType, + dashstyle, + overlay, + overlayPosition, + overlayRotate, + attributes + ); + viewEdge.setCurrentViewType(type); + return viewEdge; + } + + ViewEdge.getConditions = function () { + return conditions; + }; + + ViewEdge.getConditionConj = function () { + return conj; + }; + + ViewEdge.getArrowType = function () { + return arrowType; + }; + ViewEdge.getShapeType = function () { + return shapeType; + }; + ViewEdge.getColor = function () { + return color; + }; + ViewEdge.getOverlay = function () { + return overlay; + }; + ViewEdge.getOverlayPosition = function () { + return overlayPosition; + }; + ViewEdge.getOverlayRotate = function () { + return overlayRotate; + }; + ViewEdge.getAttributes = function () { + return attributes; + }; + ViewEdge.getTargetEdgeType = function () { + return edgeType; + }; + ViewEdge.getType = function () { + return type; + }; + ViewEdge.getArrowOverlays = function () { + var overlays = []; + if (Arrows().hasOwnProperty(arrowType)) { + overlays.push(Arrows(color)[arrowType]); + } + return overlays; + }; + ViewEdge.getShape = function () { + return this.getTargetEdgeType().getShape(); + }; + + return ViewEdge; +} + +function makeViewNode(type, $shape, anchors, attributes, nodeType, conditions, conj) { + + ViewNode.prototype.constructor = ViewNode; + function ViewNode(id, left, top, width, height, zIndex) { + var viewNode = new nodeType(id, left, top, width, height, zIndex); + + viewNode.set$shape($shape); + viewNode.setAnchorOptions(anchors); + viewNode.setCurrentViewType(type); + + return viewNode; + + } + + ViewNode.getConditions = function(){ + return conditions; + }; + + ViewNode.getConditionConj = function(){ + return conj; + }; + + ViewNode.get$shape = function(){ + return $shape; + }; + + ViewNode.getAnchors = function(){ + return anchors; + }; + + ViewNode.getTargetNodeType = function(){ + return nodeType; + }; + return ViewNode; + } + +var LogicalConjunctions = { + "AND" : "&&", + "OR" : "||" + }; + +var LogicalOperator = { + "greater" : ">", + "smaller" : "<", + "equal" : "==", + "greater_eq" : ">=", + "smaller_eq" : "<=", + "nequal" : "!=" + }; + +function ViewTypesUtil() {} + +ViewTypesUtil.GetAllNodesOfBaseModelAsSelectionList = function (nodes) { + var selectionList = {}; + for (var key in nodes) { + if (nodes.hasOwnProperty(key)) { + selectionList[key] = nodes[key].getLabel().getValue().getValue(); + } + } + return selectionList; +}; +ViewTypesUtil.GetAllNodesOfBaseModelAsSelectionList2 = function (nodes, types) { + var selectionList = {}; + selectionList["empty"] = ""; + for (var key in nodes) { + if (nodes.hasOwnProperty(key)) { + if (lodash.indexOf(types, nodes[key].type) != -1) + selectionList[key] = nodes[key].label.value.value; + } + } + return selectionList; +}; + +ViewTypesUtil.createReferenceToOrigin = function (viewtype) { + const dataMap = y.getMap("data"); + var vls = dataMap.get("metamodelpreview"); + var originEntity; + if (vls) { + var targetAttr = viewtype.getAttribute(viewtype.getEntityId() + "[target]"); + var originId = targetAttr.getValue().getValue(); + if (viewtype.getType() === "ViewObject") { + if (vls.nodes.hasOwnProperty(originId)) { + originEntity = vls.nodes[originId]; + //By default the label for the ViewObject is the same as for the Origin + viewtype.getLabel().getValue().setValue(originEntity.label); + } + } else { + if (vls.edges.hasOwnProperty(originId)) { + originEntity = vls.edges[originId]; + //By default the label for the ViewObject is the same as for the Origin + viewtype.getLabel().getValue().setValue(originEntity.label); + } + } + //Initialize the Renaming list Attribute + var originAttrs = originEntity.attributes; + var renamingList = viewtype.getAttribute("[attributes]"); + var optionMap = {}; + for (var attrKey in originAttrs) { + if (originAttrs.hasOwnProperty(attrKey)) { + var attr = originAttrs[attrKey]; + var id = Util.generateRandomId(); + var operation = new AttributeAddOperation( + id, + renamingList.getEntityId(), + viewtype.getEntityId, + "RenamingAttribute" + ); + var renamingAttr = + renamingList.propagateAttributeAddOperation(operation); + renamingAttr.getKey().setValue(attr.key); + renamingAttr.getRef().setValue(attr.key); + optionMap[id] = attr.key; + } + } + //Initialize the Condition list attribute + viewtype.getYMap().set("updateConditionOption", optionMap); + + //targetAttr.get$node().hide(); + renamingList.get$node().show(); + viewtype + .getAttribute(viewtype.getEntityId() + "[conjunction]") + .get$node() + .show(); + viewtype.getAttribute("[condition]").get$node().show(); + } +}; + +const keySelectionValueSelectionValueListAttributeHtml = "
                          \n
                          \n
                            \n
                            "; // replaced by importmap.plugin.js + +const singleQuizAttributeHtml = "
                            \n
                            \n
                            \n \n \n \n \n \n \n \n \n \n \n \n
                            Assessment Name :
                            NrQuestionCorrect IntentOptional Hint
                            \n \n +\n \n \n -\n \n \n Submit\n \n \n Display\n \n
                            \n"; // replaced by importmap.plugin.js + +const singleValueListAttributeHtml = "
                            \n
                            \n
                              \n
                              "; // replaced by importmap.plugin.js + +const canvasSingleValueAttributeHtml = "
                              \n
                              \n
                              \n
                              "; // replaced by importmap.plugin.js + +const listHtml = "
                              \n
                              \n
                                \n
                                "; // replaced by importmap.plugin.js + +const renamingAttrHTML = "
                              • \n
                                \n
                                \n
                                \n
                              • "; // replaced by importmap.plugin.js + +const singleSelectionAttributeHtml = "
                                \n
                                \n
                                \n
                                "; // replaced by importmap.plugin.js + +const singleColorValueAttributeHtml = "
                                \n
                                \n
                                \n
                                "; // replaced by importmap.plugin.js + +const keySelectionValueSelectionValueAttributeHtml = "
                              • \">\n
                                \n
                                \n
                              • "; // replaced by importmap.plugin.js + +const keySelectionValueListAttributeHtml = "
                                \n
                                \n
                                  \n
                                  "; // replaced by importmap.plugin.js + +const keySelectionValueAttributeHtml = "
                                • \">\n
                                  \n
                                  \n
                                • "; // replaced by importmap.plugin.js +const integerAttributeHtml = "
                                  \n
                                  \n
                                  \n
                                  "; // replaced by importmap.plugin.js + +let integerValueHtml = "
                                  <%= value %>
                                  "; // replaced by importmap.plugin.js +const attributeIntegerValueHtml = "\"\n value=\"0\"\n/>\n"; // replaced by importmap.plugin.js + +const valueHtml = "\" class=\"fw-bold\"> \n"; // replaced by importmap.plugin.js + +let selectionValueHtml = "
                                  <%= options[_.keys(options)[0]] %>
                                  "; // replaced by importmap.plugin.js +const attributeSelectionValueHtml = "\n"; // replaced by importmap.plugin.js + +const viewrelationshipNodeHtml$1 = "
                                  \n
                                  <%= type %>
                                  \n
                                  <<ViewRelationship>>
                                  \n
                                  \n
                                  "; // replaced by importmap.plugin.js + +const viewobjectNodeHtml = "
                                  \n
                                  <%= type %>
                                  \n
                                  <<ViewObject>>
                                  \n
                                  \n
                                  "; // replaced by importmap.plugin.js + +const nodeShapeNodeHtml = "
                                  \n
                                  <%= type %>
                                  \n
                                  <<NodeShape>>
                                  \n
                                  \n
                                  "; // replaced by importmap.plugin.js + +const modelAttributesNodeHtml = "
                                  \n
                                  \n
                                  \n
                                  "; // replaced by importmap.plugin.js + +const relationshipGroupNodeHtml = "
                                  \n
                                  <%= type %>
                                  \n
                                  <<Relation>>
                                  \n
                                  \n
                                  "; // replaced by importmap.plugin.js + +const enumNodeHtml = "
                                  \n
                                  <%= type %>
                                  \n
                                  <<Enumeration>>
                                  \n
                                  \n
                                  "; // replaced by importmap.plugin.js + +const abstractEdgeHtml = "
                                  \n
                                  <%= type %>
                                  \n
                                  \n
                                  "; // replaced by importmap.plugin.js + +const edgeShapeNodeHtml = "
                                  \n
                                  <%= type %>
                                  \n
                                  <<EdgeShape>>
                                  \n
                                  \n
                                  "; // replaced by importmap.plugin.js + +const abstractNodeHtml = "
                                  \" class=\"node\">\n
                                  "; // replaced by importmap.plugin.js +const awarenessTraceHtml = "
                                  \" class=\"trace_awareness\">\n\n \n\n
                                  "; // replaced by importmap.plugin.js + +const abstractClassNodeHtml = "
                                  \n
                                  <%= type %>
                                  \n
                                  <<abstract>>
                                  \n
                                  \n
                                  \n"; // replaced by importmap.plugin.js + +const relationshipNodeHtml = "
                                  \n
                                  <%= type %>
                                  \n
                                  <<Relationship>>
                                  \n
                                  \n
                                  "; // replaced by importmap.plugin.js +const actionNodeHtml = "
                                  \n
                                  <%= \"<\\%= type %\\>\" %>
                                  \n \n \n \n
                                  \n \t\n\t\t \n\t\t \n\t\t \t\t\n\t\t \n\t\t
                                  fa-2x\"><%= label %>
                                  \n
                                  \n
                                  "; // replaced by importmap.plugin.js +const circleNodeHtml = "
                                  \n
                                  <%= type %>
                                  \n \n \"\n stroke=\"lightgray\"\n stroke-width=\"2\"\n />\n \n
                                  \n
                                  \n
                                  \n\n"; // replaced by importmap.plugin.js +const diamondNodeHtml = "
                                  \n
                                  <%= type %>
                                  \n \n \"\n stroke=\"lightgray\"\n stroke-width=\"2\"\n transform=\"rotate(-45 50 50)\"\n />\n \n
                                  \n
                                  \n
                                  \n\n"; // replaced by importmap.plugin.js +const objectNodeHtml = "
                                  \n
                                  <%= type %>
                                  \n
                                  <<Object>>
                                  \n
                                  \n
                                  "; // replaced by importmap.plugin.js +const rectangleNodeHtml = "
                                  \n
                                  <%= type %>
                                  \n \n \"\n stroke=\"lightgray\"\n stroke-width=\"2\"\n />\n \n
                                  \n
                                  \n
                                  \n\n"; // replaced by importmap.plugin.js +const roundedRectangleNodeHtml = "
                                  \n
                                  <%= type %>
                                  \n \n \"\n stroke=\"lightgray\"\n stroke-width=\"2\"\n />\n \n
                                  \n
                                  \n
                                  \n\n"; // replaced by importmap.plugin.js +const startActivityNodeHtml = "
                                  \n
                                  <%= type %>
                                  \n \n \n \n \n \n \n \n \n \n
                                  \n \t\n\t\t \n\t\t \n\t\t \t\t\n\t\t \n\t\t
                                  \n
                                  \n
                                  "; // replaced by importmap.plugin.js +const triangleNodeHtml = "
                                  \n
                                  <%= type %>
                                  \n \n \"\n stroke=\"lightgray\"\n stroke-width=\"2\"\n />\n \n
                                  \n
                                  \n
                                  \n\n"; // replaced by importmap.plugin.js +const activityFinalNodeHtml = "
                                  \n
                                  <%= type %>
                                  \n \n \n \n \n
                                  \n
                                  \n
                                  "; // replaced by importmap.plugin.js +const callActivityNodeHtml = "
                                  \n
                                  <%= type %>
                                  \n \n \n \n
                                  \n \n \n \n \n \n
                                  \n
                                  \n
                                  "; // replaced by importmap.plugin.js +const entityNodeHtml = "
                                  \n
                                  <%= \"<\\%= type %\\>\" %>
                                  \n \n \n \n \n \n \n \n \n \n
                                  \n \t\n\t\t \n\t\t \n\t\t \t\t\n\t\t \n\t\t
                                  fa-2x\"><%= label %>
                                  \n
                                  \n
                                  "; // replaced by importmap.plugin.js +const setPropertyNodeHtml = "
                                  \n
                                  <%= \"<\\%= type %\\>\" %>
                                  \n \n \n \n
                                  \n \t\n\t\t \n\t\t \n\t\t \t\t\n\t\t \n\t\t
                                  \n
                                  \n
                                  "; // replaced by importmap.plugin.js + +var shapes = { + straight: { + type: StraightConnector.type, + options: { gap: 0 }, + }, + curved: { + type: BezierConnector.type, + options: { gap: 0 }, + }, + segmented: { + type: FlowchartConnector.type, + options: { gap: 0 }, + }, +}; + +function HistoryManager() { + var bufferSize = 20; + + var _canvas = null; + + var latestOp = null; + var undo = []; + var redo = []; + + var $undo = $("#undo"); + + var $redo = $("#redo"); + + var propagateHistoryOperationFromJson = function (json) { + var EntityManager = EntityManager; + var operation = null, + data = null, + entity; + switch (json.TYPE) { + case NodeDeleteOperation.TYPE: { + entity = EntityManager.findNode(json.id); + if (entity) { + entity.triggerDeletion(true); + operation = new NodeDeleteOperation( + json.id, + json.type, + json.left, + json.top, + json.width, + json.height, + json.zIndex, + json.containment, + json.json + ); + } + break; + } + case NodeAddOperation.TYPE: { + _canvas.createNode( + json.type, + json.left, + json.top, + json.width, + json.height, + json.zIndex, + json.containment, + json.json, + json.id, + true + ); + operation = new NodeAddOperation( + json.id, + json.type, + json.left, + json.top, + json.width, + json.height, + json.zIndex, + json.containment, + json.json + ); + break; + } + case EdgeAddOperation.TYPE: { + _canvas.createEdge( + json.type, + json.source, + json.target, + json.json, + json.id, + true + ); + operation = new EdgeAddOperation( + json.id, + json.type, + json.source, + json.target, + json.json + ); + break; + } + case EdgeDeleteOperation.TYPE: { + entity = EntityManager.findEdge(json.id); + if (entity) { + entity.triggerDeletion(true); + operation = new EdgeDeleteOperation( + json.id, + json.type, + json.source, + json.target, + json.json + ); + } + break; + } + case NodeMoveOperation.TYPE: { + entity = EntityManager.findNode(json.id); + if (entity) { + const nodesMap = y.getMap("nodes"); + operation = new NodeMoveOperation( + json.id, + json.offsetX, + json.offsetY + ); + var ymap = nodesMap.get(json.id); + data = operation.toJSON(); + data.historyFlag = true; + ymap.set(NodeMoveOperation.TYPE, data); + } + break; + } + case NodeMoveZOperation.TYPE: { + entity = EntityManager.findNode(json.id); + if (entity) { + operation = new NodeMoveZOperation(json.id, json.offsetZ); + const nodesMap = y.getMap("nodes"); + var ymap = nodesMap.get(json.id); + data = operation.toJSON(); + data.historyFlag = true; + ymap.set(NodeMoveZOperation.TYPE, data); + } + break; + } + case NodeResizeOperation.TYPE: { + entity = EntityManager.findNode(json.id); + if (entity) { + operation = new NodeResizeOperation( + json.id, + json.offsetX, + json.offsetY + ); + const nodesMap = y.getMap("nodes"); + var ymap = nodesMap.get(json.id); + data = operation.toJSON(); + data.historyFlag = true; + ymap.set(NodeResizeOperation.TYPE, data); + } + break; + } + } + return operation; + }; + + return { + init: function (canvas) { + if (!canvas) throw new Error("Canvas is null"); + _canvas = canvas; + }, + add: function (operation) { + if (operation.hasOwnProperty("inverse")) { + var inverseOp = operation.inverse(); + var json = inverseOp.toJSON(); + json.TYPE = inverseOp.constructor.name; + undo.push(json); + redo = []; + $undo.prop("disabled", false); + $redo.prop("disabled", true); + } + if (undo.length > bufferSize) { + undo.shift(); + } + }, + undo: function () { + if (undo.length > 0) { + var jsonOp = undo.pop(); + if (undo.length === 0) { + $undo.prop("disabled", true); + } + var operation = propagateHistoryOperationFromJson(jsonOp); + if (!operation) { + this.undo(); + return; + } else latestOp = operation; + + var inverseOp = operation.inverse(); + var json = inverseOp.toJSON(); + json.TYPE = inverseOp.constructor.name; + + if (redo.length === 0) $redo.prop("disabled", false); + redo.push(json); + } else { + $undo.prop("disabled", true); + } + }, + redo: function () { + if (redo.length > 0) { + var jsonOp = redo.pop(); + if (redo.length === 0) { + $redo.prop("disabled", true); + } + var operation = propagateHistoryOperationFromJson(jsonOp); + if (!operation) { + this.redo(); + return; + } else latestOp = operation; + var inverseOp = operation.inverse(); + var json = inverseOp.toJSON(); + json.TYPE = inverseOp.constructor.name; + + if (undo.length === 0) $undo.prop("disabled", false); + undo.push(json); + } else { + $redo.prop("disabled", true); + } + }, + clean: function (entityId) { + var entityIdFilter = function (value) { + if (value.id === entityId) return false; + else return true; + }; + undo = undo.filter(entityIdFilter); + redo = redo.filter(entityIdFilter); + if (undo.length === 0) { + $undo.prop("disabled", true); + } + if (redo.length === 0) { + $redo.prop("disabled", true); + } + }, + getLatestOperation: function () { + return latestOp; + }, + getUndoList: function () { + return undo; + }, + getRedoList: function () { + return redo; + }, + }; +} + +const HistoryManagerInstance = new HistoryManager(); +Object.freeze(HistoryManagerInstance); + +const openapp = new OpenAppProvider().openapp; + +/** + * Predefined node shapes, first is default + * @type {{circle: *, diamond: *, rectangle: *, triangle: *}} + */ +var nodeShapeTypes = { + circle: circleNodeHtml, + diamond: diamondNodeHtml, + rectangle: rectangleNodeHtml, + rounded_rectangle: roundedRectangleNodeHtml, + triangle: triangleNodeHtml, +}; + +/** + * jQuery object to test for valid color + * @type {$} + */ +var $colorTestElement = $("
                                  "); + +/** Determines the current layer of syncmeta. + * can be CONFIG.LAYER.MODEL or CONFIG.LAYER.META*/ +var _layer = null; + +/** + * Different node types + * @type {object} + */ +var nodeTypes = {}; + +var _initNodeTypes = function (vls) { + var _nodeTypes = {}; + + var nodes = vls.nodes, + node, + shape, + anchors; + + // Start creating nodes based on metamodel + for (var nodeId in nodes) { + if (nodes.hasOwnProperty(nodeId)) { + node = nodes[nodeId]; + if (node.shape.customShape) { + shape = node.shape.customShape; + } else { + shape = nodeShapeTypes.hasOwnProperty(node.shape.shape) + ? nodeShapeTypes[node.shape.shape] + : lodash.keys(nodeShapeTypes)[0]; + } + if (node.shape.customAnchors) { + try { + if (node.shape.customAnchors) { + anchors = JSON.parse(node.shape.customAnchors); + } + if (!node.shape.customAnchors instanceof Array) { + anchors = { + type: "Perimeter", + options: { + shape: "Rectangle", + anchorCount: 10, + }, + }; + } + } catch (e) { + anchors = { + type: "Perimeter", + options: { + shape: "Rectangle", + anchorCount: 10, + }, + }; + } + } else { + switch (node.shape.shape) { + case "circle": + anchors = { + type: "Perimeter", + options: { + shape: "Circle", + anchorCount: 10, + }, + }; + break; + case "diamond": + anchors = { + type: "Perimeter", + options: { + shape: "Diamond", + anchorCount: 10, + }, + }; + break; + case "rounded_rectangle": + anchors = { + type: "Perimeter", + options: { + shape: "Rectangle", + anchorCount: 10, + }, + }; + break; + case "triangle": + anchors = { + type: "Perimeter", + options: { + shape: "Triangle", + anchorCount: 10, + }, + }; + break; + default: + case "rectangle": + anchors = { + type: "Perimeter", + options: { + shape: "Rectangle", + anchorCount: 10, + }, + }; + break; + } + } + var color = node.shape.color + ? $colorTestElement + .css("color", "#FFFFFF") + .css("color", node.shape.color) + .css("color") + : "#FFFFFF"; + var $shape = $(lodash.template(shape)({ color: color, type: node.label })); + + if ( + node.hasOwnProperty("targetName") && + !$.isEmptyObject(nodeTypes) && + nodeTypes.hasOwnProperty(node.targetName) + ) { + _nodeTypes[node.label] = makeViewNode( + node.label, + $shape, + anchors, + node.attributes, + nodeTypes[node.targetName], + node.conditions, + node.conjunction + ); + nodeTypes[node.targetName].VIEWTYPE = node.label; + } else { + _nodeTypes[node.label] = makeNode( + node.label, + $shape, + anchors, + node.attributes + ); + } + _nodeTypes[node.label].TYPE = node.label; + _nodeTypes[node.label].DEFAULT_WIDTH = node.shape.defaultWidth; + _nodeTypes[node.label].DEFAULT_HEIGHT = node.shape.defaultHeight; + _nodeTypes[node.label].CONTAINMENT = node.shape.containment; + _nodeTypes[node.label].SHAPE = $shape; + /* + nodeTypes[node.label] = Node(node.label, $shape, anchors, node.attributes, node.jsplumb); + nodeTypes[node.label].TYPE = node.label; + nodeTypes[node.label].SHAPE = $shape; + nodeTypes[node.label].DEFAULT_WIDTH = node.shape.defaultWidth; + nodeTypes[node.label].DEFAULT_HEIGHT = node.shape.defaultHeight;*/ + } + } + return _nodeTypes; +}; + +var _initEdgeTypes = function (vls) { + var _edgeTypes = {}; + var _relations = {}; + var edges = vls.edges, + edge; + for (var edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + + if ( + edge.hasOwnProperty("targetName") && + !$.isEmptyObject(edgeTypes) && + edgeTypes.hasOwnProperty(edge.targetName) + ) { + _edgeTypes[edge.label] = makeViewEdge( + edge.label, + edge.shape.arrow, + edge.shape.shape, + edge.shape.color, + edge.shape.dashstyle, + edge.shape.overlay, + edge.shape.overlayPosition, + edge.shape.overlayRotate, + edge.attributes, + edgeTypes[edge.targetName], + edge.conditions, + edge.conjunction + ); + edgeTypes[edge.targetName].VIEWTYPE = edge.label; + } else { + _edgeTypes[edge.label] = makeEdge( + edge.label, + edge.shape.arrow, + edge.shape.shape, + edge.shape.color, + edge.shape.dashstyle, + edge.shape.overlay, + edge.shape.overlayPosition, + edge.shape.overlayRotate, + edge.attributes + ); + } + + _edgeTypes[edge.label].TYPE = edge.label; + _relations[edge.label] = edge.relations; + } + } + return { + edgeTypes: _edgeTypes, + relations: _relations, + }; +}; + +/** + * contains all view node types of the current view + * @type {{}} + */ +var viewNodeTypes = {}; + +/** + * contains all view edge types of the current view + * @type {{}} + */ +var viewEdgeTypes = {}; + +/** + * Different edge types + * @type {object} + */ +var edgeTypes = {}; +var relations = {}; +/* + if (metamodel && metamodel.hasOwnProperty("edges")) { + var res = _initEdgeTypes(metamodel); + edgeTypes = res.edgeTypes; + relations = res.relations; + } else { + edgeTypes[GeneralisationEdge.TYPE] = GeneralisationEdge; + edgeTypes[BiDirAssociationEdge.TYPE] = BiDirAssociationEdge; + edgeTypes[UniDirAssociationEdge.TYPE] = UniDirAssociationEdge; + + relations[BiDirAssociationEdge.TYPE] = BiDirAssociationEdge.RELATIONS; + relations[UniDirAssociationEdge.TYPE] = UniDirAssociationEdge.RELATIONS; + relations[GeneralisationEdge.TYPE] = GeneralisationEdge.RELATIONS; + }*/ + +/** + * AbstractEdge + * @class canvas_widget.AbstractEdge + * @extends canvas_widget.AbstractEntity + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of edge + * @param {string} type Type of edge + * @param {canvas_widget.AbstractNode} source Source node + * @param {canvas_widget.AbstractNode} target Target node + * @param {boolean} [overlayRotate] Flag if edge overlay should be flipped automatically to avoid being upside down + */ +class AbstractEdge extends AbstractEntity { + constructor(id, type, source, target, overlayRotate, y) { + super(id); + y = y || window.y; + var that = this; + + /** + * Inter widget communication wrapper + * @type {Object} + */ + var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); // y comes from the window object but should in the future be passed through the constructor since we should avoid binding to window + + var _ymap = null; + if (!y) { + throw new Error("y is not defined"); + } + + const edgeMap = y.getMap("edges"); + if (edgeMap.has(id)) { + _ymap = edgeMap.get(id); + } else if (id && type && source && target) { + _ymap = new Map$2(); + edgeMap.set(id, new Map$2()); + y.transact(() => { + _ymap.set("id", id); + _ymap.set("type", type); + _ymap.set("source", source.getEntityId()); + _ymap.set("target", target.getEntityId()); + _ymap.set("jabberId", _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]); + }); + } + + this.getYMap = function () { + return _ymap; + }; + + /** + * Type of edge + * @type {string} + * @private + */ + var _type = type; + + /** + * Label of edge + * @type {canvas_widget.SingleValueAttribute} + * @private + */ + var _label = new SingleValueAttribute(id + "[label]", "Label", this, y); + + /** + * Appearance information of edge + * @type {{source: (canvas_widget.AbstractNode), target: (canvas_widget.AbstractNode)}} + * @private + */ + var _appearance = { + source: source, + target: target, + }; + + /** + * Flag if edge overlay should be flipped automatically to avoid being upside down + * @type {boolean} + * @private + */ + var _overlayRotate = overlayRotate !== false; + + /** + * jQuery object of DOM node representing the edge's overlay + * @type {jQuery} + * @private + */ + var _$overlay = $(lodash.template(abstractEdgeHtml)({ type: type })) + .find(".edge_label") + .append(_label.get$node()) + .parent(); + + /** + * Canvas the edge is drawn on + * @type {canvas_widget.AbstractCanvas} + * @private + */ + var _canvas = null; + + /** + * jsPlumb object representing the edge + * @type {Object} + * @private + */ + var _jsPlumbConnection = null; + + /** + * Attributes of edge + * @type {Object} + * @private + */ + var _attributes = {}; + + /** + * Stores current highlighting color + * @type {string} + * @private + */ + var _highlightColor = null; + + /** + * Callback to generate list of context menu items + * @type {function} + */ + var _contextMenuItemCallback = function () { + return {}; + }; + + //noinspection JSUnusedLocalSymbols + /** + * Apply an Edge Delete Operation + * @param {operations.ot.EdgeDeleteOperation} operation + */ + var processEdgeDeleteOperation = function () { + that.remove(); + }; + + /** + * Propagate an Edge Delete Operation to the remote users and the local widgets + * @param {operations.ot.EdgeDeleteOperation} operation + */ + var propagateEdgeDeleteOperation = function (operation) { + processEdgeDeleteOperation(); + + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.ATTRIBUTE, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.getOTOperation() + ); + const activityMap = y.getMap("activity"); + activityMap.set( + ActivityOperation.TYPE, + new ActivityOperation( + "EdgeDeleteActivity", + operation.getEntityId(), + _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], + EdgeDeleteOperation.getOperationDescription( + that.getType(), + that.getLabel().getValue().getValue() + ), + {} + ).toJSON() + ); + }; + + /** + * Callback for a remote Edge Delete Operation + * @param {operations.ot.EdgeDeleteOperation} operation + */ + this.remoteEdgeDeleteCallback = function (operation) { + if ( + operation instanceof EdgeDeleteOperation && + operation.getEntityId() == that.getEntityId() + ) { + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.ATTRIBUTE, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.getOTOperation() + ); + processEdgeDeleteOperation(); + } + }; + + /** + * Get jQuery object of all DOM nodes belonging to the edge + */ + var getAllAssociatedDOMNodes = function () { + var overlays, + i, + numOfOverlays, + $e = $("." + id); + + if (_jsPlumbConnection) { + overlays = _jsPlumbConnection.getOverlays(); + for (i = 0, numOfOverlays = overlays.length; i < numOfOverlays; i++) { + if (overlays[i] instanceof jsPlumb.Overlays.Custom) { + $e = $e.add(overlays[i].getElement()); + } + } + } else throw new Error("jsPlumbConnection is null"); + return $e; + }; + + /** + * Default paint style of edge + */ + var _defaultPaintStyle; + + /** + * Set the default paint style + * @param paintStyle + */ + this.setDefaultPaintStyle = function (paintStyle) { + _defaultPaintStyle = paintStyle; + }; + + /** + * Get the default paint style + * @returns {*} + */ + this.getDefaultPaintStyle = function () { + return _defaultPaintStyle; + }; + + /** + * Send NodeDeleteOperation for node + */ + this.triggerDeletion = function (historyFlag) { + _canvas.select(null); + var operation = new EdgeDeleteOperation( + id, + that.getType(), + that.getSource().getEntityId(), + that.getTarget().getEntityId() + ); + + if (_ymap) { + propagateEdgeDeleteOperation(operation); + const edgeMap = y.getMap("edges"); + edgeMap.delete(that.getEntityId()); + } else { + propagateEdgeDeleteOperation(operation); + } + if (!historyFlag) HistoryManagerInstance.add(operation); + }; + + //noinspection JSUnusedGlobalSymbols + /** + * Get callback to generate list of context menu items + * @returns {object} + */ + this.getContextMenuItemCallback = function () { + return _contextMenuItemCallback; + }; + + /** + * Set callback to generate list of context menu items + * @param {function} contextMenuItemCallback + */ + this.setContextMenuItemCallback = function (contextMenuItemCallback) { + _contextMenuItemCallback = contextMenuItemCallback; + }; + + /** + * Adds edge to canvas + * @param {canvas_widget.AbstractCanvas} canvas + */ + this.addToCanvas = function (canvas) { + if (!canvas) throw new Error("Canvas is null"); + _canvas = canvas; + }; + + /** + * Get associated canvas + * @returns {canvas_widget.AbstractCanvas} + */ + this.getCanvas = function () { + return _canvas; + }; + + /** + * Removes edge from canvas + */ + this.removeFromCanvas = function () { + _canvas = null; + $.contextMenu("destroy", "." + that.getEntityId()); + window.jsPlumbInstance.deleteConnection(_jsPlumbConnection, { + fireEvent: false, + }); + _jsPlumbConnection = null; + }; + + /** + * Add attribute to edge + * @param {canvas_widget.AbstractAttribute} attribute + */ + this.addAttribute = function (attribute) { + var id = attribute.getEntityId(); + if (!_attributes.hasOwnProperty(id)) { + _attributes[id] = attribute; + } + }; + + /** + * Set edge's attributes + * @param {Object} attributes + */ + this.setAttributes = function (attributes) { + _attributes = attributes; + }; + + /** + * Get edge's attributes + * @returns {Object} + */ + this.getAttributes = function () { + return _attributes; + }; + + /** + * Get attribute by id + * @param {String} id Attribute's entity id + * @returns {canvas_widget.AbstractAttribute} + */ + this.getAttribute = function (id) { + if (_attributes.hasOwnProperty(id)) { + return _attributes[id]; + } + return null; + }; + + /** + * Delete attribute by id + * @param {String} id Attribute's entity id + */ + this.deleteAttribute = function (id) { + if (!_attributes.hasOwnProperty(id)) { + delete _attributes[id]; + } + }; + + /** + * Set edge label + * @param {canvas_widget.SingleValueAttribute} label + */ + this.setLabel = function (label) { + _label = label; + }; + + /** + * Get edge label + * @returns {canvas_widget.SingleValueAttribute} + */ + this.getLabel = function () { + return _label; + }; + + /** + * Get edge type + * @returns {string} + */ + this.getType = function () { + return _type; + }; + + /** + * Get source node + * @returns {canvas_widget.AbstractNode} + */ + this.getSource = function () { + return _appearance.source; + }; + + /** + * Get target node + * @returns {canvas_widget.AbstractNode} + */ + this.getTarget = function () { + //noinspection JSAccessibilityCheck + return _appearance.target; + }; + + /** + * Get jQuery object of DOM node representing the edge's overlay + * @returns {jQuery} + */ + this.get$overlay = function () { + return _$overlay; + }; + + //noinspection JSUnusedGlobalSymbols + /** + * Set flag if edge overlay should be flipped automatically to avoid being upside down + * @param {boolean} rotateOverlay + */ + this.setRotateOverlay = function (rotateOverlay) { + _overlayRotate = rotateOverlay; + }; + + //noinspection JSUnusedGlobalSymbols + /** + * Get flag if edge overlay should be flipped automatically to avoid being upside down + * @return {boolean} rotateOverlay + */ + this.isRotateOverlay = function () { + return _overlayRotate; + }; + + /** + * Set jsPlumb object representing the edge + * @param {Object} jsPlumbConnection + */ + this.setJsPlumbConnection = function (jsPlumbConnection) { + _jsPlumbConnection = jsPlumbConnection; + _defaultPaintStyle = jsPlumbConnection.getPaintStyle(); + }; + + //noinspection JSUnusedGlobalSymbols + /** + * Get jsPlumb object representing the edge + * @return {Object} jsPlumbConnection + */ + this.getJsPlumbConnection = function () { + return _jsPlumbConnection; + }; + + /** + * Repaint edge overlays (adjust angle of fixed overlays) + */ + this.repaintOverlays = function () { + function makeRotateOverlayCallback(angle) { + return function rotateOverlay() { + var $this = $(this), + oldTransform = $this.css("transform", "").css("transform"); + + if (oldTransform === "none") oldTransform = ""; + + $this.css({ + transform: oldTransform + " rotate(" + angle + "rad)", + "-o-transform": oldTransform + " rotate(" + angle + "rad)", + "-ms-transform": oldTransform + " rotate(" + angle + "rad)", + "-moz-transform": oldTransform + " rotate(" + angle + "rad)", + "-webkit-transform": oldTransform + " rotate(" + angle + "rad)", + }); + }; + } + + var i, numOfOverlays, overlays, sourceEndpoint, targetEndpoint, angle; + + if (_jsPlumbConnection) { + sourceEndpoint = _jsPlumbConnection.endpoints[0].endpoint; + targetEndpoint = _jsPlumbConnection.endpoints[1].endpoint; + angle = Math.atan2( + sourceEndpoint.y - targetEndpoint.y, + sourceEndpoint.x - targetEndpoint.x + ); + if (!_overlayRotate || Math.abs(angle) > Math.PI / 2) { + angle += Math.PI; + } + overlays = _jsPlumbConnection.getOverlays(); + for (i = 0, numOfOverlays = overlays.length; i < numOfOverlays; i++) { + if (overlays[i] instanceof jsPlumb.Overlays.Custom) { + $(overlays[i].getElement()) + .find(".fixed") + .not(".segmented") + .each(makeRotateOverlayCallback(angle)); + //Always flip type overlay + $(overlays[i].getElement()) + .find(".fixed.type") + .not(".segmented") + .each( + makeRotateOverlayCallback( + Math.abs(angle - Math.PI) > Math.PI / 2 + ? angle + : angle + Math.PI + ) + ); + } + } + } else throw new Error("jsPlumbConnection is null"); + }; + + /** + * Sets position of edge on z-axis as max of the z-indices of source and target + */ + this.setZIndex = function () { + var $e = getAllAssociatedDOMNodes(), + zIndex = Math.max(source.getZIndex(), target.getZIndex()); + $e.css("zIndex", zIndex); + }; + + /** + * Connect source and target node and draw the edge on canvas + */ + this.connect = function () { + source.addOutgoingEdge(this); + target.addIngoingEdge(this); + //noinspection JSAccessibilityCheck + _jsPlumbConnection = window.jsPlumbInstance.connect({ + source: _appearance.source.get$node().get(0), + target: _appearance.target.get$node().get(0), + paintStyle: { stroke: "black", outlineWidth: 4 }, + endpoint: "Dot", + connector: { type: FlowchartConnector.type }, + anchors: [source.getAnchorOptions(), target.getAnchorOptions()], + overlays: [ + { + type: "Custom", + options: { + create: function () { + return _$overlay.get(0); + }, + location: 0.5, + id: "label", + }, + }, + ], + cssClass: id, + }); + this.repaintOverlays(); + lodash.each(EntityManagerInstance.getEdges(), function (e) { + e.setZIndex(); + }); + }; + + /** + * Lowlight the edge + */ + this.lowlight = function () { + $("." + id).addClass("lowlighted"); + }; + + /** + * Unlowlight the edge + */ + this.unlowlight = function () { + $("." + id).removeClass("lowlighted"); + }; + + /** + * Select the edge + */ + this.select = function () { + var paintStyle = lodash.clone(_defaultPaintStyle), + overlays, + i, + numOfOverlays; + + function makeBold() { + $(this).css("fontWeight", "bold"); + } + this.unhighlight(); + if (_jsPlumbConnection) { + paintStyle.lineWidth = 4; + _jsPlumbConnection.setPaintStyle(paintStyle); + overlays = _jsPlumbConnection.getOverlays(); + for (i = 0, numOfOverlays = overlays.length; i < numOfOverlays; i++) { + if (overlays[i] instanceof jsPlumb.Overlays.Custom) { + $(overlays[i].getElement()).find(".fixed").each(makeBold); + } + } + } else throw new Error("jsPlumbConnection is null"); + }; + + /** + * Unselect the edge + */ + this.unselect = function () { + var overlays, i, numOfOverlays; + + function unmakeBold() { + $(this).css("fontWeight", ""); + } + this.highlight(_highlightColor); + if (_jsPlumbConnection) { + _jsPlumbConnection.setPaintStyle(_defaultPaintStyle); + overlays = _jsPlumbConnection.getOverlays(); + for (i = 0, numOfOverlays = overlays.length; i < numOfOverlays; i++) { + if (overlays[i] instanceof jsPlumb.Overlays.Custom) { + $(overlays[i].getElement()).find(".fixed").each(unmakeBold); + } + } + } + }; + + /** + * Highlight the edge + * @param {String} color + */ + this.highlight = function (color) { + var paintStyle = lodash.clone(_defaultPaintStyle); + + if (color) { + paintStyle.strokeStyle = color; + paintStyle.lineWidth = 4; + if (_jsPlumbConnection) _jsPlumbConnection.setPaintStyle(paintStyle); + else throw new Error("jsPlumbConnection is null"); + } + }; + + /** + * Unhighlight the edge + */ + this.unhighlight = function () { + if (_jsPlumbConnection) { + _jsPlumbConnection.setPaintStyle(_defaultPaintStyle); + } else throw new Error("jsPlumbConnection is null"); + }; + + /** + * Remove the edge + */ + this.remove = function () { + source.deleteOutgoingEdge(this); + target.deleteIngoingEdge(this); + this.removeFromCanvas(); + //this.unregisterCallbacks(); + EntityManagerInstance.deleteEdge(this.getEntityId()); + if (_ymap) { + _ymap = null; + } + }; + + /** + * Get JSON representation of the edge + * @returns {Object} + * @private + */ + this._toJSON = function () { + var attr = {}; + lodash.forEach(this.getAttributes(), function (val, key) { + attr[key] = val.toJSON(); + }); + return { + label: _label.toJSON(), + source: source.getEntityId(), + target: target.getEntityId(), + attributes: attr, + type: _type, + }; + }; + + /** + * Bind events for move tool + */ + this.bindMoveToolEvents = function () { + if (_jsPlumbConnection) { + //Enable Edge Select + $("." + id).on("click", function () { + _canvas.select(that); + }); + + $(_jsPlumbConnection.getOverlay("label").canvas) + .find("input") + .prop("disabled", false) + .css("pointerEvents", ""); + + /*$(_jsPlumbConnection.getOverlay("label").canvas).find("input[type=text]").autoGrowInput({ + comfortZone: 10, + minWidth: 40, + maxWidth: 100 + }).trigger("blur");*/ + } else throw new Error("jsPlumbConnection is null"); + + if (id) { + // view_only is used by the CAE and allows to show a model in the Canvas which is not editable + // therefore, the context menu of every edge must be disabled + const widgetConfigMap = y.getMap("widgetConfig"); + var viewOnly = widgetConfigMap.get("view_only"); + if (viewOnly) return; + } + + //Define Edge Rightclick Menu + $.contextMenu({ + selector: "." + id, + zIndex: AbstractEntity.CONTEXT_MENU_Z_INDEX, + build: function () { + var menuItems = lodash.extend(_contextMenuItemCallback(), { + delete: { + name: "Delete", + callback: function (/*key, opt*/) { + that.triggerDeletion(); + }, + }, + }); + + return { + items: menuItems, + events: { + show: function (/*opt*/) { + _canvas.select(that); + }, + }, + }; + }, + }); + + //$("."+id).contextMenu(true); + }; + + /** + * Unbind events for move tool + */ + this.unbindMoveToolEvents = function () { + if (_jsPlumbConnection) { + //Disable Edge Select + _jsPlumbConnection.unbind("click"); + + $(_jsPlumbConnection.getOverlay("label").canvas) + .find("input") + .prop("disabled", true) + .css("pointerEvents", "none"); + } else throw new Error("jsPlumbConnection is null"); + + //$("."+id).contextMenu(false); + }; + + this._registerYMap = function () { + that.getLabel().getValue().registerYType(); + }; + } + /** + * Get JSON representation of the edge + * @returns {{label: Object, source: string, target: string, attributes: Object, type: string}} + */ + toJSON() { + return this._toJSON(); + } + /** + * Hide a jsPlumb connection + */ + hide() { + var connector = this.getJsPlumbConnection(); + connector.setVisible(false); + } + /** + * Show a jsPlumb connection + */ + show() { + var connector = this.getJsPlumbConnection(); + connector.setVisible(true); + } + registerYMap() { + this._registerYMap(); + } +} + +/** + * AbstractNode + * @class canvas_widget.AbstractNode + * @extends canvas_widget.AbstractEntity + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of node + * @param {string} type Type of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {boolean} containment containment + * @param {number} zIndex Position of node on z-axis + */ +class AbstractNode extends AbstractEntity { + nodeSelector; + _$node; + constructor( + id, + type, + left, + top, + width, + height, + zIndex, + containment, + json, + y + ) { + super(id); + var that = this; + y = y || window.y; + if (!y) { + throw new Error("y is undefined"); + } + + /** + * Inter widget communication wrapper + * @type {Object} + * @private + */ + var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); + /**y-map instances which belongs to the node + * @type {YMap} + * @private + * */ + var _ymap = null; + y = y || window.y; + if (!y) { + throw new Error("y is undefined"); + } + const nodesMap = y.getMap("nodes"); + + if (nodesMap.has(id)) { + _ymap = nodesMap.get(id); + } else { + window.y.transact(() => { + _ymap = new Map$2(); + nodesMap.set(id, _ymap); + _ymap.set("modifiedBy", window.y.clientID); + _ymap.set("left", left); + _ymap.set("top", top); + _ymap.set("width", width); + _ymap.set("height", height); + _ymap.set("zIndex", zIndex); + _ymap.set("containment", containment); + _ymap.set("type", type); + _ymap.set("id", id); + if (json) _ymap.set("json", json); + if (_iwcw.getUser().globalId !== -1) + _ymap.set("jabberId", _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]); + }); + } + + this.getYMap = function () { + return _ymap; + }; + + /** + * Type of node + * @type {string} + * @private + */ + var _type = type; + + /** + * Label of edge + * @type {canvas_widget.SingleValueAttribute} + * @private + */ + var _label = new SingleValueAttribute(id + "[label]", "Label", this, y); + + /** + * Appearance information of edge + * @type {{left: number, top: number, width: number, height: number}} + * @private + */ + var _appearance = { + left: left, + top: top, + width: width, + height: height, + containment: containment, + }; + + /** + * Position of node on z-axis + * @type {number} + * @private + */ + var _zIndex = zIndex; + + /** + * Type of node + * @containment {boolean} + * @private + */ + var _containment = containment; + + /** + * Canvas the node is drawn on + * @type {canvas_widget.AbstractCanvas} + * @private + */ + var _canvas = null; + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(abstractNodeHtml)({ id: id })); + this._$node = _$node; + const resizeHandle = $( + `
                                  ` + ); + resizeHandle.css({ + position: "absolute", + bottom: "-15px", + right: "-15px", + cursor: "nwse-resize", + zIndex: 100000, + }); + + // append to node + _$node.append(resizeHandle); + resizeHandle.on("mouseover", () => { + this.disableDraggable(); + }); + resizeHandle.on("mouseout", () => { + this.enableDraggable(); + }); + + this.nodeSelector = getQuerySelectorFromNode(this._$node[0]); + + // this is the node's awareness trace. + // If I understand correctly, it is showing the activity of other users on the node. + var _$awarenessTrace = $( + lodash.template(awarenessTraceHtml)({ id: id + "_awareness" }) + ); + + var _awarenessTimer = setInterval(function () { + var opacity = _$awarenessTrace.css("opacity"); + opacity -= 0.1; + if (opacity < 0) opacity = 0; + _$awarenessTrace.css({ + opacity: opacity, + }); + }, 3000); + + this._$node.on("mousedown", function () { + _canvas.select(that); + _canvas.unbindMoveToolEvents(); + }); + + this._$node.on("mouseup", function () { + _canvas.bindMoveToolEvents(); + }); + + /** + * Attributes of node + * @type {Object} + * @private + */ + var _attributes = {}; + + /** + * Callback to generate list of context menu items + * @type {function} + */ + var _contextMenuItemCallback = function () { + return {}; + }; + + /** + * Set of ingoing edges + * @type {Object} + * @private + */ + var _ingoingEdges = {}; + + /** + * Set of outgoing edges + * @type {Object} + * @private + */ + var _outgoingEdges = {}; + + /** + * Set of nodes with an edge to the node + * @type {Object} + * @private + */ + var _ingoingNeighbors = {}; + + /** + * Set of nodes with an edge from the node + * @type {Object} + * @private + */ + var _outgoingNeighbors = {}; + + var _relatedGhostEdges = []; + + /** + * Apply a Node Move Operation + * @param {operations.ot.NodeMoveOperation} operation + */ + var processNodeMoveOperation = function (operation) { + _canvas.hideGuidanceBox(); + that.move(operation.getOffsetX(), operation.getOffsetY(), 0); + _canvas.showGuidanceBox(); + }; + + /** + * Apply a Node Move Z Operation + * @param {operations.ot.NodeMoveZOperation} operation + */ + var processNodeMoveZOperation = function (operation) { + that.move(0, 0, operation.getOffsetZ()); + }; + + /** + * Propagate a Node Move Operation to the remote users and the local widgets + * @param {operations.ot.NodeMoveOperation} operation + */ + this.propagateNodeMoveOperation = function (operation) { + operation.setJabberId(_iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]); + processNodeMoveOperation(operation); + HistoryManagerInstance.add(operation); + EntityManagerInstance.storeDataYjs(); + + hideTraceAwareness(); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.ATTRIBUTE, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.HEATMAP, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.getOTOperation() + ); + const activityMap = y.getMap("activity"); + activityMap.set( + ActivityOperation.TYPE, + new ActivityOperation( + "NodeMoveActivity", + operation.getEntityId(), + operation.getJabberId(), + NodeMoveOperation.getOperationDescription( + that.getType(), + that.getLabel().getValue().getValue() + ), + { nodeType: that.getType() } + ).toJSON() + ); + + if (_ymap) { + _ymap.set(NodeMoveOperation.TYPE, operation.toJSON()); + } + }; + + /** + * Propagate a Node Move Z Operation to the remote users and the local widgets + * @param {operations.ot.NodeMoveZOperation} operation + */ + this.propagateNodeMoveZOperation = function (operation) { + var jabberId = _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]; + operation.setJabberId(jabberId); + processNodeMoveZOperation(operation); + HistoryManagerInstance.add(operation); + hideTraceAwareness(); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.ATTRIBUTE, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.getOTOperation() + ); + const activityMap = y.getMap("activity"); + activityMap.set( + ActivityOperation.TYPE, + new ActivityOperation( + "NodeMoveActivity", + operation.getEntityId(), + jabberId, + NodeMoveOperation.getOperationDescription( + that.getType(), + that.getLabel().getValue().getValue() + ), + { nodeType: that.getType() } + ).toJSON() + ); + + if (_ymap) _ymap.set(NodeMoveZOperation.TYPE, operation.toJSON()); + }; + + /** + * Apply a Node Resize Operation + * @param {operations.ot.NodeResizeOperation} operation + */ + var processNodeResizeOperation = function (operation) { + _canvas.hideGuidanceBox(); + that.resize(operation.getOffsetX(), operation.getOffsetY()); + _canvas.showGuidanceBox(); + }; + + /** + * Propagate a Node Resize Operation to the remote users and the local widgets + * @param {operations.ot.NodeResizeOperation} operation + */ + this.propagateNodeResizeOperation = function (operation) { + operation.setJabberId(_iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]); + processNodeResizeOperation(operation); + HistoryManagerInstance.add(operation); + EntityManagerInstance.storeDataYjs(); + hideTraceAwareness(); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.ATTRIBUTE, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.HEATMAP, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.getOTOperation() + ); + const activityMap = y.getMap("activity"); + activityMap.set( + ActivityOperation.TYPE, + new ActivityOperation( + "NodeResizeActivity", + operation.getEntityId(), + operation.getJabberId(), + NodeResizeOperation.getOperationDescription( + that.getType(), + that.getLabel().getValue().getValue() + ), + { nodeType: that.getType() } + ).toJSON() + ); + + if (_ymap) _ymap.set("NodeResizeOperation", operation.toJSON()); + }; + + /** + * Apply a Node Delete Operation + * @param {operations.ot.NodeDeleteOperation} operation + */ + var processNodeDeleteOperation = function () { + var edges = that.getEdges(), + edgeId, + edge; + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + edge.remove(); + } + } + + for (var i = 0; i < _relatedGhostEdges.length; i++) { + if (typeof _relatedGhostEdges[i].remove == "function") + _relatedGhostEdges[i].remove(); + } + if (_ymap) { + _ymap = null; + } + that.remove(); + }; + + /** + * Propagate a Node Delete Operation to the remote users and the local widgets + * @param {operations.ot.NodeDeleteOperation} operation + */ + var propagateNodeDeleteOperation = function (operation) { + processNodeDeleteOperation(); + EntityManagerInstance.storeDataYjs(); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.ATTRIBUTE, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.HEATMAP, + operation.getOTOperation() + ); + const activityMap = y.getMap("activity"); + activityMap.set( + ActivityOperation.TYPE, + new ActivityOperation( + "NodeDeleteActivity", + operation.getEntityId(), + _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], + NodeDeleteOperation.getOperationDescription( + that.getType(), + that.getLabel().getValue().getValue() + ), + {} + ).toJSON() + ); + }; + + var refreshTraceAwareness = function (color) { + _$awarenessTrace.css({ + opacity: 1, + fill: color, + }); + }; + + var hideTraceAwareness = function () { + _$awarenessTrace.css({ + opacity: 0, + }); + }; + + /** + * Callback for a remote Node Move Operation + * @param {operations.ot.NodeMoveOperation} operation + */ + var remoteNodeMoveCallback = function (operation) { + if ( + operation instanceof NodeMoveOperation && + operation.getEntityId() === that.getEntityId() + ) { + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.ATTRIBUTE, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.HEATMAP, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.getOTOperation() + ); + const userMap = y.getMap("users"); + if (userMap.get(y.clientID) !== operation.getJabberId()) { + const userList = y.getMap("userList"); + var color = Util.getColor( + userList.get(operation.getJabberId()).globalId + ); + refreshTraceAwareness(color); + } + + processNodeMoveOperation(operation); + } + }; + + /** + * Callback for a remote Node Move Z Operation + * @param {operations.ot.NodeMoveZOperation} operation + */ + var remoteNodeMoveZCallback = function (operation) { + if ( + operation instanceof NodeMoveZOperation && + operation.getEntityId() === that.getEntityId() + ) { + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.ATTRIBUTE, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.getOTOperation() + ); + const userMap = y.getMap("users"); + if (userMap.get(y.clientID) !== operation.getJabberId()) { + const userList = y.getMap("userList"); + var color = Util.getColor( + userList.get(operation.getJabberId()).globalId + ); + refreshTraceAwareness(color); + } + processNodeMoveZOperation(operation); + } + }; + + /** + * Callback for a remote Node Resize Operation + * @param {operations.ot.NodeResizeOperation} operation + */ + var remoteNodeResizeCallback = function (operation) { + if ( + operation instanceof NodeResizeOperation && + operation.getEntityId() === that.getEntityId() + ) { + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.ATTRIBUTE, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.HEATMAP, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.getOTOperation() + ); + const userMap = y.getMap("users"); + if (userMap.get(y.clientID) !== operation.getJabberId()) { + const userList = y.getMap("userList"); + var color = Util.getColor( + userList.get(operation.getJabberId()).globalId + ); + refreshTraceAwareness(color); + } + processNodeResizeOperation(operation); + } + }; + + /** + * Callback for a remote Node Delete Operation + * @param {operations.ot.NodeDeleteOperation} operation + */ + this.remoteNodeDeleteCallback = function (operation) { + if ( + operation instanceof NodeDeleteOperation && + operation.getEntityId() === that.getEntityId() + ) { + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.ATTRIBUTE, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.getOTOperation() + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.HEATMAP, + operation.getOTOperation() + ); + processNodeDeleteOperation(); + HistoryManagerInstance.clean(operation.getEntityId()); + } + }; + + this.init = function () { + //Define Node Rightclick Menu + $.contextMenu({ + selector: "#" + id, + zIndex: AbstractEntity.CONTEXT_MENU_Z_INDEX, + build: function ($trigger, e) { + var menuItems; + var EntityManager = EntityManagerInstance; + + $(e.target).offset(); + that.getCanvas().get$node().offset(); + + if ( + _canvas.getSelectedEntity() === null || + _canvas.getSelectedEntity() === that + ) { + menuItems = lodash.extend(_contextMenuItemCallback(), { + connectTo: EntityManager.generateConnectToMenu(that), + sepMove: "---------", + moveToForeground: { + name: "Move to Foreground", + callback: function (/*key, opt*/) { + that.propagateNodeMoveZOperation( + new NodeMoveZOperation( + that.getEntityId(), + ++AbstractEntity.maxZIndex - _zIndex + ) + ); + }, + }, + moveToBackground: { + name: "Move to Background", + callback: function (/*key, opt*/) { + that.propagateNodeMoveZOperation( + new NodeMoveZOperation( + that.getEntityId(), + --AbstractEntity.minZIndex - _zIndex + ) + ); + }, + }, + sepDelete: "---------", + delete: { + name: "Delete", + callback: function (/*key, opt*/) { + that.triggerDeletion(); + }, + }, + quit: { + name: " ", + disabled: true, + }, + }); + + return { + items: menuItems, + events: { + show: function (/*opt*/) { + _canvas.select(that); + }, + }, + }; + } else { + _canvas.select(null); + return false; + } + }, + }); + }; + + /** + * Triggers jsPlumb's repaint function and adjusts the angle of the edge labels + */ + + /** + * Anchor options for new connections + * @type {object} + */ + var _anchorOptions = AnchorLocations.AutoDefault; + + /** + * Get options for new connections + * @returns {Object} + */ + this.getAnchorOptions = function () { + return _anchorOptions; + }; + + /** + * Send NodeDeleteOperation for node + */ + this.triggerDeletion = function (historyFlag) { + var edgeId, + edges = this.getEdges(), + edge; + _canvas.select(null); + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + edge.triggerDeletion(); + } + } + var operation = new NodeDeleteOperation( + id, + that.getType(), + _appearance.left, + _appearance.top, + _appearance.width, + _appearance.height, + _zIndex, + _appearance.containment, + that.toJSON() + ); + if (_ymap) { + propagateNodeDeleteOperation(operation); + const nodesMap = y.getMap("nodes"); + nodesMap.delete(that.getEntityId()); + } else { + propagateNodeDeleteOperation(operation); + } + if (!historyFlag) HistoryManagerInstance.add(operation); + }; + + //noinspection JSUnusedGlobalSymbols + /** + * Get callback to generate list of context menu items + * @returns {object} + */ + this.getContextMenuItemCallback = function () { + return _contextMenuItemCallback; + }; + + /** + * Set callback to generate list of context menu items + * @param {function} contextMenuItemCallback + */ + this.setContextMenuItemCallback = function (contextMenuItemCallback) { + if (typeof contextMenuItemCallback === "function") { + _contextMenuItemCallback = contextMenuItemCallback; + } + }; + + /** + * Get node appearance + * @returns {{left: number, top: number, width: number, height: number}} + */ + this.getAppearance = function () { + return _appearance; + }; + + /** + * Get position of node on z-axis + * @return {number} + */ + this.getZIndex = function () { + return _zIndex; + }; + + this.refreshTraceAwareness = function (color) { + refreshTraceAwareness(color); + }; + + /** + * Adds node to canvas + * @param {canvas_widget.AbstractCanvas} canvas + */ + this.addToCanvas = function (canvas) { + if (!canvas) throw new Error("Canvas is null"); + _canvas = canvas; + canvas.get$canvas().append(_$awarenessTrace); + canvas.get$canvas().append(this._$node); + }; + + /** + * Get associated canvas + * @returns {canvas_widget.AbstractCanvas} + */ + this.getCanvas = function () { + return _canvas; + }; + + /** + * Removes node from canvas + */ + this.removeFromCanvas = function () { + this._$node.remove(); + //destroy the context menu + $.contextMenu("destroy", "#" + that.getEntityId()); + _canvas = null; + _$awarenessTrace.remove(); + if (this.hasOwnProperty("unregisterCallbacks")) + this.unregisterCallbacks(); + }; + + /** + * Add attribute to node + * @param {canvas_widget.AbstractAttribute} attribute + */ + this.addAttribute = function (attribute) { + var id = attribute.getEntityId(); + if (!_attributes.hasOwnProperty(id)) { + _attributes[id] = attribute; + } + }; + + /** + * Get attribute by id + * @param {String} id Attribute's entity id + * @returns {canvas_widget.AbstractAttribute} + */ + this.getAttribute = function (id) { + if (_attributes.hasOwnProperty(id)) { + return _attributes[id]; + } + return null; + }; + + /** + * Delete attribute by id + * @param {String} id Attribute's entity id + */ + this.deleteAttribute = function (id) { + if (_attributes.hasOwnProperty(id)) { + delete _attributes[id]; + } + }; + + /** + * Set node's attributes + * @param {Object} attributes + */ + this.setAttributes = function (attributes) { + _attributes = attributes; + }; + + /** + * Get node's attributes + * @returns {Object} + */ + this.getAttributes = function () { + return _attributes; + }; + + /** + * Set edge label + * @param {canvas_widget.SingleValueAttribute} label + */ + this.setLabel = function (label) { + _label = label; + }; + + /** + * Get edge label + * @returns {canvas_widget.SingleValueAttribute} + */ + this.getLabel = function () { + return _label; + }; + + /** + * Get edge type + * @returns {string} + */ + this.getType = function () { + return _type; + }; + + /** + * Get edge type + * @returns {boolean} + */ + this.getContainment = function () { + return _containment; + }; + + /** + * Get jQuery object of DOM node representing the node + * @returns {jQuery} + * @private + */ + this._get$node = function () { + return this._$node; + }; + + /** + * Apply position and dimension attributes to the node + * @private + */ + this._draw = function () { + //noinspection JSAccessibilityCheck + _$awarenessTrace.css({ + left: _appearance.left + _appearance.width / 2, + top: _appearance.top + _appearance.height / 2, + width: _appearance.width * 1.2, + height: _appearance.height * 1.2, + zIndex: _zIndex - 1, + }); + this._$node.css({ + left: _appearance.left, + top: _appearance.top, + width: _appearance.width, + height: _appearance.height, + zIndex: _zIndex, + }); + }; + + /** + * Move the node + * @param {number} offsetX Offset in x-direction + * @param {number} offsetY Offset in y-direction + * @param {number} offsetZ Offset in z-direction + */ + this.move = function (offsetX, offsetY) { + const x = _appearance.left + offsetX; + const y = _appearance.top + offsetY; + if ( + x < 0 || + y < 0 || + x > _canvas.width - _appearance.width || + y > _canvas.height - _appearance.height + ) { + // reset the position + _$node.css({ + left: _appearance.left, + top: _appearance.top, + }); + console.error("Node cannot be moved outside of canvas"); + if (_ymap) { + window.y.transact(() => { + _ymap.set("left", _appearance.left); + _ymap.set("top", _appearance.top); + _ymap.set("zIndex", _zIndex); + }); + } + } else { + if (_ymap) { + window.y.transact(() => { + _ymap.set("left", (_appearance.left += offsetX)); + _ymap.set("top", (_appearance.top += offsetY)); + _ymap.set("zIndex", _zIndex); + }); + } + } + this._draw(); + this.repaint(); + }; + + this.moveAbs = function (left, top, zIndex) { + if (left < 0 || top < 0) { + console.error("Node cannot be moved outside of canvas"); + } + if ( + left > _canvas.width - _appearance.width || + top > _canvas.height - _appearance.height + ) { + console.error("Node cannot be moved outside of canvas"); + } + _appearance.left = left; + _appearance.top = top; + + if (zIndex) _zIndex = zIndex; + + if (_ymap) { + y.transact(() => { + _ymap.set("left", _appearance.left); + _ymap.set("top", _appearance.top); + if (zIndex) _ymap.set("zIndex", _zIndex); + }); + } + this._draw(); + this.repaint(); + }; + + /** + * Resize the node + * @param {number} offsetX Offset in x-direction + * @param {number} offsetY Offset in y-direction + */ + this.resize = function (offsetX, offsetY) { + _appearance.width += offsetX; + _appearance.height += offsetY; + if (_ymap) { + y.transact(() => { + _ymap.set("width", _appearance.width); + _ymap.set("height", _appearance.height); + }); + } + this._draw(); + this.repaint(); + }; + + /** + * Add ingoing edge + * @param {canvas_widget.AbstractEdge} edge + */ + this.addIngoingEdge = function (edge) { + var id = edge.getEntityId(); + var source = edge.getSource(); + var sourceEntityId = source.getEntityId(); + if (!_ingoingEdges.hasOwnProperty(id)) { + _ingoingEdges[id] = edge; + if (!_ingoingNeighbors.hasOwnProperty(sourceEntityId)) { + _ingoingNeighbors[sourceEntityId] = source; + } + } + }; + + /** + * Add outgoing edge + * @param {canvas_widget.AbstractEdge} edge + */ + this.addOutgoingEdge = function (edge) { + var id = edge.getEntityId(); + var target = edge.getTarget(); + var targetEntityId = target?.getEntityId(); + if (!_outgoingEdges.hasOwnProperty(id)) { + _outgoingEdges[id] = edge; + if (!_outgoingNeighbors.hasOwnProperty(targetEntityId)) { + _outgoingNeighbors[targetEntityId] = target; + } + } + }; + + /** + * Delete ingoing edge + * @param {canvas_widget.AbstractEdge} edge + */ + this.deleteIngoingEdge = function (edge) { + var id = edge.getEntityId(); + var source = edge.getSource(); + var sourceEntityId = source.getEntityId(); + var isMultiEdge = false; + if (_ingoingEdges.hasOwnProperty(id)) { + delete _ingoingEdges[id]; + for (var edgeId in _ingoingEdges) { + if ( + _ingoingEdges.hasOwnProperty(edgeId) && + _ingoingEdges[edgeId].getSource().getEntityId() === sourceEntityId + ) { + isMultiEdge = true; + } + } + if (!isMultiEdge) { + delete _ingoingNeighbors[sourceEntityId]; + } + } + }; + + /** + * Delete outgoing edge + * @param {canvas_widget.AbstractEdge} edge + */ + this.deleteOutgoingEdge = function (edge) { + var id = edge.getEntityId(); + var target = edge.getTarget(); + var targetEntityId = target?.getEntityId(); + var isMultiEdge = false; + if (_outgoingEdges.hasOwnProperty(id)) { + delete _outgoingEdges[id]; + for (var edgeId in _outgoingEdges) { + if ( + _outgoingEdges.hasOwnProperty(edgeId) && + _outgoingEdges[edgeId].getTarget().getEntityId() === targetEntityId + ) { + isMultiEdge = true; + } + } + if (!isMultiEdge) { + delete _outgoingNeighbors[targetEntityId]; + } + } + }; + + //noinspection JSUnusedGlobalSymbols + /** + * Get ingoing edges + * @returns {Object} + */ + this.getIngoingEdges = function () { + return _ingoingEdges; + }; + + /** + * Get outgoing edges + * @returns {Object} + */ + this.getOutgoingEdges = function () { + return _outgoingEdges; + }; + + /** + * Get all ingoing and outgoing edges + * @returns {Array} + */ + this.getEdges = function () { + return Util.union(_ingoingEdges, _outgoingEdges); + }; + + //noinspection JSUnusedGlobalSymbols + /** + * Get neighbors with an edge to the node + * @returns {Object} + */ + this.getIngoingNeighbors = function () { + return _ingoingNeighbors; + }; + + //noinspection JSUnusedGlobalSymbols + /** + * Get neighbors with an edge from the node + * @returns {Object} + */ + this.getOutgoingNeighbors = function () { + return _outgoingNeighbors; + }; + + //noinspection JSUnusedGlobalSymbols + /** + * Get neighbors with an edge to or from the node + * @returns {Object} + */ + this.getNeighbors = function () { + return Util.union(_ingoingNeighbors, _outgoingNeighbors); + }; + + /** + * Lowlight the node + */ + this.lowlight = function () { + this._$node.addClass("lowlighted"); + }; + + /** + * Unlowlight the node + */ + this.unlowlight = function () { + this._$node.removeClass("lowlighted"); + }; + + /** + * Select the node + */ + this.select = function () { + this.unhighlight(); + this._$node.addClass("selected"); + Util.delay(100).then(function () { + lodash.each(EntityManagerInstance.getEdges(), function (e) { + e.setZIndex(); + }); + }); + }; + + /** + * Unselect the node + */ + this.unselect = function () { + //this.highlight(_highlightColor,_highlightUsername); + this._$node.removeClass("selected"); + //trigger save when unselecting an entity + Util.delay(100).then(function () { + lodash.each(EntityManagerInstance.getEdges(), function (e) { + e.setZIndex(); + }); + }); + }; + + /** + * Highlight the node by assigning it the passed color and label it with the passed username + * @param {String} color + * @param {String} username + */ + this.highlight = function (color, username) { + if (color && username) { + this._$node.css({ border: "2px solid " + color }); + this._$node.append( + $("
                                  ") + .addClass("user_highlight") + .css("color", color) + .text(username) + ); + Util.delay(100).then(function () { + lodash.each(EntityManagerInstance.getEdges(), function (e) { + e.setZIndex(); + }); + }); + } + }; + + /** + * Unhighlight the node + */ + this.unhighlight = function () { + this._$node.css({ border: "" }); + this._$node.find(".user_highlight").remove(); + Util.delay(100).then(function () { + lodash.each(EntityManagerInstance.getEdges(), function (e) { + e.setZIndex(); + }); + }); + }; + + /** + * Remove the node + */ + this.remove = function () { + clearInterval(_awarenessTimer); + this.removeFromCanvas(); + jsPlumbInstance.removeAllEndpoints(_$node.get(0)); + jsPlumbInstance.unmanage(_$node.get(0)); + EntityManagerInstance.deleteNode(this.getEntityId()); + }; + + /** + * Get JSON representation of the node + * @returns {Object} + * @private + */ + this._toJSON = function () { + var attr = {}; + lodash.forEach(this.getAttributes(), function (val, key) { + attr[key] = val.toJSON(); + }); + //noinspection JSAccessibilityCheck + return { + label: _label.toJSON(), + left: _appearance.left, + top: _appearance.top, + width: _appearance.width, + height: _appearance.height, + zIndex: _zIndex, + type: _type, + attributes: attr, + }; + }; + + this.addGhostEdge = function (ghostEdge) { + _relatedGhostEdges.push(ghostEdge); + }; + + /** + * Bind events for move tool + */ + this.bindMoveToolEvents = () => { + this.enableDraggable(); + var originalPos = { + left: 0, + top: 0, + }; + + var $sizePreview = $('
                                  ').hide(); + + this.makeResizable(that, _canvas, $sizePreview, id); + + this._$node + //Enable Node Rightclick menu + .contextMenu(true) + .find("input") + .prop("disabled", false) + .css("pointerEvents", ""); + + this.jsPlumbManagedElement = jsPlumbInstance.manage(this._$node.get(0)); + + jsPlumbInstance.bind(EVENT_DRAG_START, (params) => { + if (params.el.id !== this._$node.attr("id")) return true; + + originalPos.top = params.el.offsetTop; + originalPos.left = params.el.offsetLeft; + + _canvas.hideGuidanceBox(); + _$node.css({ opacity: 0.5 }); + + return true; + }); + + jsPlumbInstance.bind(EVENT_DRAG_STOP, (params) => { + if (params.el.id !== this._$node.attr("id")) return true; + + _$node.css({ opacity: "" }); + _canvas.bindMoveToolEvents(); + var offsetX = Math.round(params.el.offsetLeft - originalPos.left); + var offsetY = Math.round(params.el.offsetTop - originalPos.top); + // if offset is 0, no need to send the operation + if (offsetX === 0 && offsetY === 0) return; + // if offset bigger than canvas size, no need to send the operation + if ( + params.el.offsetLeft < 0 || + params.el.offsetTop < 0 || + params.el.offsetLeft > _canvas.width || + params.el.offsetTop > _canvas.height + ) { + console.error(" offset bigger than canvas size"); + return; + } + + var operation = new NodeMoveOperation( + that.getEntityId(), + offsetX, + offsetY + ); + that.propagateNodeMoveOperation(operation); + + //Avoid node selection on drag stop + _canvas.showGuidanceBox(); + }); + + // view_only is used by the CAE and allows to show a model in the Canvas which is not editable + // therefore, the nodes should not be draggable and their context menu should be disabled + const widgetConfigMap = y.getMap("widgetConfig"); + var viewOnly = widgetConfigMap.get("view_only"); + if (viewOnly) { + this.disableDraggable(); + _$node.on("click").contextMenu(false); + } + }; + + /** + * Unbind events for move tool + */ + this.unbindMoveToolEvents = () => { + //Disable Node Selection + // called for e.g. if we want to draw an edge + this._$node + .off("click") + .contextMenu(false) + .find("input") + .prop("disabled", true) + .css("pointerEvents", "none"); + + //Disable Node Dragging + this.disableDraggable(); + }; + + /** + * Bind source node events for edge tool + */ + this.makeSource = () => { + _$node.addClass("source"); + this.endPoint = window.jsPlumbInstance.addEndpoint(this._$node.get(0), { + connectorPaintStyle: { fill: "black", strokeWidth: 4 }, + source: true, + endpoint: { + type: "Rectangle", + options: { + width: _$node.width() + 50, + height: _$node.height() + 50, + }, + }, + paintStyle: { fill: "transparent" }, + anchor: AnchorLocations.Center, + deleteOnEmpty: true, + //maxConnections:1, + uniqueEndpoint: false, + deleteEndpointsOnDetach: true, + onMaxConnections: function (info /*, originalEvent*/) { + console.log( + "element is ", + info.element, + "maxConnections is", + info.maxConnections + ); + }, + }); + }; + + /** + * Bind target node events for edge tool + */ + this.makeTarget = () => { + _$node.addClass("target"); + this.endPoint = window.jsPlumbInstance.addEndpoint(this._$node.get(0), { + target: true, + endpoint: { + type: "Rectangle", + options: { + width: _$node.width() + 50, + height: _$node.height() + 50, + }, + }, + paintStyle: { fill: "transparent" }, + anchor: AnchorLocations.Center, + uniqueEndpoint: false, + //maxConnections:1, + deleteOnEmpty: true, + onMaxConnections: function (info /*, originalEvent*/) { + console.log( + "user tried to drop connection", + info.connection, + "on element", + info.element, + "with max connections", + info.maxConnections + ); + }, + }); + }; + + /** + * Unbind events for edge tool + */ + this.unbindEdgeToolEvents = function () { + try { + _$node.removeClass("source target"); + jsPlumbInstance.getEndpoints(_$node.get(0)).forEach((endpoint) => { + // We need to remove the endpoint that was created to enable node connection by dragging + // since we are not using the edge tool anymore + if (endpoint.connections.length === 0) { + jsPlumbInstance.deleteEndpoint(endpoint); + } + }); + } catch (error) { + console.error(error); + } + }; + + that.init(); + + this._registerYMap = function () { + _ymap.observe(function (event) { + const array = Array.from(event.changes.keys.entries()); + array.forEach(([key]) => { + if (event.value && event.value.historyFlag) { + var operation; + var data = event.value; + const userMap = y.getMap("users"); + var jabberId = userMap.get(yUserId); + switch (key) { + case NodeMoveOperation.TYPE: { + operation = new NodeMoveOperation( + data.id, + data.offsetX, + data.offsetY, + jabberId + ); + remoteNodeMoveCallback(operation); + break; + } + case NodeMoveZOperation.TYPE: { + operation = new NodeMoveZOperation( + data.id, + data.offsetZ, + jabberId + ); + remoteNodeMoveZCallback(operation); + break; + } + case NodeResizeOperation.TYPE: { + operation = new NodeResizeOperation( + data.id, + data.offsetX, + data.offsetY, + jabberId + ); + remoteNodeResizeCallback(operation); + break; + } + } + } + }); + }); + }; + + jsPlumbInstance.manage(this._$node.get(0)); + // EntityManagerInstance.storeDataYjs(); + } + nodeSelector; + jsPlumbManagedElement; + endPoint; + + repaint() { + window.jsPlumbInstance.repaint(this._$node.get(0)); + + lodash.each(EntityManagerInstance.getEdges(), function (e) { + e.setZIndex(); + }); + } + + enableDraggable() { + jsPlumbInstance.setDraggable(this._$node.get(0), true); + } + + disableDraggable() { + jsPlumbInstance.setDraggable(this._$node.get(0), false); + } + + makeResizable(that, _canvas, $sizePreview, id) { + const initialSize = { + width: that._$node.width(), + height: that._$node.height(), + }; + interact(that.nodeSelector) + .resizable({ + // resize from all edges and corners + edges: { right: ".bi", bottom: ".bi" }, + square: true, + listeners: { + move(event) { + that.disableDraggable(); + let { x, y } = event.target.dataset; + + x = (parseFloat(x) || 0) + event.deltaRect.left; + y = (parseFloat(y) || 0) + event.deltaRect.top; + + Object.assign(event.target.style, { + width: `${event.rect.width}px`, + height: `${event.rect.height}px`, + transform: `translate(${x}px, ${y}px)`, + }); + + Object.assign(event.target.dataset, { x, y }); + + event.rect.width = Math.max(50, event.rect.width); + event.rect.height = Math.max(50, event.rect.height); + + $sizePreview.text( + Math.round(event.rect.width) + + "\u00D7" + + Math.round(event.rect.height) + ); + // that.repaint(); + }, + }, + modifiers: [ + // keep the edges inside the parent + interact.modifiers.restrictEdges({ + outer: "parent", + }), + // minimum size + interact.modifiers.restrictSize({ + min: { width: 40, height: 40 }, + }), + ], + inertia: { enabled: false }, + }) + .on(["resizestart"], () => { + // add resizing class + that._$node.addClass("resizing"); + that.disableDraggable(); + _canvas.hideGuidanceBox(); + $sizePreview.show(); + that._$node.css({ opacity: 0.5 }); + that._$node.append($sizePreview); + initialSize.width = that._$node.width(); + initialSize.height = that._$node.height(); + _canvas.unbindMoveToolEvents(); + }) + .on(["resizeend"], (event) => { + // remove resizing class + that._$node.removeClass("resizing"); + that.enableDraggable(); + const offsetX = event.rect.width - initialSize.width; + const offsetY = event.rect.height - initialSize.height; + $sizePreview.hide(); + that._$node.css({ opacity: "" }); + that.repaint(); + var operation = new NodeResizeOperation(id, offsetX, offsetY); + that.propagateNodeResizeOperation(operation); + _canvas.bindMoveToolEvents(); + }) + .draggable(); + } + + disableResizable() { + interact(this.nodeSelector).unset(); + } + + /** + * Apply position and dimension attributes to the node + */ + draw() { + return this._draw(); + } + /** + * Get jQuery object of DOM node representing the node + * @returns {jQuery} + */ + get$node() { + return this._get$node(); + } + /** + * Get JSON representation of the node + * @returns {{label: Object, left: number, top: number, width: number, height: number, type: string, attributes: Object}} + */ + toJSON() { + return this._toJSON(); + } + /** + * hide the node and all associated edges + */ + hide() { + this.get$node().hide(); + window.jsPlumbInstance.hide(this.get$node()); + } + /** + * show the node and all associated edges + */ + show() { + this.get$node().show(); + window.jsPlumbInstance.show(this.get$node()[0]); + window.jsPlumbInstance.repaint(this.get$node()[0]); + } + registerYMap() { + this._registerYMap(); + } +} + +/** + * Abstract Class Node + * @class canvas_widget.EnumNode + * @extends canvas_widget.AbstractNode + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {number} zIndex Position of node on z-axis + */ +class EnumNode extends AbstractNode { + static TYPE = "Enumeration"; + static DEFAULT_WIDTH = 150; + static DEFAULT_HEIGHT = 100; + constructor(id, left, top, width, height, zIndex, json) { + super(id, EnumNode.TYPE, left, top, width, height, zIndex, json); + var that = this; + + /** + * jQuery object of node template + * @type {jQuery} + * @private + */ + var _$template = $(lodash.template(enumNodeHtml)({ type: that.getType() })); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = AbstractNode.prototype.get$node + .call(this) + .append(_$template) + .addClass("class"); + + /** + * jQuery object of DOM node representing the attributes + * @type {jQuery} + * @private + */ + var _$attributeNode = _$node.find(".attributes"); + + /** + * Attributes of node + * @type {Object} + * @private + */ + var _attributes = this.getAttributes(); + + /** + * Get JSON representation of the node + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractNode.prototype.toJSON.call(this); + json.type = EnumNode.TYPE; + return json; + }; + var attr = new SingleValueListAttribute("[attributes]", "Attributes", this); + this.addAttribute(attr); + + this.registerYMap = function () { + AbstractNode.prototype.registerYMap.call(this); + that.getLabel().getValue().registerYType(); + attr.registerYMap(); + }; + this.unregisterCallbacks = function () { + that.getAttribute("[attributes]").unregisterCallbacks(); + }; + this.registerYTextAttributes = function (map) { + map.get(that.getLabel().getValue().getEntityId()).then(function (ytext) { + that.getLabel().getValue().registerYType(ytext); + }); + }; + + _$node.find(".label").append(this.getLabel().get$node()); + + for (var attributeKey in _attributes) { + if (_attributes.hasOwnProperty(attributeKey)) { + _$attributeNode.append(_attributes[attributeKey].get$node()); + } + } + } +} + +/** + * Abstract Class Node + * @class canvas_widget.NodeShapeNode + * @extends canvas_widget.AbstractNode + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {number} zIndex Position of node on z-axis + * @param {boolean} containment containment + */ +class NodeShapeNode extends AbstractNode { + static TYPE = "Node Shape"; + static DEFAULT_WIDTH = 150; + static DEFAULT_HEIGHT = 150; + constructor(id, left, top, width, height, zIndex, containment, json) { + super( + id, + "Node Shape", + left, + top, + width, + height, + zIndex, + containment, + json + ); + var that = this; + + /** + * jQuery object of node template + * @type {jQuery} + * @private + */ + var _$template = $(lodash.template(nodeShapeNodeHtml)({ type: that.getType() })); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = AbstractNode.prototype.get$node + .call(this) + .append(_$template) + .addClass("class"); + + /** + * jQuery object of DOM node representing the attributes + * @type {jQuery} + * @private + */ + var _$attributeNode = _$node.find(".attributes"); + + /** + * Attributes of node + * @type {Object} + * @private + */ + var _attributes = this.getAttributes(); + + /** + * Get JSON representation of the node + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractNode.prototype.toJSON.call(this); + json.type = NodeShapeNode.TYPE; + return json; + }; + + var attrShapeSelect = new SingleSelectionAttribute( + this.getEntityId() + "[shape]", + "Shape", + this, + { + circle: "Circle", + diamond: "Diamond", + rectangle: "Rectangle", + rounded_rectangle: "Rounded Rectangle", + triangle: "Triangle", + } + ); + var attrWidth = new IntegerAttribute( + this.getEntityId() + "[defaultWidth]", + "Default Width", + this + ); + var attrHeight = new IntegerAttribute( + this.getEntityId() + "[defaultHeight]", + "Default Height", + this + ); + var attrColor = new SingleColorValueAttribute( + this.getEntityId() + "[color]", + "Color", + this + ); + var attrContaintment = new BooleanAttribute( + this.getEntityId() + "[containment]", + "Containment", + this + ); + var attrCustomShape = new SingleMultiLineValueAttribute( + this.getEntityId() + "[customShape]", + "Custom Shape", + this + ); + var attrAnchors = new SingleValueAttribute( + this.getEntityId() + "[customAnchors]", + "Custom Anchors", + this + ); + + this.addAttribute(attrShapeSelect); + this.addAttribute(attrColor); + this.addAttribute(attrWidth); + this.addAttribute(attrHeight); + this.addAttribute(attrContaintment); + this.addAttribute(attrCustomShape); + this.addAttribute(attrAnchors); + + _$node.find(".label").append(this.getLabel().get$node()); + + for (var attributeKey in _attributes) { + if (_attributes.hasOwnProperty(attributeKey)) { + _$attributeNode.append(_attributes[attributeKey].get$node()); + } + } + + this.registerYMap = function () { + AbstractNode.prototype.registerYMap.call(this); + attrShapeSelect.getValue().registerYType(); + attrWidth.getValue().registerYType(); + attrHeight.getValue().registerYType(); + attrContaintment.getValue().registerYType(); + that.getLabel().getValue().registerYType(); + attrColor.getValue().registerYType(); + attrAnchors.getValue().registerYType(); + attrCustomShape.getValue().registerYType(); + }; + } +} + +/** + * EntityManager + * @class canvas_widget.EntityManager + * @memberof canvas_widget + * @constructor + */ +let EntityManager$1 = class EntityManager { + y = null; + setSharedDocument(y) { + this.y = y; + } + _nodes; + _edges; + + constructor() { + /** + * the view id indicates if the EntityManager should use View types for modeling or node types + * @type {string} + * @private + */ + var _viewId = undefined; + + /** + * Model attributes node + * @type {canvas_widget.ModelAttributesNode} + * @private + */ + var _modelAttributesNode = null; + /** + * Nodes of the graph + * @type {{}} + * @private + */ + var _nodes = {}; + this._nodes = _nodes; + /** + * Edges of the graph + * @type {{}} + * @private + */ + var _edges = {}; + this._edges = _edges; + + var metamodel = null; + + var guidancemodel = null; + + //noinspection JSUnusedGlobalSymbols + return { + /** + * Create a new node + * @memberof canvas_widget.EntityManager# + * @param {string} type Type of node + * @param {string} id Entity identifier of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {number} zIndex Position of node on z-axis + * @param {object} json the json representation + * @param {number} y the yjs map + * @param {boolean} store if the node should be stored in the meta model + * @returns {canvas_widget.AbstractNode} + */ + createNode: function ( + type, + id, + left, + top, + width, + height, + zIndex, + containment, + json, + y, + store = true + ) { + var node; + AbstractEntity.maxZIndex = Math.max(AbstractEntity.maxZIndex, zIndex); + AbstractEntity.minZIndex = Math.min(AbstractEntity.minZIndex, zIndex); + + if (_viewId && viewNodeTypes.hasOwnProperty(type)) { + node = viewNodeTypes[type]( + id, + left, + top, + width, + height, + zIndex, + containment, + json, + y + ); + } else if (nodeTypes.hasOwnProperty(type)) { + node = new nodeTypes[type]( + id, + left, + top, + width, + height, + zIndex, + containment, + json, + y + ); + } + _nodes[id] = node; + if (store) EntityManagerInstance.storeDataYjs(); + return node; + }, + saveState: function () { + // if metamodel + const viewId = ViewManager.getCurrentView(); + if (viewId && !metamodel) { + ViewManager.updateViewContent(viewId); + } else { + EntityManager.storeDataYjs(); + } + }, + findObjectNodeByLabel(searchTerm) { + const re = new RegExp(searchTerm, "gi"); + const { nodes } = EntityManagerInstance.graphToJSON(); + for (const [nodeId, node] of Object.entries(nodes)) { + if (node?.type.match(re)) { + // type matches searchTerm + return EntityManagerInstance.find(nodeId); + } + if (node?.label?.value?.value.match(re)) { + // label matches searchTerm + return EntityManagerInstance.find(nodeId); + } + for (const attr of Object.values(node?.attributes)) { + // search attributes + if (typeof attr?.value?.value !== "string") { + continue; + } + if (attr?.value?.value.match(re)) { + // attribute value matches searchTerm + return EntityManagerInstance.find(nodeId); + } + } + } + return null; + }, + /** + * Create model Attributes node + * @returns {canvas_widget.ModelAttributesNode} + */ + createModelAttributesNode: function (y) { + if (_modelAttributesNode === null) { + if (metamodel) + _modelAttributesNode = new ModelAttributesNode( + "modelAttributes", + metamodel.attributes, + y + ); + else + _modelAttributesNode = new ModelAttributesNode( + "modelAttributes", + null, + y + ); + return _modelAttributesNode; + } + return _modelAttributesNode; + }, + /** + * Find nodeby attr + * @memberof attribute_widget.EntityManager# + * @param {string} name Entity name + * @returns {canvas_widget.AbstractNode} + */ + findNodeByAttribute: function (attr, name) { + for (const key in _nodes) { + const node = _nodes[key]; + if (node.getAttribute(attr) === name) { + return node; + } + } + }, + + /** + * Find node by id + * @memberof canvas_widget.EntityManager# + * @param {string} id Entity id + * @returns {canvas_widget.AbstractNode} + */ + findNode: function (id) { + if (_nodes.hasOwnProperty(id)) { + return _nodes[id]; + } + return null; + }, + /** + * Find node or edge by id + * @memberof attribute_widget.EntityManager# + * @param {string} id Entity id + * @returns {*} + */ + find: function (id) { + return this.findNode(id) || this.findEdge(id); + }, + /** + * Delete node by id + * @memberof canvas_widget.EntityManager# + * @param {string} id Entity id + */ + deleteNode: function (id) { + if (_nodes.hasOwnProperty(id)) { + delete _nodes[id]; + } + EntityManagerInstance.storeDataYjs(); + }, + /** + * Get all nodes + * @memberof canvas_widget.EntityManager# + * @returns {object} + */ + getNodes: function () { + return _nodes; + }, + /** + * Get nodes by type + * @memberof canvas_widget.EntityManager# + * @param {string|string[]} type Entity type + * @returns {object} + */ + getNodesByType: function (type) { + var nodeId, + node, + nodesByType = {}; + + if (typeof type === "string") { + type = [type]; + } + + for (nodeId in _nodes) { + if (_nodes.hasOwnProperty(nodeId)) { + node = _nodes[nodeId]; + if (type.indexOf(node.getType()) !== -1) { + nodesByType[nodeId] = node; + } + } + } + return nodesByType; + }, + /** + * Create a new edge + * @memberof canvas_widget.EntityManager# + * @param {string} type Type of edge + * @param {string} id Entity identifier of edge + * @param {canvas_widget.AbstractNode} source Source node + * @param {canvas_widget.AbstractNode} target Target node + * @returns {canvas_widget.AbstractEdge} + */ + //TODO: switch id and type + createEdge: function (type, id, source, target, store = true) { + var edge; + + if (_viewId && viewEdgeTypes.hasOwnProperty(type)) { + edge = viewEdgeTypes[type](id, source, target); + } else if (edgeTypes.hasOwnProperty(type)) { + edge = new edgeTypes[type](id, source, target); + } else { + return undefined; + } + source.addOutgoingEdge(edge); + target?.addIngoingEdge(edge); + _edges[id] = edge; + if (store) EntityManagerInstance.storeDataYjs(); + return edge; + }, + /** + * Find edge by id + * @memberof canvas_widget.EntityManager# + * @param {string} id Entity id + * @returns {*} + */ + findEdge: function (id) { + if (_edges.hasOwnProperty(id)) { + return _edges[id]; + } + return null; + }, + /** + * Delete edge by id + * @memberof canvas_widget.EntityManager# + * @param {string} id Entity id + */ + deleteEdge: function (id) { + if (_edges.hasOwnProperty(id)) { + delete _edges[id]; + } + EntityManagerInstance.storeDataYjs(); + }, + /** + * Get all edges + * @memberof canvas_widget.EntityManager# + * @returns {object} + */ + getEdges: function () { + return _edges; + }, + /** + * Get edges by type + * @memberof canvas_widget.EntityManager# + * @param {string} type Entity type + * @returns {object} + */ + getEdgesByType: function (type) { + var edgeId, + edge, + edgesByType = {}; + + for (edgeId in _edges) { + if (_edges.hasOwnProperty(edgeId)) { + edge = _edges[edgeId]; + if (edge.getType() === type) { + edgesByType[edgeId] = edge; + } + } + } + return edgesByType; + }, + /** + * Get JSON representation of whole graph + * @memberof canvas_widget.EntityManager# + * @returns {object} + */ + graphToJSON: function () { + var attributesJSON; + var nodesJSON = {}; + var edgesJSON = {}; + attributesJSON = _modelAttributesNode + ? _modelAttributesNode?.toJSON() + : {}; + lodash.forEach(_nodes, function (val, key) { + nodesJSON[key] = val?.toJSON(); + }); + lodash.forEach(_edges, function (val, key) { + edgesJSON[key] = val?.toJSON(); + }); + return { + attributes: attributesJSON, + nodes: nodesJSON, + edges: edgesJSON, + }; + }, + /** + * Create model attributes node by its JSON representation + * @memberof canvas_widget.EntityManager# + * @param {object} json JSON representation + * @returns {canvas_widget.AbstractNode} + */ + createModelAttributesNodeFromJSON: function (json) { + var node = this.createModelAttributesNode(); + if (node) { + node.getLabel().getValue().setValue(json.label.value.value); + for (var attrId in json.attributes) { + if (json.attributes.hasOwnProperty(attrId)) { + var attr = node.getAttribute(attrId); + if (attr) { + attr.setValueFromJSON(json.attributes[attrId]); + } + } + } + } + return node; + }, + /** + * Create a new node by its JSON representation + * @memberof canvas_widget.EntityManager# + * @param {string} type Type of node + * @param {string} id Entity identifier of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {object} json JSON representation + * @param {number} zIndex Position of node on z-axis + * @returns {canvas_widget.AbstractNode} + */ + createNodeFromJSON: function ( + type, + id, + left, + top, + width, + height, + zIndex, + containment, + json, + y + ) { + var node = this.createNode( + type, + id, + left, + top, + width, + height, + zIndex, + containment, + json, + y, + false + ); + if (node) { + node.getLabel().getValue().setValue(json.label.value.value); + for (var attrId in json.attributes) { + if (json.attributes.hasOwnProperty(attrId)) { + var attr = node.getAttribute(attrId); + if (attr) { + attr.setValueFromJSON(json.attributes[attrId]); + } else { + var newId = attrId.replace(/[^\[\]]*/, id); + attr = node.getAttribute(newId); + if (attr) { + attr.setValueFromJSON(json.attributes[attrId]); + } + } + } + } + } + return node; + }, + /** + * Create a new node by its JSON representation + * @memberof canvas_widget.EntityManager# + * @param {string} type Type of edge + * @param {string} id Entity identifier of edge + * @param {canvas_widget.AbstractNode} source Source node entity id + * @param {canvas_widget.AbstractNode} target Target node entity id + * @param {object} json JSON representation + * @returns {canvas_widget.AbstractEdge} + */ + createEdgeFromJSON: function (type, id, source, target, json) { + const sourceNode = this.findNode(source); + const targetNode = this.findNode(target); + var edge = this.createEdge(type, id, sourceNode, targetNode, false); + if (edge) { + edge.getLabel().getValue().setValue(json.label.value.value); + for (var attrId in json.attributes) { + if (json.attributes.hasOwnProperty(attrId)) { + var attr = edge.getAttribute(attrId); + if (attr) { + attr.setValueFromJSON(json.attributes[attrId]); + } + } + } + } + return edge; + }, + /** + * Generate the 'Add node..' context menu options + * @param canvas Canvas to add node to + * @param left Position of node on x-axis + * @param top Position of node on <-axis + * @returns {object} Menu items + */ + generateAddNodeMenu: function (canvas, left, top) { + function makeAddNodeCallback(nodeType, width, height, containment) { + return function () { + canvas.createNode( + nodeType, + left, + top, + width, + height, + 32000, + containment + ); + }; + } + var items = {}, + nodeType, + _nodeTypes; + + if (_viewId && _layer === CONFIG.LAYER.MODEL) { + _nodeTypes = viewNodeTypes; + } else { + _nodeTypes = nodeTypes; + } + + for (nodeType in _nodeTypes) { + if (_nodeTypes.hasOwnProperty(nodeType)) { + if ( + _layer === CONFIG.LAYER.META && + !_viewId && + (nodeType === "ViewObject" || nodeType === "ViewRelationship") + ) + continue; + if ( + _layer === CONFIG.LAYER.META && + _viewId && + (nodeType === "Object" || + nodeType === "Relationship" || + nodeType === "Enumeration" || + nodeType === "Abstract Class") + ) + continue; + + items[nodeType] = { + name: ".." + nodeType, + callback: makeAddNodeCallback( + nodeType, + _nodeTypes[nodeType].DEFAULT_WIDTH, + _nodeTypes[nodeType].DEFAULT_HEIGHT, + _nodeTypes[nodeType].CONTAINMENT + ), + }; + } + } + return items; + }, + /** + * generates the context menu for the show and hide operations on node types + * @returns {object} + */ + generateVisibilityNodeMenu: function (visibility) { + var _applyVisibilityCallback = function (nodeType, vis) { + return function () { + if (vis !== "show" && vis !== "hide") return; + + var nodes; + if (_viewId && _layer === CONFIG.LAYER.MODEL) { + nodes = that.getNodesByViewType(nodeType); + } else { + nodes = that.getNodesByType(nodeType); + } + for (var nKey in nodes) { + if (nodes.hasOwnProperty(nKey)) { + nodes[nKey][vis](); + } + } + if (vis === "hide") { + this.data("show" + nodeType + "Disabled", true); + } else { + this.data("show" + nodeType + "Disabled", false); + } + + return false; + }; + }; + + var that = this; + var items = {}, + nodeType, + _nodeTypes; + + if (_viewId && _layer === CONFIG.LAYER.MODEL) { + _nodeTypes = viewNodeTypes; + } else { + _nodeTypes = nodeTypes; + } + + for (nodeType in _nodeTypes) { + if (_nodeTypes.hasOwnProperty(nodeType)) { + if ( + _layer === CONFIG.LAYER.META && + !_viewId && + (nodeType === "ViewObject" || nodeType === "ViewRelationship") + ) + continue; + if ( + _layer === CONFIG.LAYER.META && + _viewId && + (nodeType === "Object" || + nodeType === "Relationship" || + nodeType === "Enumeration" || + nodeType === "Abstract Class") + ) + continue; + + items[visibility + nodeType] = { + name: ".." + nodeType, + callback: _applyVisibilityCallback(nodeType, visibility), + disabled: (function (nodeType) { + return function () { + if (visibility === "hide") + return this.data(visibility + nodeType + "Disabled"); + else return !this.data(visibility + nodeType + "Disabled"); + }; + })(nodeType), + }; + } + } + return items; + }, + /** + * generates a the context menu for the show and hide operations on edge types + * @returns {object} + */ + generateVisibilityEdgeMenu: function (visibility) { + function _applyVisibilityCallback(edgeType, vis) { + return function () { + if (vis !== "show" && vis !== "hide") return; + var edges; + if (_viewId && _layer === CONFIG.LAYER.MODEL) { + edges = that.getEdgesByViewType(edgeType); + } else { + edges = that.getEdgesByType(edgeType); + } + for (var eKey in edges) { + if (edges.hasOwnProperty(eKey)) { + edges[eKey][vis](); + } + } + if (vis === "hide") { + this.data("show" + edgeType + "Disabled", true); + } else { + this.data("show" + edgeType + "Disabled", false); + } + }; + } + var that = this; + var items = {}, + edgeType, + _edgeTypes; + + if (_viewId && _layer === CONFIG.LAYER.MODEL) { + _edgeTypes = viewEdgeTypes; + } else { + _edgeTypes = edgeTypes; + } + + for (edgeType in _edgeTypes) { + if (_edgeTypes.hasOwnProperty(edgeType)) { + items[visibility + edgeType] = { + name: ".." + edgeType, + callback: _applyVisibilityCallback(edgeType, visibility), + disabled: (function (edgeType) { + return function () { + if (visibility === "hide") + return this.data(visibility + edgeType + "Disabled"); + else return !this.data(visibility + edgeType + "Disabled"); + }; + })(edgeType), + }; + } + } + return items; + }, + /** + * Generate the 'Connect to..' context menu options for the passed node + * @param {canvas_widget.AbstractNode} node + */ + generateConnectToMenu: function (node) { + function makeTargetNodeCallback(connectionType, targetNodeId) { + return function (/*key, opt*/) { + node + .getCanvas() + .createEdge(connectionType, node.getEntityId(), targetNodeId); + }; + } + + var connectionType, + sourceNodeTypes, + targetNodeTypes, + targetNodeType, + connectionItems, + targetNodeTypeItems, + targetNodeItems, + i, + numOfRelations, + j, + numOfTargetTypes, + targetNodes, + targetNodeId, + targetNode, + targetAppearance, + sourceAppearance = node.getAppearance(); + + connectionItems = {}; + for (connectionType in relations) { + if (relations.hasOwnProperty(connectionType)) { + targetNodeTypeItems = {}; + for ( + i = 0, numOfRelations = relations[connectionType].length; + i < numOfRelations; + i++ + ) { + sourceNodeTypes = relations[connectionType][i].sourceTypes; + targetNodeTypes = relations[connectionType][i].targetTypes; + if ( + sourceNodeTypes.indexOf(node.getType()) !== -1 || + (_layer === CONFIG.LAYER.MODEL && + _viewId && + sourceNodeTypes.indexOf(node.getCurrentViewType()) !== -1) + ) { + for ( + j = 0, numOfTargetTypes = targetNodeTypes.length; + j < numOfTargetTypes; + j++ + ) { + targetNodeType = targetNodeTypes[j]; + targetNodeItems = {}; + if (_viewId && _layer === CONFIG.LAYER.MODEL) { + targetNodes = this.getNodesByViewType(targetNodeType); + } else { + targetNodes = this.getNodesByType(targetNodeType); + } + for (targetNodeId in targetNodes) { + if (targetNodes.hasOwnProperty(targetNodeId)) { + targetNode = targetNodes[targetNodeId]; + if (targetNode === node) continue; + if ( + _layer === CONFIG.LAYER.MODEL && + _viewId && + targetNode.getCurrentViewType() === null + ) + continue; + targetAppearance = targetNode.getAppearance(); + if ( + !targetNode + .getNeighbors() + .hasOwnProperty(node.getEntityId()) + ) { + targetNodeItems[ + connectionType + targetNodeType + i + targetNodeId + ] = { + name: + ".." + + (targetNode.getLabel().getValue().getValue() || + targetNode.getType()), + callback: makeTargetNodeCallback( + connectionType, + targetNodeId + ), + distanceSquare: + Math.pow( + targetAppearance.left - sourceAppearance.left, + 2 + ) + + Math.pow( + targetAppearance.top - sourceAppearance.top, + 2 + ), + targetNodeId: + connectionType + targetNodeType + i + targetNodeId, + }; + } + } + } + if (lodash.size(targetNodeItems) > 0) { + var targetNodeItemsTmp = lodash.sortBy( + targetNodeItems, + "distanceSquare" + ); + targetNodeItems = {}; + for ( + var k = 0, numOfItems = targetNodeItemsTmp.length; + k < numOfItems; + k++ + ) { + targetNodeItems[k + targetNodeItemsTmp[k].targetNodeId] = + targetNodeItemsTmp[k]; + } + targetNodeTypeItems[connectionType + targetNodeType + i] = { + name: "..to " + targetNodeType + "..", + items: targetNodeItems, + }; + } + } + } + } + if (lodash.size(targetNodeTypeItems) > 0) { + connectionItems[connectionType] = { + name: "..with " + connectionType + "..", + items: targetNodeTypeItems, + }; + } + } + } + + return { + name: "Connect..", + items: connectionItems, + disabled: (function (connectionItems) { + return lodash.size(connectionItems) === 0; + })(connectionItems), + }; + }, + generateGuidanceMetamodel: function () { + var metamodel = this.generateMetaModel(); + var actionNodeLabels = []; + var createEntityNodeLabels = []; + //Create guidance metamodel + var guidanceMetamodel = { + attributes: {}, + nodes: {}, + edges: {}, + }; + + //Create initial node + var initialNode = { + label: guidancemodel.INITIAL_NODE_LABEL, + shape: { + shape: "", + color: "", + defaultWidth: 200, + defaultHeight: 60, + containment: false, + customShape: startActivityNodeHtml, + customAnchors: "", + }, + attributes: {}, + }; + + //Add a label attribute to the initial node + initialNode.attributes[Util.generateRandomId()] = { + key: "label", + value: "string", + }; + + guidanceMetamodel.nodes[Util.generateRandomId()] = initialNode; + + //Create final node + var finalNode = { + label: guidancemodel.ACTIVITY_FINAL_NODE_LABEL, + shape: { + shape: "circle", + color: "", + defaultWidth: 50, + defaultHeight: 50, + containment: false, + customShape: activityFinalNodeHtml, + customAnchors: ["Perimeter", { shape: "Circle", anchorCount: 60 }], + }, + attributes: {}, + }; + + guidanceMetamodel.nodes[Util.generateRandomId()] = finalNode; + + //Create merge node + var mergeNode = { + label: guidancemodel.MERGE_NODE_LABEL, + shape: { + shape: "diamond", + color: "yellow", + defaultWidth: 0, + defaultHeight: 0, + containment: false, + customShape: "", + customAnchors: "", + }, + attributes: {}, + }; + + guidanceMetamodel.nodes[Util.generateRandomId()] = mergeNode; + + //Create 'call activity node' + var callActivityNode = { + label: guidancemodel.CALL_ACTIVITY_NODE_LABEL, + shape: { + shape: "rounded_rectangle", + color: "", + defaultWidth: 100, + defaultHeight: 50, + containment: false, + customShape: callActivityNodeHtml, + customAnchors: "", + }, + attributes: {}, + }; + + actionNodeLabels.push(guidancemodel.CALL_ACTIVITY_NODE_LABEL); + + //Add a label attribute to the call activity node + callActivityNode.attributes[Util.generateRandomId()] = { + key: "label", + value: "string", + }; + + guidanceMetamodel.nodes[Util.generateRandomId()] = callActivityNode; + + //Create concurrency node + var concurrencyNode = { + label: guidancemodel.CONCURRENCY_NODE_LABEL, + shape: { + shape: "rectangle", + color: "black", + defaultWidth: 10, + defaultHeight: 200, + containment: false, + customShape: "", + customAnchors: "", + }, + attributes: {}, + }; + + guidanceMetamodel.nodes[Util.generateRandomId()] = concurrencyNode; + + var flowEdgeRelations = []; + var dataFlowEdgeRelations = []; + + var nodes = metamodel.nodes; + for (var nodeId in nodes) { + if (nodes.hasOwnProperty(nodeId)) { + var node = nodes[nodeId]; + + var createObjectNodeToEntityNodeRelation = { + sourceTypes: [], + targetTypes: [], + }; + //Generate the 'create object node' + var label = guidancemodel.getCreateObjectNodeLabelForType( + node.label + ); + createObjectNodeToEntityNodeRelation.sourceTypes.push(label); + actionNodeLabels.push(label); + createEntityNodeLabels.push(label); + var id = Util.generateRandomId(); + guidanceMetamodel.nodes[id] = { + label: label, + attributes: {}, + shape: { + shape: "rounded_rectangle", + color: "", + defaultWidth: 100, + defaultHeight: 50, + containment: false, + customShape: lodash.template(actionNodeHtml)({ + label: node.label, + icon: "plus", + }), + customAnchors: "", + }, + }; + + guidanceMetamodel.nodes[id]; + + //Generate the 'entity node' + var entityLabel = guidancemodel.getEntityNodeLabelForType( + node.label + ); + createObjectNodeToEntityNodeRelation.targetTypes.push(label); + id = Util.generateRandomId(); + guidanceMetamodel.nodes[id] = { + label: entityLabel, + attributes: {}, + shape: { + shape: "rectangle", + color: "", + defaultWidth: 100, + defaultHeight: 50, + containment: false, + customShape: lodash.template(entityNodeHtml)({ + icon: "square", + label: node.label, + }), + customAnchors: "", + }, + }; + + //Generate the 'set property node' + setPropertyLabel = guidancemodel.getSetPropertyNodeLabelForType( + node.label + ); + actionNodeLabels.push(setPropertyLabel); + id = Util.generateRandomId(); + guidanceMetamodel.nodes[id] = { + label: setPropertyLabel, + attributes: {}, + shape: { + shape: "", + defaultWidth: 130, + defaultHeight: 50, + containment: false, + customShape: lodash.template(setPropertyNodeHtml)(), + customAnchors: "", + }, + }; + + var options = {}; + for (var attributeId in node.attributes) { + var attribute = node.attributes[attributeId]; + options[attribute.key] = attribute.key; + } + + guidanceMetamodel.nodes[id].attributes[Util.generateRandomId()] = { + key: "Property", + value: "Value", + options: options, + }; + + guidanceMetamodel.nodes[id]; + + //Define the 'create object node' to 'entity node' relation + dataFlowEdgeRelations.push({ + sourceTypes: [label], + targetTypes: [entityLabel], + }); + + //Define the 'entity node' to 'set property node' relation + dataFlowEdgeRelations.push({ + sourceTypes: [entityLabel], + targetTypes: [setPropertyLabel], + }); + + //Define the 'entity node' to 'create relationship node' relation + for (var edgeId in metamodel.edges) { + var edge = metamodel.edges[edgeId]; + for (var relationId in edge.relations) { + var relation = edge.relations[relationId]; + if ( + relation.sourceTypes.indexOf(node.label) > -1 || + relation.targetTypes.indexOf(node.label) > -1 + ) { + dataFlowEdgeRelations.push({ + sourceTypes: [entityLabel], + targetTypes: + guidancemodel.getCreateRelationshipNodeLabelForType( + edge.label + ), + }); + break; + } + } + } + } + } + var edgesByLabel = {}; + + var edges = metamodel.edges; + for (var edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + var edge = edges[edgeId]; + //Generate 'create relationship node' + var label = guidancemodel.getCreateRelationshipNodeLabelForType( + edge.label + ); + actionNodeLabels.push(label); + createEntityNodeLabels.push(label); + edgesByLabel[edge.label] = edge; + + var id = Util.generateRandomId(); + guidanceMetamodel.nodes[id] = { + label: label, + attributes: {}, + shape: { + shape: "rounded_rectangle", + color: "", + defaultWidth: 100, + defaultHeight: 50, + containment: false, + customShape: lodash.template(actionNodeHtml)({ + label: edge.label, + icon: "plus", + }), + customAnchors: "", + }, + }; + + guidanceMetamodel.nodes[id]; + + //Generate 'entity node' + var entityLabel = guidancemodel.getEntityNodeLabelForType( + edge.label + ); + + var id = Util.generateRandomId(); + guidanceMetamodel.nodes[id] = { + label: entityLabel, + attributes: {}, + shape: { + shape: "rectangle", + color: "black", + defaultWidth: 100, + defaultHeight: 50, + containment: false, + customShape: lodash.template(entityNodeHtml)({ + icon: "exchange", + label: edge.label, + }), + customAnchors: "", + }, + }; + + guidanceMetamodel.nodes[id]; + + //Generate the 'set property node' + if (Object.keys(edge.attributes).length > 0) { + var setPropertyLabel = + guidancemodel.getSetPropertyNodeLabelForType(edge.label); + actionNodeLabels.push(setPropertyLabel); + id = Util.generateRandomId(); + guidanceMetamodel.nodes[id] = { + label: setPropertyLabel, + attributes: {}, + shape: { + shape: "", + defaultWidth: 0, + defaultHeight: 0, + containment: false, + customShape: lodash.template(setPropertyNodeHtml)({ + type: setPropertyLabel, + color: "white", + }), + customAnchors: "", + }, + }; + + var options = {}; + for (var attributeId in edge.attributes) { + var attribute = edge.attributes[attributeId]; + options[attribute.key] = attribute.key; + } + + guidanceMetamodel.nodes[id].attributes[Util.generateRandomId()] = + { + key: "Property", + value: "Value", + options: options, + }; + } + + //Define the 'create relationship node' to 'entity node' relation + dataFlowEdgeRelations.push({ + sourceTypes: [label], + targetTypes: [entityLabel], + }); + + //Define the 'entity node' to 'set property node' relation + dataFlowEdgeRelations.push({ + sourceTypes: [entityLabel], + targetTypes: [setPropertyLabel], + }); + } + } + + //Create the flow edge + + //Relations between all action nodes + flowEdgeRelations = flowEdgeRelations.concat({ + sourceTypes: actionNodeLabels, + targetTypes: actionNodeLabels.concat([ + guidancemodel.MERGE_NODE_LABEL, + guidancemodel.ACTIVITY_FINAL_NODE_LABEL, + guidancemodel.CONCURRENCY_NODE_LABEL, + ]), + }); + + //Relations for the initial node + flowEdgeRelations = flowEdgeRelations.concat({ + sourceTypes: [guidancemodel.INITIAL_NODE_LABEL], + targetTypes: [ + guidancemodel.CALL_ACTIVITY_NODE_LABEL, + guidancemodel.MERGE_NODE_LABEL, + guidancemodel.CONCURRENCY_NODE_LABEL, + ].concat(createEntityNodeLabels), + }); + + //Relations for the merge node + flowEdgeRelations = flowEdgeRelations.concat({ + sourceTypes: [guidancemodel.MERGE_NODE_LABEL], + targetTypes: [ + guidancemodel.ACTIVITY_FINAL_NODE_LABEL, + guidancemodel.MERGE_NODE_LABEL, + guidancemodel.CONCURRENCY_NODE_LABEL, + ].concat(actionNodeLabels), + }); + + //Relations for the concurrency node + flowEdgeRelations = flowEdgeRelations.concat({ + sourceTypes: [guidancemodel.CONCURRENCY_NODE_LABEL], + targetTypes: [ + guidancemodel.ACTIVITY_FINAL_NODE_LABEL, + guidancemodel.CONCURRENCY_NODE_LABEL, + guidancemodel.MERGE_NODE_LABEL, + ].concat(actionNodeLabels), + }); + + //Create the action flow edge + guidanceMetamodel.edges[Util.generateRandomId()] = { + label: "Action flow edge", + shape: { + arrow: "unidirassociation", + shape: "curved", + color: "black", + overlay: "", + overlayPosition: "top", + overlayRotate: true, + }, + relations: flowEdgeRelations, + }; + + //Create the data flow edge + var dataFlowEdge = { + label: "Data flow edge", + shape: { + arrow: "unidirassociation", + shape: "curved", + color: "black", + overlay: "", + overlayPosition: "top", + overlayRotate: true, + }, + attributes: {}, + relations: dataFlowEdgeRelations, + }; + + dataFlowEdge.attributes[Util.generateRandomId()] = { + key: "Destination", + value: "Value", + options: { + Source: "Source", + Target: "Target", + }, + }; + guidanceMetamodel.edges[Util.generateRandomId()] = dataFlowEdge; + + //Create the association edge + guidanceMetamodel.edges[Util.generateRandomId()] = { + label: "Association edge", + shape: { + arrow: "unidirassociation", + shape: "curved", + color: "", + dashstyle: "4 2", + overlay: "", + overlayPosition: "hidden", + overlayRotate: true, + }, + relations: [ + { + sourceTypes: [guidancemodel.CALL_ACTIVITY_NODE_LABEL], + targetTypes: [guidancemodel.INITIAL_NODE_LABEL], + }, + ], + }; + + return guidanceMetamodel; + }, + generateLogicalGuidanceRepresentation: function (m) { + const dataMap = y.getMap("data"); + var graph = new graphlib.Graph(); + var model; + if (m) model = m; + else model = dataMap.get("guidancemodel"); + if (!model) return null; + var nodes = model.nodes; + var edges = model.edges; + //Returns successor node which belong to the action flow (everything except entity nodes) + var getFlowSuccessors = function (nodeId) { + var targets = []; + var labels = []; + for (var edgeId in edges) { + var edge = edges[edgeId]; + if (edge.source == nodeId) { + //var targetType = nodes[edge.target].type + if (edge.type == "Action flow edge") { + targets.push(edge.target); + labels.push(edge.label.value.value); + } + } + } + return { + targets: targets, + labels: labels, + }; + }; + + var getEntitySuccessor = function (nodeId) { + for (var edgeId in edges) { + var edge = edges[edgeId]; + if (edge.source == nodeId) { + var targetType = nodes[edge.target].type; + if ((targetType = guidancemodel.isEntityNodeLabel(targetType))) + return edge.target; + } + } + return ""; + }; + + var getEntityPredecessorsForCreateRelationshipAction = function ( + nodeId + ) { + var entities = { + Source: "", + Target: "", + }; + for (var edgeId in edges) { + var edge = edges[edgeId]; + if (edge.target == nodeId) { + var sourceType = nodes[edge.source].type; + if ((sourceType = guidancemodel.isEntityNodeLabel(sourceType))) { + var destination = getAttributeValue(edge, "Destination"); + entities[destination] = edge.source; + } + } + } + return entities; + }; + + var getEntityPredecessorForSetPropertyAction = function (nodeId) { + for (var edgeId in edges) { + var edge = edges[edgeId]; + if (edge.target == nodeId) { + var sourceType = nodes[edge.source].type; + if ((sourceType = guidancemodel.isEntityNodeLabel(sourceType))) { + return edge.source; + } + } + } + return ""; + }; + + var getInitialNodeForCallActivityAction = function (nodeId) { + for (var edgeId in edges) { + var edge = edges[edgeId]; + if (edge.source == nodeId && edge.type == "Association edge") { + return edge.target; + } + } + return ""; + }; + + var getAttributeValue = function (node, attributeName) { + for (var attributeId in node.attributes) { + var attribute = node.attributes[attributeId]; + if (attribute.name == attributeName) return attribute.value.value; + } + return ""; + }; + + for (var nodeId in nodes) { + var node = nodes[nodeId]; + var type = node.type; + var subType = ""; + + if (type == guidancemodel.INITIAL_NODE_LABEL) { + var successors = getFlowSuccessors(nodeId); + graph.setNode(nodeId, { + type: "INITIAL_NODE", + name: getAttributeValue(node, "label"), + }); + for (var i = 0; i < successors.targets.length; i++) { + graph.setEdge( + nodeId, + successors.targets[i], + successors.labels[i] + ); + } + } else if (type == guidancemodel.MERGE_NODE_LABEL) { + var successors = getFlowSuccessors(nodeId); + graph.setNode(nodeId, { + type: "MERGE_NODE", + }); + for (var i = 0; i < successors.targets.length; i++) { + graph.setEdge( + nodeId, + successors.targets[i], + successors.labels[i] + ); + } + } else if (type == guidancemodel.CONCURRENCY_NODE_LABEL) { + var successors = getFlowSuccessors(nodeId); + graph.setNode(nodeId, { + type: "CONCURRENCY_NODE", + }); + for (var i = 0; i < successors.targets.length; i++) { + graph.setEdge( + nodeId, + successors.targets[i], + successors.labels[i] + ); + } + } else if (type == guidancemodel.ACTIVITY_FINAL_NODE_LABEL) { + graph.setNode(nodeId, { + type: "ACTIVITY_FINAL_NODE", + }); + } else if ((subType = guidancemodel.isCreateObjectNodeLabel(type))) { + var successors = getFlowSuccessors(nodeId); + graph.setNode(nodeId, { + type: "CREATE_OBJECT_ACTION", + objectType: subType, + createdObjectId: getEntitySuccessor(nodeId), + }); + for (var i = 0; i < successors.targets.length; i++) { + graph.setEdge( + nodeId, + successors.targets[i], + successors.labels[i] + ); + } + } else if ( + (subType = guidancemodel.isCreateRelationshipNodeLabel(type)) + ) { + var entities = + getEntityPredecessorsForCreateRelationshipAction(nodeId); + var successors = getFlowSuccessors(nodeId); + graph.setNode(nodeId, { + type: "CREATE_RELATIONSHIP_ACTION", + relationshipType: subType, + createdRelationshipId: getEntitySuccessor(nodeId), + sourceObjectId: entities["Source"], + targetObjectId: entities["Target"], + }); + for (var i = 0; i < successors.targets.length; i++) { + graph.setEdge( + nodeId, + successors.targets[i], + successors.labels[i] + ); + } + } else if ((subType = guidancemodel.isSetPropertyNodeLabel(type))) { + var successors = getFlowSuccessors(nodeId); + graph.setNode(nodeId, { + type: "SET_PROPERTY_ACTION", + entityType: subType, + propertyName: getAttributeValue(node, "Property"), + sourceObjectId: getEntityPredecessorForSetPropertyAction(nodeId), + }); + for (var i = 0; i < successors.targets.length; i++) { + graph.setEdge( + nodeId, + successors.targets[i], + successors.labels[i] + ); + } + } else if (type == guidancemodel.CALL_ACTIVITY_NODE_LABEL) { + var successors = getFlowSuccessors(nodeId); + graph.setNode(nodeId, { + type: "CALL_ACTIVITY_ACTION", + initialNodeId: getInitialNodeForCallActivityAction(nodeId), + }); + for (var i = 0; i < successors.targets.length; i++) { + graph.setEdge( + nodeId, + successors.targets[i], + successors.labels[i] + ); + } + } + } + return graphlib.json.write(graph); + }, + generateGuidanceRules: function () { + var guidanceRules = { objectToolRules: [] }; + var nodes = guidancemodel.guidancemodel.nodes; + var edges = guidancemodel.guidancemodel.edges; + for (var nodeId in nodes) { + var node = nodes[nodeId]; + var type = node.type; + + if (guidancemodel.isObjectToolType(type)) { + var srcObjectType = + guidancemodel.getObjectTypeForObjectToolType(type); + var destObjectType = null; + var relationshipType = null; + var relevantEdges = []; + var label = ""; + //Get the label attribute + for (var attributeId in node.attributes) { + if (node.attributes[attributeId].name == "label") + label = node.attributes[attributeId].value.value; + } + var edgeId; + for (edgeId in edges) { + if (edges[edgeId].source == nodeId) + relevantEdges.push(edges[edgeId]); + } + for (var i = 0; i < relevantEdges.length; i++) { + var edge = relevantEdges[i]; + var target = nodes[edge.target]; + if (guidancemodel.isObjectContextType(target.type)) { + destObjectType = + guidancemodel.getObjectTypeForObjectContextType(target.type); + } else if (guidancemodel.isRelationshipContextType(target.type)) { + relationshipType = + guidancemodel.getRelationshipTypeForRelationshipContextType( + target.type + ); + } + } + if (destObjectType !== null && relationshipType !== null) { + var objectToolRule = { + srcObjectType: srcObjectType, + destObjectType: destObjectType, + relationshipType: relationshipType, + label: label, + }; + guidanceRules.objectToolRules.push(objectToolRule); + } + } + } + return guidanceRules; + }, + /** + * Generate the JSON Representation of the meta-model for a new editor instance based on the current graph + * @returns {{nodes: {}, edges: {}}} JSON representation of meta model + */ + generateMetaModel: function () { + /** + * Determine the type of the concrete classes (ObjectNodes) of the class diagram contained in the sub graph rooted by the passed node + * @param node Node to start with + * @param [visitedNodes] List of node that already have been visited + * @returns {object} + */ + function getConcreteObjectNodeTypes(node, visitedNodes) { + var edgeId, + edge, + ingoingEdges, + source, + type, + classTypes = []; + + if (!visitedNodes) visitedNodes = []; + + if (visitedNodes.indexOf(node) !== -1) return []; + + visitedNodes.push(node); + + type = node.getLabel().getValue().getValue(); + if (node instanceof ObjectNode && classTypes.indexOf(type) === -1) { + classTypes.push(type); + } + + ingoingEdges = node.getIngoingEdges(); + for (edgeId in ingoingEdges) { + if (ingoingEdges.hasOwnProperty(edgeId)) { + edge = ingoingEdges[edgeId]; + source = edge.getSource(); + if ( + (edge instanceof GeneralisationEdge && + source instanceof ObjectNode) || + (edge instanceof GeneralisationEdge && + source instanceof AbstractClassNode) + ) { + classTypes = classTypes.concat( + getConcreteObjectNodeTypes(source, visitedNodes) + ); + } + } + } + return classTypes; + } + + /** + * Determine the attributes of the passed node by traversing the underlying class diagram + * @param node Node to start with + * @param [visitedNodes] List of node that already have been visited + * @returns {object} + */ + function getNodeAttributes(node, visitedNodes) { + var nodeAttributes, attributeId, attribute; + var edgeId, edge, edges; + var source, target; + var neighbor, options; + var attributes = {}; + var obj = {}; + + if (!visitedNodes) visitedNodes = []; + + if (visitedNodes.indexOf(node) !== -1) return {}; + + visitedNodes.push(node); + + //Traverse edges to check for inheritance and linked enums + edges = node.getOutgoingEdges(); + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + source = edge.getSource(); + target = edge.getTarget(); + + //Does the node inherit attributes from a parent node? + if ( + (edge instanceof GeneralisationEdge && + target instanceof AbstractClassNode) || + (edge instanceof GeneralisationEdge && + node instanceof ObjectNode && + target instanceof ObjectNode) || + (edge instanceof GeneralisationEdge && + node instanceof RelationshipNode && + target instanceof RelationshipNode) || + (edge instanceof GeneralisationEdge && + node instanceof EnumNode && + target instanceof EnumNode) + ) { + Util.merge(attributes, getNodeAttributes(target, visitedNodes)); + + //Is there an enum linked to the node + } else if ( + (edge instanceof BiDirAssociationEdge && + ((target === node && + (neighbor = source) instanceof EnumNode) || + (source === node && + (neighbor = target) instanceof EnumNode))) || + (edge instanceof UniDirAssociationEdge && + (neighbor = target) instanceof EnumNode) + ) { + options = {}; + nodeAttributes = {}; + Util.merge(nodeAttributes, getNodeAttributes(neighbor, [])); + for (attributeId in nodeAttributes) { + if (nodeAttributes.hasOwnProperty(attributeId)) { + attribute = nodeAttributes[attributeId]; + options[attribute.value] = attribute.value; + } + } + obj = {}; + obj[neighbor.getEntityId()] = { + key: edge.getLabel().getValue().getValue(), + value: neighbor.getLabel().getValue().getValue(), + options: options, + }; + Util.merge(attributes, obj); + } + } + } + //Compute node attributes + nodeAttributes = node.getAttribute("[attributes]").getAttributes(); + for (attributeId in nodeAttributes) { + if (nodeAttributes.hasOwnProperty(attributeId)) { + attribute = nodeAttributes[attributeId]; + if (node instanceof RelationshipNode) { + obj = {}; + obj[attributeId] = { + key: attribute.getKey().getValue(), + value: attribute.getValue().getValue(), + position: attribute.getValue2().getValue(), + }; + Util.merge(attributes, obj); + } else if (node instanceof EnumNode) { + obj = {}; + obj[attributeId] = { + value: attribute.getValue().getValue(), + }; + Util.merge(attributes, obj); + } else { + obj = {}; + obj[attributeId] = { + key: attribute.getKey().getValue(), + value: attribute.getValue().getValue(), + }; + Util.merge(attributes, obj); + } + } + } + return attributes; + } + + var metamodel = { + attributes: {}, + nodes: {}, + edges: {}, + }; + + var nodeId, node; + var attributes; + var edge, edgeId, edges; + var source, target; + var neighbor; + var groupSource, groupTarget; + var groupNeighbor; + var shape; + var sourceTypes, targetTypes, concreteTypes; + var groupSourceTypes, groupTargetTypes, groupConcreteTypes; + var relations; + var groupEdge, groupEdgeId, groupEdges; + + for (nodeId in _nodes) { + if (_nodes.hasOwnProperty(nodeId)) { + node = _nodes[nodeId]; + if (node instanceof ObjectNode) { + if ( + node.getLabel().getValue().getValue() === "Model Attributes" + ) { + attributes = getNodeAttributes(node); + metamodel.attributes = attributes; + } else { + attributes = getNodeAttributes(node); + edges = node.getEdges(); + shape = null; + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + source = edge.getSource(); + target = edge.getTarget(); + if ( + (edge instanceof BiDirAssociationEdge && + ((target === node && + (neighbor = source) instanceof NodeShapeNode) || + (source === node && + (neighbor = target) instanceof NodeShapeNode))) || + (edge instanceof UniDirAssociationEdge && + (neighbor = target) instanceof NodeShapeNode) + ) { + shape = { + shape: neighbor + .getAttribute(neighbor.getEntityId() + "[shape]") + .getValue() + .getValue(), + color: neighbor + .getAttribute(neighbor.getEntityId() + "[color]") + .getValue() + .getValue(), + defaultWidth: parseInt( + neighbor + .getAttribute( + neighbor.getEntityId() + "[defaultWidth]" + ) + .getValue() + .getValue() + ), + defaultHeight: parseInt( + neighbor + .getAttribute( + neighbor.getEntityId() + "[defaultHeight]" + ) + .getValue() + .getValue() + ), + containment: neighbor + .getAttribute( + neighbor.getEntityId() + "[containment]" + ) + .getValue() + .getValue(), + customShape: neighbor + .getAttribute( + neighbor.getEntityId() + "[customShape]" + ) + .getValue() + .getValue(), + customAnchors: neighbor + .getAttribute( + neighbor.getEntityId() + "[customAnchors]" + ) + .getValue() + .getValue(), + }; + } + } + } + metamodel.nodes[nodeId] = { + label: node.getLabel().getValue().getValue(), + attributes: attributes, + shape: shape || { + shape: "rectangle", + color: "white", + containment: false, + customShape: "", + customAnchors: "", + defaultWidth: 0, + defaultHeight: 0, + }, + }; + } + } else if (node instanceof RelationshipNode) { + attributes = getNodeAttributes(node); + edges = node.getEdges(); + sourceTypes = []; + targetTypes = []; + relations = []; + shape = null; + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + source = edge.getSource(); + target = edge.getTarget(); + if ( + edge instanceof BiDirAssociationEdge && + ((target === node && + (neighbor = source) instanceof ObjectNode) || + (source === node && + (neighbor = target) instanceof ObjectNode)) + ) { + concreteTypes = getConcreteObjectNodeTypes(neighbor); + sourceTypes = sourceTypes.concat(concreteTypes); + targetTypes = targetTypes.concat(concreteTypes); + } else if ( + edge instanceof UniDirAssociationEdge && + source === node && + target instanceof ObjectNode + ) { + targetTypes = targetTypes.concat( + getConcreteObjectNodeTypes(target) + ); + } else if ( + edge instanceof UniDirAssociationEdge && + target === node && + source instanceof ObjectNode + ) { + sourceTypes = sourceTypes.concat( + getConcreteObjectNodeTypes(source) + ); + } else if ( + edge instanceof BiDirAssociationEdge && + ((target === node && + (neighbor = source) instanceof AbstractClassNode) || + (source === node && + (neighbor = target) instanceof AbstractClassNode)) + ) { + concreteTypes = getConcreteObjectNodeTypes(neighbor); + sourceTypes = sourceTypes.concat(concreteTypes); + targetTypes = targetTypes.concat(concreteTypes); + } else if ( + edge instanceof UniDirAssociationEdge && + source === node && + target instanceof AbstractClassNode + ) { + targetTypes = targetTypes.concat( + getConcreteObjectNodeTypes(target) + ); + } else if ( + edge instanceof UniDirAssociationEdge && + target === node && + source instanceof AbstractClassNode + ) { + sourceTypes = sourceTypes.concat( + getConcreteObjectNodeTypes(source) + ); + } else if ( + (edge instanceof BiDirAssociationEdge && + ((target === node && + (neighbor = source) instanceof EdgeShapeNode) || + (source === node && + (neighbor = target) instanceof EdgeShapeNode))) || + (edge instanceof UniDirAssociationEdge && + source === node && + (neighbor = target) instanceof EdgeShapeNode) + ) { + shape = { + arrow: neighbor + .getAttribute(neighbor.getEntityId() + "[arrow]") + .getValue() + .getValue(), + shape: neighbor + .getAttribute(neighbor.getEntityId() + "[shape]") + .getValue() + .getValue(), + color: neighbor + .getAttribute(neighbor.getEntityId() + "[color]") + .getValue() + .getValue(), + overlay: neighbor + .getAttribute(neighbor.getEntityId() + "[overlay]") + .getValue() + .getValue(), + overlayPosition: neighbor + .getAttribute( + neighbor.getEntityId() + "[overlayPosition]" + ) + .getValue() + .getValue(), + overlayRotate: neighbor + .getAttribute( + neighbor.getEntityId() + "[overlayRotate]" + ) + .getValue() + .getValue(), + }; + } else if ( + edge instanceof GeneralisationEdge && + target === node && + (neighbor = source) instanceof RelationshipGroupNode + ) { + groupEdges = neighbor.getEdges(); + groupSourceTypes = []; + groupTargetTypes = []; + for (groupEdgeId in groupEdges) { + if (groupEdges.hasOwnProperty(groupEdgeId)) { + groupEdge = groupEdges[groupEdgeId]; + groupSource = groupEdge.getSource(); + groupTarget = groupEdge.getTarget(); + if ( + groupEdge instanceof BiDirAssociationEdge && + ((groupTarget === neighbor && + (groupNeighbor = groupSource) instanceof + ObjectNode) || + (groupSource === neighbor && + (groupNeighbor = groupTarget) instanceof + ObjectNode)) + ) { + groupConcreteTypes = + getConcreteObjectNodeTypes(groupNeighbor); + groupSourceTypes = + groupSourceTypes.concat(groupConcreteTypes); + groupTargetTypes = + groupTargetTypes.concat(groupConcreteTypes); + } else if ( + groupEdge instanceof UniDirAssociationEdge && + groupSource === neighbor && + groupTarget instanceof ObjectNode + ) { + groupTargetTypes = groupTargetTypes.concat( + getConcreteObjectNodeTypes(groupTarget) + ); + } else if ( + groupEdge instanceof UniDirAssociationEdge && + groupTarget === neighbor && + groupSource instanceof ObjectNode + ) { + groupSourceTypes = groupSourceTypes.concat( + getConcreteObjectNodeTypes(groupSource) + ); + } else if ( + groupEdge instanceof BiDirAssociationEdge && + ((groupTarget === neighbor && + (groupNeighbor = groupSource) instanceof + AbstractClassNode) || + (groupSource === neighbor && + (groupNeighbor = groupTarget) instanceof + AbstractClassNode)) + ) { + groupConcreteTypes = + getConcreteObjectNodeTypes(groupNeighbor); + groupSourceTypes = + groupSourceTypes.concat(groupConcreteTypes); + groupTargetTypes = + groupTargetTypes.concat(groupConcreteTypes); + } else if ( + groupEdge instanceof UniDirAssociationEdge && + groupSource === neighbor && + groupTarget instanceof AbstractClassNode + ) { + groupTargetTypes = groupTargetTypes.concat( + getConcreteObjectNodeTypes(groupTarget) + ); + } else if ( + groupEdge instanceof UniDirAssociationEdge && + groupTarget === neighbor && + groupSource instanceof AbstractClassNode + ) { + groupSourceTypes = groupSourceTypes.concat( + getConcreteObjectNodeTypes(groupSource) + ); + } + } + } + + if ( + groupSourceTypes.length > 0 && + groupTargetTypes.length > 0 + ) { + relations.push({ + sourceTypes: groupSourceTypes, + targetTypes: groupTargetTypes, + }); + } + } + } + } + + if (sourceTypes.length > 0 && targetTypes.length > 0) { + relations.push({ + sourceTypes: sourceTypes, + targetTypes: targetTypes, + }); + } + + metamodel.edges[nodeId] = { + label: node.getLabel().getValue().getValue(), + shape: shape || { + arrow: "bidirassociation", + shape: "straight", + color: "black", + overlay: "", + overlayPosition: "top", + overlayRotate: true, + }, + relations: relations, + attributes: attributes, + }; + } + } + } + return metamodel; + }, + /** + * Store current graph representation in the ROLE space + * @returns {Deferred} + */ + storeData: function () { + var resourceSpace = new openapp.oo.Resource(openapp.param.space()); + + var data = this.graphToJSON(); + + var resourcesToSave = []; + var promises = []; + + //In the guidance model editor update the guidance model + if (guidancemodel.isGuidanceEditor()) { + resourcesToSave.push({ + typeName: CONFIG.NS.MY.GUIDANCEMODEL, + representation: data, + }); + } + //In the metamodel editor create the guidance metamodel needed for the guidance editor + else if (!metamodel.hasOwnProperty("nodes")) { + resourcesToSave.push({ + typeName: CONFIG.NS.MY.METAMODELPREVIEW, + representation: this.generateMetaModel(), + }); + resourcesToSave.push({ + typeName: CONFIG.NS.MY.GUIDANCEMETAMODEL, + representation: this.generateGuidanceMetamodel(), + }); + resourcesToSave.push({ + typeName: CONFIG.NS.MY.MODEL, + representation: data, + }); + } + //In the model editor just update the model + else { + resourcesToSave.push({ + typeName: CONFIG.NS.MY.MODEL, + representation: data, + }); + } + + var recreateResource = function (type, representation) { + var deferred = $.Deferred(); + var innerDeferred = $.Deferred(); + //noinspection JSUnusedGlobalSymbols + resourceSpace.getSubResources({ + relation: openapp.ns.role + "data", + type: type, + onEach: function (doc) { + doc.del(); + }, + onAll: function () { + innerDeferred.resolve(); + }, + }); + innerDeferred.then(function () { + resourceSpace.create({ + relation: openapp.ns.role + "data", + type: type, + representation: representation, + callback: function () { + deferred.resolve(); + }, + }); + }); + return deferred.promise(); + }; + + for (var i = 0; i < resourcesToSave.length; i++) { + var item = resourcesToSave[i]; + promises.push(recreateResource(item.typeName, item.representation)); + } + + return $.when.apply($, promises); + }, + storeDataYjs: function () { + var data = this.graphToJSON(); + const dataMap = y.getMap("data"); + window.y.transact(() => { + if (guidancemodel.isGuidanceEditor()) { + dataMap.set("guidancemodel", data); + } else if (!metamodel) { + dataMap.set("metamodelpreview", this.generateMetaModel()); + dataMap.set("guidancemetamodel", this.generateGuidanceMetamodel()); + dataMap.set("model", data); + } else { + dataMap.set("model", data); + } + }); + }, + /** + * Delete the Model Attribute Node + */ + deleteModelAttribute: function () { + _modelAttributesNode = null; + }, + /** + * resets the EntityManager + */ + reset: function () { + _nodes = {}; + _edges = {}; + this.deleteModelAttribute(); + }, + /** + * initializes the node types + * @param vls the vvs + */ + initNodeTypes: function (vls) { + nodeTypes = _initNodeTypes(vls); + }, + /** + * initializes the view edge types + * @param vls the vvs + */ + initEdgeTypes: function (vls) { + var res = _initEdgeTypes(vls); + edgeTypes = res.edgeTypes; + relations = res.relations; + }, + /** + * initializes both the node types- and the edge types Object + * @param vls the vvs + */ + initModelTypes: function (vls) { + this.initNodeTypes(vls); + this.initEdgeTypes(vls); + }, + /** + * Get the node type by its name + * @param type the name of the node type + * @returns {object} + */ + getNodeType: function (type) { + return nodeTypes.hasOwnProperty(type) ? nodeTypes[type] : null; + }, + /** + * Get the edge type bt its name + * @param {string} type the name of the edge type + * @returns {*} + */ + getEdgeType: function (type) { + return edgeTypes.hasOwnProperty(type) ? edgeTypes[type] : null; + }, + /** + * initializes the node types of a view + * @param vvs + */ + initViewNodeTypes: function (vvs) { + //delete the old view type references + for (var nodeTypeName in nodeTypes) { + if (nodeTypes.hasOwnProperty(nodeTypeName)) { + delete nodeTypes[nodeTypeName].VIEWTYPE; + } + } + viewNodeTypes = _initNodeTypes(vvs); + }, + /** + * initializes the edge types of a view + * @param vvs + */ + initViewEdgeTypes: function (vvs) { + //delete the old view type references + for (var edgeTypeName in edgeTypes) { + if (edgeTypes.hasOwnProperty(edgeTypeName)) { + delete edgeTypes[edgeTypeName].VIEWTYPE; + } + } + var res = _initEdgeTypes(vvs); + viewEdgeTypes = res.edgeTypes; + relations = res.relations; + }, + /** + * initializes the node and edge types of view + * @param vvs + */ + initViewTypes: function (vvs) { + this.setViewId(vvs.id); + this.initViewNodeTypes(vvs); + this.initViewEdgeTypes(vvs); + }, + /** + * get a view node type + * @param {string} type the name of the view type + * @returns {*} + */ + getViewNodeType: function (type) { + return viewNodeTypes.hasOwnProperty(type) ? viewNodeTypes[type] : null; + }, + /** + * get a view edge type + * @param {string} type the name of the view edge type + * @returns {*} + */ + getViewEdgeType: function (type) { + return viewEdgeTypes.hasOwnProperty(type) ? viewEdgeTypes[type] : null; + }, + /** + * set the identifier of the view + * @param {string} viewId + */ + setViewId: function (viewId) { + _viewId = viewId; + }, + /** + * get the identifier of the view + * @returns {*} + */ + getViewId: function () { + return _viewId; + }, + /** + * get nodes by view type + * @param {string} type the name of the view type + * @returns {object} a map of objects with key as identifier and value as Node + */ + getNodesByViewType: function (type) { + if (viewNodeTypes.hasOwnProperty(type)) { + return this.getNodesByType( + viewNodeTypes[type].getTargetNodeType().TYPE + ); + } + return null; + }, + /** + * get edges by view type + * @param {string}type the view type + * @returns {*} + */ + getEdgesByViewType: function (type) { + if (viewEdgeTypes.hasOwnProperty(type)) { + return this.getEdgesByType( + viewEdgeTypes[type].getTargetEdgeType().TYPE + ); + } + return null; + }, + /** + * Get the current layer you are operating on + * @returns {string} CONFIG.LAYER.META or CONFIG.LAYER.MODEL + */ + getLayer: function () { + return _layer; + }, + /** + * Get the relations between nodes and edges types + * @returns {{}} + */ + getRelations: function () { + return relations; + }, + setGuidance: function (guidance) { + guidancemodel = guidance; + }, + init: function (mm) { + metamodel = mm; + if (metamodel && metamodel.hasOwnProperty("nodes")) { + nodeTypes = _initNodeTypes(metamodel); + _layer = CONFIG.LAYER.MODEL; + } else { + _layer = CONFIG.LAYER.META; + + nodeTypes[ObjectNode.TYPE] = ObjectNode; + nodeTypes[AbstractClassNode.TYPE] = AbstractClassNode; + nodeTypes[RelationshipNode.TYPE] = RelationshipNode; + nodeTypes[RelationshipGroupNode.TYPE] = RelationshipGroupNode; + nodeTypes[EnumNode.TYPE] = EnumNode; + nodeTypes[NodeShapeNode.TYPE] = NodeShapeNode; + nodeTypes[EdgeShapeNode.TYPE] = EdgeShapeNode; + + //add view types + nodeTypes[ViewObjectNode.TYPE] = ViewObjectNode; + nodeTypes[ViewRelationshipNode$1.TYPE] = ViewRelationshipNode$1; + } + + if (metamodel && metamodel.hasOwnProperty("edges")) { + var res = _initEdgeTypes(metamodel); + edgeTypes = res.edgeTypes; + relations = res.relations; + } else { + edgeTypes[GeneralisationEdge.TYPE] = GeneralisationEdge; + edgeTypes[BiDirAssociationEdge.TYPE] = BiDirAssociationEdge; + edgeTypes[UniDirAssociationEdge.TYPE] = UniDirAssociationEdge; + + relations[BiDirAssociationEdge.TYPE] = BiDirAssociationEdge.RELATIONS; + relations[UniDirAssociationEdge.TYPE] = + UniDirAssociationEdge.RELATIONS; + relations[GeneralisationEdge.TYPE] = GeneralisationEdge.RELATIONS; + } + }, + }; + } +}; + +const EntityManagerInstance = new EntityManager$1(); +Object.freeze(EntityManagerInstance); + +/** + * Node + * @class canvas_widget.makeNode + * @memberof canvas_widget + * @constructor + * @param type Type of node + * @param $shape + * @param anchors + * @param attributes + * @returns {Node} + */ +function makeNode(type, $shape, anchors, attributes) { + /** + * Node + * @class canvas_widget.Node + * @extends canvas_widget.AbstractNode + * @constructor + * @param {string} id Entity identifier of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {number} zIndex Position of node on z-axis + * @param {boolean} containment containment + */ + class Node extends AbstractNode { + constructor(id, left, top, width, height, zIndex, containment) { + super(id, type, left, top, width, height, zIndex, containment); + var that = this; + + var currentViewType = null; + + this.setCurrentViewType = function (type) { + currentViewType = type; + }; + + this.getCurrentViewType = function () { + return currentViewType; + }; + + /** + * jQuery object of node template + * @type {jQuery} + * @private + */ + var _$template = $shape.clone(); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = AbstractNode.prototype.get$node + .call(this) + .append(_$template); + + /** + * Options for new connections + * @type {object} + */ + var _anchorOptions = anchors; + + this.nodeSelector = getQuerySelectorFromNode(_$node); + + var init = function () { + var attribute, attributeId, attrObj; + attrObj = {}; + for (attributeId in attributes) { + if (attributes.hasOwnProperty(attributeId)) { + attribute = attributes[attributeId]; + var key = attribute.key.toLowerCase(); + switch (attribute.value) { + case "boolean": + attrObj[attributeId] = new BooleanAttribute( + id + "[" + attribute.key.toLowerCase() + "]", + attribute.key, + that + ); + break; + case "string": + attrObj[attributeId] = new SingleValueAttribute( + id + "[" + attribute.key.toLowerCase() + "]", + attribute.key, + that + ); + if ( + attribute.key.toLowerCase() === "label" || + attribute.key.toLowerCase() === "title" || + attribute.key.toLowerCase() === "name" + ) { + that.setLabel(attrObj[attributeId]); + } + break; + case "integer": + attrObj[attributeId] = new IntegerAttribute( + id + "[" + attribute.key.toLowerCase() + "]", + attribute.key, + that + ); + break; + case "file": + attrObj[attributeId] = new FileAttribute( + id + "[" + attribute.key.toLowerCase() + "]", + attribute.key, + that + ); + break; + case "quiz": + attrObj[attributeId] = new QuizAttribute( + id + "[" + attribute.key.toLowerCase() + "]", + attribute.key, + that + ); + if ( + attribute.key.toLowerCase() === "label" || + attribute.key.toLowerCase() === "title" || + attribute.key.toLowerCase() === "name" + ) { + that.setLabel(attrObj[attributeId]); + } + default: + if (attribute.options) { + attrObj[attributeId] = new SingleSelectionAttribute( + id + "[" + attribute.key.toLowerCase() + "]", + attribute.key, + that, + attribute.options + ); + } + } + _$node.find("." + key).append(attrObj[attributeId].get$node()); + } + } + that.setAttributes(attrObj); + }; + + /** + * Get anchor options for new connections + * @returns {Object} + */ + this.getAnchorOptions = function () { + return _anchorOptions; + }; + + /** Set anchor options for new connections + * + */ + this.setAnchorOptions = function (anchors) { + _anchorOptions = anchors; + }; + + /** + * Bind source node events for edge tool + */ + this.makeSource = () => { + _$node.addClass("source"); + window.jsPlumbInstance.addEndpoint(_$node.get(0), { + connectorPaintStyle: { fill: "black", strokeWidth: 4 }, + source: true, + endpoint: { + type: "Rectangle", + options: { + width: _$node.width() + 50, + height: _$node.height() + 50, + }, + }, + paintStyle: { fill: "transparent" }, + anchor: AnchorLocations.Center, + deleteOnEmpty: true, + uuid: id + "_eps1", + //maxConnections:1, + uniqueEndpoint: false, + deleteEndpointsOnDetach: true, + onMaxConnections: function (info /*, originalEvent*/) { + console.log( + "element is ", + info.element, + "maxConnections is", + info.maxConnections + ); + }, + }); + }; + + /** + * Bind target node events for edge tool + */ + this.makeTarget = () => { + _$node.addClass("target"); + window.jsPlumbInstance.addEndpoint(_$node.get(0), { + target: true, + endpoint: { + type: "Rectangle", + options: { + width: _$node.width() + 50, + height: _$node.height() + 50, + }, + }, + uuid: id + "_ept1", + paintStyle: { fill: "transparent" }, + anchor: AnchorLocations.Center, + uniqueEndpoint: false, + //maxConnections:1, + deleteOnEmpty: true, + onMaxConnections: function (info /*, originalEvent*/) { + console.log( + "user tried to drop connection", + info.connection, + "on element", + info.element, + "with max connections", + info.maxConnections + ); + }, + }); + + //local user wants to create an edge selected from the pallette + window.jsPlumbInstance.bind("beforeDrop", function (info) { + var allConn = window.jsPlumbInstance.getConnections({ + target: info.targetId, + source: info.sourceId, + }); + var length = allConn.length; + //if true => Detected a duplicated edge + if (length > 0) return false; //don't create the edge + else return true; //no duplicate create the edge + }); + }; + + /** + * Unbind events for edge tool + */ + this.unbindEdgeToolEvents = function () { + try { + _$node.removeClass("source target"); + jsPlumbInstance.getEndpoints(_$node.get(0)).forEach((endpoint) => { + // We need to remove the endpoint that was created to enable node connection by dragging + // since we are not using the edge tool anymore + if (endpoint.connections.length === 0) { + jsPlumbInstance.deleteEndpoint(endpoint); + } + }); + } catch (error) { + console.error(error); + } + }; + + /** + * Get JSON representation of the node + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractNode.prototype.toJSON.call(this); + json.type = type; + return json; + }; + + /** + * set a new shape for the node + * @param $shape + */ + this.set$shape = function ($shape) { + _$template.remove(); + var _$shape = $shape.clone(); + + var attributes = that.getAttributes(); + for (var attrKey in attributes) { + if (attributes.hasOwnProperty(attrKey)) { + var attribute = attributes[attrKey]; + var $tmp = _$shape.find("." + attribute.getName().toLowerCase()); + if ($tmp.length > 0) { + //initialize the value again + if (attribute.getValue().hasOwnProperty("init")) + attribute.getValue().init(); + $tmp.append(attribute.get$node()); + break; + } + } + } + _$template = _$shape; + _$node.append(_$shape); + }; + + this.get$node = function () { + return _$node; + }; + + init(); + + this.registerYMap = function () { + AbstractNode.prototype.registerYMap.call(this); + var labelAttr = that.getLabel(); + if (labelAttr) labelAttr.registerYType(); + var attr = that.getAttributes(); + for (var key in attr) { + if (attr.hasOwnProperty(key)) { + var val = attr[key].getValue(); + if (val.hasOwnProperty("registerYType")) { + val.registerYType(); + } + } + } + }; + } + nodeSelector; + /** + * Get the jquery shape object from the node type + * @static + * @returns {*} + */ + static get$shape() { + return $shape; + } + /** + * Get the anchors of the node type + * @static + * @returns {*} + */ + static getAnchors() { + return anchors; + } + static getAttributes() { + return attributes; + } + } + + return Node; +} + +/** + * AbstractNode + * @class canvas_widget.AbstractNode + * @extends canvas_widget.AbstractEntity + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of node + * @param {string} type Type of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {boolean} containment containment + * @param {number} zIndex Position of node on z-axis + */ + +/** + * ObjectNode + * @class canvas_widget.ObjectNode + * @extends canvas_widget.AbstractNode + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {number} zIndex Position of node on z-axis + */ +class ObjectNode extends AbstractNode { + static TYPE = "Object"; + static DEFAULT_WIDTH = 150; + static DEFAULT_HEIGHT = 100; + constructor(id, left, top, width, height, zIndex, json, y) { + super(id, ObjectNode.TYPE, left, top, width, height, zIndex, json, y); + var that = this; + + /** + * jQuery object of node template + * @type {jQuery} + * @private + */ + var _$template = $(lodash.template(objectNodeHtml)({ type: that.getType() })); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = AbstractNode.prototype.get$node + .call(this) + .append(_$template) + .addClass("object"); + + /** + * jQuery object of DOM node representing the attributes + * @type {jQuery} + * @private + */ + var _$attributeNode = _$node.find(".attributes"); + + /** + * Attributes of node + * @type {Object} + * @private + */ + var _attributes = this.getAttributes(); + + /** + * Get JSON representation of the node + * @returns {Object} + */ + this.toJSON = function () { + return AbstractNode.prototype.toJSON.call(this); + }; + var attr = new KeySelectionValueListAttribute( + "[attributes]", + "Attributes", + this, + { + string: "String", + boolean: "Boolean", + integer: "Integer", + file: "File", + quiz: "Questions", + } + ); + this.addAttribute(attr); + + this.registerYMap = function () { + AbstractNode.prototype.registerYMap.call(this); + that.getLabel().getValue().registerYType(); + attr.registerYMap(); + }; + + _$node.find(".label").append(this.getLabel().get$node()); + + for (var attributeKey in _attributes) { + if (_attributes.hasOwnProperty(attributeKey)) { + _$attributeNode.append(_attributes[attributeKey].get$node()); + } + } + + this.unregisterCallbacks = function () { + that.getAttribute("[attributes]").unregisterCallbacks(); + }; + + this.setContextMenuItemCallback(function () { + return { + addShape: { + name: "Add Node Shape", + callback: function () { + var canvas = that.getCanvas(), + appearance = that.getAppearance(); + + //noinspection JSAccessibilityCheck + const id = canvas.createNode( + NodeShapeNode.TYPE, + appearance.left + appearance.width + 50, + appearance.top, + 150, + 100 + ); + canvas.createEdge( + BiDirAssociationEdge.TYPE, + that.getEntityId(), + id + ); + }, + disabled: function () { + var edges = that.getEdges(), + edge, + edgeId; + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if ( + (edge instanceof BiDirAssociationEdge && + ((edge.getTarget() === that && + edge.getSource() instanceof NodeShapeNode) || + (edge.getSource() === that && + edge.getTarget() instanceof NodeShapeNode))) || + (edge instanceof UniDirAssociationEdge && + edge.getTarget() instanceof NodeShapeNode) + ) { + return true; + } + } + } + return false; + }, + }, + sepConvertTo: "---------", + convertTo: { + name: "Convert to..", + items: { + abstractClassNode: { + name: "..Abstract Class", + callback: function () { + var canvas = that.getCanvas(), + appearance = that.getAppearance(), + nodeId; + + //noinspection JSAccessibilityCheck + nodeId = canvas.createNode( + AbstractClassNode.TYPE, + appearance.left, + appearance.top, + appearance.width, + appearance.height, + that.getZIndex(), + that.toJSON() + ); + var edges = that.getOutgoingEdges(), + edge, + edgeId; + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + canvas.createEdge( + edge.getType(), + nodeId, + edge.getTarget().getEntityId(), + edge.toJSON() + ); + } + } + + edges = that.getIngoingEdges(); + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if (edge.getSource() !== edge.getTarget()) { + canvas.createEdge( + edge.getType(), + edge.getSource().getEntityId(), + nodeId, + edge.toJSON() + ); + } + } + } + + that.triggerDeletion(); + }, + }, + relationshipNode: { + name: "..Relationship", + callback: function () { + var canvas = that.getCanvas(), + appearance = that.getAppearance(), + nodeId; + + //noinspection JSAccessibilityCheck + nodeId = canvas.createNode( + RelationshipNode.TYPE, + appearance.left, + appearance.top, + appearance.width, + appearance.height, + that.getZIndex(), + that.toJSON() + ); + var edges = that.getOutgoingEdges(), + edge, + edgeId; + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + canvas.createEdge( + edge.getType(), + nodeId, + edge.getTarget().getEntityId(), + edge.toJSON() + ); + } + } + + edges = that.getIngoingEdges(); + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if (edge.getSource() !== edge.getTarget()) { + canvas.createEdge( + edge.getType(), + edge.getSource().getEntityId(), + nodeId, + edge.toJSON() + ); + } + } + } + + that.triggerDeletion(); + }, + }, + relationshipGroupNode: { + name: "..Relationship Group", + callback: function () { + var canvas = that.getCanvas(), + appearance = that.getAppearance(), + nodeId; + + //noinspection JSAccessibilityCheck + nodeId = canvas.createNode( + RelationshipGroupNode.TYPE, + appearance.left, + appearance.top, + appearance.width, + appearance.height, + that.getZIndex(), + that.toJSON() + ); + var edges = that.getOutgoingEdges(), + edge, + edgeId; + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + canvas.createEdge( + edge.getType(), + nodeId, + edge.getTarget().getEntityId(), + edge.toJSON() + ); + } + } + + edges = that.getIngoingEdges(); + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if (edge.getSource() !== edge.getTarget()) { + canvas.createEdge( + edge.getType(), + edge.getSource().getEntityId(), + nodeId, + edge.toJSON() + ); + } + } + } + + that.triggerDeletion(); + }, + }, + }, + }, + sep: "---------", + }; + }); + } +} + +/** + * Abstract Class Node + * @class canvas_widget.AbstractClassNode + * @extends canvas_widget.AbstractNode + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {number} zIndex Position of node on z-axis + */ +class AbstractClassNode extends AbstractNode { + static TYPE = "Abstract Class"; + static DEFAULT_WIDTH = 150; + static DEFAULT_HEIGHT = 100; + + constructor(id, left, top, width, height, zIndex, json) { + super(id, AbstractClassNode.TYPE, left, top, width, height, zIndex, json); + + var that = this; + + /** + * jQuery object of node template + * @type {jQuery} + * @private + */ + var _$template = $( + lodash.template(abstractClassNodeHtml)({ type: that.getType() }) + ); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = AbstractNode.prototype.get$node + .call(this) + .append(_$template) + .addClass("class"); + + /** + * jQuery object of DOM node representing the attributes + * @type {jQuery} + * @private + */ + var _$attributeNode = _$node.find(".attributes"); + + /** + * Attributes of node + * @type {Object} + * @private + */ + var _attributes = this.getAttributes(); + + /** + * Get JSON representation of the node + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractNode.prototype.toJSON.call(this); + json.type = AbstractClassNode.TYPE; + return json; + }; + + var attr = new KeySelectionValueListAttribute( + "[attributes]", + "Attributes", + this, + { + string: "String", + boolean: "Boolean", + integer: "Integer", + file: "File", + quiz: "Questions", + } + ); + this.addAttribute(attr); + + this.registerYMap = function () { + AbstractNode.prototype.registerYMap.call(this); + that.getLabel().getValue().registerYType(); + attr.registerYMap(); + }; + + this.unregisterCallbacks = function () { + that.getAttribute("[attributes]").unregisterCallbacks(); + }; + + _$node.find(".label").append(this.getLabel().get$node()); + + for (var attributeKey in _attributes) { + if (_attributes.hasOwnProperty(attributeKey)) { + _$attributeNode.append(_attributes[attributeKey].get$node()); + } + } + + this.setContextMenuItemCallback(function () { + return { + convertTo: { + name: "Convert to..", + items: { + objectNode: { + name: "..Object", + callback: function () { + var canvas = that.getCanvas(), + appearance = that.getAppearance(), + nodeId; + + //noinspection JSAccessibilityCheck + nodeId = canvas.createNode( + ObjectNode.TYPE, + appearance.left, + appearance.top, + appearance.width, + appearance.height, + that.getZIndex(), + that.getContainment(), + that.toJSON() + ); + var edges = that.getOutgoingEdges(), + edge, + edgeId; + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + canvas.createEdge( + edge.getType(), + nodeId, + edge.getTarget().getEntityId(), + edge.toJSON() + ); + } + } + + edges = that.getIngoingEdges(); + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if (edge.getSource() !== edge.getTarget()) { + canvas.createEdge( + edge.getType(), + edge.getSource().getEntityId(), + nodeId, + edge.toJSON() + ); + } + } + } + + that.triggerDeletion(); + }, + }, + relationshipNode: { + name: "..Relationship", + callback: function () { + var canvas = that.getCanvas(), + appearance = that.getAppearance(), + nodeId; + + //noinspection JSAccessibilityCheck + nodeId = canvas.createNode( + RelationshipNode.TYPE, + appearance.left, + appearance.top, + appearance.width, + appearance.height, + that.getZIndex(), + that.getContainment(), + that.toJSON() + ); + var edges = that.getOutgoingEdges(), + edge, + edgeId; + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + canvas.createEdge( + edge.getType(), + nodeId, + edge.getTarget().getEntityId(), + edge.toJSON() + ); + } + } + + edges = that.getIngoingEdges(); + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if (edge.getSource() !== edge.getTarget()) { + canvas.createEdge( + edge.getType(), + edge.getSource().getEntityId(), + nodeId, + edge.toJSON() + ); + } + } + } + + that.triggerDeletion(); + }, + }, + relationshipGroupNode: { + name: "..Relationship Group", + callback: function () { + var canvas = that.getCanvas(), + appearance = that.getAppearance(), + nodeId; + + //noinspection JSAccessibilityCheck + nodeId = canvas.createNode( + RelationshipGroupNode.TYPE, + appearance.left, + appearance.top, + appearance.width, + appearance.height, + that.getZIndex(), + that.getContainment(), + that.toJSON() + ); + var edges = that.getOutgoingEdges(), + edge, + edgeId; + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + canvas.createEdge( + edge.getType(), + nodeId, + edge.getTarget().getEntityId(), + edge.toJSON() + ); + } + } + + edges = that.getIngoingEdges(); + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if (edge.getSource() !== edge.getTarget()) { + canvas.createEdge( + edge.getType(), + edge.getSource().getEntityId(), + nodeId, + edge.toJSON() + ); + } + } + } + + that.triggerDeletion(); + }, + }, + }, + }, + sep: "---------", + }; + }); + } +} + +/** + * RelationshipNode + * @class canvas_widget.RelationshipNode + * @extends canvas_widget.AbstractNode + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {number} zIndex Position of node on z-axis + */ +class RelationshipNode extends AbstractNode { + static TYPE = "Relationship"; + static DEFAULT_WIDTH = 150; + static DEFAULT_HEIGHT = 100; + + constructor(id, left, top, width, height, zIndex, json) { + super(id, "Relationship", left, top, width, height, zIndex, json); + var that = this; + + /** + * jQuery object of node template + * @type {jQuery} + * @private + */ + var _$template = $( + lodash.template(relationshipNodeHtml)({ type: that.getType() }) + ); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var $node = AbstractNode.prototype.get$node + .call(this) + .append(_$template) + .addClass("relation"); + + /** + * jQuery object of DOM node representing the attributes + * @type {jQuery} + * @private + */ + var _$attributeNode = $node.find(".attributes"); + + /** + * Attributes of node + * @type {Object} + * @private + */ + var _attributes = this.getAttributes(); + + /** + * Get JSON representation of the node + * @returns {Object} + */ + this.toJSON = function () { + return AbstractNode.prototype.toJSON.call(this); + }; + + var attr = new KeySelectionValueSelectionValueListAttribute( + "[attributes]", + "Attributes", + this, + { + string: "String", + boolean: "Boolean", + integer: "Integer", + file: "File", + }, + { hidden: "Hide", top: "Top", center: "Center", bottom: "Bottom" } + ); + this.addAttribute(attr); + + this.registerYMap = function () { + AbstractNode.prototype.registerYMap.call(this); + that.getLabel().getValue().registerYType(); + attr.registerYMap(); + }; + + this.unregisterCallbacks = function () { + that.getAttribute("[attributes]").unregisterCallbacks(); + }; + + $node.find(".label").append(this.getLabel().get$node()); + + for (var attributeKey in _attributes) { + if (_attributes.hasOwnProperty(attributeKey)) { + _$attributeNode.append(_attributes[attributeKey].get$node()); + } + } + + this.setContextMenuItemCallback(function () { + return { + addShape: { + name: "Add Edge Shape", + callback: function () { + var canvas = that.getCanvas(), + appearance = that.getAppearance(); + + //noinspection JSAccessibilityCheck + canvas + .createNode( + EdgeShapeNode.TYPE, + appearance.left + appearance.width + 50, + appearance.top, + 150, + 100 + ) + .done(function (nodeId) { + canvas.createEdge( + BiDirAssociationEdge.TYPE, + that.getEntityId(), + nodeId + ); + }); + }, + disabled: function () { + var edges = that.getEdges(), + edge, + edgeId; + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if ( + (edge instanceof BiDirAssociationEdge && + ((edge.getTarget() === that && + edge.getSource() instanceof EdgeShapeNode) || + (edge.getSource() === that && + edge.getTarget() instanceof EdgeShapeNode))) || + (edge instanceof UniDirAssociationEdge && + edge.getTarget() instanceof EdgeShapeNode) + ) { + return true; + } + } + } + return false; + }, + }, + sepConvertTo: "---------", + convertTo: { + name: "Convert to..", + items: { + abstractNode: { + name: "..Abstract Class Node", + callback: function () { + var canvas = that.getCanvas(), + appearance = that.getAppearance(), + nodeId; + + //noinspection JSAccessibilityCheck + nodeId = canvas.createNode( + AbstractClassNode.TYPE, + appearance.left, + appearance.top, + appearance.width, + appearance.height, + that.getZIndex(), + that.toJSON() + ); + var edges = that.getOutgoingEdges(), + edge, + edgeId; + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + canvas.createEdge( + edge.getType(), + nodeId, + edge.getTarget().getEntityId(), + edge.toJSON() + ); + } + } + + edges = that.getIngoingEdges(); + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if (edge.getSource() !== edge.getTarget()) { + canvas.createEdge( + edge.getType(), + edge.getSource().getEntityId(), + nodeId, + edge.toJSON() + ); + } + } + } + + that.triggerDeletion(); + }, + }, + objectNode: { + name: "..Object Node", + callback: function () { + var canvas = that.getCanvas(), + appearance = that.getAppearance(), + nodeId; + + //noinspection JSAccessibilityCheck + nodeId = canvas.createNode( + ObjectNode.TYPE, + appearance.left, + appearance.top, + appearance.width, + appearance.height, + that.getZIndex(), + that.toJSON() + ); + var edges = that.getOutgoingEdges(), + edge, + edgeId; + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + canvas.createEdge( + edge.getType(), + nodeId, + edge.getTarget().getEntityId(), + edge.toJSON() + ); + } + } + + edges = that.getIngoingEdges(); + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if (edge.getSource() !== edge.getTarget()) { + canvas.createEdge( + edge.getType(), + edge.getSource().getEntityId(), + nodeId, + edge.toJSON() + ); + } + } + } + + that.triggerDeletion(); + }, + }, + relationshipGroupNode: { + name: "..Relationship Group", + callback: function () { + var canvas = that.getCanvas(), + appearance = that.getAppearance(), + nodeId; + + //noinspection JSAccessibilityCheck + nodeId = canvas.createNode( + RelationshipGroupNode.TYPE, + appearance.left, + appearance.top, + appearance.width, + appearance.height, + that.getZIndex(), + that.toJSON() + ); + var edges = that.getOutgoingEdges(), + edge, + edgeId; + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + canvas.createEdge( + edge.getType(), + nodeId, + edge.getTarget().getEntityId(), + edge.toJSON() + ); + } + } + + edges = that.getIngoingEdges(); + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if (edge.getSource() !== edge.getTarget()) { + canvas.createEdge( + edge.getType(), + edge.getSource().getEntityId(), + nodeId, + edge.toJSON() + ); + } + } + } + + that.triggerDeletion(); + }, + }, + }, + }, + sep: "---------", + }; + }); + } +} + +/** + * Abstract Class Node + * @class canvas_widget.EdgeShapeNode + * @extends canvas_widget.AbstractNode + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {number} zIndex Position of node on z-axis + */ +class EdgeShapeNode extends AbstractNode { + static TYPE = "Edge Shape"; + static DEFAULT_WIDTH = 150; + static DEFAULT_HEIGHT = 150; + + constructor(id, left, top, width, height, zIndex, json) { + super(id, EdgeShapeNode.TYPE, left, top, width, height, zIndex, json); + var that = this; + + /** + * jQuery object of node template + * @type {jQuery} + * @private + */ + var _$template = $(lodash.template(edgeShapeNodeHtml)({ type: that.getType() })); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = AbstractNode.prototype.get$node + .call(this) + .append(_$template) + .addClass("class"); + + /** + * jQuery object of DOM node representing the attributes + * @type {jQuery} + * @private + */ + var _$attributeNode = _$node.find(".attributes"); + + /** + * Attributes of node + * @type {Object} + * @private + */ + var _attributes = this.getAttributes(); + + /** + * Get JSON representation of the node + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractNode.prototype.toJSON.call(this); + json.type = EdgeShapeNode.TYPE; + return json; + }; + + var attrArrow = new SingleSelectionAttribute( + this.getEntityId() + "[arrow]", + "Arrow", + this, + { + bidirassociation: "---", + unidirassociation: "-->", + generalisation: "--▷", + diamond: "-◁▷", + } + ); + var attrShape = new SingleSelectionAttribute( + this.getEntityId() + "[shape]", + "Shape", + this, + { straight: "Straight", curved: "Curved", segmented: "Segmented" } + ); + var attrColor = new SingleColorValueAttribute( + this.getEntityId() + "[color]", + "Color", + this + ); + var attrOverlay = new SingleValueAttribute( + this.getEntityId() + "[overlay]", + "Overlay Text", + this + ); + var attrOverlayPos = new SingleSelectionAttribute( + this.getEntityId() + "[overlayPosition]", + "Overlay Position", + this, + { hidden: "Hide", top: "Top", center: "Center", bottom: "Bottom" } + ); + var attrOverlayRotate = new BooleanAttribute( + this.getEntityId() + "[overlayRotate]", + "Autoflip Overlay", + this + ); + + this.addAttribute(attrArrow); + this.addAttribute(attrShape); + this.addAttribute(attrColor); + this.addAttribute(attrOverlay); + this.addAttribute(attrOverlayPos); + this.addAttribute(attrOverlayRotate); + + this.registerYMap = function (map) { + AbstractNode.prototype.registerYMap.call(this, map); + attrArrow.getValue().registerYType(); + attrShape.getValue().registerYType(); + attrOverlayPos.getValue().registerYType(); + attrOverlayRotate.getValue().registerYType(); + that.getLabel().getValue().registerYType(); + attrColor.getValue().registerYType(); + attrOverlay.getValue().registerYType(); + }; + + _$node.find(".label").append(this.getLabel().get$node()); + + for (var attributeKey in _attributes) { + if (_attributes.hasOwnProperty(attributeKey)) { + _$attributeNode.append(_attributes[attributeKey].get$node()); + } + } + } +} + +/** + * makeEdge + * @class canvas_widget.makeEdge + * @memberof canvas_widget + * @constructor + * @param {string} type Type of edge + * @param arrowType + * @param shapeType + * @param color + * @param dashstyle + * @param overlay + * @param overlayPosition + * @param overlayRotate + * @param attributes + * @returns {Edge} + */ +function makeEdge( + type, + arrowType, + shapeType, + color, + dashstyle, + overlay, + overlayPosition, + overlayRotate, + attributes +) { + var shape = shapes.hasOwnProperty(shapeType) + ? shapes[shapeType] + : lodash.values(shapes)[0]; + color = color + ? $colorTestElement.css("color", "#000000").css("color", color).css("color") + : "#000000"; + + /** + * Edge + * @class canvas_widget.Edge + * @extends canvas_widget.AbstractEdge + * @constructor + * @param {string} id Entity identifier of edge + * @param {canvas_widget.AbstractNode} source Source node + * @param {canvas_widget.AbstractNode} target Target node + */ + class Edge extends AbstractEdge { + constructor(id, source, target) { + super(id, type, source, target, overlayRotate); + var that = this; + + var currentViewType = null; + + /** + * Set the currently applied view type + * @param {string} type + */ + this.setCurrentViewType = function (type) { + currentViewType = type; + }; + + /** + * Get the currently applied view type + * @returns {string} the view type + */ + this.getCurrentViewType = function () { + return currentViewType; + }; + + /** + * Stores jsPlumb overlays for the edge + * @type {Array} + */ + var overlays = []; + + /** + * make jsPlumb overlay + * @param text + * @returns {Function} + */ + var makeOverlayFunction = function (text) { + return function () { + return $("
                                  ").append( + $("
                                  ") + .addClass("edge_label fixed") + .css("color", color) + .text(text) + ); + }; + }; + + /** + * make a jsPlumb overlay for a attribute + * @param attribute + * @returns {Function} + */ + var makeAttributeOverlayFunction = function (attribute) { + return function () { + const $node = $("
                                  ").append( + $("
                                  ").addClass("edge_label").append(attribute.get$node()) + ); + return $node.get(0); + }; + }; + var init = function () { + var attribute, attributeId, attrObj; + + if (Arrows().hasOwnProperty(arrowType)) { + overlays.push(Arrows(color)[arrowType]); + } + + if (overlay) { + switch (overlayPosition) { + case "top": + overlays.push({ + type: "Custom", + options: { + create: makeOverlayFunction(overlay), + location: 0.9, + id: "label", + }, + }); + break; + case "bottom": + overlays.push({ + type: "Custom", + options: { + create: makeOverlayFunction(overlay), + location: 0.1, + id: "label", + }, + }); + break; + default: + case "center": + overlays.push({ + type: "Custom", + options: { + create: makeOverlayFunction(overlay), + location: 0.5, + id: "label", + }, + }); + break; + } + } + + attrObj = {}; + for (attributeId in attributes) { + if (attributes.hasOwnProperty(attributeId)) { + attribute = attributes[attributeId]; + switch (attribute.value) { + case "boolean": + attrObj[attributeId] = new BooleanAttribute( + id + "[" + attribute.key.toLowerCase() + "]", + attribute.key, + that + ); + break; + case "string": + attrObj[attributeId] = new SingleValueAttribute( + id + "[" + attribute.key.toLowerCase() + "]", + attribute.key, + that + ); + break; + case "integer": + attrObj[attributeId] = new IntegerAttribute( + id + "[" + attribute.key.toLowerCase() + "]", + attribute.key, + that + ); + break; + case "file": + attrObj[attributeId] = new FileAttribute( + id + "[" + attribute.key.toLowerCase() + "]", + attribute.key, + that + ); + break; + default: + if (attribute.options) { + attrObj[attributeId] = new SingleSelectionAttribute( + id + "[" + attribute.key.toLowerCase() + "]", + attribute.key, + that, + attribute.options + ); + } + } + + switch (attribute.position) { + case "top": + overlays.push({ + type: "Custom", + options: { + create: makeAttributeOverlayFunction(attrObj[attributeId]), + location: 1, + id: "label " + attributeId, + }, + }); + break; + case "center": + overlays.push({ + type: "Custom", + options: { + create: makeAttributeOverlayFunction(attrObj[attributeId]), + location: 0.5, + id: "label " + attributeId, + }, + }); + break; + case "bottom": + overlays.push({ + type: "Custom", + options: { + create: makeAttributeOverlayFunction(attrObj[attributeId]), + location: 0, + id: "label " + attributeId, + }, + }); + break; + } + } + } + that.setAttributes(attrObj); + + overlays.push({ + type: "Custom", + options: { + create: function () { + that.get$overlay().hide().find(".type").addClass(shapeType); + return that.get$overlay().get(0); + }, + location: 0.5, + id: "label", + }, + }); + + if (overlay) { + that + .get$overlay() + .find("input[name='Label']") + .css("visibility", "hidden"); + } + + that.setDefaultPaintStyle({ + stroke: color, + strokeWidth: 4, + }); + }; + + /** + * Connect source and target node and draw the edge on canvas + */ + this.connect = function () { + var source = this.getSource(); + var target = this.getTarget(); + var connectOptions = { + source: source.get$node().get(0), + target: target.get$node().get(0), + paintStyle: that.getDefaultPaintStyle(), + endpoint: "Dot", + anchors: [source.getAnchorOptions(), target.getAnchorOptions()], + connector: shape, + overlays: overlays, + cssClass: this.getEntityId(), + }; + + if (source === target) { + connectOptions.anchors = ["TopCenter", "LeftMiddle"]; + } + + source.addOutgoingEdge(this); + target.addIngoingEdge(this); + this.setJsPlumbConnection( + window.jsPlumbInstance.connect(connectOptions) + ); + + this.repaintOverlays(); + lodash.each(EntityManagerInstance.getEdges(), function (e) { + e.setZIndex(); + }); + }; + + /** + * Get JSON representation of the edge + * @returns {object} + */ + this.toJSON = function () { + var json = AbstractEdge.prototype.toJSON.call(this); + json.type = type; + return json; + }; + + /** + * restyles the edge + * @param arrowType + * @param color + * @param shapeType + * @param dashstyle + * @param overlay + * @param overlayPosition + * @param overlayRotate + * @param attributes + */ + this.restyle = function ( + arrowType, + color, + shapeType, + dashstyle, + overlay, + overlayPosition, + overlayRotate, + attributes + ) { + overlays = []; + + color = color + ? $colorTestElement + .css("color", "black") + .css("color", color) + .css("color") + : "black"; + + if (Arrows().hasOwnProperty(arrowType)) { + overlays.push(Arrows(color)[arrowType]); + } + + if (overlay) { + switch (overlayPosition) { + case "top": + overlays.push({ + type: "Custom", + options: { + create: makeOverlayFunction(overlay), + location: 0.9, + id: "label", + }, + }); + break; + case "bottom": + overlays.push({ + type: "Custom", + options: { + create: makeOverlayFunction(overlay), + location: 0.1, + id: "label", + }, + }); + break; + default: + case "center": + overlays.push({ + type: "Custom", + options: { + create: makeOverlayFunction(overlay), + location: 0.5, + id: "label", + }, + }); + break; + } + } + + overlays.push({ + type: "Custom", + options: { + create: function () { + that.get$overlay().hide().find(".type").addClass(shapeType); + return that.get$overlay().get(0); + }, + location: 0.5, + id: "label", + }, + }); + + if (overlay) { + that + .get$overlay() + .find("input[name='Label']") + .css("visibility", "hidden"); + } + + for (var attributeId in attributes) { + if (attributes.hasOwnProperty(attributeId)) { + var attribute = attributes[attributeId]; + switch (attribute.position) { + case "top": + overlays.push({ + type: "Custom", + options: { + create: makeAttributeOverlayFunction( + that.getAttribute(attributeId) + ), + location: 1, + id: "label " + attributeId, + }, + }); + break; + case "center": + overlays.push({ + type: "Custom", + options: { + create: makeAttributeOverlayFunction( + that.getAttribute(attributeId) + ), + location: 0.5, + id: "label " + attributeId, + }, + }); + break; + case "bottom": + overlays.push({ + type: "Custom", + options: { + create: makeAttributeOverlayFunction( + that.getAttribute(attributeId) + ), + location: 0, + id: "label " + attributeId, + }, + }); + break; + } + } + } + + var paintStyle = { + strokeStyle: color, + lineWidth: 2, + dashstyle: dashstyle, + }; + + that.setDefaultPaintStyle(paintStyle); + that.setRotateOverlay(overlayRotate); + + if (that.getJsPlumbConnection()) { + //if the edge is drawn on the canvas + that.getJsPlumbConnection().removeAllOverlays(); + for (var i = 0; i < overlays.length; i++) { + that.getJsPlumbConnection().addOverlay(overlays[i]); + } + that.getJsPlumbConnection().setPaintStyle(paintStyle); + that.repaintOverlays(); + } + }; + + this.registerYMap = function () { + AbstractEdge.prototype.registerYMap.call(this); + + var attr = that.getAttributes(); + for (var key in attr) { + if (attr.hasOwnProperty(key)) { + var val = attr[key].getValue(); + if (val.hasOwnProperty("registerYType")) { + val.registerYType(); + } + } + } + }; + + init(); + } + /** + * Get the arrow type of the edge type + * @static + * @returns {*} + */ + static getArrowType() { + return arrowType; + } + /** + * Get the shape type of the edge type + * @static + * @returns {*} + */ + static getShapeType() { + return shapeType; + } + /** + * Get the color of the edge type + * @static + * @returns {*} + */ + static getShape() { + return shape; + } + static getColor() { + return color; + } + /** + * Get the overlay of the edge type + * @static + * @returns {*} + */ + static getOverlay() { + return overlay; + } + /** + * Get the overlay position of the edge type + * @static + * @returns {*} + */ + static getOverlayPosition() { + return overlayPosition; + } + /** + * Get the overlay rotate of the edge type + * @static + * @returns {*} + */ + static getOverlayRotate() { + return overlayRotate; + } + /** + * Get the attribute definition of the edge type + * @static + * @returns {*} + */ + static getAttributes() { + return attributes; + } + static getType() { + return type; + } + static getArrowOverlays() { + var overlays = []; + if (Arrows().hasOwnProperty(arrowType)) { + overlays.push(Arrows(color)[arrowType]); + } + return overlays; + } + } + + return Edge; +} + +/** + * AbstractNode + * @class canvas_widget.AbstractNode + * @extends canvas_widget.AbstractEntity + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of node + * @param {string} type Type of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {boolean} containment containment + * @param {number} zIndex Position of node on z-axis + */ + +/** + * Abstract Class Node + * @class canvas_widget.RelationshipGroupNode + * @extends canvas_widget.AbstractNode + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {number} zIndex Position of node on z-axis + */ +class RelationshipGroupNode extends AbstractNode { + static TYPE = "Relation"; + static DEFAULT_WIDTH = 150; + static DEFAULT_HEIGHT = 100; + constructor(id, left, top, width, height, zIndex) { + super(id, RelationshipGroupNode.TYPE, left, top, width, height, zIndex); + var that = this; + + /** + * jQuery object of node template + * @type {jQuery} + * @private + */ + var _$template = $( + lodash.template(relationshipGroupNodeHtml)({ type: that.getType() }) + ); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = AbstractNode.prototype.get$node + .call(this) + .append(_$template) + .addClass("class"); + + /** + * jQuery object of DOM node representing the attributes + * @type {jQuery} + * @private + */ + var _$attributeNode = _$node.find(".attributes"); + + /** + * Attributes of node + * @type {Object} + * @private + */ + var _attributes = this.getAttributes(); + + /** + * Get JSON representation of the node + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractNode.prototype.toJSON.call(this); + json.type = RelationshipGroupNode.TYPE; + return json; + }; + + this.registerYMap = function () { + AbstractNode.prototype.registerYMap.call(this); + that.getLabel().getValue().registerYType(); + }; + + _$node.find(".label").append(this.getLabel().get$node()); + + for (var attributeKey in _attributes) { + if (_attributes.hasOwnProperty(attributeKey)) { + _$attributeNode.append(_attributes[attributeKey].get$node()); + } + } + } +} + +/** + * SelectionValue + * @class canvas_widget.SelectionValue + * @extends canvas_widget.AbstractValue + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier + * @param {string} name Name of attribute + * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {canvas_widget.AbstractNode|canvas_widget.AbstractEdge} rootSubjectEntity Topmost entity in the chain of entity the attribute is assigned to + * @param {Object} options Selection options + */ +class SelectionValue extends AbstractValue { + constructor( + id, + name, + subjectEntity, + rootSubjectEntity, + options, + useAttributeHtml + ) { + super(id, name, subjectEntity, rootSubjectEntity); + + var that = this; + + useAttributeHtml = + typeof useAttributeHtml !== "undefinded" ? useAttributeHtml : false; + + /** + * Value + * @type {string} + * @private + */ + var _value = lodash.keys(options)[0]; + + if (useAttributeHtml) { + selectionValueHtml = attributeSelectionValueHtml; + } + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = $( + lodash.template(selectionValueHtml)({ + name: name, + options: options, + }) + ); + + if (useAttributeHtml) { + _$node.off(); + } + + /** + * Inter widget communication wrapper + * @type {Object} + * @private + */ + y = y || window.y; + var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); + + /** + * Apply a Value Change Operation + * @param {operations.ot.ValueChangeOperation} operation + */ + var processValueChangeOperation = function (operation) { + that.setValue(operation.getValue()); + }; + + /** + * Set value + * @param {string} value + */ + this.setValue = function (value) { + _value = value; + if (useAttributeHtml) { + _$node.val(value); + if (value == "Quiz") { + Object.values(rootSubjectEntity.getAttributes()).forEach((value) => { + if (value instanceof QuizAttribute) { + value.showTable(); + } + }); + } else + Object.values(rootSubjectEntity.getAttributes()).forEach((value) => { + if (value instanceof QuizAttribute) { + value.hideTable(); + } + }); + } else _$node.text(options[value]); + }; + + /** + * Get value + * @returns {string} + */ + this.getValue = function () { + return _value; + }; + + /** + * Get jQuery object of DOM node representing the value + * @returns {jQuery} + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the edge + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractValue.prototype.toJSON.call(this); + json.value = _value; + return json; + }; + + /** + * Set value by its JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + this.setValue(json.value); + }; + + this.registerYType = function () { + //observer + that + .getRootSubjectEntity() + .getYMap() + .observeDeep(function ([event]) { + const array = Array.from(event.changes.keys.entries()); + array.forEach(([key]) => { + const updated = event.currentTarget.get(key); + if ( + updated?.type !== "update" || + !(updated?.entityId === that.getEntityId()) + ) + return; + var operation = new ValueChangeOperation( + updated.entityId, + updated.value, + updated.type, + updated.position, + updated.jabberId + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.getOTOperation() + ); + processValueChangeOperation(operation); + + //Only the local user Propagates the activity and saves the state of the model + if ( + _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID] === + operation.getJabberId() + ) { + const activityMap = y.getMap("activity"); + + activityMap.set( + ActivityOperation.TYPE, + new ActivityOperation( + "ValueChangeActivity", + that.getEntityId(), + _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], + ValueChangeOperation.getOperationDescription( + that.getSubjectEntity().getName(), + that.getRootSubjectEntity().getType(), + that.getRootSubjectEntity().getLabel().getValue().getValue() + ), + { + value: operation.getValue(), + subjectEntityName: that.getSubjectEntity().getName(), + rootSubjectEntityType: that + .getRootSubjectEntity() + .getType(), + rootSubjectEntityId: that + .getRootSubjectEntity() + .getEntityId(), + } + ).toJSON() + ); + + //its a view type and create a reference to the origin + if (updated.entityId.indexOf("[target]") != -1) { + ViewTypesUtil.createReferenceToOrigin( + that.getRootSubjectEntity() + ); + //CVG + Promise.resolve().then(function () { return ClosedViewGeneration; }).then(function (CVG) { + CVG(rootSubjectEntity); + }); + } + //trigger the save + EntityManagerInstance.storeDataYjs(); + } else { + //the remote users propagtes the change to their local attribute widget + //TODO(PENDING): can be replaced with yjs as well + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.ATTRIBUTE, + operation.getOTOperation() + ); + } + }); + }); + }; + } +} + +/** + * IntegerAttribute + * @class canvas_widget.IntegerAttribute + * @extends canvas_widget.AbstractAttribute + * @memberof canvas_widget + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to + */ +class IntegerAttribute extends AbstractAttribute { + constructor(id, name, subjectEntity, useAttributeHtml) { + super(id, name, subjectEntity); + useAttributeHtml = + typeof useAttributeHtml !== "undefined" ? useAttributeHtml : false; + + /*** + * Value object of value + * @type {canvas_widget.IntegerValue} + * @private + */ + var _value = new IntegerValue( + id, + name, + this, + this.getRootSubjectEntity(), + useAttributeHtml + ); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(integerAttributeHtml)()); + + /** + * Set Value object of value + * @param {canvas_widget.IntegerValue} value + */ + this.setValue = function (value) { + _value = value; + _$node.val(value); + }; + + /** + * Get Value object of value + * @return {canvas_widget.IntegerValue} value + */ + this.getValue = function () { + return _value; + }; + + /** + * jQuery object of DOM node representing the attribute + * @type {jQuery} + * @private + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the attribute + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.value = _value.toJSON(); + return json; + }; + + /** + * Set attribute value by its JSON representation + * @param {Object} json + */ + this.setValueFromJSON = function (json) { + _value.setValueFromJSON(json.value); + }; + + _$node.find(".name").text(this.getName()); + _$node.find(".value").append(_value.get$node()); + } +} + +/** + * SingleSelectionAttribute + * @class canvas_widget.SingleSelectionAttribute + * @extends canvas_widget.AbstractAttribute + * @memberof canvas_widget + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {Object} options Selection options as key value object + */ + +class SingleSelectionAttribute extends AbstractAttribute { + constructor(id, name, subjectEntity, options, useAttributeHtml) { + super(id, name, subjectEntity); + useAttributeHtml = + typeof useAttributeHtml !== "undefinded" ? useAttributeHtml : false; + var that = this; + /*** + * Value object of value + * @type {canvas_widget.SelectionValue} + * @private + */ + var _value = new SelectionValue( + id, + name, + this, + this.getRootSubjectEntity(), + options, + useAttributeHtml + ); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(singleSelectionAttributeHtml)()); + + /** + * Set Value object of value + * @param {canvas_widget.SelectionValue} value + */ + this.setValue = function (value) { + _value = value; + _$node.val(value); + }; + + /** + * Get Value object of value + * @return {canvas_widget.SelectionValue} value + */ + this.getValue = function () { + return _value; + }; + + /** + * jQuery object of DOM node representing the attribute + * @type {jQuery} + * @private + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get the options object for the Attribute + * @returns {Object} + */ + this.getOptionValue = function () { + return options.hasOwnProperty(_value.getValue()) + ? options[_value.getValue()] + : null; + }; + + /** + * Get JSON representation of the attribute + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.value = _value.toJSON(); + json.option = that.getOptionValue(); + return json; + }; + + this.getOptions = function () { + return options; + }; + + /** + * Set attribute value by its JSON representation + * @param {Object} json + */ + this.setValueFromJSON = function (json) { + _value.setValueFromJSON(json.value); + }; + + _$node.find(".name").text(this.getName()); + _$node.find(".value").append(_value.get$node()); + } +} + +/** + * IntegerValue + * @class canvas_widget.IntegerValue + * @extends canvas_widget.AbstractValue + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier + * @param {string} name Name of attribute + * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {canvas_widget.AbstractNode|canvas_widget.AbstractEdge} rootSubjectEntity Topmost entity in the chain of entity the attribute is assigned to + */ +class IntegerValue extends AbstractValue { + constructor(id, name, subjectEntity, rootSubjectEntity, useAttributeHtml) { + super(id, name, subjectEntity, rootSubjectEntity); + var that = this; + + if (useAttributeHtml) integerValueHtml = attributeIntegerValueHtml; + + /** + * Value + * @type {number} + * @private + */ + var _value = 0; + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(integerValueHtml)({ value: _value })); + + /** + * Inter widget communication wrapper + * @type {Object} + * @private + */ + y = y || window.y; + var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); + + /** + * Apply a Value Change Operation + * @param {operations.ot.ValueChangeOperation} operation + */ + var processValueChangeOperation = function (operation) { + that.setValue(operation.getValue()); + }; + + var init = function () { + _$node.off(); + }; + + /** + * Set value + * @param {number} value + */ + this.setValue = function (value) { + _value = value; + if (useAttributeHtml) _$node.val(value); + else _$node.text(value); + }; + + /** + * Get value + * @returns {number} + */ + this.getValue = function () { + return _value; + }; + + /** + * Get jQuery object of DOM node representing the value + * @returns {jQuery} + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the edge + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractValue.prototype.toJSON.call(this); + json.value = _value; + return json; + }; + + /** + * Set value by its JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + this.setValue(json?.value); + }; + + this.registerYType = function () { + //observer + that + .getRootSubjectEntity() + .getYMap() + .observe(function (event) { + const array = Array.from(event.changes.keys.entries()); + array.forEach(([key, change]) => { + if (change.action !== "update") return; + // check if key is the entity id + if (key !== that.getEntityId()) return; + const data = event.target.get(key); + var operation = new ValueChangeOperation( + data.entityId, + data.value, + data.type, + data.position, + data.jabberId + ); + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.GUIDANCE, + operation.getOTOperation() + ); + processValueChangeOperation(operation); + + //Only the local user Propagates the activity + if ( + _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID] === + operation.getJabberId() + ) { + EntityManagerInstance.storeDataYjs(); + const activityMap = y.getMap("activity"); + + activityMap.set( + ActivityOperation.TYPE, + new ActivityOperation( + "ValueChangeActivity", + that.getEntityId(), + _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID], + ValueChangeOperation.getOperationDescription( + that.getSubjectEntity().getName(), + that.getRootSubjectEntity().getType(), + that.getRootSubjectEntity().getLabel().getValue().getValue() + ), + { + value: operation.getValue(), + subjectEntityName: that.getSubjectEntity().getName(), + rootSubjectEntityType: that + .getRootSubjectEntity() + .getType(), + rootSubjectEntityId: that + .getRootSubjectEntity() + .getEntityId(), + } + ).toJSON() + ); + } else { + //the remote users propagtes the change to their local attribute widget + //TODO(PENDING): can be replaced with yjs as well + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.ATTRIBUTE, + operation.getOTOperation() + ); + } + }); + }); + }; + + init(); + } +} + +/** + * SingleValueAttribute + * @class canvas_widget.SingleValueAttribute + * @extends canvas_widget.AbstractAttribute + * @memberof canvas_widget + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to + */ +class SingleValueAttribute extends AbstractAttribute { + value; + constructor(id, name, subjectEntity, y) { + y = y || window.y; + if (!y) { + throw new Error("y is undefined"); + } + super(id, name, subjectEntity); + + /*** + * Value object of value + * @type {canvas_widget.Value} + * @private + */ + var _value = new Value(id, name, this, this.getRootSubjectEntity(), y); + this.value = _value; + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(canvasSingleValueAttributeHtml)()); + + /** + * Set Value object of value + * @param {canvas_widget.Value} value + */ + this.setValue = function (value) { + _value = value; + this.value = value; + }; + + /** + * Get Value object of value + * @returns {canvas_widget.Value} + */ + this.getValue = function () { + return _value; + }; + + /** + * jQuery object of DOM node representing the attribute + * @type {jQuery} + * @private + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the attribute + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.value = _value.toJSON(); + return json; + }; + + /** + * Set attribute value by its JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + _value.setValueFromJSON(json.value); + }; + + this.registerYType = function () { + _value.registerYType(); + }; + + _$node.find(".name").text(this.getName()); + _$node.find(".value").append(_value.get$node()); + } +} + +/** + * SingleValueListAttribute + * @class canvas_widget.SingleValueListAttribute + * @extends canvas_widget.AbstractAttribute + * @memberof canvas_widget + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to + */ +class SingleValueListAttribute extends AbstractAttribute { + static TYPE = "SingleValueListAttribute"; + constructor(id, name, subjectEntity) { + super(id, name, subjectEntity); + var that = this; + + /** + * List of attributes + * @type {Object} + * @private + */ + var _list = {}; + + /** + * jQuery object of DOM node representing the attribute + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(singleValueListAttributeHtml)()); + y = y || window.y; + /** + * Inter widget communication wrapper + * @type {Object} + */ + var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); + + /** + * Apply an Attribute Add Operation + * @param {operations.ot.AttributeAddOperation} operation + */ + var processAttributeAddOperation = function (operation) { + var attribute = new SingleValueAttribute( + operation.getEntityId() + "[value]", + "Attribute", + that + ); + attribute.registerYType(); + that.addAttribute(attribute); + _$node.find(".list").append(attribute.get$node()); + }; + + /** + * Apply an Attribute Delete Operation + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var processAttributeDeleteOperation = function (operation) { + var attribute = that.getAttribute(operation.getEntityId()); + if (attribute) { + that.deleteAttribute(attribute.getEntityId()); + attribute.get$node().remove(); + } + }; + /** + * Propagate an Attribute Add Operation to the remote users and the local widgets + * @param {operations.ot.AttributeAddOperation} operation + */ + var propagateAttributeAddOperation = function (operation) { + processAttributeAddOperation(operation); + EntityManagerInstance.storeDataYjs(); + }; + + /** + * Propagate an Attribute Delete Operation to the remote users and the local widgets + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var propagateAttributeDeleteOperation = function (operation) { + processAttributeDeleteOperation(operation); + var ynode = that.getRootSubjectEntity().getYMap(); + ynode.delete(operation.getEntityId()); + EntityManagerInstance.storeDataYjs(); + }; + + /** + * Callback for a remote Attrbute Add Operation + * @param {operations.ot.AttributeAddOperation} operation + */ + var remoteAttributeAddCallback = function (operation) { + if ( + operation instanceof AttributeAddOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + processAttributeAddOperation(operation); + } + }; + + /** + * Callback for a remote Attribute Delete Operation + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var remoteAttributeDeleteCallback = function (operation) { + if ( + operation instanceof AttributeDeleteOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + processAttributeDeleteOperation(operation); + } + }; + + var localAttributeAddCallback = function (operation) { + if ( + operation instanceof AttributeAddOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + propagateAttributeAddOperation(operation); + } + }; + + /** + * Callback for a local Attribute Delete Operation + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var localAttributeDeleteCallback = function (operation) { + if ( + operation instanceof AttributeDeleteOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + propagateAttributeDeleteOperation(operation); + } + }; + + /** + * Add attribute to attribute list + * @param {canvas_widget.AbstractAttribute} attribute + */ + this.addAttribute = function (attribute) { + var id = attribute.getEntityId(); + if (!_list.hasOwnProperty(id)) { + _list[id] = attribute; + } + }; + + /** + * Get attribute of attribute list by its entity id + * @param id + * @returns {canvas_widget.AbstractAttribute} + */ + this.getAttribute = function (id) { + if (_list.hasOwnProperty(id)) { + return _list[id]; + } + return null; + }; + + /** + * Delete attribute from attribute list by its entity id + * @param {string} id + */ + this.deleteAttribute = function (id) { + if (_list.hasOwnProperty(id)) { + delete _list[id]; + } + }; + + /** + * Get attribute list + * @returns {Object} + */ + this.getAttributes = function () { + return _list; + }; + + /** + * Set attribute list + * @param {Object} list + */ + this.setAttributes = function (list) { + _list = list; + }; + + /** + * Get jQuery object of the DOM node representing the attribute (list) + * @returns {jQuery} + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the attribute (list) + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.type = SingleValueListAttribute.TYPE; + var attr = {}; + lodash.forEach(this.getAttributes(), function (val, key) { + attr[key] = val.toJSON(); + }); + json.list = attr; + return json; + }; + + /** + * Set attribute list by its JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + lodash.forEach(json.list, function (val, key) { + var attribute = new SingleValueAttribute(key, key, that, y); + attribute.setValueFromJSON(json.list[key]); + that.addAttribute(attribute); + _$node.find(".list").append(attribute.get$node()); + }); + }; + + /** + * Register inter widget communication callbacks + */ + this.registerCallbacks = function () { + _iwcw.registerOnDataReceivedCallback(localAttributeAddCallback); + _iwcw.registerOnDataReceivedCallback(localAttributeDeleteCallback); + }; + + /** + * Unregister inter widget communication callbacks + */ + this.unregisterCallbacks = function () { + _iwcw.unregisterOnDataReceivedCallback(localAttributeAddCallback); + _iwcw.unregisterOnDataReceivedCallback(localAttributeDeleteCallback); + }; + + _$node.find(".name").text(this.getName()); + + for (var attributeId in _list) { + if (_list.hasOwnProperty(attributeId)) { + _$node.find(".list").append(_list[attributeId].get$node()); + } + } + + if (_iwcw) { + that.registerCallbacks(); + } + this.registerYMap = function () { + var ymap = that.getRootSubjectEntity().getYMap(); + + var attrs = that.getAttributes(); + for (var key in attrs) { + if (attrs.hasOwnProperty(key)) { + var attr = attrs[key]; + attr.getValue().registerYType(); + } + } + + ymap.observe(function (event) { + var operation; + + const array = Array.from(event.changes.keys.entries()); + array.forEach(([key, change]) => { + if (key.indexOf("[value]") != -1) { + switch (change.action) { + case "add": { + if (event.currentTarget.get("modifiedBy") === window.y.clientID) + return; + + operation = new AttributeAddOperation( + key.replace(/\[\w*\]/g, ""), + that.getEntityId(), + that.getRootSubjectEntity().getEntityId(), + that.constructor.name + ); + remoteAttributeAddCallback(operation); + break; + } + case "delete": { + operation = new AttributeDeleteOperation( + key, + that.getEntityId(), + that.getRootSubjectEntity().getEntityId(), + that.constructor.name + ); + remoteAttributeDeleteCallback(operation); + } + } + } + }); + }); + }; + } +} + +/** + * Value + * @class canvas_widget.Value + * @extends canvas_widget.AbstractValue + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier + * @param {string} name Name of attribute + * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {canvas_widget.AbstractNode|canvas_widget.AbstractEdge} rootSubjectEntity Topmost entity in the chain of entity the attribute is assigned to + */ +class Value extends AbstractValue { + value = ""; + constructor(id, name, subjectEntity, rootSubjectEntity, y) { + super(id, name, subjectEntity, rootSubjectEntity); + y = y || window.y; + if (!y) throw new Error("y is undefined"); + var _ytext = null; + + const yMap = rootSubjectEntity.getYMap(); + if (!yMap) { + throw new Error("yMap is undefined"); + } + y.transact(() => { + if (yMap?.has(id)) { + _ytext = rootSubjectEntity.getYMap().get(id); + if (!(_ytext instanceof Text)) { + _ytext = new Text(); + rootSubjectEntity.getYMap().set(id, _ytext); + } + } else { + _ytext = new Text(); + rootSubjectEntity.getYMap().set(id, _ytext); + } + rootSubjectEntity.getYMap().set("modifiedBy", window.y.clientID); + }); + + var that = this; + /** + * Value + * @type {string} + * @private + */ + var _value = ""; + this.value = _value; + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(valueHtml)({ name: name })); + + /** + * Set value + * @param {string} value + */ + this.setValue = function (value) { + _value = value; + _$node.text(value); + + this.value = _ytext.toString(); + }; + + /** + * Get value + * @returns {string} + */ + this.getValue = function () { + return _value; + }; + + /** + * Get jQuery object of DOM node representing the value + * @returns {jQuery} + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the edge + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractValue.prototype.toJSON.call(this); + json.value = _value; + return json; + }; + + /** + * Set value by its JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + this.setValue(json.value); + }; + + this.registerYType = function () { + _ytext.observe( + lodash.debounce(function (event) { + _value = _ytext.toString().replace(/\n/g, ""); + that.setValue(_value); + if (event.currentTarget.get("modifiedBy") === window.y.clientID) { + EntityManagerInstance.storeDataYjs(); + const userMap = y.getMap("users"); + const jabberId = userMap.get(event.currentTarget.doc.clientID); + + const activityMap = y.getMap("activity"); + activityMap.set( + ActivityOperation.TYPE, + new ActivityOperation( + "ValueChangeActivity", + that.getEntityId(), + jabberId, + ValueChangeOperation.getOperationDescription( + that.getSubjectEntity().getName(), + that.getRootSubjectEntity().getType(), + that.getRootSubjectEntity().getLabel().getValue().getValue() + ), + { + value: _value, + subjectEntityName: that.getSubjectEntity().getName(), + rootSubjectEntityType: that.getRootSubjectEntity().getType(), + rootSubjectEntityId: that + .getRootSubjectEntity() + .getEntityId(), + } + ).toJSON() + ); + } + }, 500) + ); + }; + + this.getYText = function () { + return _ytext; + }; + + //automatically determines the size of input + _$node + .autoGrowInput({ + comfortZone: 15, + minWidth: 40, + maxWidth: 1000, + }) + .trigger("blur"); + } +} + +/** + * QuizAttribute + * @class attribute_widget.SingleValueAttribute + * @memberof attribute_widget + * @extends attribute_widget.AbstractAttribute + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {attribute_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to + */ +class QuizAttribute extends AbstractAttribute { + constructor(id, name, subjectEntity) { + super(id, name, subjectEntity); + /*** + * Value object of value + * @type {attribute_widget.Value} + * @private + */ + var _value = new Value(id, name, this, this.getRootSubjectEntity()); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(singleQuizAttributeHtml)({ id: id })); + + /** + * Set Value object of value + * @param {attribute_widget.Value} value + */ + this.setValue = function (value) { + _value = value; + }; + + /** + * Get Value object of value + * @returns {attribute_widget.Value} + */ + this.getValue = function () { + return _value; + }; + + /** + * jQuery object of DOM node representing the attribute + * @type {jQuery} + * @public + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the attribute + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.value = _value.toJSON(); + return json; + }; + + /** + * Set attribute value by its JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + _value.setValueFromJSON(json.value); + }; + + this.registerYType = function () { + _value.registerYType(); + }; + + _$node.find(".name").text(this.getName()); + _$node.find(".value").append(_value.get$node()); + + function addRow() { + var table = _$node.find("#table")[0]; + var rows = table.rows.length; + var row = table.insertRow(table.rows.length); + var cell0 = row.insertCell(0); + var cell1 = row.insertCell(1); + var cell2 = row.insertCell(2); + var cell3 = row.insertCell(3); + var input0 = document.createElement("input"); + var input1 = document.createElement("input"); + var input2 = document.createElement("input"); + var input3 = document.createElement("input"); + input0.id = rows + "0"; + input1.id = rows + "1"; + input2.id = rows + "2"; + input3.id = rows + "3"; + input1.type = "text"; + input2.type = "text"; + input3.type = "text"; + cell0.appendChild(input0); + cell1.appendChild(input1); + cell2.appendChild(input2); + cell3.appendChild(input3); + } + + this.showTable = function () { + _$node.find("#table")[0].style.visibility = "visible"; + _$node.find("#b")[0].style.visibility = "visible"; + _$node.find("#c")[0].style.visibility = "visible"; + _$node.find("#submit")[0].style.visibility = "visible"; + _$node.find("#display")[0].style.visibility = "visible"; + }; + + this.hideTable = function () { + _$node.find("#table")[0].style.visibility = "hidden"; + _$node.find("#b")[0].style.visibility = "hidden"; + _$node.find("#c")[0].style.visibility = "hidden"; + _$node.find("#submit")[0].style.visibility = "hidden"; + _$node.find("#display")[0].style.visibility = "hidden"; + }; + + _$node.find("#b").click(function () { + addRow(); + }); + + // remove rows from table + _$node.find("#c").click(function () { + var table = _$node.find("#table")[0]; + var rows = table.rows.length; + table.deleteRow(rows - 1); + }); + + // write table input into attribute field + _$node.find("#submit").click(function () { + var table = _$node.find("#table")[0]; + var Json = {}; + Json["topic"] = _$node.find("#topic")[0].value; + var Sequence = []; + var Questions = []; + var Intents = []; + var Hints = []; + var row = table.rows.length; + for (var i = 2; i < row; i++) { + if ( + _$node.find("#" + i.toString() + "1")[0].value == "" || + _$node.find("#" + i.toString() + "2")[0].value == "" + ) { + continue; + } + Sequence.push(_$node.find("#" + i.toString() + "0")[0].value); + Questions.push(_$node.find("#" + i.toString() + "1")[0].value); + Intents.push(_$node.find("#" + i.toString() + "2")[0].value); + if (_$node.find("#" + i.toString() + "3")[0].value == "") { + Hints.push("No Hint Available for this Question"); + } else Hints.push(_$node.find("#" + i.toString() + "3")[0].value); + } + Json["Questions"] = Questions; + Json["Sequence"] = Sequence; + Json["Intents"] = Intents; + Json["Hints"] = Hints; + console.log(JSON.stringify(Json)); + _$node.find(".val")[0].value = JSON.stringify(Json); + var field = _$node.find(".val")[0]; + field.dispatchEvent(new Event("input")); + }); + + // take content from attribute field and display as table + _$node.find("#display").click(function () { + var table = _$node.find("#table")[0]; + var Json = _$node.find(".val")[0].value; + console.log(Json); + var content = JSON.parse(Json); + _$node.find("#topic")[0].value = content.topic; + var rowNumb = content.Questions.length; + console.log(rowNumb); + var currRows = table.rows.length - 2; + console.log(currRows); + if (currRows < rowNumb) { + for (currRows; currRows < rowNumb; currRows++) { + addRow(); + } + } + for (var i = 2; i < rowNumb + 2; i++) { + if (_$node.find("#" + i.toString() + "0")[0].value == null) { + break; + } + _$node.find("#" + i.toString() + "0")[0].value = + content.Sequence[i - 2]; + _$node.find("#" + i.toString() + "1")[0].value = + content.Questions[i - 2]; + _$node.find("#" + i.toString() + "2")[0].value = content.Intents[i - 2]; + _$node.find("#" + i.toString() + "3")[0].value = content.Hints[i - 2]; + } + }); + } +} + +/** + * KeySelectionValueAttribute + * @class canvas_widget.KeySelectionValueAttribute + * @extends canvas_widget.AbstractAttribute + * @memberof canvas_widget + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {Object} options Selection options + */ +class KeySelectionValueAttribute extends AbstractAttribute { + constructor(id, name, subjectEntity, options) { + super(id, name, subjectEntity); + + var _ymap = null; + + //noinspection UnnecessaryLocalVariableJS + /** + * Selection options + * @type {Object} + * @private + */ + var _options = options; + + /** + * Value object of key + * @type {canvas_widget.Value} + * @private + */ + var _key = new Value(id + "[key]", "", this, this.getRootSubjectEntity()); + + /*** + * Value object of value + * @type {canvas_widget.Value} + * @private + */ + var _value = new SelectionValue( + id + "[value]", + "", + this, + this.getRootSubjectEntity(), + _options + ); + + /** + * jQuery object of the DOM node representing the attribute + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(keySelectionValueAttributeHtml)({ id: id })); + + //noinspection JSUnusedGlobalSymbols + /** + * Set Value object of key + * @param {canvas_widget.Value} key + */ + this.setKey = function (key) { + _key = key; + }; + + /** + * Get Value object of key + * @returns {canvas_widget.Value} + */ + this.getKey = function () { + return _key; + }; + + /** + * Set Value object of value + * @param {canvas_widget.Value} value + */ + this.setValue = function (value) { + _value = value; + }; + + /** + * Get Value object of value + * @returns {canvas_widget.Value} + */ + this.getValue = function () { + return _value; + }; + + /** + * Get jQuery object of the DOM node representing the attribute + * @returns {jQuery} + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the attribute + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.key = _key.toJSON(); + json.value = _value.toJSON(); + return json; + }; + + /** + * Set value of key and value by their JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + _key.setValueFromJSON(json.key); + _value.setValueFromJSON(json.value); + }; + + this.registerYMap = function () { + _key.registerYType(); + _value.registerYType(); + }; + + this.getYMap = function () { + return _ymap; + }; + + _$node.find(".key").append(_key.get$node()); + _$node.find(".value").append(_value.get$node()); + } +} + +/** + * ConditionListAttribute + * @class canvas_widget.ConditionListAttribute + * @extends canvas_widget.AbstractAttribute + * @memberof canvas_widget + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {Object} options Selection options + * @param {Object} options2 Selection options + */ +class ConditionListAttribute extends AbstractAttribute { + static TYPE = "ConditionListAttribute"; + constructor(id, name, subjectEntity, options, options2, y) { + y = y || window.y; + super(id, name, subjectEntity); + var that = this; + + /** + * Selection options + * @type {Object} + * @private + */ + var _options = options; + + /** + * Selection options + * @type {Object} + * @private + */ + var _options2 = options2; + + /** + * List of attributes + * @type {Object} + * @private + */ + var _list = {}; + + /** + * jQuery object of DOM node representing the attribute + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(listHtml)()); + + /** + * Inter widget communication wrapper + * @type {Object} + */ + var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); + + /** + * Apply an Attribute Add Operation + * @param {operations.ot.AttributeAddOperation} operation + * @param {YText} ytext + */ + var processAttributeAddOperation = function (operation) { + var attribute = new ConditionPredicateAttribute( + operation.getEntityId(), + "Attribute", + that, + _options, + _options2 + ); + attribute.registerYMap(); + that.addAttribute(attribute); + _$node.find(".list").append(attribute.get$node()); + }; + + /** + * Propagate an Attribute Add Operation to the remote users and the local widgets + * @param {operations.ot.AttributeAddOperation} operation + */ + var propagateAttributeAddOperation = function (operation) { + processAttributeAddOperation(operation); + EntityManagerInstance.storeDataYjs(); + }; + + /** + * Apply an Attribute Delete Operation + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var processAttributeDeleteOperation = function (operation) { + var attribute = that.getAttribute(operation.getEntityId()); + if (attribute) { + that.deleteAttribute(attribute.getEntityId()); + attribute.get$node().remove(); + } + EntityManagerInstance.storeDataYjs(); + }; + + /** + * Propagate an Attribute Delete Operation to the remote users and the local widgets + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var propagateAttributeDeleteOperation = function (operation) { + processAttributeDeleteOperation(operation); + var ymap = that.getRootSubjectEntity().getYMap(); + ymap.delete(operation.getEntityId() + "[val]"); + }; + + /** + * Callback for a remote Attrbute Add Operation + * @param {operations.ot.AttributeAddOperation} operation + */ + var remoteAttributeAddCallback = function (operation) { + if ( + operation instanceof AttributeAddOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + processAttributeAddOperation(operation); + } + }; + + /** + * Callback for a remote Attribute Delete Operation + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var remoteAttributeDeleteCallback = function (operation) { + if ( + operation instanceof AttributeDeleteOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + processAttributeDeleteOperation(operation); + } + }; + + /** + * Callback for a local Attribute Add Operation + * @param {operations.ot.AttributeAddOperation} operation + */ + var localAttributeAddCallback = function (operation) { + if ( + operation instanceof AttributeAddOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + propagateAttributeAddOperation(operation); + } + }; + + /** + * Callback for a local Attribute Delete Operation + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var localAttributeDeleteCallback = function (operation) { + if ( + operation instanceof AttributeDeleteOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + propagateAttributeDeleteOperation(operation); + } + }; + + /** + * Add attribute to attribute list + * @param {canvas_widget.AbstractAttribute} attribute + */ + this.addAttribute = function (attribute) { + var id = attribute.getEntityId(); + if (!_list.hasOwnProperty(id)) { + _list[id] = attribute; + } + }; + + /** + * Get attribute of attribute list by its entity id + * @param id + * @returns {canvas_widget.AbstractAttribute} + */ + this.getAttribute = function (id) { + if (_list.hasOwnProperty(id)) { + return _list[id]; + } + return null; + }; + + /** + * Delete attribute from attribute list by its entity id + * @param {string} id + */ + this.deleteAttribute = function (id) { + if (_list.hasOwnProperty(id)) { + delete _list[id]; + } + }; + + /** + * Get attribute list + * @returns {Object} + */ + this.getAttributes = function () { + return _list; + }; + + /** + * Set attribute list + * @param {Object} list + */ + this.setAttributes = function (list) { + _list = list; + }; + + /** + * Get jQuery object of the DOM node representing the attribute (list) + * @returns {jQuery} + */ + this.get$node = function () { + return _$node; + }; + + this.setOptions = function (options) { + _options = options; + }; + + /** + * Get JSON representation of the attribute (list) + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.type = ConditionListAttribute.TYPE; + var attr = {}; + lodash.forEach(this.getAttributes(), function (val, key) { + attr[key] = val.toJSON(); + }); + json.list = attr; + return json; + }; + + /** + * Set attribute list by its JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + lodash.forEach(json.list, function (val, key) { + var attribute = new ConditionPredicateAttribute( + key, + key, + that, + _options, + _options2 + ); + attribute.setValueFromJSON(json.list[key]); + that.addAttribute(attribute); + _$node.find(".list").append(attribute.get$node()); + }); + }; + + /** + * Register inter widget communication callbacks + */ + this.registerCallbacks = function () { + _iwcw.registerOnDataReceivedCallback(localAttributeAddCallback); + _iwcw.registerOnDataReceivedCallback(localAttributeDeleteCallback); + }; + + /** + * Unregister inter widget communication callbacks + */ + this.unregisterCallbacks = function () { + _iwcw.unregisterOnDataReceivedCallback(localAttributeAddCallback); + _iwcw.unregisterOnDataReceivedCallback(localAttributeDeleteCallback); + }; + + _$node.find(".name").text(this.getName()); + + for (var attributeId in _list) { + if (_list.hasOwnProperty(attributeId)) { + _$node.find(".list").append(_list[attributeId].get$node()); + } + } + + this.registerYMap = function () { + var ymap = that.getRootSubjectEntity().getYMap(); + var attrs = that.getAttributes(); + for (var key in attrs) { + if (attrs.hasOwnProperty(key)) { + attrs[key].registerYMap(); + } + } + + ymap.observe(function (event) { + const array = Array.from(event.changes.keys.entries()); + array.forEach(([key, change]) => { + if (key.indexOf("[value]") != -1) { + var operation; + switch (change.action) { + case "add": { + if (eventWasTriggeredByMe(event)) return; + const jabberId = event.currentTarget.get("jabberId"); + if (jabberId === _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]) + return; + operation = new AttributeAddOperation( + key.replace(/\[\w*\]/g, ""), + that.getEntityId(), + that.getRootSubjectEntity().getEntityId(), + that.constructor.name + ); + remoteAttributeAddCallback(operation); + + break; + } + case "delete": { + operation = new AttributeDeleteOperation( + key.replace(/\[\w*\]/g, ""), + that.getEntityId(), + that.getRootSubjectEntity().getEntityId(), + that.constructor.name + ); + remoteAttributeDeleteCallback(operation); + break; + } + } + } else if (key.indexOf("updateConditionOption") != -1) { + that.setOptions(event.value); + } + }); + }); + }; + + if (_iwcw) { + that.registerCallbacks(); + } + } +} + +/** + * RenamingAttribute + * @class canvas_widget.ConditionPredicateAttribute + * @memberof canvas_widget + * @extends canvas_widget.AbstractAttribute + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {Object} options Selection options + * @constructor + */ +class RenamingAttribute extends AbstractAttribute { + static TYPE = "RenamingAttribute"; + constructor(id, name, subjectEntity, options) { + super(id, name, subjectEntity); + + //noinspection UnnecessaryLocalVariableJS + /** + * Selection options + * @type {Object} + * @private + */ + var _options = options; + + /** + * Value object of key + * @type {canvas_widget.Value} + * @private + */ + var _key = new Value( + id + "[val]", + "Attribute Name", + this, + this.getRootSubjectEntity() + ); + + /*** + * Value object of ref + * @type {canvas_widget.Value} + * @private + */ + var _ref = new Value( + id + "[ref]", + "Attribute Reference", + this, + this.getRootSubjectEntity() + ); + + /*** + * Value object of vis + * @type {canvas_widget.Value} + * @private + */ + var _vis = new SelectionValue( + id + "[vis]", + "Attribute Visibility", + this, + this.getRootSubjectEntity(), + _options + ); + + /** + * jQuery object of the DOM node representing the attribute + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(renamingAttrHTML)()); + + //noinspection JSUnusedGlobalSymbols + /** + * Set Value object of key + * @param {canvas_widget.Value} key + */ + this.setKey = function (key) { + _key = key; + }; + + /** + * Get Value object of key + * @returns {canvas_widget.Value} + */ + this.getKey = function () { + return _key; + }; + + /** + * Get Value object of value + * @returns {canvas_widget.Value} + */ + this.getRef = function () { + return _ref; + }; + + /** + * Get Visibility object of value + * @returns {canvas_widget.Value} + */ + this.getVis = function () { + return _vis; + }; + + //noinspection JSUnusedGlobalSymbols + /** + * Set Value object of value + * @param {canvas_widget.Value} value + */ + this.setVis = function (value) { + _vis = value; + }; + + /** + * Get jQuery object of the DOM node representing the attribute + * @returns {jQuery} + */ + this.get$node = function () { + return _$node; + }; + + /** + * Set value of key and value by their JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + _key.setValueFromJSON(json.val); + _ref.setValueFromJSON(json.ref); + _vis.setValueFromJSON(json.vis || { value: "" }); + }; + + /** + * Get JSON representation of the attribute + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.val = _key.toJSON(); + json.ref = _ref.toJSON(); + json.vis = _vis.toJSON(); + return json; + }; + _$node.find(".val").append(_key.get$node()); + _$node.find(".ref").append(_ref.get$node()).hide(); + _$node.find(".vis").append(_vis.get$node()); + + this.registerYMap = function () { + _key.registerYType(); + _ref.registerYType(); + _vis.registerYType(); + }; + } +} + +/** + * KeySelectionValueSelectionValueListAttribute + * @class canvas_widget.KeySelectionValueSelectionValueListAttribute + * @extends canvas_widget.AbstractAttribute + * @memberof canvas_widget + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {Object} options Selection options + * @param {Object} options2 Selection options + */ +class KeySelectionValueSelectionValueListAttribute extends AbstractAttribute { + static TYPE = "KeySelectionValueSelectionValueListAttribute"; + + constructor(id, name, subjectEntity, options, options2) { + super(id, name, subjectEntity); + var that = this; + + /** + * Selection options + * @type {Object} + * @private + */ + var _options = options; + + /** + * Selection options + * @type {Object} + * @private + */ + var _options2 = options2; + + /** + * List of attributes + * @type {Object} + * @private + */ + var _list = {}; + + /** + * jQuery object of DOM node representing the attribute + * @type {jQuery} + * @private + */ + var _$node = $( + lodash.template(keySelectionValueSelectionValueListAttributeHtml)() + ); + + /** + * Inter widget communication wrapper + * @type {Object} + */ + y = y || window.y; + var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); + + /** + * Apply an Attribute Add Operation + * @param {operations.ot.AttributeAddOperation} operation + */ + var processAttributeAddOperation = function (operation) { + var attribute = new KeySelectionValueSelectionValueAttribute( + operation.getEntityId(), + "Attribute", + that, + _options, + _options2 + ); + attribute.registerYType(); + that.addAttribute(attribute); + if (_$node.find(".list").find("#" + attribute.getEntityId()).length == 0) + _$node.find(".list").append(attribute.get$node()); + EntityManagerInstance.storeDataYjs(); + }; + + /** + * Apply an Attribute Delete Operation + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var processAttributeDeleteOperation = function (operation) { + var attribute = that.getAttribute(operation.getEntityId()); + if (attribute) { + that.deleteAttribute(attribute.getEntityId()); + attribute.get$node().remove(); + } + EntityManagerInstance.storeDataYjs(); + }; + + /** + * Propagate an Attribute Add Operation to the remote users and the local widgets + * @param {operations.ot.AttributeAddOperation} operation + */ + var propagateAttributeAddOperation = function (operation) { + processAttributeAddOperation(operation); + }; + + /** + * Propagate an Attribute Delete Operation to the remote users and the local widgets + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var propagateAttributeDeleteOperation = function (operation) { + processAttributeDeleteOperation(operation); + var ynode = that.getRootSubjectEntity().getYMap(); + ynode.delete(operation.getEntityId() + "[key]"); + }; + + /** + * Callback for a remote Attrbute Add Operation + * @param {operations.ot.AttributeAddOperation} operation + */ + var remoteAttributeAddCallback = function (operation) { + if ( + operation instanceof AttributeAddOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + processAttributeAddOperation(operation); + } + }; + + /** + * Callback for a remote Attribute Delete Operation + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var remoteAttributeDeleteCallback = function (operation) { + if ( + operation instanceof AttributeDeleteOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + _iwcw.sendLocalOTOperation( + CONFIG.WIDGET.NAME.ATTRIBUTE, + operation.getOTOperation() + ); + processAttributeDeleteOperation(operation); + } + }; + + var localAttributeAddCallback = function (operation) { + if ( + operation instanceof AttributeAddOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + propagateAttributeAddOperation(operation); + } + }; + + /** + * Callback for a local Attribute Delete Operation + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var localAttributeDeleteCallback = function (operation) { + if ( + operation instanceof AttributeDeleteOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + propagateAttributeDeleteOperation(operation); + } + }; + + /** + * Add attribute to attribute list + * @param {canvas_widget.AbstractAttribute} attribute + */ + this.addAttribute = function (attribute) { + var id = attribute.getEntityId(); + if (!_list.hasOwnProperty(id)) { + _list[id] = attribute; + } + }; + + /** + * Get attribute of attribute list by its entity id + * @param id + * @returns {canvas_widget.AbstractAttribute} + */ + this.getAttribute = function (id) { + if (_list.hasOwnProperty(id)) { + return _list[id]; + } + return null; + }; + + /** + * Delete attribute from attribute list by its entity id + * @param {string} id + */ + this.deleteAttribute = function (id) { + if (_list.hasOwnProperty(id)) { + delete _list[id]; + } + }; + + /** + * Get attribute list + * @returns {Object} + */ + this.getAttributes = function () { + return _list; + }; + + /** + * Set attribute list + * @param {Object} list + */ + this.setAttributes = function (list) { + _list = list; + }; + + /** + * Get jQuery object of the DOM node representing the attribute (list) + * @returns {jQuery} + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the attribute (list) + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.type = KeySelectionValueSelectionValueListAttribute.TYPE; + var attr = {}; + lodash.forEach(this.getAttributes(), function (val, key) { + attr[key] = val.toJSON(); + }); + json.list = attr; + return json; + }; + + /** + * Set attribute list by its JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + lodash.forEach(json.list, function (val, key) { + var attribute = new KeySelectionValueSelectionValueAttribute( + key, + key, + that, + _options, + _options2 + ); + attribute.setValueFromJSON(json.list[key]); + that.addAttribute(attribute); + if ( + _$node.find(".list").find("#" + attribute.getEntityId()).length == 0 + ) + _$node.find(".list").append(attribute.get$node()); + }); + }; + + /** + * Register inter widget communication callbacks + */ + this.registerCallbacks = function () { + _iwcw.registerOnDataReceivedCallback(localAttributeAddCallback); + _iwcw.registerOnDataReceivedCallback(localAttributeDeleteCallback); + }; + + /** + * Unregister inter widget communication callbacks + */ + this.unregisterCallbacks = function () { + _iwcw.unregisterOnDataReceivedCallback(localAttributeAddCallback); + _iwcw.unregisterOnDataReceivedCallback(localAttributeDeleteCallback); + }; + + _$node.find(".name").text(this.getName()); + + for (var attributeId in _list) { + if (_list.hasOwnProperty(attributeId)) { + _$node.find(".list").append(_list[attributeId].get$node()); + } + } + + if (_iwcw) { + that.registerCallbacks(); + } + + this.registerYMap = function () { + var ymap = that.getRootSubjectEntity().getYMap(); + var attrs = that.getAttributes(); + for (var key in attrs) { + if (attrs.hasOwnProperty(key)) { + var attr = attrs[key]; + attr.registerYType(); + } + } + + ymap.observe(function (event) { + const array = Array.from(event.changes.keys.entries()); + array.forEach(([key, change]) => { + if (key.indexOf("[key]") != -1) { + var operation; + switch (change.action) { + case "add": { + const jabberId = event.currentTarget.get("jabberId"); + if (jabberId === _iwcw.getUser()[CONFIG.NS.PERSON.JABBERID]) + return; + operation = new AttributeAddOperation( + key.replace(/\[\w*\]/g, ""), + that.getEntityId(), + that.getRootSubjectEntity().getEntityId(), + that.constructor.name + ); + remoteAttributeAddCallback(operation); + break; + } + case "delete": { + operation = new AttributeDeleteOperation( + key.replace(/\[\w*\]/g, ""), + that.getEntityId(), + that.getRootSubjectEntity().getEntityId(), + that.constructor.name + ); + remoteAttributeDeleteCallback(operation); + break; + } + } + } + }); + }); + }; + } +} + +/** + * RenamingListAttribute + * @class canvas_widget.RenamingListAttribute + * @extends canvas_widget.AbstractAttribute + * @memberof canvas_widget + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {Object} options Selection options + */ +class RenamingListAttribute extends AbstractAttribute { + static TYPE = "RenamingListAttribute"; + constructor(id, name, subjectEntity, options, y) { + y = y || window.y; + super(id, name, subjectEntity); + var that = this; + + /** + * Selection options + * @type {Object} + * @private + */ + var _options = options; + + /** + * List of attributes + * @type {Object} + * @private + */ + var _list = {}; + + /** + * jQuery object of DOM node representing the attribute + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(listHtml)()); + + /** + * Inter widget communication wrapper + * @type {Object} + */ + var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); + + /** + * Apply an Attribute Add Operation + * @param {operations.ot.AttributeAddOperation} operation + * @param { YText} ytext + */ + var processAttributeAddOperation = function (operation) { + var attribute = new RenamingAttribute( + operation.getEntityId(), + "Attribute", + that, + _options + ); + that.addAttribute(attribute); + attribute.registerYMap(); + _$node.find(".list").append(attribute.get$node()); + EntityManagerInstance.storeDataYjs(); + return attribute; + }; + + /** + * Propagate an Attribute Add Operation to the remote users and the local widgets + * @param {operations.ot.AttributeAddOperation} operation + */ + this.propagateAttributeAddOperation = function (operation) { + return processAttributeAddOperation(operation); + }; + + /** + * Apply an Attribute Delete Operation + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var processAttributeDeleteOperation = function (operation) { + var attribute = that.getAttribute(operation.getEntityId()); + if (attribute) { + that.deleteAttribute(attribute.getEntityId()); + attribute.get$node().remove(); + } + }; + + /** + * Propagate an Attribute Delete Operation to the remote users and the local widgets + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var propagateAttributeDeleteOperation = function (operation) { + processAttributeDeleteOperation(operation); + var ymap = that.getRootSubjectEntity().getYMap(); + ymap.delete(operation.getEntityId() + "[val]"); + EntityManagerInstance.storeDataYjs(); + }; + + /** + * Callback for a remote Attrbute Add Operation + * @param {operations.ot.AttributeAddOperation} operation + */ + var remoteAttributeAddCallback = function (operation) { + if ( + operation instanceof AttributeAddOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + processAttributeAddOperation(operation); + subjectEntity.showAttributes(); + } + }; + + /** + * Callback for a remote Attribute Delete Operation + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var remoteAttributeDeleteCallback = function (operation) { + if ( + operation instanceof AttributeDeleteOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + processAttributeDeleteOperation(operation); + } + }; + + /** + * Callback for a local Attribute Add Operation + * @param {operations.ot.AttributeAddOperation} operation + */ + var localAttributeAddCallback = function (operation) { + if ( + operation instanceof AttributeAddOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + propagateAttributeAddOperation(operation); + } + }; + + /** + * Callback for a local Attribute Delete Operation + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var localAttributeDeleteCallback = function (operation) { + if ( + operation instanceof AttributeDeleteOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + propagateAttributeDeleteOperation(operation); + } + }; + + /** + * Add attribute to attribute list + * @param {canvas_widget.AbstractAttribute} attribute + */ + this.addAttribute = function (attribute) { + var id = attribute.getEntityId(); + if (!_list.hasOwnProperty(id)) { + _list[id] = attribute; + } + }; + + /** + * Get attribute of attribute list by its entity id + * @param id + * @returns {canvas_widget.AbstractAttribute} + */ + this.getAttribute = function (id) { + if (_list.hasOwnProperty(id)) { + return _list[id]; + } + return null; + }; + + /** + * Delete attribute from attribute list by its entity id + * @param {string} id + */ + this.deleteAttribute = function (id) { + if (_list.hasOwnProperty(id)) { + delete _list[id]; + } + }; + + /** + * Get attribute list + * @returns {Object} + */ + this.getAttributes = function () { + return _list; + }; + + /** + * Set attribute list + * @param {Object} list + */ + this.setAttributes = function (list) { + _list = list; + }; + + /** + * Get jQuery object of the DOM node representing the attribute (list) + * @returns {jQuery} + */ + this.get$node = function () { + return _$node; + }; + + this.setOptions = function (options) { + _options = options; + }; + + /** + * Get JSON representation of the attribute (list) + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.type = RenamingListAttribute.TYPE; + var attr = {}; + lodash.forEach(this.getAttributes(), function (val, key) { + attr[key] = val.toJSON(); + }); + json.list = attr; + return json; + }; + + /** + * Set attribute list by its JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + lodash.forEach(json.list, function (val, key) { + var attribute = new RenamingAttribute(key, key, that, _options); + attribute.setValueFromJSON(json.list[key]); + that.addAttribute(attribute); + _$node.find(".list").append(attribute.get$node()); + }); + }; + + /** + * Register inter widget communication callbacks + */ + this.registerCallbacks = function () { + _iwcw.registerOnDataReceivedCallback(localAttributeAddCallback); + _iwcw.registerOnDataReceivedCallback(localAttributeDeleteCallback); + }; + + /** + * Unregister inter widget communication callbacks + */ + this.unregisterCallbacks = function () { + _iwcw.unregisterOnDataReceivedCallback(localAttributeAddCallback); + _iwcw.unregisterOnDataReceivedCallback(localAttributeDeleteCallback); + }; + + _$node.find(".name").text(this.getName()); + + for (var attributeId in _list) { + if (_list.hasOwnProperty(attributeId)) { + _$node.find(".list").append(_list[attributeId].get$node()); + } + } + + if (_iwcw) { + that.registerCallbacks(); + } + this.registerYMap = function () { + var ymap = that.getRootSubjectEntity().getYMap(); + var attrs = that.getAttributes(); + for (var key in attrs) { + if (attrs.hasOwnProperty(key)) { + var attr = attrs[key]; + attr.registerYMap(); + } + } + + ymap.observe(function (event) { + const array = Array.from(event.changes.keys.entries()); + array.forEach(([key, change]) => { + if (key.indexOf("[val]") != -1) { + switch (change.action) { + case "add": { + // var yUserId = event.object.map[key][0]; + // if (yUserId === y.clientID) return; + const operation = new AttributeAddOperation( + key.replace(/\[\w*\]/g, ""), + that.getEntityId(), + that.getRootSubjectEntity().getEntityId(), + that.constructor.name + ); + remoteAttributeAddCallback(operation); + + break; + } + case "delete": { + const operation = new AttributeDeleteOperation( + key.replace(/\[\w*\]/g, ""), + that.getEntityId(), + that.getRootSubjectEntity().getEntityId(), + that.constructor.name + ); + remoteAttributeDeleteCallback(operation); + break; + } + } + } + }); + }); + }; + } +} + +/** + * ConditionPredicateAttribute + * @class attribute_widget.ConditionPredicateAttribute + * @memberof attribute_widget + * @extends attribute_widget.AbstractAttribute + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {Object} options Selection options + * @param {Object} options2 Selection options + * @constructor + */ +class ConditionPredicateAttribute extends AbstractAttribute { + static TYPE = "ConditionPredicateAttribute"; + constructor(id, name, subjectEntity, options, options2) { + super(id, name, subjectEntity); + + //noinspection UnnecessaryLocalVariableJS + /** + * Selection options + * @type {Object} + * @private + */ + var _options = options; + + //noinspection UnnecessaryLocalVariableJS + /** + * Selection options + * @type {Object} + * @private + */ + var _options2 = options2; + + //var _options3 = options3; + /** + * Value object of key + * @type {attribute_widget.Value} + * @private + */ + var _key = new Value( + id + "[value]", + "Attribute Value", + this, + this.getRootSubjectEntity() + ); + + /*** + * Value object of value + * @type {attribute_widget.Value} + * @private + */ + var _value = new SelectionValue( + id + "[property]", + "Attribute Name", + this, + this.getRootSubjectEntity(), + _options + ); + + /*** + * Value object of value + * @type {attribute_widget.Value} + * @private + */ + var _value2 = new SelectionValue( + id + "[operator]", + "Logical Operator", + this, + this.getRootSubjectEntity(), + _options2 + ); + + /** + * jQuery object of the DOM node representing the attribute + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(condition_predicateHtml)()); + + //noinspection JSUnusedGlobalSymbols + /** + * Set Value object of key + * @param {attribute_widget.Value} key + */ + this.setKey = function (key) { + _key = key; + }; + + /** + * Get Value object of key + * @returns {attribute_widget.Value} + */ + this.getKey = function () { + return _key; + }; + + /** + * Set Value object of value + * @param {attribute_widget.Value} value + */ + this.setValue = function (value) { + _value = value; + }; + + /** + * Get Value object of value + * @returns {attribute_widget.Value} + */ + this.getValue = function () { + return _value; + }; + + //noinspection JSUnusedGlobalSymbols + /** + * Set Value object of value + * @param {attribute_widget.Value} value + */ + this.setValue2 = function (value) { + _value2 = value; + }; + + /** + * Get Value object of value + * @returns {attribute_widget.Value} + */ + this.getValue2 = function () { + return _value2; + }; + + /** + * Get jQuery object of the DOM node representing the attribute + * @returns {jQuery} + */ + this.get$node = function () { + return _$node; + }; + + /** + * Set value of key and value by their JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + _key.setValueFromJSON(json.val); + _value.setValueFromJSON(json.property); + _value2.setValueFromJSON(json.operator || { value: "" }); + }; + /** + * Get JSON representation of the attribute + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.val = _key.toJSON(); + json.property = _value.toJSON(); + json.operator = _value2.toJSON(); + return json; + }; + _$node.find(".val").append(_key.get$node()); + _$node.find(".property").append(_value.get$node()); + _$node.find(".operator").append(_value2.get$node()); + //_$node.find(".operator2").append(_value3.get$node()); + this.registerYMap = function () { + _key.registerYType(); + _value.registerYType(); + _value2.registerYType(); + }; + } +} + +/** + * SingleColorValueAttribute + * @class canvas_widget.SingleColorValueAttribute + * @extends canvas_widget.AbstractAttribute + * @memberof canvas_widget + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {canvas_widget.AbstractEntity} subjectEntity Entity the attribute is assigned to + */ +class SingleColorValueAttribute extends AbstractAttribute { + constructor(id, name, subjectEntity) { + super(id, name, subjectEntity); + + /*** + * Value object of value + * @type {canvas_widget.Value} + * @private + */ + var _value = new Value(id, name, this, this.getRootSubjectEntity()); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(singleColorValueAttributeHtml)()); + + /** + * Set Value object of value + * @param {canvas_widget.Value} value + */ + this.setValue = function (value) { + _value = value; + }; + + /** + * Get Value object of value + * @returns {canvas_widget.Value} + */ + this.getValue = function () { + return _value; + }; + + /** + * jQuery object of DOM node representing the attribute + * @type {jQuery} + * @private + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the attribute + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.value = _value.toJSON(); + return json; + }; + + /** + * Set attribute value by its JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + _value.setValueFromJSON(json.value); + }; + + _$node.find(".name").text(this.getName()); + _$node.find(".value").append(_value.get$node()); + } +} + +/** + * KeySelectionValueSelectionValueAttribute + * @class canvas_widget.KeySelectionValueSelectionValueAttribute + * @extends canvas_widget.AbstractAttribute + * @memberof canvas_widget + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {Object} options Selection options + * @param {Object} options2 Selection options + */ +class KeySelectionValueSelectionValueAttribute extends AbstractAttribute { + constructor(id, name, subjectEntity, options, options2) { + super(id, name, subjectEntity); + + //noinspection UnnecessaryLocalVariableJS + /** + * Selection options + * @type {Object} + * @private + */ + var _options = options; + + //noinspection UnnecessaryLocalVariableJS + /** + * Selection options + * @type {Object} + * @private + */ + var _options2 = options2; + + /** + * Value object of key + * @type {canvas_widget.Value} + * @private + */ + var _key = new Value(id + "[key]", "", this, this.getRootSubjectEntity()); + + /*** + * Value object of value + * @type {canvas_widget.Value} + * @private + */ + var _value = new SelectionValue( + id + "[value]", + "", + this, + this.getRootSubjectEntity(), + _options + ); + + /*** + * Value object of value + * @type {canvas_widget.Value} + * @private + */ + var _value2 = new SelectionValue( + id + "[value2]", + "", + this, + this.getRootSubjectEntity(), + _options2 + ); + + /** + * jQuery object of the DOM node representing the attribute + * @type {jQuery} + * @private + */ + var _$node = $( + lodash.template(keySelectionValueSelectionValueAttributeHtml)({ id: id }) + ); + + //noinspection JSUnusedGlobalSymbols + /** + * Set Value object of key + * @param {canvas_widget.Value} key + */ + this.setKey = function (key) { + _key = key; + }; + + /** + * Get Value object of key + * @returns {canvas_widget.Value} + */ + this.getKey = function () { + return _key; + }; + + /** + * Set Value object of value + * @param {canvas_widget.Value} value + */ + this.setValue = function (value) { + _value = value; + }; + + /** + * Get Value object of value + * @returns {canvas_widget.Value} + */ + this.getValue = function () { + return _value; + }; + + /** + * Set Value object of value + * @param {canvas_widget.Value} value + */ + this.setValue2 = function (value) { + _value2 = value; + }; + + /** + * Get Value object of value + * @returns {canvas_widget.Value} + */ + this.getValue2 = function () { + return _value2; + }; + + /** + * Get jQuery object of the DOM node representing the attribute + * @returns {jQuery} + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the attribute + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.key = _key.toJSON(); + json.value = _value.toJSON(); + json.value2 = _value2.toJSON(); + return json; + }; + + /** + * Set value of key and value by their JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + _key.setValueFromJSON(json.key); + _value.setValueFromJSON(json.value); + _value2.setValueFromJSON(json.value2 || { value: "" }); + }; + + this.registerYType = function () { + _key.registerYType(); + _value.registerYType(); + _value2.registerYType(); + }; + + _$node.find(".key").append(_key.get$node()); + _$node.find(".value").append(_value.get$node()); + } +} + +/** + * KeySelectionValueListAttribute + * @class canvas_widget.KeySelectionValueListAttribute + * @extends canvas_widget.AbstractAttribute + * @memberof canvas_widget + * @constructor + * @param {string} id Entity id + * @param {string} name Name of attribute + * @param {AbstractEntity} subjectEntity Entity the attribute is assigned to + * @param {Object} options Selection options + */ +class KeySelectionValueListAttribute extends AbstractAttribute { + static TYPE = "KeySelectionValueListAttribute"; + constructor(id, name, subjectEntity, options) { + super(id, name, subjectEntity); + var that = this; + + /** + * Selection options + * @type {Object} + * @private + */ + var _options = options; + + /** + * List of attributes + * @type {Object} + * @private + */ + var _list = {}; + + /** + * jQuery object of DOM node representing the attribute + * @type {jQuery} + * @private + */ + var _$node = $(lodash.template(keySelectionValueListAttributeHtml)()); + + /** + * Inter widget communication wrapper + * @type {Object} + */ + y = y || window.y; + var _iwcw = IWCW.getInstance(CONFIG.WIDGET.NAME.MAIN, y); + + /** + * Apply an Attribute Add Operation + * @param {operations.ot.AttributeAddOperation} operation + */ + var processAttributeAddOperation = function (operation) { + var attribute = new KeySelectionValueAttribute( + operation.getEntityId(), + "Attribute", + that, + _options + ); + attribute.registerYMap(); + that.addAttribute(attribute); + if (_$node.find(".list").find("#" + attribute.getEntityId()).length == 0) + _$node.find(".list").append(attribute.get$node()); + }; + + /** + * Apply an Attribute Delete Operation + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var processAttributeDeleteOperation = function (operation) { + var attribute = that.getAttribute(operation.getEntityId()); + if (attribute) { + that.deleteAttribute(attribute.getEntityId()); + attribute.get$node().remove(); + } + }; + + /** + * Propagate an Attribute Add Operation to the remote users and the local widgets + * @param {operations.ot.AttributeAddOperation} operation + */ + var propagateAttributeAddOperation = function (operation) { + processAttributeAddOperation(operation); + EntityManagerInstance.storeDataYjs(); + }; + + /** + * Propagate an Attribute Delete Operation to the remote users and the local widgets + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var propagateAttributeDeleteOperation = function (operation) { + processAttributeDeleteOperation(operation); + var ymap = that.getRootSubjectEntity().getYMap(); + ymap.delete(operation.getEntityId() + "[key]"); + EntityManagerInstance.storeDataYjs(); + }; + + /** + * Callback for a remote Attrbute Add Operation + * @param {operations.ot.AttributeAddOperation} operation + */ + var remoteAttributeAddCallback = function (operation) { + if ( + operation instanceof AttributeAddOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + processAttributeAddOperation(operation); + } + }; + + /** + * Callback for a remote Attribute Delete Operation + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var remoteAttributeDeleteCallback = function (operation) { + if ( + operation instanceof AttributeDeleteOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + processAttributeDeleteOperation(operation); + } + }; + + var localAttributeAddCallback = function (operation) { + if ( + operation instanceof AttributeAddOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + propagateAttributeAddOperation(operation); + } + }; + /** + * Callback for a local Attribute Delete Operation + * @param {operations.ot.AttributeDeleteOperation} operation + */ + var localAttributeDeleteCallback = function (operation) { + if ( + operation instanceof AttributeDeleteOperation && + operation.getRootSubjectEntityId() === + that.getRootSubjectEntity().getEntityId() && + operation.getSubjectEntityId() === that.getEntityId() + ) { + propagateAttributeDeleteOperation(operation); + } + }; + + /** + * Add attribute to attribute list + * @param {canvas_widget.AbstractAttribute} attribute + */ + this.addAttribute = function (attribute) { + var id = attribute.getEntityId(); + if (!_list.hasOwnProperty(id)) { + _list[id] = attribute; + } + }; + + /** + * Get attribute of attribute list by its entity id + * @param id + * @returns {canvas_widget.AbstractAttribute} + */ + this.getAttribute = function (id) { + if (_list.hasOwnProperty(id)) { + return _list[id]; + } + return null; + }; + + /** + * Delete attribute from attribute list by its entity id + * @param {string} id + */ + this.deleteAttribute = function (id) { + if (_list.hasOwnProperty(id)) { + delete _list[id]; + } + }; + + /** + * Get attribute list + * @returns {Object} + */ + this.getAttributes = function () { + return _list; + }; + + /** + * Set attribute list + * @param {Object} list + */ + this.setAttributes = function (list) { + _list = list; + }; + + /** + * Get jQuery object of the DOM node representing the attribute (list) + * @returns {jQuery} + */ + this.get$node = function () { + return _$node; + }; + + /** + * Get JSON representation of the attribute (list) + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractAttribute.prototype.toJSON.call(this); + json.type = KeySelectionValueListAttribute.TYPE; + var attr = {}; + lodash.forEach(this.getAttributes(), function (val, key) { + attr[key] = val.toJSON(); + }); + json.list = attr; + return json; + }; + + /** + * Set attribute list by its JSON representation + * @param json + */ + this.setValueFromJSON = function (json) { + lodash.forEach(json.list, function (val, key) { + var attribute = new KeySelectionValueAttribute( + key, + key, + that, + _options + ); + attribute.setValueFromJSON(json.list[key]); + that.addAttribute(attribute); + if ( + _$node.find(".list").find("#" + attribute.getEntityId()).length == 0 + ) + _$node.find(".list").append(attribute.get$node()); + }); + }; + + /** + * Register inter widget communication callbacks + */ + this.registerCallbacks = function () { + _iwcw.registerOnDataReceivedCallback(localAttributeAddCallback); + _iwcw.registerOnDataReceivedCallback(localAttributeDeleteCallback); + }; + + /** + * Unregister inter widget communication callbacks + */ + this.unregisterCallbacks = function () { + _iwcw.unregisterOnDataReceivedCallback(localAttributeAddCallback); + _iwcw.unregisterOnDataReceivedCallback(localAttributeDeleteCallback); + }; + + _$node.find(".name").text(this.getName()); + + for (var attributeId in _list) { + if (_list.hasOwnProperty(attributeId)) { + _$node.find(".list").append(_list[attributeId].get$node()); + } + } + + if (_iwcw) { + that.registerCallbacks(); + } + + this.registerYMap = function () { + var ymap = that.getRootSubjectEntity().getYMap(); + var attrs = that.getAttributes(); + for (var key in attrs) { + if (attrs.hasOwnProperty(key)) { + var attr = attrs[key]; + attr.getKey().registerYType(); + attr.getValue().registerYType(); + } + } + + ymap.observe(function (event) { + const array = Array.from(event.changes.keys.entries()); + array.forEach(([key, change]) => { + if (key.indexOf("[key]") != -1) { + var operation; + switch (change.action) { + case "add": { + // var yUserId = event.object.map[key][0]; + // if (yUserId === y.clientID) return; + operation = new AttributeAddOperation( + key.replace(/\[\w*\]/g, ""), + that.getEntityId(), + that.getRootSubjectEntity().getEntityId(), + that.constructor.name + ); + remoteAttributeAddCallback(operation); + + break; + } + case "delete": { + operation = new AttributeDeleteOperation( + key.replace(/\[\w*\]/g, ""), + that.getEntityId(), + that.getRootSubjectEntity().getEntityId(), + that.constructor.name + ); + remoteAttributeDeleteCallback(operation); + break; + } + } + } + }); + }); + }; + } +} + +/** + * Abstract Class Node + * @class canvas_widget.ModelAttributesNode + * @extends canvas_widget.AbstractNode + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of node + * @param {object} [attr] model attributes + */ +class ModelAttributesNode extends AbstractNode { + static TYPE = "ModelAttributesNode"; + + constructor(id, attr, y) { + super(id, ModelAttributesNode.TYPE, 0, 0, 0, 0, 0, null, null, y); + y = y || window.y; + if (!y) { + throw new Error("y is not defined"); + } + + /** + * jQuery object of node template + * @type {jQuery} + * @private + */ + var _$template = $(lodash.template(modelAttributesNodeHtml)()); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = AbstractNode.prototype.get$node + .call(this) + .append(_$template) + .addClass("class"); + + /** + * jQuery object of DOM node representing the attributes + * @type {jQuery} + * @private + */ + var _$attributeNode = _$node.find(".attributes"); + + /** + * Attributes of node + * @type {Object} + * @private + */ + var _attributes = this.getAttributes(); + + /** + * Get JSON representation of the node + * @returns {Object} + */ + this.toJSON = function () { + var json = AbstractNode.prototype.toJSON.call(this); + json.type = ModelAttributesNode.TYPE; + return json; + }; + + if (attr) { + for (var attrKey in attr) { + if (attr.hasOwnProperty(attrKey)) { + switch (attr[attrKey].value) { + case "boolean": + this.addAttribute( + new BooleanAttribute( + this.getEntityId() + + "[" + + attr[attrKey].key.toLowerCase() + + "]", + attr[attrKey].key, + this + ) + ); + break; + case "string": + this.addAttribute( + new SingleValueAttribute( + this.getEntityId() + + "[" + + attr[attrKey].key.toLowerCase() + + "]", + attr[attrKey].key, + this + ) + ); + break; + case "integer": + this.addAttribute( + new IntegerAttribute( + this.getEntityId() + + "[" + + attr[attrKey].key.toLowerCase() + + "]", + attr[attrKey].key, + this + ) + ); + break; + case "file": + this.addAttribute( + new FileAttribute( + this.getEntityId() + + "[" + + attr[attrKey].key.toLowerCase() + + "]", + attr[attrKey].key, + this + ) + ); + break; + default: + if (attr[attrKey].options) { + this.addAttribute( + new SingleSelectionAttribute( + this.getEntityId() + + "[" + + attr[attrKey].key.toLowerCase() + + "]", + attr[attrKey].key, + this, + attr[attrKey].options + ) + ); + } + break; + } + } + } + } else { + this.addAttribute( + new SingleValueAttribute(this.getEntityId() + "[name]", "Name", this, y) + ); + this.addAttribute( + new SingleMultiLineValueAttribute( + this.getEntityId() + "[description]", + "Description", + this, + y + ) + ); + } + + this.getLabel().getValue().setValue("Model Attributes"); + + _$node.find(".label").text("Model Attributes"); + _$node.hide(); + + for (var attributeKey in _attributes) { + if (_attributes.hasOwnProperty(attributeKey)) { + _$attributeNode.append(_attributes[attributeKey].get$node()); + } + } + + this.registerYMap = function () { + AbstractNode.prototype.registerYMap.call(this); + var attrs = this.getAttributes(); + for (var key in attrs) { + if (attrs.hasOwnProperty(key)) { + var attr = attrs[key]; + if ( + attr instanceof SingleValueAttribute || + attr instanceof SingleMultiLineValueAttribute + ) { + attr.getValue().registerYType(); + } else if ( + !(attr instanceof FileAttribute) && + !(attr instanceof SingleValueAttribute) && + !(attr instanceof SingleMultiLineValueAttribute) + ) { + attr.getValue().registerYType(); + } + } + } + }; + } +} + +/** + * ViewObjectNode + * @class canvas_widget.ViewObjectNode + * @extends canvas_widget.AbstractNode + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {number} zIndex Position of node on z-axis + * @param {object} jsonFromResource the ViewObjectNode is created from a json + */ +class ViewObjectNode extends AbstractNode { + static TYPE = "ViewObject"; + static DEFAULT_WIDTH = 150; + static DEFAULT_HEIGHT = 100; + constructor(id, left, top, width, height, zIndex, json) { + var that = this; + + super(id, "ViewObject", left, top, width, height, zIndex, json); + + /** + * jQuery object of node template + * @type {jQuery} + * @private + */ + var _$template = $( + lodash.template(viewobjectNodeHtml)({ type: that.getType() }) + ); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = AbstractNode.prototype.get$node + .call(this) + .append(_$template) + .addClass("viewobject"); + + /** + * jQuery object of DOM node representing the attributes + * @type {jQuery} + * @private + */ + var _$attributeNode = _$node.find(".attributes"); + + /** + * Get JSON representation of the node + * @returns {Object} + */ + this.toJSON = function () { + return AbstractNode.prototype.toJSON.call(this); + }; + + this.createConditionListAttribute = function (refAttrs) { + var targetAttrList = {}; + if (refAttrs && refAttrs.constructor.name === "RenamingListAttribute") { + var attrs = refAttrs.getAttributes(); + for (var key in attrs) { + if (attrs.hasOwnProperty(key)) { + targetAttrList[key] = attrs[key].getKey().getValue(); + } + } + } else { + for (var key in refAttrs) { + if (refAttrs.hasOwnProperty(key)) { + targetAttrList[key] = refAttrs[key].val.value; + } + } + } + var conditionListAttr = new ConditionListAttribute( + "[condition]", + "Conditions", + that, + targetAttrList, + LogicalOperator + ); + that.addAttribute(conditionListAttr); + _$attributeNode.append(conditionListAttr.get$node()); + conditionListAttr.get$node().hide(); + return conditionListAttr; + }; + + this.registerYMap = function () { + AbstractNode.prototype.registerYMap.call(this); + that.getLabel().getValue().registerYType(); + renamingList.registerYMap(); + if (cla) cla.registerYMap(); + targetAttribute.getValue().registerYType(); + conjSelection.getValue().registerYType(); + }; + + this.showAttributes = function () { + if (renamingList.get$node().is(":hidden")) renamingList.get$node().show(); + if (conjSelection.get$node().is(":hidden")) + conjSelection.get$node().show(); + if (cla.get$node().is(":hidden")) cla.get$node().show(); + if (!targetAttribute.get$node().is(":hidden")) + targetAttribute.get$node().hide(); + }; + + var targetAttribute, renamingList, conjSelection, cla; + _$node.find(".label").append(this.getLabel().get$node()); + if (window.hasOwnProperty("y")) { + const dataMap = y.getMap("data"); + var model = dataMap.get("model"); + if (model) { + var selectionValues = + ViewTypesUtil.GetAllNodesOfBaseModelAsSelectionList2(model.nodes, [ + "Object", + ]); + targetAttribute = new SingleSelectionAttribute( + id + "[target]", + "Target", + that, + selectionValues + ); + that.addAttribute(targetAttribute); + _$attributeNode.prepend(targetAttribute.get$node()); + } + if (json) + cla = that.createConditionListAttribute( + json.attributes["[attributes]"].list + ); + else cla = that.createConditionListAttribute(); + } + + renamingList = new RenamingListAttribute( + "[attributes]", + "Attributes", + that, + { + show: "Visible", + hide: "Hidden", + } + ); + that.addAttribute(renamingList); + _$attributeNode.append(renamingList.get$node()); + renamingList.get$node().hide(); + + conjSelection = new SingleSelectionAttribute( + id + "[conjunction]", + "Conjunction", + that, + LogicalConjunctions + ); + that.addAttribute(conjSelection); + _$attributeNode.append(conjSelection.get$node()); + conjSelection.get$node().hide(); + + if (json && conjSelection && cla && renamingList && targetAttribute) + that.showAttributes(); + + this.setContextMenuItemCallback(function () { + var viewId = $("#lblCurrentView").text(); + return { + addShape: { + name: "Add Node Shape", + callback: function () { + var canvas = that.getCanvas(), + appearance = that.getAppearance(); + + //noinspection JSAccessibilityCheck + canvas + .createNode( + NodeShapeNode.TYPE, + appearance.left + appearance.width + 50, + appearance.top, + 150, + 100 + ) + .done(function (nodeId) { + canvas.createEdge( + BiDirAssociationEdge.TYPE, + that.getEntityId(), + nodeId, + null, + null, + viewId + ); + }); + }, + disabled: function () { + var edges = that.getEdges(), + edge, + edgeId; + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if ( + (edge instanceof BiDirAssociationEdge && + ((edge.getTarget() === that && + edge.getSource() instanceof NodeShapeNode) || + (edge.getSource() === that && + edge.getTarget() instanceof NodeShapeNode))) || + (edge instanceof UniDirAssociationEdge && + edge.getTarget() instanceof NodeShapeNode) + ) { + return true; + } + } + } + return false; + }, + }, + sep: "---------", + }; + }); + } +} + +/** + * ViewRelationshipNode + * @class canvas_widget.ViewRelationshipNode + * @extends canvas_widget.AbstractNode + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {number} zIndex Position of node on z-axis + * @param {object} json indicates if the ViewObjectNode is created from a json + + */ +let ViewRelationshipNode$1 = class ViewRelationshipNode extends AbstractNode { + static TYPE = "ViewRelationship"; + static DEFAULT_WIDTH = 150; + static DEFAULT_HEIGHT = 100; + constructor(id, left, top, width, height, zIndex, json) { + super(id, "ViewRelationship", left, top, width, height, zIndex, json); + var that = this; + + /** + * jQuery object of node template + * @type {jQuery} + * @private + */ + var _$template = $( + lodash.template(viewrelationshipNodeHtml$1)({ + type: that.getType(), + }) + ); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = AbstractNode.prototype.get$node + .call(this) + .append(_$template) + .addClass("viewrelationship"); + + /** + * jQuery object of DOM node representing the attributes + * @type {jQuery} + * @private + */ + var _$attributeNode = _$node.find(".attributes"); + + /** + * Get JSON representation of the node + * @returns {Object} + */ + this.toJSON = function () { + return AbstractNode.prototype.toJSON.call(this); + }; + + this.registerYMap = function () { + AbstractNode.prototype.registerYMap.call(this); + that.getLabel().getValue().registerYType(); + attributeList.registerYMap(); + if (cla) cla.registerYMap(); + attribute.getValue().registerYType(); + conjSelection.getValue().registerYType(); + }; + + this.showAttributes = function () { + if (renamingList.get$node().is(":hidden")) renamingList.get$node().show(); + if (conjSelection.get$node().is(":hidden")) + conjSelection.get$node().show(); + if (cla.get$node().is(":hidden")) cla.get$node().show(); + if (!targetAttribute.get$node().is(":hidden")) + targetAttribute.get$node().hide(); + }; + + this.createConditionListAttribute = function (refAttrs) { + var targetAttrList = {}; + if (refAttrs && refAttrs.constructor.name === "RenamingListAttribute") { + var attrs = refAttrs.getAttributes(); + for (var key in attrs) { + if (attrs.hasOwnProperty(key)) { + targetAttrList[key] = attrs[key].getKey().getValue(); + } + } + } else { + for (var key in refAttrs) { + if (refAttrs.hasOwnProperty(key)) { + targetAttrList[key] = refAttrs[key].val.value; + } + } + } + var conditionListAttr = new ConditionListAttribute( + "[condition]", + "Conditions", + that, + targetAttrList, + LogicalOperator + ); + that.addAttribute(conditionListAttr); + _$attributeNode.append(conditionListAttr.get$node()); + conditionListAttr.get$node().hide(); + return conditionListAttr; + }; + + this.registerYMap = function () { + AbstractNode.prototype.registerYMap.call(this); + that.getLabel().getValue().registerYType(); + renamingList.registerYMap(); + if (cla) cla.registerYMap(); + targetAttribute.getValue().registerYType(); + conjSelection.getValue().registerYType(); + }; + + var targetAttribute, renamingList, conjSelection, cla; + _$node.find(".label").append(this.getLabel().get$node()); + if (window.hasOwnProperty("y")) { + const dataMap = y.getMap("data"); + var model = dataMap.get("model"); + if (model) { + var selectionValues = + ViewTypesUtil.GetAllNodesOfBaseModelAsSelectionList2(model.nodes, [ + "Relationship", + ]); + targetAttribute = new SingleSelectionAttribute( + id + "[target]", + "Reference", + that, + selectionValues + ); + that.addAttribute(targetAttribute); + _$attributeNode.prepend(targetAttribute.get$node()); + + if (json) + cla = that.createConditionListAttribute( + json.attributes["[attributes]"].list + ); + else cla = that.createConditionListAttribute(); + } + } + + renamingList = new RenamingListAttribute( + "[attributes]", + "Attributes", + that, + { + hidden: "Show", + top: "Show Top", + center: "Show Center", + bottom: "Show Bottom", + hide: "Hide", + } + ); + that.addAttribute(renamingList); + _$attributeNode.append(renamingList.get$node()); + renamingList.get$node().hide(); + + conjSelection = new SingleSelectionAttribute( + id + "[conjunction]", + "Conjunction", + that, + LogicalConjunctions + ); + that.addAttribute(conjSelection); + _$attributeNode.append(conjSelection.get$node()); + conjSelection.get$node().hide(); + + if (json && conjSelection && cla && renamingList && targetAttribute) + that.showAttributes(); + + this.setContextMenuItemCallback(function () { + var viewId = $("#lblCurrentView").text(); + return { + addShape: { + name: "Add Edge Shape", + callback: function () { + var canvas = that.getCanvas(), + appearance = that.getAppearance(), + nodeId; + + canvas.createNode( + EdgeShapeNode.TYPE, + appearance.left + appearance.width + 50, + appearance.top, + 150, + 100 + ); + canvas.createEdge( + BiDirAssociationEdge.TYPE, + that.getEntityId(), + nodeId, + null, + null, + viewId + ); + }, + disabled: function () { + var edges = that.getEdges(), + edge, + edgeId; + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if ( + (edge instanceof BiDirAssociationEdge && + ((edge.getTarget() === that && + edge.getSource() instanceof EdgeShapeNode) || + (edge.getSource() === that && + edge.getTarget() instanceof EdgeShapeNode))) || + (edge instanceof UniDirAssociationEdge && + edge.getTarget() instanceof EdgeShapeNode) + ) { + return true; + } + } + } + return false; + }, + }, + sep: "---------", + }; + }); + } +}; + +/** + * BiDirAssociationEdge + * @class canvas_widget.BiDirAssociationEdge + * @extends canvas_widget.AbstractEdge + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of edge + * @param {canvas_widget.AbstractNode} source Source node + * @param {canvas_widget.AbstractNode} target Target node + */ + +/** + * GeneralisationEdge + * @class GeneralisationEdge + * @extends AbstractEdge + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of edge + * @param {canvas_widget.AbstractNode} source Source node + * @param {canvas_widget.AbstractNode} target Target node + */ +class GeneralisationEdge extends AbstractEdge { + static TYPE = "Generalisation"; + static RELATIONS = [ + { + sourceTypes: [ObjectNode.TYPE], + targetTypes: [ObjectNode.TYPE, AbstractClassNode.TYPE], + }, + { + sourceTypes: [RelationshipNode.TYPE], + targetTypes: [RelationshipNode.TYPE, AbstractClassNode.TYPE], + }, + { + sourceTypes: [RelationshipGroupNode.TYPE], + targetTypes: [RelationshipNode.TYPE, ViewRelationshipNode$1.TYPE], + }, + { + sourceTypes: [AbstractClassNode.TYPE], + targetTypes: [AbstractClassNode.TYPE], + }, + { + sourceTypes: [EnumNode.TYPE], + targetTypes: [EnumNode.TYPE], + }, + ]; + + constructor(id, source, target) { + super(id, GeneralisationEdge.TYPE, source, target); + var that = this; + + /** + * Connect source and target node and draw the edge on canvas + */ + this.connect = function () { + var source = this.getSource(); + var target = this.getTarget(); + var connectOptions = { + source: source.get$node().get(0), + target: target.get$node().get(0), + paintStyle: { + stroke: "black", + strokeWidth: 4, + }, + endpoint: "Dot", + anchors: [source.getAnchorOptions(), target.getAnchorOptions()], + connector: { + type: StraightConnector.type, + options: { gap: 0 }, + }, + overlays: [ + { + type: "Arrow", + options: { + width: 20, + length: 25, + location: 1, + foldback: 1, + paintStyle: { + fill: "#ffffff", + outlineWidth: 2, + dashstyle: "black", + }, + }, + }, + { + type: "Custom", + options: { + create: function () { + return that.get$overlay().get(0); + }, + location: 0.5, + id: "label", + }, + }, + ], + cssClass: this.getEntityId(), + }; + + if (source === target) { + connectOptions.anchor = ["TopCenter", "LeftMiddle"]; + } + + source.addOutgoingEdge(this); + target.addIngoingEdge(this); + this.setJsPlumbConnection(window.jsPlumbInstance.connect(connectOptions)); + + this.repaintOverlays(); + lodash.each(EntityManagerInstance.getEdges(), function (e) { + e.setZIndex(); + }); + }; + + this.get$overlay().find(".type").addClass("segmented"); + } +} + +/** + * UniDirAssociationEdge + * @class canvas_widget.UniDirAssociationEdge + * @extends canvas_widget.AbstractEdge + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of edge + * @param {canvas_widget.AbstractNode} source Source node + * @param {canvas_widget.AbstractNode} target Target node + */ +class UniDirAssociationEdge extends AbstractEdge { + static TYPE = "Uni-Dir-Association"; + static RELATIONS = [ + { + sourceTypes: [ObjectNode.TYPE], + targetTypes: [ + EnumNode.TYPE, + NodeShapeNode.TYPE, + RelationshipNode.TYPE, + RelationshipGroupNode.TYPE, + ViewRelationshipNode$1.TYPE, + ], + }, + { + sourceTypes: [RelationshipNode.TYPE], + targetTypes: [ + EnumNode.TYPE, + EdgeShapeNode.TYPE, + ObjectNode.TYPE, + AbstractClassNode.TYPE, + ViewObjectNode.TYPE, + ], + }, + { + sourceTypes: [RelationshipGroupNode.TYPE], + targetTypes: [ObjectNode.TYPE, AbstractClassNode.TYPE], + }, + { + sourceTypes: [AbstractClassNode.TYPE], + targetTypes: [ + EnumNode.TYPE, + RelationshipNode.TYPE, + RelationshipGroupNode.TYPE, + ], + }, + { + sourceTypes: [ViewObjectNode.TYPE], + targetTypes: [ + EnumNode.TYPE, + NodeShapeNode.TYPE, + RelationshipNode.TYPE, + RelationshipGroupNode.TYPE, + ViewRelationshipNode$1.TYPE, + ], + }, + { + sourceTypes: [ViewRelationshipNode$1.TYPE], + targetTypes: [ + EnumNode.TYPE, + EdgeShapeNode.TYPE, + ObjectNode.TYPE, + AbstractClassNode.TYPE, + ViewObjectNode.TYPE, + ], + }, + ]; + + constructor(id, source, target) { + super(id, UniDirAssociationEdge.TYPE, source, target); + var that = this; + + /** + * Connect source and target node and draw the edge on canvas + */ + this.connect = function () { + var source = this.getSource(); + var target = this.getTarget(); + var connectOptions = { + source: source.get$node().get(0), + target: target.get$node().get(0), + paintStyle: { + stroke: "black", + strokeWidth: 4, + }, + endpoint: "Dot", + anchors: [source.getAnchorOptions(), target.getAnchorOptions()], + connector: { + type: StraightConnector.type, + options: { gap: 0 }, + }, + overlays: [ + { + type: "Arrow", + options: { + width: 20, + length: 30, + location: 1, + foldback: 0.5, + paintStyle: { + fill: "#ffffff", + outlineWidth: 2, + outlineStroke: "black", + }, + }, + }, + { + type: "Custom", + options: { + create: function () { + return that.get$overlay().get(0); + }, + location: 0.5, + id: "label", + }, + }, + ], + cssClass: this.getEntityId(), + }; + + if (source === target) { + connectOptions.anchors = ["TopCenter", "LeftMiddle"]; + } + + source.addOutgoingEdge(this); + target.addIngoingEdge(this); + this.setJsPlumbConnection(window.jsPlumbInstance.connect(connectOptions)); + + this.repaintOverlays(); + lodash.each(EntityManagerInstance.getEdges(), function (e) { + e.setZIndex(); + }); + }; + + this.get$overlay().find(".type").addClass("segmented"); + + /*this.setContextMenuItems({ + sep0: "---------", + convertToBiDirAssociationEdge: { + name: "Convert to Bi-Dir. Assoc. Edge", + callback: function(){ + var canvas = that.getCanvas(); + + //noinspection JSAccessibilityCheck + canvas.createEdge(require('canvas_widget/BiDirAssociationEdge').TYPE,that.getSource().getEntityId(),that.getTarget().getEntityId(),that.toJSON()); + + that.triggerDeletion(); + + } + } + });*/ + } +} + +class BiDirAssociationEdge extends AbstractEdge { + static TYPE = "Bi-Dir-Association"; + static RELATIONS = [ + { + sourceTypes: [ObjectNode.TYPE], + targetTypes: [ + EnumNode.TYPE, + NodeShapeNode.TYPE, + RelationshipNode.TYPE, + RelationshipGroupNode.TYPE, + ViewRelationshipNode$1.TYPE, + ], + }, + { + sourceTypes: [RelationshipNode.TYPE], + targetTypes: [ + EnumNode.TYPE, + EdgeShapeNode.TYPE, + ObjectNode.TYPE, + AbstractClassNode.TYPE, + ViewObjectNode.TYPE, + ], + }, + { + sourceTypes: [RelationshipGroupNode.TYPE], + targetTypes: [ObjectNode.TYPE, AbstractClassNode.TYPE], + }, + { + sourceTypes: [AbstractClassNode.TYPE], + targetTypes: [ + EnumNode.TYPE, + RelationshipNode.TYPE, + RelationshipGroupNode.TYPE, + ], + }, + { + sourceTypes: [EnumNode.TYPE], + targetTypes: [ + ObjectNode.TYPE, + RelationshipNode.TYPE, + AbstractClassNode.TYPE, + ], + }, + { + sourceTypes: [NodeShapeNode.TYPE], + targetTypes: [ObjectNode.TYPE], + }, + { + sourceTypes: [EdgeShapeNode.TYPE], + targetTypes: [RelationshipNode.TYPE], + }, + { + sourceTypes: [ViewObjectNode.TYPE], + targetTypes: [ + EnumNode.TYPE, + NodeShapeNode.TYPE, + RelationshipNode.TYPE, + RelationshipGroupNode.TYPE, + ViewRelationshipNode$1.TYPE, + ], + }, + { + sourceTypes: [ViewRelationshipNode$1.TYPE], + targetTypes: [ + EnumNode.TYPE, + EdgeShapeNode.TYPE, + ObjectNode.TYPE, + AbstractClassNode.TYPE, + ViewObjectNode.TYPE, + ], + }, + ]; + constructor(id, source, target) { + super(id, BiDirAssociationEdge.TYPE, source, target); + var that = this; + + /** + * Connect source and target node and draw the edge on canvas + */ + this.connect = function () { + var source = this.getSource(); + var target = this.getTarget(); + var connectOptions = { + source: source.get$node().get(0), + target: target.get$node().get(0), + paintStyle: { + stroke: "black", + strokeWidth: 4, + }, + endpoint: "Dot", + anchors: [source.getAnchorOptions(), target.getAnchorOptions()], + connector: { + type: StraightConnector.type, + options: { gap: 0 }, + }, + overlays: [ + { + type: "Custom", + options: { + create: function () { + return that.get$overlay().get(0); + }, + location: 0.5, + id: "label", + }, + }, + ], + cssClass: this.getEntityId(), + }; + + if (source === target) { + connectOptions.anchors = ["TopCenter", "LeftMiddle"]; + } + + source.addOutgoingEdge(this); + target.addIngoingEdge(this); + this.setJsPlumbConnection(window.jsPlumbInstance.connect(connectOptions)); + + this.repaintOverlays(); + lodash.each(EntityManagerInstance.getEdges(), function (e) { + e.setZIndex(); + }); + }; + + this.get$overlay().find(".type").addClass("segmented"); + } +} + +const viewrelationshipNodeHtml = "
                                  \n
                                  <%= type %>
                                  \n
                                  <<ViewRelationship>>
                                  \n
                                  \n
                                  "; // replaced by importmap.plugin.js + +/** + * ViewRelationshipNode + * @class canvas_widget.ViewRelationshipNode + * @extends canvas_widget.AbstractNode + * @memberof canvas_widget + * @constructor + * @param {string} id Entity identifier of node + * @param {number} left x-coordinate of node position + * @param {number} top y-coordinate of node position + * @param {number} width Width of node + * @param {number} height Height of node + * @param {number} zIndex Position of node on z-axis + * @param {object} json indicates if the ViewObjectNode is created from a json + + */ +class ViewRelationshipNode extends AbstractNode { + static TYPE = "ViewRelationship"; + static DEFAULT_WIDTH = 150; + static DEFAULT_HEIGHT = 100; + constructor(id, left, top, width, height, zIndex, json) { + super(id, "ViewRelationship", left, top, width, height, zIndex, json); + var that = this; + + /** + * jQuery object of node template + * @type {jQuery} + * @private + */ + var _$template = $( + lodash.template(viewrelationshipNodeHtml)({ + type: that.getType(), + }) + ); + + /** + * jQuery object of DOM node representing the node + * @type {jQuery} + * @private + */ + var _$node = AbstractNode.prototype.get$node + .call(this) + .append(_$template) + .addClass("viewrelationship"); + + /** + * jQuery object of DOM node representing the attributes + * @type {jQuery} + * @private + */ + var _$attributeNode = _$node.find(".attributes"); + + /** + * Attributes of node + * @type {Object} + * @private + */ + this.getAttributes(); + + /** + * Get JSON representation of the node + * @returns {Object} + */ + this.toJSON = function () { + return AbstractNode.prototype.toJSON.call(this); + }; + + this.registerYMap = function () { + AbstractNode.prototype.registerYMap.call(this); + that.getLabel().getValue().registerYType(); + attributeList.registerYMap(); + if (cla) cla.registerYMap(); + attribute.getValue().registerYType(); + conjSelection.getValue().registerYType(); + }; + + this.showAttributes = function () { + if (renamingList.get$node().is(":hidden")) renamingList.get$node().show(); + if (conjSelection.get$node().is(":hidden")) + conjSelection.get$node().show(); + if (cla.get$node().is(":hidden")) cla.get$node().show(); + if (!targetAttribute.get$node().is(":hidden")) + targetAttribute.get$node().hide(); + }; + + this.createConditionListAttribute = function (refAttrs) { + var targetAttrList = {}; + if (refAttrs && refAttrs.constructor.name === "RenamingListAttribute") { + var attrs = refAttrs.getAttributes(); + for (var key in attrs) { + if (attrs.hasOwnProperty(key)) { + targetAttrList[key] = attrs[key].getKey().getValue(); + } + } + } else { + for (var key in refAttrs) { + if (refAttrs.hasOwnProperty(key)) { + targetAttrList[key] = refAttrs[key].val.value; + } + } + } + var conditionListAttr = new ConditionListAttribute( + "[condition]", + "Conditions", + that, + targetAttrList, + LogicalOperator + ); + that.addAttribute(conditionListAttr); + _$attributeNode.append(conditionListAttr.get$node()); + conditionListAttr.get$node().hide(); + return conditionListAttr; + }; + + this.registerYMap = function () { + AbstractNode.prototype.registerYMap.call(this); + that.getLabel().getValue().registerYType(); + renamingList.registerYMap(); + if (cla) cla.registerYMap(); + targetAttribute.getValue().registerYType(); + conjSelection.getValue().registerYType(); + }; + + var targetAttribute, renamingList, conjSelection, cla; + _$node.find(".label").append(this.getLabel().get$node()); + if (window.hasOwnProperty("y")) { + const dataMap = y.getMap("data"); + var model = dataMap.get("model"); + if (model) { + var selectionValues = + ViewTypesUtil.GetAllNodesOfBaseModelAsSelectionList2(model.nodes, [ + "Relationship", + ]); + targetAttribute = new SingleSelectionAttribute( + id + "[target]", + "Reference", + that, + selectionValues + ); + that.addAttribute(targetAttribute); + _$attributeNode.prepend(targetAttribute.get$node()); + + if (json) + cla = that.createConditionListAttribute( + json.attributes["[attributes]"].list + ); + else cla = that.createConditionListAttribute(); + } + } + + renamingList = new RenamingListAttribute( + "[attributes]", + "Attributes", + that, + { + hidden: "Show", + top: "Show Top", + center: "Show Center", + bottom: "Show Bottom", + hide: "Hide", + } + ); + that.addAttribute(renamingList); + _$attributeNode.append(renamingList.get$node()); + renamingList.get$node().hide(); + + conjSelection = new SingleSelectionAttribute( + id + "[conjunction]", + "Conjunction", + that, + LogicalConjunctions + ); + that.addAttribute(conjSelection); + _$attributeNode.append(conjSelection.get$node()); + conjSelection.get$node().hide(); + + if (json && conjSelection && cla && renamingList && targetAttribute) + that.showAttributes(); + + this.setContextMenuItemCallback(function () { + var viewId = $("#lblCurrentView").text(); + return { + addShape: { + name: "Add Edge Shape", + callback: function () { + var canvas = that.getCanvas(), + appearance = that.getAppearance(), + nodeId; + + canvas.createNode( + EdgeShapeNode.TYPE, + appearance.left + appearance.width + 50, + appearance.top, + 150, + 100 + ); + canvas.createEdge( + BiDirAssociationEdge.TYPE, + that.getEntityId(), + nodeId, + null, + null, + viewId + ); + }, + disabled: function () { + var edges = that.getEdges(), + edge, + edgeId; + + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + if ( + (edge instanceof BiDirAssociationEdge && + ((edge.getTarget() === that && + edge.getSource() instanceof EdgeShapeNode) || + (edge.getSource() === that && + edge.getTarget() instanceof EdgeShapeNode))) || + (edge instanceof UniDirAssociationEdge && + edge.getTarget() instanceof EdgeShapeNode) + ) { + return true; + } + } + } + return false; + }, + }, + sep: "---------", + }; + }); + } } -const viewrelationshipNodeHtml = "
                                  \r\n
                                  <%= type %>
                                  \r\n
                                  <<ViewRelationship>>
                                  \r\n
                                  \r\n
                                  "; // replaced by importmap.plugin.js - -/** - * ViewRelationshipNode - * @class canvas_widget.ViewRelationshipNode - * @extends canvas_widget.AbstractNode - * @memberof canvas_widget - * @constructor - * @param {string} id Entity identifier of node - * @param {number} left x-coordinate of node position - * @param {number} top y-coordinate of node position - * @param {number} width Width of node - * @param {number} height Height of node - * @param {number} zIndex Position of node on z-axis - * @param {object} json indicates if the ViewObjectNode is created from a json - - */ -class ViewRelationshipNode extends AbstractNode { - static TYPE = "ViewRelationship"; - static DEFAULT_WIDTH = 150; - static DEFAULT_HEIGHT = 100; - constructor(id, left, top, width, height, zIndex, json) { - super(id, "ViewRelationship", left, top, width, height, zIndex, json); - var that = this; - - /** - * jQuery object of node template - * @type {jQuery} - * @private - */ - var _$template = $( - lodash.template(viewrelationshipNodeHtml)({ - type: that.getType(), - }) - ); - - /** - * jQuery object of DOM node representing the node - * @type {jQuery} - * @private - */ - var _$node = AbstractNode.prototype.get$node - .call(this) - .append(_$template) - .addClass("viewrelationship"); - - /** - * jQuery object of DOM node representing the attributes - * @type {jQuery} - * @private - */ - var _$attributeNode = _$node.find(".attributes"); - - /** - * Attributes of node - * @type {Object} - * @private - */ - this.getAttributes(); - - /** - * Get JSON representation of the node - * @returns {Object} - */ - this.toJSON = function () { - return AbstractNode.prototype.toJSON.call(this); - }; - - this.registerYMap = function () { - AbstractNode.prototype.registerYMap.call(this); - that.getLabel().getValue().registerYType(); - attributeList.registerYMap(); - if (cla) cla.registerYMap(); - attribute.getValue().registerYType(); - conjSelection.getValue().registerYType(); - }; - - this.showAttributes = function () { - if (renamingList.get$node().is(":hidden")) renamingList.get$node().show(); - if (conjSelection.get$node().is(":hidden")) - conjSelection.get$node().show(); - if (cla.get$node().is(":hidden")) cla.get$node().show(); - if (!targetAttribute.get$node().is(":hidden")) - targetAttribute.get$node().hide(); - }; - - this.createConditionListAttribute = function (refAttrs) { - var targetAttrList = {}; - if (refAttrs && refAttrs.constructor.name === "RenamingListAttribute") { - var attrs = refAttrs.getAttributes(); - for (var key in attrs) { - if (attrs.hasOwnProperty(key)) { - targetAttrList[key] = attrs[key].getKey().getValue(); - } - } - } else { - for (var key in refAttrs) { - if (refAttrs.hasOwnProperty(key)) { - targetAttrList[key] = refAttrs[key].val.value; - } - } - } - var conditionListAttr = new ConditionListAttribute( - "[condition]", - "Conditions", - that, - targetAttrList, - LogicalOperator - ); - that.addAttribute(conditionListAttr); - _$attributeNode.append(conditionListAttr.get$node()); - conditionListAttr.get$node().hide(); - return conditionListAttr; - }; - - this.registerYMap = function () { - AbstractNode.prototype.registerYMap.call(this); - that.getLabel().getValue().registerYType(); - renamingList.registerYMap(); - if (cla) cla.registerYMap(); - targetAttribute.getValue().registerYType(); - conjSelection.getValue().registerYType(); - }; - - var targetAttribute, renamingList, conjSelection, cla; - _$node.find(".label").append(this.getLabel().get$node()); - if (window.hasOwnProperty("y")) { - const dataMap = y.getMap("data"); - var model = dataMap.get("model"); - if (model) { - var selectionValues = - ViewTypesUtil.GetAllNodesOfBaseModelAsSelectionList2(model.nodes, [ - "Relationship", - ]); - targetAttribute = new SingleSelectionAttribute( - id + "[target]", - "Reference", - that, - selectionValues - ); - that.addAttribute(targetAttribute); - _$attributeNode.prepend(targetAttribute.get$node()); - - if (json) - cla = that.createConditionListAttribute( - json.attributes["[attributes]"].list - ); - else cla = that.createConditionListAttribute(); - } - } - - renamingList = new RenamingListAttribute( - "[attributes]", - "Attributes", - that, - { - hidden: "Show", - top: "Show Top", - center: "Show Center", - bottom: "Show Bottom", - hide: "Hide", - } - ); - that.addAttribute(renamingList); - _$attributeNode.append(renamingList.get$node()); - renamingList.get$node().hide(); - - conjSelection = new SingleSelectionAttribute( - id + "[conjunction]", - "Conjunction", - that, - LogicalConjunctions - ); - that.addAttribute(conjSelection); - _$attributeNode.append(conjSelection.get$node()); - conjSelection.get$node().hide(); - - if (json && conjSelection && cla && renamingList && targetAttribute) - that.showAttributes(); - - this.setContextMenuItemCallback(function () { - var viewId = $("#lblCurrentView").text(); - return { - addShape: { - name: "Add Edge Shape", - callback: function () { - var canvas = that.getCanvas(), - appearance = that.getAppearance(), - nodeId; - - canvas.createNode( - EdgeShapeNode.TYPE, - appearance.left + appearance.width + 50, - appearance.top, - 150, - 100 - ); - canvas.createEdge( - BiDirAssociationEdge.TYPE, - that.getEntityId(), - nodeId, - null, - null, - viewId - ); - }, - disabled: function () { - var edges = that.getEdges(), - edge, - edgeId; - - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - if ( - (edge instanceof BiDirAssociationEdge && - ((edge.getTarget() === that && - edge.getSource() instanceof EdgeShapeNode) || - (edge.getSource() === that && - edge.getTarget() instanceof EdgeShapeNode))) || - (edge instanceof UniDirAssociationEdge && - edge.getTarget() instanceof EdgeShapeNode) - ) { - return true; - } - } - } - return false; - }, - }, - sep: "---------", - }; - }); - } -} - -function GenerateViewpointModel(viewpointModel, y) { - EntityManagerInstance.init(); - - for (var node_key in viewpointModel.nodes) { - if (viewpointModel.nodes.hasOwnProperty(node_key)) { - var vpNode = viewpointModel.nodes[node_key]; - const width = vpNode.width || vpNode.containment.width; - const height = vpNode.height || vpNode.containment.height; - const left = vpNode.left || vpNode.containment.left; - const top = vpNode.top || vpNode.containment.top; - const zIndex = vpNode.zIndex || vpNode.containment.zIndex; - EntityManagerInstance.createNodeFromJSON( - vpNode.type, - node_key, - left, - top, - width, - height, - zIndex, - vpNode.containment, - vpNode, - y - ); - } - } - - for (var edge_key in viewpointModel.edges) { - if (viewpointModel.edges.hasOwnProperty(edge_key)) { - var vpEdge = viewpointModel.edges[edge_key]; - EntityManagerInstance.createEdgeFromJSON( - vpEdge.type, - edge_key, - vpEdge.source, - vpEdge.target, - vpEdge - ); - } - } - - /** - * Determine the type of the concrete classes (ObjectNodes) of the class diagram contained in the sub graph rooted by the passed node - * @param node Node to start with - * @param [visitedNodes] List of node that already have been visited - * @returns {object} - */ - function getConcreteObjectNodeTypes(node, visitedNodes) { - var edgeId, - edge, - ingoingEdges, - source, - type, - classTypes = []; - - if (!visitedNodes) visitedNodes = []; - - if (visitedNodes.indexOf(node) !== -1) return []; - - visitedNodes.push(node); - - type = node.getLabel().getValue().getValue(); - if ( - (node instanceof ObjectNode || node instanceof ViewObjectNode) && - classTypes.indexOf(type) === -1 - ) { - classTypes.push(type); - } - - ingoingEdges = node.getIngoingEdges(); - for (edgeId in ingoingEdges) { - if (ingoingEdges.hasOwnProperty(edgeId)) { - edge = ingoingEdges[edgeId]; - source = edge.getSource(); - if ( - (edge instanceof GeneralisationEdge && - source instanceof ObjectNode) || - (edge instanceof GeneralisationEdge && - source instanceof AbstractClassNode) || - (edge instanceof GeneralisationEdge && - source instanceof ViewObjectNode) - ) { - classTypes = classTypes.concat( - getConcreteObjectNodeTypes(source, visitedNodes) - ); - } - } - } - return classTypes; - } - - /** - * Determine the attributes of the passed node by traversing the underlying class diagram - * @param node Node to start with - * @param [visitedNodes] List of node that already have been visited - * @returns {object} - */ - function getNodeAttributes(node, visitedNodes) { - var nodeAttributes, attributeId, attribute; - var edgeId, edge, outgoingEdges; - var source, target; - var neighbor, options; - var attributes = {}; - var obj = {}; - - if (!visitedNodes) visitedNodes = []; - - if (visitedNodes.indexOf(node) !== -1) return {}; - - visitedNodes.push(node); - - //Traverse outgoing edges to check for inheritance and linked enums - outgoingEdges = node.getOutgoingEdges(); - for (edgeId in outgoingEdges) { - if (outgoingEdges.hasOwnProperty(edgeId)) { - edge = outgoingEdges[edgeId]; - source = edge.getSource(); - target = edge.getTarget(); - - //Does the node inherit attributes from a parent node? - if ( - (edge instanceof GeneralisationEdge && - target instanceof AbstractClassNode) || - (edge instanceof GeneralisationEdge && - node instanceof ObjectNode && - target instanceof ObjectNode) || - (edge instanceof GeneralisationEdge && - node instanceof RelationshipNode && - target instanceof RelationshipNode) || - (edge instanceof GeneralisationEdge && - node instanceof EnumNode && - target instanceof EnumNode) - ) { - Util.merge(attributes, getNodeAttributes(target, visitedNodes)); - - //Is there an enum linked to the node - } else if ( - (edge instanceof BiDirAssociationEdge && - ((target === node && (neighbor = source) instanceof EnumNode) || - (source === node && (neighbor = target) instanceof EnumNode))) || - (edge instanceof UniDirAssociationEdge && - (neighbor = target) instanceof EnumNode) - ) { - options = {}; - nodeAttributes = {}; - Util.merge(nodeAttributes, getNodeAttributes(neighbor, [])); - for (attributeId in nodeAttributes) { - if (nodeAttributes.hasOwnProperty(attributeId)) { - attribute = nodeAttributes[attributeId]; - options[attribute.value] = attribute.value; - } - } - obj = {}; - obj[neighbor.getEntityId()] = { - key: edge.getLabel().getValue().getValue(), - value: neighbor.getLabel().getValue().getValue(), - options: options, - }; - Util.merge(attributes, obj); - } - } - } - //Compute node attributes - nodeAttributes = node.getAttribute("[attributes]").getAttributes(); - for (attributeId in nodeAttributes) { - if (nodeAttributes.hasOwnProperty(attributeId)) { - attribute = nodeAttributes[attributeId]; - if (node instanceof RelationshipNode) { - obj = {}; - obj[attributeId] = { - key: attribute.getKey().getValue(), - value: attribute.getValue().getValue(), - position: attribute.getValue2().getValue(), - }; - Util.merge(attributes, obj); - } else if (node instanceof ViewRelationshipNode) { - obj = {}; - obj[attributeId] = { - key: attribute.getKey().getValue(), - ref: attribute.getRef().getValue(), - position: attribute.getVis().getValue(), - }; - Util.merge(attributes, obj); - } else if (node instanceof EnumNode) { - obj = {}; - obj[attributeId] = { - value: attribute.getValue().getValue(), - }; - Util.merge(attributes, obj); - } else if (node instanceof ViewObjectNode) { - obj = {}; - obj[attributeId] = { - key: attribute.getKey().getValue(), - ref: attribute.getRef().getValue(), - visibility: attribute.getVis().getValue(), - }; - Util.merge(attributes, obj); - } else { - obj = {}; - obj[attributeId] = { - key: attribute.getKey().getValue(), - value: attribute.getValue().getValue(), - }; - Util.merge(attributes, obj); - } - } - } - return attributes; - } - - function getViewTypeAttributes(node) { - var target, targetName; - var conjunction; - var conditions = {}; - var nodeid = node.getEntityId(); - if (viewpointModel.nodes.hasOwnProperty(nodeid)) { - if ( - viewpointModel.nodes[nodeid].attributes.hasOwnProperty( - nodeid + "[target]" - ) - ) { - var attr = viewpointModel.nodes[nodeid].attributes[nodeid + "[target]"]; - target = attr.value.value; - targetName = attr.hasOwnProperty("option") ? attr.option : null; - } - if ( - viewpointModel.nodes[nodeid].attributes.hasOwnProperty("[condition]") - ) { - var conditionsList = - viewpointModel.nodes[nodeid].attributes["[condition]"].list; - for (var condId in conditionsList) { - if (conditionsList.hasOwnProperty(condId)) { - conditions[condId] = { - property: conditionsList[condId].property.value, - operator: conditionsList[condId].operator.value, - value: conditionsList[condId].val.value, - //conjunction: conditionsList[condId].operator2.value - }; - } - } - } - if ( - viewpointModel.nodes[nodeid].attributes.hasOwnProperty( - nodeid + "[conjunction]" - ) - ) { - conjunction = - viewpointModel.nodes[nodeid].attributes[nodeid + "[conjunction]"] - .value.value; - } - } - return { - target: target, - targetName: targetName, - conditions: conditions, - conjunction: conjunction, - }; - } - - var metamodel = { - attributes: {}, - nodes: {}, - edges: {}, - }; - - var nodeId, node; - var attributes; - var edge, edgeId, edges; - var source, target; - var neighbor; - var groupSource, groupTarget; - var groupNeighbor; - var shape; - var sourceTypes, targetTypes, concreteTypes; - var groupSourceTypes, groupTargetTypes, groupConcreteTypes; - var relations; - var groupEdge, groupEdgeId, groupEdges; - var viewtypeAttrs; - - var _nodes = EntityManagerInstance.getNodes(); - for (nodeId in _nodes) { - if (_nodes.hasOwnProperty(nodeId)) { - node = _nodes[nodeId]; - if (node instanceof ObjectNode || node instanceof ViewObjectNode) { - if (node.getLabel().getValue().getValue() === "Model Attributes") { - attributes = getNodeAttributes(node); - metamodel.attributes = attributes; - } else { - attributes = getNodeAttributes(node); - edges = node.getEdges(); - shape = null; - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - source = edge.getSource(); - target = edge.getTarget(); - if ( - (edge instanceof BiDirAssociationEdge && - ((target === node && - (neighbor = source) instanceof NodeShapeNode) || - (source === node && - (neighbor = target) instanceof NodeShapeNode))) || - (edge instanceof UniDirAssociationEdge && - (neighbor = target) instanceof NodeShapeNode) - ) { - shape = { - shape: neighbor - .getAttribute(neighbor.getEntityId() + "[shape]") - .getValue() - .getValue(), - color: neighbor - .getAttribute(neighbor.getEntityId() + "[color]") - .getValue() - .getValue(), - defaultWidth: parseInt( - neighbor - .getAttribute(neighbor.getEntityId() + "[defaultWidth]") - .getValue() - .getValue() - ), - defaultHeight: parseInt( - neighbor - .getAttribute(neighbor.getEntityId() + "[defaultHeight]") - .getValue() - .getValue() - ), - containment: neighbor - .getAttribute(neighbor.getEntityId() + "[containment]") - .getValue() - .getValue(), - customShape: neighbor - .getAttribute(neighbor.getEntityId() + "[customShape]") - .getValue() - .getValue(), - customAnchors: neighbor - .getAttribute(neighbor.getEntityId() + "[customAnchors]") - .getValue() - .getValue(), - }; - } - } - } - - metamodel.nodes[nodeId] = { - label: node.getLabel().getValue().getValue(), - attributes: attributes, - shape: shape || { - shape: "rectangle", - color: "white", - containment: false, - customShape: "", - customAnchors: "", - defaultWidth: 0, - defaultHeight: 0, - }, - }; - if (node instanceof ViewObjectNode) { - viewtypeAttrs = getViewTypeAttributes(node); - Util.merge(metamodel.nodes[nodeId], viewtypeAttrs); - } - } - } else if ( - node instanceof RelationshipNode || - node instanceof ViewRelationshipNode - ) { - attributes = getNodeAttributes(node); - edges = node.getEdges(); - sourceTypes = []; - targetTypes = []; - relations = []; - shape = null; - for (edgeId in edges) { - if (edges.hasOwnProperty(edgeId)) { - edge = edges[edgeId]; - source = edge.getSource(); - target = edge.getTarget(); - if ( - edge instanceof BiDirAssociationEdge && - ((target === node && (neighbor = source) instanceof ObjectNode) || - (target === node && - (neighbor = source) instanceof ViewObjectNode) || - (source === node && - (neighbor = target) instanceof ObjectNode) || - (source === node && - (neighbor = target) instanceof ViewObjectNode)) - ) { - concreteTypes = getConcreteObjectNodeTypes(neighbor); - sourceTypes = sourceTypes.concat(concreteTypes); - targetTypes = targetTypes.concat(concreteTypes); - } else if ( - edge instanceof UniDirAssociationEdge && - source === node && - (target instanceof ObjectNode || target instanceof ViewObjectNode) - ) { - targetTypes = targetTypes.concat( - getConcreteObjectNodeTypes(target) - ); - } else if ( - edge instanceof UniDirAssociationEdge && - target === node && - (source instanceof ObjectNode || source instanceof ViewObjectNode) - ) { - sourceTypes = sourceTypes.concat( - getConcreteObjectNodeTypes(source) - ); - } else if ( - edge instanceof BiDirAssociationEdge && - ((target === node && - (neighbor = source) instanceof AbstractClassNode) || - (source === node && - (neighbor = target) instanceof AbstractClassNode)) - ) { - concreteTypes = getConcreteObjectNodeTypes(neighbor); - sourceTypes = sourceTypes.concat(concreteTypes); - targetTypes = targetTypes.concat(concreteTypes); - } else if ( - edge instanceof UniDirAssociationEdge && - source === node && - target instanceof AbstractClassNode - ) { - targetTypes = targetTypes.concat( - getConcreteObjectNodeTypes(target) - ); - } else if ( - edge instanceof UniDirAssociationEdge && - target === node && - source instanceof AbstractClassNode - ) { - sourceTypes = sourceTypes.concat( - getConcreteObjectNodeTypes(source) - ); - } else if ( - (edge instanceof BiDirAssociationEdge && - ((target === node && - (neighbor = source) instanceof EdgeShapeNode) || - (source === node && - (neighbor = target) instanceof EdgeShapeNode))) || - (edge instanceof UniDirAssociationEdge && - source === node && - (neighbor = target) instanceof EdgeShapeNode) - ) { - shape = { - arrow: neighbor - .getAttribute(neighbor.getEntityId() + "[arrow]") - .getValue() - .getValue(), - shape: neighbor - .getAttribute(neighbor.getEntityId() + "[shape]") - .getValue() - .getValue(), - color: neighbor - .getAttribute(neighbor.getEntityId() + "[color]") - .getValue() - .getValue(), - overlay: neighbor - .getAttribute(neighbor.getEntityId() + "[overlay]") - .getValue() - .getValue(), - overlayPosition: neighbor - .getAttribute(neighbor.getEntityId() + "[overlayPosition]") - .getValue() - .getValue(), - overlayRotate: neighbor - .getAttribute(neighbor.getEntityId() + "[overlayRotate]") - .getValue() - .getValue(), - }; - } else if ( - edge instanceof GeneralisationEdge && - target === node && - (neighbor = source) instanceof RelationshipGroupNode - ) { - groupEdges = neighbor.getEdges(); - groupSourceTypes = []; - groupTargetTypes = []; - for (groupEdgeId in groupEdges) { - if (groupEdges.hasOwnProperty(groupEdgeId)) { - groupEdge = groupEdges[groupEdgeId]; - groupSource = groupEdge.getSource(); - groupTarget = groupEdge.getTarget(); - if ( - groupEdge instanceof BiDirAssociationEdge && - ((groupTarget === neighbor && - (groupNeighbor = groupSource) instanceof ObjectNode) || - (groupSource === neighbor && - (groupNeighbor = groupTarget) instanceof ObjectNode) || - (groupTarget === neighbor && - (groupNeighbor = groupSource) instanceof - ViewObjectNode) || - (groupSource === neighbor && - (groupNeighbor = groupTarget) instanceof - ViewObjectNode)) - ) { - groupConcreteTypes = - getConcreteObjectNodeTypes(groupNeighbor); - groupSourceTypes = - groupSourceTypes.concat(groupConcreteTypes); - groupTargetTypes = - groupTargetTypes.concat(groupConcreteTypes); - } else if ( - groupEdge instanceof UniDirAssociationEdge && - groupSource === neighbor && - (groupTarget instanceof ObjectNode || - groupTarget instanceof ViewObjectNode) - ) { - groupTargetTypes = groupTargetTypes.concat( - getConcreteObjectNodeTypes(groupTarget) - ); - } else if ( - groupEdge instanceof UniDirAssociationEdge && - groupTarget === neighbor && - (groupSource instanceof ObjectNode || - groupSource instanceof ViewObjectNode) - ) { - groupSourceTypes = groupSourceTypes.concat( - getConcreteObjectNodeTypes(groupSource) - ); - } else if ( - groupEdge instanceof BiDirAssociationEdge && - ((groupTarget === neighbor && - (groupNeighbor = groupSource) instanceof - AbstractClassNode) || - (groupSource === neighbor && - (groupNeighbor = groupTarget) instanceof - AbstractClassNode)) - ) { - groupConcreteTypes = - getConcreteObjectNodeTypes(groupNeighbor); - groupSourceTypes = - groupSourceTypes.concat(groupConcreteTypes); - groupTargetTypes = - groupTargetTypes.concat(groupConcreteTypes); - } else if ( - groupEdge instanceof UniDirAssociationEdge && - groupSource === neighbor && - groupTarget instanceof AbstractClassNode - ) { - groupTargetTypes = groupTargetTypes.concat( - getConcreteObjectNodeTypes(groupTarget) - ); - } else if ( - groupEdge instanceof UniDirAssociationEdge && - groupTarget === neighbor && - groupSource instanceof AbstractClassNode - ) { - groupSourceTypes = groupSourceTypes.concat( - getConcreteObjectNodeTypes(groupSource) - ); - } - } - } - - if (groupSourceTypes.length > 0 && groupTargetTypes.length > 0) { - relations.push({ - sourceTypes: groupSourceTypes, - targetTypes: groupTargetTypes, - }); - } - } - } - } - - if (sourceTypes.length > 0 && targetTypes.length > 0) { - relations.push({ - sourceTypes: sourceTypes, - targetTypes: targetTypes, - }); - } - - metamodel.edges[nodeId] = { - label: node.getLabel().getValue().getValue(), - shape: shape || { - arrow: "bidirassociation", - shape: "straight", - color: "black", - overlay: "", - overlayPosition: "top", - overlayRotate: true, - }, - relations: relations, - attributes: attributes, - }; - if (node instanceof ViewRelationshipNode) { - viewtypeAttrs = getViewTypeAttributes(node); - Util.merge(metamodel.edges[nodeId], viewtypeAttrs); - } - } - } - } - metamodel["id"] = viewpointModel.id; - EntityManagerInstance.reset(); - return metamodel; -} - -async function yjsSync( - spaceTitle, - yjsServer = "localhost:1234", - yjsProtocol = "ws" -) { - let title; - - if (!spaceTitle) { - if (window.caeRoom) { - title = window.caeRoom; - } else if (localStorage.getItem("syncmetaSpace")) { - title = localStorage.getItem("syncmetaSpace"); - } else { - title = Util.getSpaceTitle(location.href); - } - } - - if (window.y && title === spaceTitle) { - // yjs is already initialized and we are using the same spaceTitle - return new Promise((resolve) => resolve(window.y)); - } - - const doc = new Doc(); - - // Sync clients with the y-websocket provider - const websocketProvider = new WebsocketProvider( - `${yjsProtocol}://${yjsServer}`, - title, - doc - ); - - await new Promise((resolve, reject) => { - websocketProvider.on("status", (event) => { - // console.log(event.status); // logs "connected" or "disconnected" - - if (event.status == "connected") { - if (!window.y) { - window.y = doc; - } - resolve(title); - } - }); - setTimeout(() => { - reject("YJS connection timed out. This means syncmeta widgets wont work"); - }, 5000); - }); - if (window.y) { - // it could be that another yjsSync call was made before this one resolved - return window.y; - } - return doc; -} - -function init () { - var createReloadHandler = function () { - var iwcClient = window._iwc_instance_; - var intent_listener = []; - if (iwcClient && iwcClient.onIntent != null) { - var previous_iwc_onIntent = iwcClient.onIntent; - iwcClient.onIntent = function (message) { - if (message.action === "RELOAD") { - console.log(" K!!!!!!!!!!!!!!!!!!!!!!!!!!!! RELOAD!!!!!!!!!!!!!!!!!!!!!"); - window.location.reload(); - } - else { - for (var i = 0; i < intent_listener.length; i++) { - intent_listener[i].apply(this, arguments); - } - } - previous_iwc_onIntent.apply(this, arguments); - }; - window._addIwcIntentListener = function (f) { - intent_listener.push(f); - }; - window._reloadThisFuckingInstance = function () { - console.log("Reloading Everything"); - var message = { - action: "RELOAD", - component: "", - data: "", - dataType: "", - flags: ["PUBLISH_GLOBAL"], - extras: { - reload: true, - }, - }; - iwcClient.publish(message); - }; - } - else { - setTimeout(createReloadHandler, 5000); - } - }; - setTimeout(createReloadHandler, 10000); -} - -const SyncMetaWidget = (superClass, widgetName) => { - if (!widgetName) { - throw new Error("widgetName cannot be empty"); - } - class SyncMetaWidgetElement extends superClass { - constructor() { - super(...arguments); - this.widgetName = widgetName; - } - createRenderRoot() { - return this; - } - render() { - return html ` `; - } - firstUpdated() { - this.hideErrorAlert(); - } - connectedCallback() { - super.connectedCallback(); - init(); - if (!window.hasOwnProperty("y")) { - yjsSync().then((y) => { - if (!window.hasOwnProperty("y")) - window.y = y; - }); - } - } - disconnectedCallback() { - super.disconnectedCallback(); - } - hideErrorAlert() { - $(this.widgetName).find("#alert-message").text(""); - $(this.widgetName).find("error-alert").hide(); - } - showErrorAlert(message) { - $(this.widgetName).find("#alert-message").text(message); - $(this.widgetName).find("error-alert").hide(); - } - } - SyncMetaWidgetElement.styles = css ` - .loading { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - /*noinspection CssUnknownTarget*/ - background: white url("/img/loading.gif") no-repeat center center; - z-index: 32032; - opacity: 0.75; - } - - #oauthPersonalize, - #oauthPersonalizeDone, - #oauthPersonalizeComplete { - position: relative; - z-index: 32033; - } - - #q { - position: absolute; - width: 100%; - height: 3px; - bottom: 0; - left: 0; - cursor: s-resize; - } - `; - return SyncMetaWidgetElement; +function GenerateViewpointModel(viewpointModel, y) { + EntityManagerInstance.init(); + + for (var node_key in viewpointModel.nodes) { + if (viewpointModel.nodes.hasOwnProperty(node_key)) { + var vpNode = viewpointModel.nodes[node_key]; + const width = vpNode.width || vpNode.containment.width; + const height = vpNode.height || vpNode.containment.height; + const left = vpNode.left || vpNode.containment.left; + const top = vpNode.top || vpNode.containment.top; + const zIndex = vpNode.zIndex || vpNode.containment.zIndex; + EntityManagerInstance.createNodeFromJSON( + vpNode.type, + node_key, + left, + top, + width, + height, + zIndex, + vpNode.containment, + vpNode, + y + ); + } + } + + for (var edge_key in viewpointModel.edges) { + if (viewpointModel.edges.hasOwnProperty(edge_key)) { + var vpEdge = viewpointModel.edges[edge_key]; + EntityManagerInstance.createEdgeFromJSON( + vpEdge.type, + edge_key, + vpEdge.source, + vpEdge.target, + vpEdge + ); + } + } + + /** + * Determine the type of the concrete classes (ObjectNodes) of the class diagram contained in the sub graph rooted by the passed node + * @param node Node to start with + * @param [visitedNodes] List of node that already have been visited + * @returns {object} + */ + function getConcreteObjectNodeTypes(node, visitedNodes) { + var edgeId, + edge, + ingoingEdges, + source, + type, + classTypes = []; + + if (!visitedNodes) visitedNodes = []; + + if (visitedNodes.indexOf(node) !== -1) return []; + + visitedNodes.push(node); + + type = node.getLabel().getValue().getValue(); + if ( + (node instanceof ObjectNode || node instanceof ViewObjectNode) && + classTypes.indexOf(type) === -1 + ) { + classTypes.push(type); + } + + ingoingEdges = node.getIngoingEdges(); + for (edgeId in ingoingEdges) { + if (ingoingEdges.hasOwnProperty(edgeId)) { + edge = ingoingEdges[edgeId]; + source = edge.getSource(); + if ( + (edge instanceof GeneralisationEdge && + source instanceof ObjectNode) || + (edge instanceof GeneralisationEdge && + source instanceof AbstractClassNode) || + (edge instanceof GeneralisationEdge && + source instanceof ViewObjectNode) + ) { + classTypes = classTypes.concat( + getConcreteObjectNodeTypes(source, visitedNodes) + ); + } + } + } + return classTypes; + } + + /** + * Determine the attributes of the passed node by traversing the underlying class diagram + * @param node Node to start with + * @param [visitedNodes] List of node that already have been visited + * @returns {object} + */ + function getNodeAttributes(node, visitedNodes) { + var nodeAttributes, attributeId, attribute; + var edgeId, edge, outgoingEdges; + var source, target; + var neighbor, options; + var attributes = {}; + var obj = {}; + + if (!visitedNodes) visitedNodes = []; + + if (visitedNodes.indexOf(node) !== -1) return {}; + + visitedNodes.push(node); + + //Traverse outgoing edges to check for inheritance and linked enums + outgoingEdges = node.getOutgoingEdges(); + for (edgeId in outgoingEdges) { + if (outgoingEdges.hasOwnProperty(edgeId)) { + edge = outgoingEdges[edgeId]; + source = edge.getSource(); + target = edge.getTarget(); + + //Does the node inherit attributes from a parent node? + if ( + (edge instanceof GeneralisationEdge && + target instanceof AbstractClassNode) || + (edge instanceof GeneralisationEdge && + node instanceof ObjectNode && + target instanceof ObjectNode) || + (edge instanceof GeneralisationEdge && + node instanceof RelationshipNode && + target instanceof RelationshipNode) || + (edge instanceof GeneralisationEdge && + node instanceof EnumNode && + target instanceof EnumNode) + ) { + Util.merge(attributes, getNodeAttributes(target, visitedNodes)); + + //Is there an enum linked to the node + } else if ( + (edge instanceof BiDirAssociationEdge && + ((target === node && (neighbor = source) instanceof EnumNode) || + (source === node && (neighbor = target) instanceof EnumNode))) || + (edge instanceof UniDirAssociationEdge && + (neighbor = target) instanceof EnumNode) + ) { + options = {}; + nodeAttributes = {}; + Util.merge(nodeAttributes, getNodeAttributes(neighbor, [])); + for (attributeId in nodeAttributes) { + if (nodeAttributes.hasOwnProperty(attributeId)) { + attribute = nodeAttributes[attributeId]; + options[attribute.value] = attribute.value; + } + } + obj = {}; + obj[neighbor.getEntityId()] = { + key: edge.getLabel().getValue().getValue(), + value: neighbor.getLabel().getValue().getValue(), + options: options, + }; + Util.merge(attributes, obj); + } + } + } + //Compute node attributes + nodeAttributes = node.getAttribute("[attributes]").getAttributes(); + for (attributeId in nodeAttributes) { + if (nodeAttributes.hasOwnProperty(attributeId)) { + attribute = nodeAttributes[attributeId]; + if (node instanceof RelationshipNode) { + obj = {}; + obj[attributeId] = { + key: attribute.getKey().getValue(), + value: attribute.getValue().getValue(), + position: attribute.getValue2().getValue(), + }; + Util.merge(attributes, obj); + } else if (node instanceof ViewRelationshipNode) { + obj = {}; + obj[attributeId] = { + key: attribute.getKey().getValue(), + ref: attribute.getRef().getValue(), + position: attribute.getVis().getValue(), + }; + Util.merge(attributes, obj); + } else if (node instanceof EnumNode) { + obj = {}; + obj[attributeId] = { + value: attribute.getValue().getValue(), + }; + Util.merge(attributes, obj); + } else if (node instanceof ViewObjectNode) { + obj = {}; + obj[attributeId] = { + key: attribute.getKey().getValue(), + ref: attribute.getRef().getValue(), + visibility: attribute.getVis().getValue(), + }; + Util.merge(attributes, obj); + } else { + obj = {}; + obj[attributeId] = { + key: attribute.getKey().getValue(), + value: attribute.getValue().getValue(), + }; + Util.merge(attributes, obj); + } + } + } + return attributes; + } + + function getViewTypeAttributes(node) { + var target, targetName; + var conjunction; + var conditions = {}; + var nodeid = node.getEntityId(); + if (viewpointModel.nodes.hasOwnProperty(nodeid)) { + if ( + viewpointModel.nodes[nodeid].attributes.hasOwnProperty( + nodeid + "[target]" + ) + ) { + var attr = viewpointModel.nodes[nodeid].attributes[nodeid + "[target]"]; + target = attr.value.value; + targetName = attr.hasOwnProperty("option") ? attr.option : null; + } + if ( + viewpointModel.nodes[nodeid].attributes.hasOwnProperty("[condition]") + ) { + var conditionsList = + viewpointModel.nodes[nodeid].attributes["[condition]"].list; + for (var condId in conditionsList) { + if (conditionsList.hasOwnProperty(condId)) { + conditions[condId] = { + property: conditionsList[condId].property.value, + operator: conditionsList[condId].operator.value, + value: conditionsList[condId].val.value, + //conjunction: conditionsList[condId].operator2.value + }; + } + } + } + if ( + viewpointModel.nodes[nodeid].attributes.hasOwnProperty( + nodeid + "[conjunction]" + ) + ) { + conjunction = + viewpointModel.nodes[nodeid].attributes[nodeid + "[conjunction]"] + .value.value; + } + } + return { + target: target, + targetName: targetName, + conditions: conditions, + conjunction: conjunction, + }; + } + + var metamodel = { + attributes: {}, + nodes: {}, + edges: {}, + }; + + var nodeId, node; + var attributes; + var edge, edgeId, edges; + var source, target; + var neighbor; + var groupSource, groupTarget; + var groupNeighbor; + var shape; + var sourceTypes, targetTypes, concreteTypes; + var groupSourceTypes, groupTargetTypes, groupConcreteTypes; + var relations; + var groupEdge, groupEdgeId, groupEdges; + var viewtypeAttrs; + + var _nodes = EntityManagerInstance.getNodes(); + for (nodeId in _nodes) { + if (_nodes.hasOwnProperty(nodeId)) { + node = _nodes[nodeId]; + if (node instanceof ObjectNode || node instanceof ViewObjectNode) { + if (node.getLabel().getValue().getValue() === "Model Attributes") { + attributes = getNodeAttributes(node); + metamodel.attributes = attributes; + } else { + attributes = getNodeAttributes(node); + edges = node.getEdges(); + shape = null; + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + source = edge.getSource(); + target = edge.getTarget(); + if ( + (edge instanceof BiDirAssociationEdge && + ((target === node && + (neighbor = source) instanceof NodeShapeNode) || + (source === node && + (neighbor = target) instanceof NodeShapeNode))) || + (edge instanceof UniDirAssociationEdge && + (neighbor = target) instanceof NodeShapeNode) + ) { + shape = { + shape: neighbor + .getAttribute(neighbor.getEntityId() + "[shape]") + .getValue() + .getValue(), + color: neighbor + .getAttribute(neighbor.getEntityId() + "[color]") + .getValue() + .getValue(), + defaultWidth: parseInt( + neighbor + .getAttribute(neighbor.getEntityId() + "[defaultWidth]") + .getValue() + .getValue() + ), + defaultHeight: parseInt( + neighbor + .getAttribute(neighbor.getEntityId() + "[defaultHeight]") + .getValue() + .getValue() + ), + containment: neighbor + .getAttribute(neighbor.getEntityId() + "[containment]") + .getValue() + .getValue(), + customShape: neighbor + .getAttribute(neighbor.getEntityId() + "[customShape]") + .getValue() + .getValue(), + customAnchors: neighbor + .getAttribute(neighbor.getEntityId() + "[customAnchors]") + .getValue() + .getValue(), + }; + } + } + } + + metamodel.nodes[nodeId] = { + label: node.getLabel().getValue().getValue(), + attributes: attributes, + shape: shape || { + shape: "rectangle", + color: "white", + containment: false, + customShape: "", + customAnchors: "", + defaultWidth: 0, + defaultHeight: 0, + }, + }; + if (node instanceof ViewObjectNode) { + viewtypeAttrs = getViewTypeAttributes(node); + Util.merge(metamodel.nodes[nodeId], viewtypeAttrs); + } + } + } else if ( + node instanceof RelationshipNode || + node instanceof ViewRelationshipNode + ) { + attributes = getNodeAttributes(node); + edges = node.getEdges(); + sourceTypes = []; + targetTypes = []; + relations = []; + shape = null; + for (edgeId in edges) { + if (edges.hasOwnProperty(edgeId)) { + edge = edges[edgeId]; + source = edge.getSource(); + target = edge.getTarget(); + if ( + edge instanceof BiDirAssociationEdge && + ((target === node && (neighbor = source) instanceof ObjectNode) || + (target === node && + (neighbor = source) instanceof ViewObjectNode) || + (source === node && + (neighbor = target) instanceof ObjectNode) || + (source === node && + (neighbor = target) instanceof ViewObjectNode)) + ) { + concreteTypes = getConcreteObjectNodeTypes(neighbor); + sourceTypes = sourceTypes.concat(concreteTypes); + targetTypes = targetTypes.concat(concreteTypes); + } else if ( + edge instanceof UniDirAssociationEdge && + source === node && + (target instanceof ObjectNode || target instanceof ViewObjectNode) + ) { + targetTypes = targetTypes.concat( + getConcreteObjectNodeTypes(target) + ); + } else if ( + edge instanceof UniDirAssociationEdge && + target === node && + (source instanceof ObjectNode || source instanceof ViewObjectNode) + ) { + sourceTypes = sourceTypes.concat( + getConcreteObjectNodeTypes(source) + ); + } else if ( + edge instanceof BiDirAssociationEdge && + ((target === node && + (neighbor = source) instanceof AbstractClassNode) || + (source === node && + (neighbor = target) instanceof AbstractClassNode)) + ) { + concreteTypes = getConcreteObjectNodeTypes(neighbor); + sourceTypes = sourceTypes.concat(concreteTypes); + targetTypes = targetTypes.concat(concreteTypes); + } else if ( + edge instanceof UniDirAssociationEdge && + source === node && + target instanceof AbstractClassNode + ) { + targetTypes = targetTypes.concat( + getConcreteObjectNodeTypes(target) + ); + } else if ( + edge instanceof UniDirAssociationEdge && + target === node && + source instanceof AbstractClassNode + ) { + sourceTypes = sourceTypes.concat( + getConcreteObjectNodeTypes(source) + ); + } else if ( + (edge instanceof BiDirAssociationEdge && + ((target === node && + (neighbor = source) instanceof EdgeShapeNode) || + (source === node && + (neighbor = target) instanceof EdgeShapeNode))) || + (edge instanceof UniDirAssociationEdge && + source === node && + (neighbor = target) instanceof EdgeShapeNode) + ) { + shape = { + arrow: neighbor + .getAttribute(neighbor.getEntityId() + "[arrow]") + .getValue() + .getValue(), + shape: neighbor + .getAttribute(neighbor.getEntityId() + "[shape]") + .getValue() + .getValue(), + color: neighbor + .getAttribute(neighbor.getEntityId() + "[color]") + .getValue() + .getValue(), + overlay: neighbor + .getAttribute(neighbor.getEntityId() + "[overlay]") + .getValue() + .getValue(), + overlayPosition: neighbor + .getAttribute(neighbor.getEntityId() + "[overlayPosition]") + .getValue() + .getValue(), + overlayRotate: neighbor + .getAttribute(neighbor.getEntityId() + "[overlayRotate]") + .getValue() + .getValue(), + }; + } else if ( + edge instanceof GeneralisationEdge && + target === node && + (neighbor = source) instanceof RelationshipGroupNode + ) { + groupEdges = neighbor.getEdges(); + groupSourceTypes = []; + groupTargetTypes = []; + for (groupEdgeId in groupEdges) { + if (groupEdges.hasOwnProperty(groupEdgeId)) { + groupEdge = groupEdges[groupEdgeId]; + groupSource = groupEdge.getSource(); + groupTarget = groupEdge.getTarget(); + if ( + groupEdge instanceof BiDirAssociationEdge && + ((groupTarget === neighbor && + (groupNeighbor = groupSource) instanceof ObjectNode) || + (groupSource === neighbor && + (groupNeighbor = groupTarget) instanceof ObjectNode) || + (groupTarget === neighbor && + (groupNeighbor = groupSource) instanceof + ViewObjectNode) || + (groupSource === neighbor && + (groupNeighbor = groupTarget) instanceof + ViewObjectNode)) + ) { + groupConcreteTypes = + getConcreteObjectNodeTypes(groupNeighbor); + groupSourceTypes = + groupSourceTypes.concat(groupConcreteTypes); + groupTargetTypes = + groupTargetTypes.concat(groupConcreteTypes); + } else if ( + groupEdge instanceof UniDirAssociationEdge && + groupSource === neighbor && + (groupTarget instanceof ObjectNode || + groupTarget instanceof ViewObjectNode) + ) { + groupTargetTypes = groupTargetTypes.concat( + getConcreteObjectNodeTypes(groupTarget) + ); + } else if ( + groupEdge instanceof UniDirAssociationEdge && + groupTarget === neighbor && + (groupSource instanceof ObjectNode || + groupSource instanceof ViewObjectNode) + ) { + groupSourceTypes = groupSourceTypes.concat( + getConcreteObjectNodeTypes(groupSource) + ); + } else if ( + groupEdge instanceof BiDirAssociationEdge && + ((groupTarget === neighbor && + (groupNeighbor = groupSource) instanceof + AbstractClassNode) || + (groupSource === neighbor && + (groupNeighbor = groupTarget) instanceof + AbstractClassNode)) + ) { + groupConcreteTypes = + getConcreteObjectNodeTypes(groupNeighbor); + groupSourceTypes = + groupSourceTypes.concat(groupConcreteTypes); + groupTargetTypes = + groupTargetTypes.concat(groupConcreteTypes); + } else if ( + groupEdge instanceof UniDirAssociationEdge && + groupSource === neighbor && + groupTarget instanceof AbstractClassNode + ) { + groupTargetTypes = groupTargetTypes.concat( + getConcreteObjectNodeTypes(groupTarget) + ); + } else if ( + groupEdge instanceof UniDirAssociationEdge && + groupTarget === neighbor && + groupSource instanceof AbstractClassNode + ) { + groupSourceTypes = groupSourceTypes.concat( + getConcreteObjectNodeTypes(groupSource) + ); + } + } + } + + if (groupSourceTypes.length > 0 && groupTargetTypes.length > 0) { + relations.push({ + sourceTypes: groupSourceTypes, + targetTypes: groupTargetTypes, + }); + } + } + } + } + + if (sourceTypes.length > 0 && targetTypes.length > 0) { + relations.push({ + sourceTypes: sourceTypes, + targetTypes: targetTypes, + }); + } + + metamodel.edges[nodeId] = { + label: node.getLabel().getValue().getValue(), + shape: shape || { + arrow: "bidirassociation", + shape: "straight", + color: "black", + overlay: "", + overlayPosition: "top", + overlayRotate: true, + }, + relations: relations, + attributes: attributes, + }; + if (node instanceof ViewRelationshipNode) { + viewtypeAttrs = getViewTypeAttributes(node); + Util.merge(metamodel.edges[nodeId], viewtypeAttrs); + } + } + } + } + metamodel["id"] = viewpointModel.id; + EntityManagerInstance.reset(); + return metamodel; +} + +async function yjsSync( + spaceTitle, + yjsServer = "localhost:1234", + yjsProtocol = "ws" +) { + let title; + + if (!spaceTitle) { + if (window.caeRoom) { + title = window.caeRoom; + } else if (localStorage.getItem("syncmetaSpace")) { + title = localStorage.getItem("syncmetaSpace"); + } else { + title = Util.getSpaceTitle(location.href); + } + } + + if (window.y && title === spaceTitle) { + // yjs is already initialized and we are using the same spaceTitle + return new Promise((resolve) => resolve(window.y)); + } + + const doc = new Doc(); + + // Sync clients with the y-websocket provider + const websocketProvider = new WebsocketProvider( + `${yjsProtocol}://${yjsServer}`, + title, + doc + ); + + await new Promise((resolve, reject) => { + websocketProvider.on("status", (event) => { + // console.log(event.status); // logs "connected" or "disconnected" + + if (event.status == "connected") { + if (!window.y) { + window.y = doc; + } + resolve(title); + } + }); + setTimeout(() => { + reject("YJS connection timed out. This means syncmeta widgets wont work"); + }, 5000); + }); + if (window.y) { + // it could be that another yjsSync call was made before this one resolved + return window.y; + } + return doc; +} + +function init () { + var createReloadHandler = function () { + var iwcClient = window._iwc_instance_; + var intent_listener = []; + if (iwcClient && iwcClient.onIntent != null) { + var previous_iwc_onIntent = iwcClient.onIntent; + iwcClient.onIntent = function (message) { + if (message.action === "RELOAD") { + console.log(" K!!!!!!!!!!!!!!!!!!!!!!!!!!!! RELOAD!!!!!!!!!!!!!!!!!!!!!"); + window.location.reload(); + } + else { + for (var i = 0; i < intent_listener.length; i++) { + intent_listener[i].apply(this, arguments); + } + } + previous_iwc_onIntent.apply(this, arguments); + }; + window._addIwcIntentListener = function (f) { + intent_listener.push(f); + }; + window._reloadThisFuckingInstance = function () { + console.log("Reloading Everything"); + var message = { + action: "RELOAD", + component: "", + data: "", + dataType: "", + flags: ["PUBLISH_GLOBAL"], + extras: { + reload: true, + }, + }; + iwcClient.publish(message); + }; + } + else { + setTimeout(createReloadHandler, 5000); + } + }; + setTimeout(createReloadHandler, 10000); +} + +const SyncMetaWidget = (superClass, widgetName) => { + if (!widgetName) { + throw new Error("widgetName cannot be empty"); + } + class SyncMetaWidgetElement extends superClass { + constructor() { + super(...arguments); + this.widgetName = widgetName; + } + createRenderRoot() { + return this; + } + render() { + return html ` `; + } + firstUpdated() { + this.hideErrorAlert(); + } + connectedCallback() { + super.connectedCallback(); + init(); + if (!window.hasOwnProperty("y")) { + yjsSync().then((y) => { + if (!window.hasOwnProperty("y")) + window.y = y; + }); + } + } + disconnectedCallback() { + super.disconnectedCallback(); + } + hideErrorAlert() { + $(this.widgetName).find("#alert-message").text(""); + $(this.widgetName).find("error-alert").hide(); + } + showErrorAlert(message) { + $(this.widgetName).find("#alert-message").text(message); + $(this.widgetName).find("error-alert").hide(); + } + } + SyncMetaWidgetElement.styles = css ` + .loading { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + /*noinspection CssUnknownTarget*/ + background: white url("/img/loading.gif") no-repeat center center; + z-index: 32032; + opacity: 0.75; + } + + #oauthPersonalize, + #oauthPersonalizeDone, + #oauthPersonalizeComplete { + position: relative; + z-index: 32033; + } + + #q { + position: absolute; + width: 100%; + height: 3px; + bottom: 0; + left: 0; + cursor: s-resize; + } + `; + return SyncMetaWidgetElement; }; -let ViewControlWidget = class ViewControlWidget extends SyncMetaWidget(LitElement, getWidgetTagName(CONFIG.WIDGET.NAME.VIEWCONTROL)) { - async firstUpdated(_changedProperties) { - super.firstUpdated(_changedProperties); - try { - const y = await yjsSync(); - console.info("VIEWCONTROL: Yjs successfully initialized in room " + - window.spaceTitle + - " with y-user-id: " + - y.clientID); - const dataMap = y.getMap("data"); - var metamodel = dataMap.get("metamodel"); - var iwc = IWCW.getInstance("VIEWCONTROL"); - var GetList = function (appendTo, tpl) { - const viewsMap = y.getMap("views"); - var list = viewsMap.keys(); - for (var i = 0; i < list.length; i++) { - var data = viewsMap.get(list[i]); - if (data) { - var $viewEntry = $(tpl({ name: data.id })); - $viewEntry.find(".json").click(function (event) { - var $this = $(this).addClass("loading_button"); - var viewId = $(event.target) - .parents("tr") - .find(".lblviewname") - .text(); - var data = viewsMap.get(viewId); - var link = document.createElement("a"); - link.download = data.id + ".json"; - link.href = "data:," + encodeURI(JSON.stringify(data, null, 4)); - link.click(); - $this.removeClass("loading_button"); - }); - $viewEntry.find(".del").click(function (event) { - var viewId = $(event.target) - .parents("tr") - .find(".lblviewname") - .text(); - viewsMap.set(viewId, null); - $("#btnRefresh").click(); - }); - $viewEntry.find(".ToSpace").click(function (event) { - var viewId = $(event.target) - .parents("tr") - .find(".lblviewname") - .text(); - var viewpointmodel = GenerateViewpointModel(viewsMap.get(viewId)); - addMetamodelToYjs($("#space_label_view").val(), viewpointmodel); - }); - $(appendTo).append($viewEntry); - } - } - }; - var GetViewpointListEntryTemplate = function () { - var templateString = '<<= name >>' - .replace(/<>/g, "%" + ">"); - return lodash.template(templateString); - }; - var getFileContent = function () { - var fileReader, files = $("#btnImport")[0].files, file, deferred = $.Deferred(); - if (!files || files.length === 0) - deferred.resolve([]); - file = files[0]; - fileReader = new FileReader(); - fileReader.onload = function (e) { - var data = e.target.result; - try { - data = JSON.parse(data); - } - catch (e) { - data = []; - } - deferred.resolve(data); - }; - fileReader.readAsText(file); - return deferred.promise(); - }; - var LoadFileAndStoreToSpace = function () { - const viewsMap = y.getMap("views"); - getFileContent().then(function (data) { - if (data.id) { - if (metamodel) { - try { - var vvs = GenerateViewpointModel(data); - viewsMap.set(vvs.id, vvs); - } - catch (e) { - console.error(e); - viewsMap.set(data.id, data); - } - } - else - viewsMap.set(data.id, data); - $("#btnRefresh").click(); - } - }); - }; - if (!metamodel) { - $("#div1").show(); - } - $("#btnLoadViewpoint").click(function () { - LoadFileAndStoreToSpace(); - }); - GetList("#viewpointlist", GetViewpointListEntryTemplate()); - $("#btnRefresh").click(function () { - $("#viewpointlist").empty(); - GetList("#viewpointlist", GetViewpointListEntryTemplate()); - var operation = new UpdateViewListOperation(); - iwc.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.MAIN, operation.toNonOTOperation()); - }); - } - catch (error) { - console.error(error); - } - } - render() { - return html ` - - -
                                  - -
                                  -
                                  Select a JSON file
                                  - -
                                  -
                                  -
                                  Control Elements
                                  - - -
                                  -
                                  - Viewpoint List -
                                  -
                                  -
                                  - `; - } - connectedCallback() { - super.connectedCallback(); - init(); - } - disconnectedCallback() { - super.disconnectedCallback(); - } -}; -ViewControlWidget.styles = css ` - td { - padding: 5; - } - .seperating_box { - border: 1px solid; - border-radius: 7px; - margin: 18px 20px 7px 7px; - padding: 7px 20px 7px 7px; - position: relative; - } - .seperating_box > h5 { - font-weight: normal; - font-style: italic; - position: absolute; - top: -40px; - left: 4px; - } - `; -ViewControlWidget = __decorate([ - e(getWidgetTagName(CONFIG.WIDGET.NAME.VIEWCONTROL)) -], ViewControlWidget); -function addMetamodelToYjs(roomName, metamodel) { - yjsSync(roomName).then(function (yInstance) { - yInstance.getMap("data").set("metamodel", metamodel); - }); -} - -/** - * The closed-view-generation(CVG) algorithm - * Searches for neighbors of a referenced object/relationship node and adds the neighbors to the viewpoint model - * @param viewType the view type node - * @constructor - */ -function CVG(viewType) { - //the metamodel as json from the y-space - const dataMap = y.getMap("data"); - var metamodel = dataMap.get("model"); - //initilaize the current metamodel using the graphlib.Graph - var metaGraph = new graphlib.Graph(); - lodash.forEach(metamodel.nodes, function (value, index) { - metaGraph.setNode(index, value); - }); - lodash.forEach(metamodel.edges, function (value, index) { - value.id = index; - metaGraph.setEdge(value.source, value.target, value); - }); - - var originId = viewType - .getAttribute(viewType.getEntityId() + "[target]") - .getValue() - .getValue(); - var neighborsOfOrigin = metaGraph.neighbors(originId); - var canvas = viewType.getCanvas(); - var viewpointName = $("#lblCurrentView").text().replace("View:", ""); - - lodash.forEach(neighborsOfOrigin, function (neighborId) { - var node = metaGraph.node(neighborId); - var newNodeId; - //if neighbor is shape or relation just add it and the corresponding assocation - if ( - node.type === "Node Shape" || - node.type === "Edge Shape" || - node.type === "Relation" - ) { - newNodeId = viewpointName + "_" + neighborId; - if (!EntityManagerInstance.findNode(newNodeId)) - canvas.createNode( - node.type, - node.left, - node.top, - node.width, - node.height, - node.zIndex, - node.containment, - node, - newNodeId - ); - } else if ( - viewType.getType() === "ViewObject" && - node.type === "Relationship" - ) { - var viewtypes = EntityManagerInstance.getNodesByType("ViewRelationship"); - for (var key in viewtypes) { - if (viewtypes.hasOwnProperty(key)) { - var viewType2 = viewtypes[key]; - if ( - viewType2 - .getAttribute(viewType2.getEntityId() + "[target]") - .getValue() - .getValue() === neighborId - ) - newNodeId = viewType2.getEntityId(); - } - } - } else if ( - viewType.getType() === "ViewRelationship" && - node.type === "Object" - ) { - var viewtypes = EntityManagerInstance.getNodesByType("ViewObject"); - for (var key in viewtypes) { - if (viewtypes.hasOwnProperty(key)) { - var viewType2 = viewtypes[key]; - if ( - viewType2 - .getAttribute(viewType2.getEntityId() + "[target]") - .getValue() - .getValue() === neighborId - ) - newNodeId = viewType2.getEntityId(); - } - } - } - if (newNodeId) { - var edge = metaGraph.edge(originId, neighborId); - if (!edge) { - //try the other direction - edge = metaGraph.edge(neighborId, originId); - canvas.createEdge( - edge.type, - newNodeId, - viewType.getEntityId(), - edge, - viewpointName + "_" + edge.id, - viewpointName - ); - } else { - canvas.createEdge( - edge.type, - viewType.getEntityId(), - newNodeId, - edge, - viewpointName + "_" + edge.id, - viewpointName - ); - } - } - }); +let ViewControlWidget = class ViewControlWidget extends SyncMetaWidget(LitElement, getWidgetTagName(CONFIG.WIDGET.NAME.VIEWCONTROL)) { + async firstUpdated(_changedProperties) { + super.firstUpdated(_changedProperties); + try { + const y = await yjsSync(); + console.info("VIEWCONTROL: Yjs successfully initialized in room " + + window.spaceTitle + + " with y-user-id: " + + y.clientID); + const dataMap = y.getMap("data"); + var metamodel = dataMap.get("metamodel"); + var iwc = IWCW.getInstance("VIEWCONTROL"); + var GetList = function (appendTo, tpl) { + const viewsMap = y.getMap("views"); + var list = viewsMap.keys(); + for (var i = 0; i < list.length; i++) { + var data = viewsMap.get(list[i]); + if (data) { + var $viewEntry = $(tpl({ name: data.id })); + $viewEntry.find(".json").click(function (event) { + var $this = $(this).addClass("loading_button"); + var viewId = $(event.target) + .parents("tr") + .find(".lblviewname") + .text(); + var data = viewsMap.get(viewId); + var link = document.createElement("a"); + link.download = data.id + ".json"; + link.href = "data:," + encodeURI(JSON.stringify(data, null, 4)); + link.click(); + $this.removeClass("loading_button"); + }); + $viewEntry.find(".del").click(function (event) { + var viewId = $(event.target) + .parents("tr") + .find(".lblviewname") + .text(); + viewsMap.set(viewId, null); + $("#btnRefresh").click(); + }); + $viewEntry.find(".ToSpace").click(function (event) { + var viewId = $(event.target) + .parents("tr") + .find(".lblviewname") + .text(); + var viewpointmodel = GenerateViewpointModel(viewsMap.get(viewId)); + addMetamodelToYjs($("#space_label_view").val(), viewpointmodel); + }); + $(appendTo).append($viewEntry); + } + } + }; + var GetViewpointListEntryTemplate = function () { + var templateString = '<<= name >>' + .replace(/<>/g, "%" + ">"); + return lodash.template(templateString); + }; + var getFileContent = function () { + var fileReader, files = $("#btnImport")[0].files, file, deferred = $.Deferred(); + if (!files || files.length === 0) + deferred.resolve([]); + file = files[0]; + fileReader = new FileReader(); + fileReader.onload = function (e) { + var data = e.target.result; + try { + data = JSON.parse(data); + } + catch (e) { + data = []; + } + deferred.resolve(data); + }; + fileReader.readAsText(file); + return deferred.promise(); + }; + var LoadFileAndStoreToSpace = function () { + const viewsMap = y.getMap("views"); + getFileContent().then(function (data) { + if (data.id) { + if (metamodel) { + try { + var vvs = GenerateViewpointModel(data); + viewsMap.set(vvs.id, vvs); + } + catch (e) { + console.error(e); + viewsMap.set(data.id, data); + } + } + else + viewsMap.set(data.id, data); + $("#btnRefresh").click(); + } + }); + }; + if (!metamodel) { + $("#div1").show(); + } + $("#btnLoadViewpoint").click(function () { + LoadFileAndStoreToSpace(); + }); + GetList("#viewpointlist", GetViewpointListEntryTemplate()); + $("#btnRefresh").click(function () { + $("#viewpointlist").empty(); + GetList("#viewpointlist", GetViewpointListEntryTemplate()); + var operation = new UpdateViewListOperation(); + iwc.sendLocalNonOTOperation(CONFIG.WIDGET.NAME.MAIN, operation.toNonOTOperation()); + }); + } + catch (error) { + console.error(error); + } + } + render() { + return html ` + + +
                                  + +
                                  +
                                  Select a JSON file
                                  + +
                                  +
                                  +
                                  Control Elements
                                  + + +
                                  +
                                  + Viewpoint List +
                                  +
                                  +
                                  + `; + } + connectedCallback() { + super.connectedCallback(); + init(); + } + disconnectedCallback() { + super.disconnectedCallback(); + } +}; +ViewControlWidget.styles = css ` + td { + padding: 5; + } + .seperating_box { + border: 1px solid; + border-radius: 7px; + margin: 18px 20px 7px 7px; + padding: 7px 20px 7px 7px; + position: relative; + } + .seperating_box > h5 { + font-weight: normal; + font-style: italic; + position: absolute; + top: -40px; + left: 4px; + } + `; +ViewControlWidget = __decorate([ + e(getWidgetTagName(CONFIG.WIDGET.NAME.VIEWCONTROL)) +], ViewControlWidget); +function addMetamodelToYjs(roomName, metamodel) { + yjsSync(roomName).then(function (yInstance) { + yInstance.getMap("data").set("metamodel", metamodel); + }); +} + +/** + * The closed-view-generation(CVG) algorithm + * Searches for neighbors of a referenced object/relationship node and adds the neighbors to the viewpoint model + * @param viewType the view type node + * @constructor + */ +function CVG(viewType) { + //the metamodel as json from the y-space + const dataMap = y.getMap("data"); + var metamodel = dataMap.get("model"); + //initilaize the current metamodel using the graphlib.Graph + var metaGraph = new graphlib.Graph(); + lodash.forEach(metamodel.nodes, function (value, index) { + metaGraph.setNode(index, value); + }); + lodash.forEach(metamodel.edges, function (value, index) { + value.id = index; + metaGraph.setEdge(value.source, value.target, value); + }); + + var originId = viewType + .getAttribute(viewType.getEntityId() + "[target]") + .getValue() + .getValue(); + var neighborsOfOrigin = metaGraph.neighbors(originId); + var canvas = viewType.getCanvas(); + var viewpointName = $("#lblCurrentView").text().replace("View:", ""); + + lodash.forEach(neighborsOfOrigin, function (neighborId) { + var node = metaGraph.node(neighborId); + var newNodeId; + //if neighbor is shape or relation just add it and the corresponding assocation + if ( + node.type === "Node Shape" || + node.type === "Edge Shape" || + node.type === "Relation" + ) { + newNodeId = viewpointName + "_" + neighborId; + if (!EntityManagerInstance.findNode(newNodeId)) + canvas.createNode( + node.type, + node.left, + node.top, + node.width, + node.height, + node.zIndex, + node.containment, + node, + newNodeId + ); + } else if ( + viewType.getType() === "ViewObject" && + node.type === "Relationship" + ) { + var viewtypes = EntityManagerInstance.getNodesByType("ViewRelationship"); + for (var key in viewtypes) { + if (viewtypes.hasOwnProperty(key)) { + var viewType2 = viewtypes[key]; + if ( + viewType2 + .getAttribute(viewType2.getEntityId() + "[target]") + .getValue() + .getValue() === neighborId + ) + newNodeId = viewType2.getEntityId(); + } + } + } else if ( + viewType.getType() === "ViewRelationship" && + node.type === "Object" + ) { + var viewtypes = EntityManagerInstance.getNodesByType("ViewObject"); + for (var key in viewtypes) { + if (viewtypes.hasOwnProperty(key)) { + var viewType2 = viewtypes[key]; + if ( + viewType2 + .getAttribute(viewType2.getEntityId() + "[target]") + .getValue() + .getValue() === neighborId + ) + newNodeId = viewType2.getEntityId(); + } + } + } + if (newNodeId) { + var edge = metaGraph.edge(originId, neighborId); + if (!edge) { + //try the other direction + edge = metaGraph.edge(neighborId, originId); + canvas.createEdge( + edge.type, + newNodeId, + viewType.getEntityId(), + edge, + viewpointName + "_" + edge.id, + viewpointName + ); + } else { + canvas.createEdge( + edge.type, + viewType.getEntityId(), + newNodeId, + edge, + viewpointName + "_" + edge.id, + viewpointName + ); + } + } + }); } var ClosedViewGeneration = /*#__PURE__*/Object.freeze({ diff --git a/build/widgets/partials/viewcontrol.widget.js.map b/build/widgets/partials/viewcontrol.widget.js.map index 7d0f9d29..89993104 100644 --- a/build/widgets/partials/viewcontrol.widget.js.map +++ b/build/widgets/partials/viewcontrol.widget.js.map @@ -1 +1 @@ -{"version":3,"file":"viewcontrol.widget.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"} \ No newline at end of file +{"version":3,"file":"viewcontrol.widget.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"} \ No newline at end of file diff --git a/build/widgets/partials/widgets/partials/activity.widget.d.ts b/build/widgets/partials/widgets/partials/activity.widget.d.ts index 6fd11333..702f0994 100644 --- a/build/widgets/partials/widgets/partials/activity.widget.d.ts +++ b/build/widgets/partials/widgets/partials/activity.widget.d.ts @@ -5,7 +5,10 @@ import "../../error-alert"; import "../../loading-spinner"; declare const ActivityWidget_base: typeof LitElement; export declare class ActivityWidget extends ActivityWidget_base { + widgetName: any; protected firstUpdated(_changedProperties: PropertyValueMap | Map): void; + hideErrorAlert(): void; + showErrorAlert(message: string): void; render(): import("lit-html").TemplateResult<1>; connectedCallback(): void; disconnectedCallback(): void; diff --git a/build/widgets/partials/widgets/partials/debug.widget.d.ts b/build/widgets/partials/widgets/partials/debug.widget.d.ts index 7e0facd8..d98b95e4 100644 --- a/build/widgets/partials/widgets/partials/debug.widget.d.ts +++ b/build/widgets/partials/widgets/partials/debug.widget.d.ts @@ -4,10 +4,16 @@ import { LitElement, PropertyValueMap } from "lit"; declare const DebugWidget_base: typeof LitElement; export declare class DebugWidget extends DebugWidget_base { widgetName: any; + $spinner: JQuery; + $fileObject: any; protected firstUpdated(_changedProperties: PropertyValueMap | Map): void; hideErrorAlert(): void; showErrorAlert(message: string): void; render(): import("lit-html").TemplateResult<1>; + importModel(): void; + deleteModel(): void; + deleteMetamodel(): void; + feedback(msg: string): void; connectedCallback(): void; disconnectedCallback(): void; } diff --git a/build/widgets/widget.container.min.js b/build/widgets/widget.container.min.js index 0f5b206d..99272b36 100644 --- a/build/widgets/widget.container.min.js +++ b/build/widgets/widget.container.min.js @@ -1,14 +1,14 @@ -import{css as t,html as e,LitElement as n}from"lit";import"https://unpkg.com/jquery@3.6.0/dist/jquery.js";import"https://cdnjs.cloudflare.com/ajax/libs/jquery-migrate/1.4.1/jquery-migrate.min.js";import"https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.13.2/jquery-ui.min.js";import"https://cdnjs.cloudflare.com/ajax/libs/jquery-mousewheel/3.1.13/jquery.mousewheel.min.js";import"https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.9.2/jquery.contextMenu.js";import"https://cdnjs.cloudflare.com/ajax/libs/dagre/0.8.5/dagre.min.js";import{Text as r,Map as i,Doc as o}from"yjs";import{WebsocketProvider as a}from"y-websocket";import"https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js";import{QuillBinding as s}from"y-quill";import"https://cdnjs.cloudflare.com/ajax/libs/graphlib/2.1.8/graphlib.min.js";function l(t,e,n,r){var i,o=arguments.length,a=o<3?e:null===r?r=Object.getOwnPropertyDescriptor(e,n):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(t,e,n,r);else for(var s=t.length-1;s>=0;s--)(i=t[s])&&(a=(o<3?i(a):o>3?i(e,n,a):i(e,n))||a);return o>3&&a&&Object.defineProperty(e,n,a),a +import{css as t,html as e,LitElement as n}from"lit";import"https://unpkg.com/jquery@3.6.0/dist/jquery.js";import"https://cdnjs.cloudflare.com/ajax/libs/jquery-migrate/1.4.1/jquery-migrate.min.js";import"https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.13.2/jquery-ui.min.js";import"https://cdnjs.cloudflare.com/ajax/libs/jquery-mousewheel/3.1.13/jquery.mousewheel.min.js";import"https://cdnjs.cloudflare.com/ajax/libs/jquery-contextmenu/2.9.2/jquery.contextMenu.js";import"https://cdnjs.cloudflare.com/ajax/libs/dagre/0.8.5/dagre.min.js";import{Text as i,Map as r,Doc as o}from"yjs";import{WebsocketProvider as a}from"y-websocket";import"https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js";import{QuillBinding as s}from"y-quill";import"https://cdnjs.cloudflare.com/ajax/libs/graphlib/2.1.8/graphlib.min.js";function l(t,e,n,i){var r,o=arguments.length,a=o<3?e:null===i?i=Object.getOwnPropertyDescriptor(e,n):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(t,e,n,i);else for(var s=t.length-1;s>=0;s--)(r=t[s])&&(a=(o<3?r(a):o>3?r(e,n,a):r(e,n))||a);return o>3&&a&&Object.defineProperty(e,n,a),a /** * @license * Copyright 2017 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */}const u=t=>e=>"function"==typeof e?((t,e)=>(customElements.define(t,e),e))(t,e):((t,e)=>{const{kind:n,elements:r}=e;return{kind:n,elements:r,finisher(e){customElements.define(t,e)}}})(t,e) + */}const u=t=>e=>"function"==typeof e?((t,e)=>(customElements.define(t,e),e))(t,e):((t,e)=>{const{kind:n,elements:i}=e;return{kind:n,elements:i,finisher(e){customElements.define(t,e)}}})(t,e) /** * @license * Copyright 2021 Google LLC * SPDX-License-Identifier: BSD-3-Clause - */;var c;function d(t,e){void 0===e&&(e={});var n=e.insertAt;if(t&&"undefined"!=typeof document){var r=document.head||document.getElementsByTagName("head")[0],i=document.createElement("style");i.type="text/css","top"===n&&r.firstChild?r.insertBefore(i,r.firstChild):r.appendChild(i),i.styleSheet?i.styleSheet.cssText=t:i.appendChild(document.createTextNode(t))}}null===(c=window.HTMLSlotElement)||void 0===c||c.prototype.assignedElements;d("/* \n Default styles for jsPlumb Toolkit\n\n Copyright 2020 https://jsplumbtoolkit.com\n*/\n\n/* --------------------------------------------------------------------------------------------- */\n/* --- SURFACE WIDGET -------------------------------------------------------------------------- */\n/* --------------------------------------------------------------------------------------------- */\n\n/*\n Assigned to SVG elements for edges. This style allows overlays to paint outside the bounds, and\n for arbitrary stroke widths for connectors.\n */\n.jtk-connector {\n overflow:visible;\n}\n\n/*\n Assigned to every Node managed by an instance of the Toolkit. They are required to be positioned absolute, to\n enable dragging to work properly.\n*/\n.jtk-node {\n position: absolute;\n}\n\n/*\n Assigned to every Group managed by an instance of the Toolkit. They are required to be positioned absolute, to\n enable dragging to work properly. We set overflow:visible on Group elements too, as a drag outside of the bounds\n is automatically reverted anyway, and without overflow:visible you cannot drag a node to some other element. You can\n also drag a node out of the element's viewport and if you drop it you can never get it back.\n*/\n.jtk-group {\n position: absolute;\n overflow: visible;\n}\n\n/*\n Default behaviour for children of a collapsed group - hide them.\n */\n[data-jtk-group].jtk-group-collapsed [data-jtk-managed] {\n display:none;\n}\n\n/*\n\n This is the attribute used to mark which part of a Group DOM element should contain the child Nodes. We mark it\n as having `position:relative` so that the absolute positioned Nodes are drawn correctly.\n*/\n[data-jtk-group-content] {\n position:relative;\n}\n\n/*\n This style was created in response to this Chrome bug:\n http://stackoverflow.com/questions/13758215/artifacts-when-css-scaled-in-chrome\n\n Basically it's about how sometimes there can be artefacts left on screen when the user drags an element. It seems\n the issue has been fixed in more recent versions of Chrome, but the style is left here in case you come across\n the problem.\n*/\n.jtk-node.jtk-drag {\n /*-webkit-backface-visibility: hidden;*/\n}\n\n/*\n Suppresses the pointer events on an element that was created by Katavorio in response to a drag in which the element\n should first be cloned. Having this clone ignore pointer events means there is less chance that any other\n mouse activity (such as click) on the original element will not be consumed by katavorio.\n */\n.katavorio-clone-drag {\n pointer-events:none;\n}\n\n/*\n Assigned to an element that is the `Container` in a `render` call.\n Elements that are acting as Surface widgets should have overflow:hidden set to prevent libs from\n scrolling them during drag (we don't want scrollbars; we have an infinite canvas). Position is set to\n `relative` as this is the parent for nodes, which are positioned absolute (and for absolute positioning\n to work, you need to ensure the parent node has `position:relative`). This style also sets some default\n values for the cursor - using a `grab` cursor where supported.\n*/\n.jtk-surface {\n overflow: hidden !important;\n position: relative;\n cursor: move;\n cursor: -moz-grab;\n cursor: -webkit-grab;\n\n /*\n For IE10+. As discussed on this page:\n\n https://msdn.microsoft.com/en-us/library/ie/jj583807(v=vs.85).aspx\n\n Microsoft have very helpfully implemented default behaviours for a bunch of touch events and\n then consumed the events so you don't have to be bothered by them. They've \"done a lot of research\"\n about this stuff and put together a really great default experience for everyone in the entire world.\n */\n touch-action:none;\n\n /*\n Another Chrome issue that appears to have been fixed in later versions\n http://stackoverflow.com/questions/15464055/css-transition-effect-makes-image-blurry-moves-image-1px-in-chrome\n */\n /*\n -webkit-backface-visibility: hidden;\n -webkit-transform: translateZ(0) scale(1.0, 1.0);\n */\n}\n\n/**\n* Assigned to a Surface element when direct rendering is switched on - no pan or zoom, the underlying canvas scaled to fit its contents at zoom:1.\n */\n.jtk-surface-direct-render {\n overflow:hidden !important;\n}\n\n/*\n Assigned to the surface when it is being panned. The default is to change the cursor (in browsers that support\n a `grabbing` cursor), and to disable text selection.\n*/\n.jtk-surface-panning {\n cursor: -moz-grabbing;\n cursor: -webkit-grabbing;\n -webkit-touch-callout: none;\n -webkit-user-select: none;\n -khtml-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n\n/*\n The work area in a surface renderer.\n*/\n.jtk-surface-canvas {\n overflow: visible !important;\n}\n\n/*\n For IE10+. Discussed above in the .jtk-surface styles. This one is specific to elements that are configured\n to be droppable on a Surface via its `registerDroppableNodes` method.\n*/\n.jtk-surface-droppable-node {\n touch-action:none;\n}\n\n/*\n Assigned to a Surface widget when panning is disabled (and therefore the app is relying on scrollbars when the content overflows).\n*/\n.jtk-surface-nopan {\n overflow: scroll !important;\n cursor:default;\n}\n\n/*\nAssigned to tile images in a tiled background\n*/\n.jtk-surface-tile {\n border:none;\n outline:none;\n margin:0;\n -webkit-transition: opacity .3s ease .15s;\n -moz-transition: opacity .3s ease .15s;\n -o-transition: opacity .3s ease .15s;\n -ms-transition: opacity .3s ease .15s;\n transition: opacity .3s ease .15s;\n}\n\n/*\n Assigned to the element used for node select with the mouse (\"lasso\").\n*/\n.jtk-lasso {\n border: 2px solid rgb(49, 119, 184);\n background-color: WhiteSmoke;\n opacity: 0.5;\n display: none;\n z-index: 20000;\n position: absolute;\n}\n\n/*\n This class is added to the document body on lasso drag start and removed at the end of lasso dragging. Its purpose\n is to switch off text selection on all elements while the user is dragging the lasso.\n*/\n.jtk-lasso-select-defeat * {\n -webkit-touch-callout: none;\n -webkit-user-select: none;\n -khtml-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n\n/**\n Added to the lasso mask when it is operating in 'inverted' mode, ie. the excluded parts of the UI are covered, rather\n than the normal mode in which the selected parts of the UI are covered.\n*/\n.jtk-lasso-mask {\n position:fixed;\n z-index:20000;\n display:none;\n opacity:0.5;\n background-color: #07234E;\n top:0;\n bottom:0;\n left:0;\n right:0;\n}\n\n/*\n Assigned to some element that has been selected (either via lasso or programmatically).\n*/\n.jtk-surface-selected-element {\n border: 2px dotted #c7726c !important;\n}\n\n/*\n Assigned to all pan buttons in a surface widget.\n*/\n.jtk-surface-pan {\n background-color: Azure;\n opacity: 0.4;\n text-align: center;\n cursor: pointer;\n z-index: 2;\n -webkit-transition: background-color 0.15s ease-in;\n -moz-transition: background-color 0.15s ease-in;\n -o-transition: background-color 0.15s ease-in;\n transition: background-color 0.15s ease-in;\n}\n\n/*\n Specific styles for the top and bottom pan buttons.\n Top/bottom are 100% width and 20px high by default\n*/\n.jtk-surface-pan-top, .jtk-surface-pan-bottom {\n width: 100%;\n height: 20px;\n display: flex;\n justify-content: center;\n}\n\n/*\n Hover styles for all pan buttons.\n On hover, change color, background color, font weight and opacity.\n*/\n.jtk-surface-pan-top:hover, .jtk-surface-pan-bottom:hover, .jtk-surface-pan-left:hover, .jtk-surface-pan-right:hover {\n opacity: 0.6;\n background-color: rgb(49, 119, 184);\n color: white;\n font-weight: bold;\n}\n\n/*\n Specific styles for the left and right pan buttons.\n Left/right pan buttons are 100% height and 20px wide\n*/\n.jtk-surface-pan-left, .jtk-surface-pan-right {\n width: 20px;\n height: 100%;\n display: flex;\n align-items: center;\n}\n\n\n/*\n Assigned to a pan button when the user is pressing it.\n*/\n.jtk-surface-pan-active, .jtk-surface-pan-active:hover {\n background-color: #f76258;\n}\n\n/* --------------------------------------------------------------------------------------------- */\n/* --- MINIVIEW WIDGET ------------------------------------------------------------------------- */\n/* --------------------------------------------------------------------------------------------- */\n\n/*\n Assigned to an element that is acting as a Miniview.\n As with Surface, Miniview elements should have overflow:hidden set to prevent\n libs from scrolling them during drag. This style also provides a default width/height for a miniview,\n which you may wish to override.\n*/\n.jtk-miniview {\n overflow: hidden !important;\n width: 125px;\n height: 125px;\n position: relative;\n background-color: transparent;\n border: 2px solid #d4d8dc;\n border-radius: 4px;\n opacity: 0.8;\n}\n\n/*\n Assigned to the element that shows the size of the related viewport in a Miniview widget, and which can be dragged to\n move the surface.\n*/\n.jtk-miniview-panner {\n border: 5px dotted WhiteSmoke;\n opacity: 0.4;\n background-color: rgb(79, 111, 126);\n cursor: move;\n cursor: -moz-grab;\n cursor: -webkit-grab;\n}\n\n/*\n Assigned to the miniview's panner when it is being dragged.\n*/\n.jtk-miniview-panning {\n cursor: -moz-grabbing;\n cursor: -webkit-grabbing;\n}\n\n/*\n Added to all elements displayed in a miniview.\n*/\n.jtk-miniview-element {\n background-color: rgb(96, 122, 134);\n position: absolute;\n}\n\n/*\n Added to Group elements displayed in a miniview\n*/\n.jtk-miniview-group-element {\n background: transparent;\n border: 3px solid black;\n}\n\n/*\n Assigned to the collapse/expand miniview button\n*/\n.jtk-miniview-collapse {\n color: whiteSmoke;\n position: absolute;\n font-size: 18px;\n top: -1px;\n right: 3px;\n cursor: pointer;\n font-weight: bold;\n}\n\n/*\n The '-' symbol when the miniview is expanded\n*/\n.jtk-miniview-collapse:before {\n content: \"\\2012\";\n}\n\n/*\n Assigned to the miniview element when it is collapsed.\n*/\n.jtk-miniview-collapsed {\n background-color: #449ea6;\n border-radius: 4px;\n height: 22px;\n margin-right: 0;\n padding: 4px;\n width: 21px;\n}\n\n/*\n Hide all children of the miniview (except the expand button) when it is collapsed so you don't see anything\n poking through under the + icon.\n*/\n.jtk-miniview-collapsed .jtk-miniview-element, .jtk-miniview-collapsed .jtk-miniview-panner {\n visibility: hidden;\n}\n\n/*\n The '+' symbol when the miniview is collapsed.\n*/\n.jtk-miniview-collapsed .jtk-miniview-collapse:before {\n content: \"+\";\n}\n\n/*\n Hover state for the collapse/expand icon.\n*/\n.jtk-miniview-collapse:hover {\n color: #E4F013;\n}\n\n/* -------------------------------------------------------------------------------------------- */\n/* --- DRAWING TOOLS -------------------------------------------------------------------------- */\n/* -------------------------------------------------------------------------------------------- */\n\n/*\n Assigned to the element that is drawn around some other element when a drawing operation is taking place.\n*/\n.jtk-draw-skeleton {\n position: absolute;\n left: 0;\n right: 0;\n top: 0;\n bottom: 0;\n outline: 2px solid #84acb3;\n opacity: 0.8;\n}\n\n/*\n Assigned to every handle (top left, top right, bottom left, bottom right, center) in a draw skeleton.\n*/\n.jtk-draw-handle {\n position: absolute;\n width: 7px;\n height: 7px;\n background-color: #84acb3;\n}\n\n/*\n Assigned to the top left handle in a draw skeleton\n*/\n.jtk-draw-handle-tl {\n left: 0;\n top: 0;\n cursor: nw-resize;\n}\n\n/*\n Assigned to the top right handle in a draw skeleton\n*/\n.jtk-draw-handle-tr {\n right: 0;\n top: 0;\n cursor: ne-resize;\n}\n\n/*\n Assigned to the bottom left handle in a draw skeleton\n*/\n.jtk-draw-handle-bl {\n left: 0;\n bottom: 0;\n cursor: sw-resize;\n}\n\n/*\n Assigned to the bottom right handle in a draw skeleton\n*/\n.jtk-draw-handle-br {\n bottom: 0;\n right: 0;\n cursor: se-resize;\n}\n\n/*\n Assigned to the center handle in a draw skeleton (the handle by which the element may be dragged). This is\n not visible by defaut; enable if you need it.\n*/\n.jtk-draw-drag {\n display:none;\n position: absolute;\n left: 50%;\n top: 50%;\n margin-left: -10px;\n margin-top: -10px;\n width: 20px;\n height: 20px;\n background-color: #84acb3;\n cursor: move;\n}\n\n/*\n This class is added to the document body on drag resize start and removed at the end of resizing. Its purpose\n is to switch off text selection on all elements while the user is resizing an element.\n*/\n.jtk-drag-select-defeat * {\n -webkit-touch-callout: none;\n -webkit-user-select: none;\n -khtml-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n");function f(t,e,n){return"*"===t||(t.length>0?-1!==t.indexOf(e):!n)}function p(t,e,n){var r,i=t=t||{},o=e=e||{};if(n)for(r=0;r-1&&t.splice(n,1),-1!==n}function j(t){if(null!=Array.fromArray)return Array.from(t);var e=[];return Array.prototype.push.apply(e,t),e}function N(t,e){var n=t.indexOf(e);return n>-1&&t.splice(n,1),-1!==n}function S(t,e,n,r){var i=t[e];return null==i&&(i=[],t[e]=i),i[r?"unshift":"push"](n),i}function M(t,e,n){return-1===t.indexOf(e)&&(n?t.unshift(e):t.push(e),!0)}d('.ui-resizable {\r\n /*jquery-ui adds this class to resizable objects. \r\n However, the jsplumb library requires the position to be absolute, otherwise \r\n offsets will be wrong. So we need to override this here.\r\n see https://github.com/rwth-acis/syncmeta/issues/86\r\n */\r\n position: absolute !important;\r\n}\r\n\r\n.button_bar {\r\n width: 50%;\r\n float: left;\r\n display: flex;\r\n flex-wrap: wrap;\r\n}\r\n\r\n.main-container {\r\n position: relative;\r\n}\r\n\r\n.button_bar.left {\r\n text-align: left;\r\n}\r\n\r\n.button_bar.right {\r\n text-align: right;\r\n}\r\n\r\n.node {\r\n z-index: 1;\r\n position: absolute;\r\n overflow: visible;\r\n border: 2px solid transparent;\r\n}\r\n\r\n.trace_awareness {\r\n z-index: 0;\r\n position: absolute;\r\n overflow: visible;\r\n opacity: 0;\r\n pointer-events: none;\r\n}\r\n\r\ndiv.class_node {\r\n height: inherit;\r\n width: inherit;\r\n border: 1px solid #aaa;\r\n border-radius: 1px;\r\n box-shadow: 2px 2px 2px #cccccc;\r\n color: #666 !important;\r\n font-size: 12px;\r\n}\r\n\r\ndiv.default_node {\r\n height: inherit;\r\n width: inherit;\r\n}\r\n\r\ndiv.custom_node {\r\n height: 100%;\r\n width: 100%;\r\n position: relative;\r\n}\r\n\r\ndiv.custom_node .fill_parent {\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n bottom: 0;\r\n right: 0;\r\n width: inherit;\r\n height: inherit;\r\n}\r\n\r\n/*adjust label of custom nodes*/\r\ndiv.custom_node .fill_parent>div {\r\n left: 50%;\r\n top: -8px !important;\r\n -webkit-transform: translateY(-50%) translateX(-50%);\r\n -moz-transform: translateY(-50%) translateX(-50%);\r\n transform: translateY(-50%) translateX(-50%);\r\n pointer-events: none;\r\n overflow-x: auto;\r\n}\r\n\r\ndiv.simple_node {\r\n height: inherit;\r\n width: inherit;\r\n display: table;\r\n}\r\n\r\n.center .single_value_attribute .name {\r\n display: none;\r\n}\r\n\r\n.center .single_value_attribute .value .val {\r\n text-align: center;\r\n}\r\n\r\ndiv.simple_node div.label {\r\n display: table-cell;\r\n text-align: center;\r\n vertical-align: middle;\r\n}\r\n\r\n.box-overlay {\r\n position: absolute;\r\n background-color: #bbbbbb;\r\n opacity: 0;\r\n border-radius: 10px;\r\n cursor: move;\r\n}\r\n\r\n.selected {\r\n border: 3px solid #2bff6e;\r\n}\r\n\r\n#canvas-frame {\r\n overflow: hidden;\r\n width: 100%;\r\n height: 100%;\r\n position: relative;\r\n background-color: #afafaf;\r\n}\r\n\r\n#canvas {\r\n width: 100%;\r\n height: 100%;\r\n max-width: none !important;\r\n max-height: none !important;\r\n border-radius: 6px;\r\n position: relative !important;\r\n /*important because jsplumb will position according to this*/\r\n background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAzsAAASRCAYAAAAQD4IpAAAAAXNSR0IArs4c6QAAAp90RVh0bXhmaWxlACUzQ214ZmlsZSUyMGhvc3QlM0QlMjJ3d3cuZHJhdy5pbyUyMiUyMG1vZGlmaWVkJTNEJTIyMjAyMy0wMy0yMlQxNSUzQTI2JTNBMTUuOTM5WiUyMiUyMGFnZW50JTNEJTIyNS4wJTIwKE1hY2ludG9zaCUzQiUyMEludGVsJTIwTWFjJTIwT1MlMjBYJTIwMTBfMTVfNyklMjBBcHBsZVdlYktpdCUyRjUzNy4zNiUyMChLSFRNTCUyQyUyMGxpa2UlMjBHZWNrbyklMjBDaHJvbWUlMkYxMDQuMC41MTEyLjEwMiUyMFNhZmFyaSUyRjUzNy4zNiUyMiUyMGV0YWclM0QlMjJzeFdZTGwyVUdZTThRQnRLMks2USUyMiUyMHZlcnNpb24lM0QlMjIyMS4wLjEwJTIyJTNFJTNDZGlhZ3JhbSUyMG5hbWUlM0QlMjJQYWdlLTElMjIlMjBpZCUzRCUyMkhWSkRESVpkc0VfN29vQWx0cl9lJTIyJTNFZGRITkVvSWdFQURncCUyQkZ1VUZwbnM3cDA4dENaa1UyWVFkZEJHcTJuVDJjMVk2d0xzM3k3c1B3d2tWYjkyY2xHWDFHQlpUeFNQUk5IeG5rU2kyRWM0VW13alhZRXBUT0thTE5BYmw0d1lUVHB3eWhvZzBLUGFMMXBRaXl3cnFId2dVbm5zQXZMN21qRHJvMHNZUVY1SWUxYWIwWjVUYnJueWVJWE1LV2VPMiUyRmlBMlVxT1JkUE4ybTFWTmg5a2NpWVNCMmlwNmpxVTdEajI4M3ZRdXRPZjdLZmd6bW8lMkZZOEZRN0RzUFV5Q0R4TFpHdyUzRCUzRCUzQyUyRmRpYWdyYW0lM0UlM0MlMkZteGZpbGUlM0WOPzA6AAAgAElEQVR4Xry9y5JlRa4tusKAxoEmpEH+/2/t080ES6qZ7EaBxTW56zEkf2jMqjw3rayIWDGXT3e9Xy69/c///Z/3n/7PT6/X28v/vb/k1/n/4z+v99f7620+oh/F4/E3+Un+9/Y2/6or+A/x+/vr/c1eCS+2L8F7/vrr62vsT9az74yFYn/vb+/6K7x37Nu+M/f4ep8f5v3FacffxhH0y296Zj/N3Jif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);\r\n background-repeat: round;\r\n opacity: 1 !important;\r\n border-radius: 20px;\r\n border: 10px solid #000000;\r\n}\r\n\r\n#canvas.tool-move {\r\n cursor: move !important;\r\n}\r\n\r\n#canvas.tool-move ._jsPlumb_connector {\r\n cursor: pointer !important;\r\n}\r\n\r\n#canvas.tool-node {\r\n cursor: pointer !important;\r\n}\r\n\r\n#canvas.tool-edge {\r\n cursor: default !important;\r\n}\r\n\r\n#canvas.tool-edge.dragging {\r\n cursor: move !important;\r\n}\r\n\r\n#canvas.tool-edge .node,\r\n#canvas.tool-node .node {\r\n opacity: 1;\r\n}\r\n\r\n#canvas.tool-edge .node {\r\n cursor: pointer !important;\r\n}\r\n\r\n#canvas.tool-edge.dragging .node {\r\n cursor: move !important;\r\n}\r\n\r\n#feedback {\r\n margin: 10px;\r\n color: #777777;\r\n}\r\n\r\nbutton[disabled="disabled"],\r\nbutton:disabled {\r\n opacity: 0.5;\r\n}\r\n\r\n._jsPlumb_overlay {\r\n font-size: 12px;\r\n}\r\n\r\n.class_node,\r\n.edge_shape_node,\r\n.node_shape_node,\r\n.enum_node,\r\n.abstract_class_node,\r\n.object_node,\r\n.relation_node {\r\n overflow: hidden;\r\n}\r\n\r\n.class_node .label,\r\n.edge_shape_node .label,\r\n.node_shape_node .label,\r\n.enum_node .label,\r\n.abstract_class_node .label,\r\n.object_node .label,\r\n.relation_node .label {\r\n border-bottom: 1px solid #999999;\r\n}\r\n\r\n.edge_label .single_value_attribute .name,\r\n.label .single_value_attribute .name,\r\n.title .single_value_attribute .name,\r\n.name .single_value_attribute .name {\r\n display: none;\r\n}\r\n\r\n.class_node .label,\r\n.edge_shape_node .label,\r\n.node_shape_node .label,\r\n.enum_node .label,\r\n.abstract_class_node .label,\r\n.object_node .label,\r\n.relation_node .label {\r\n text-align: center;\r\n font-weight: bold;\r\n display: block;\r\n}\r\n\r\n.value input {\r\n border: 0;\r\n background: none;\r\n outline: none;\r\n}\r\n\r\n.edge_label {\r\n width: 200px;\r\n cursor: pointer;\r\n}\r\n\r\n.edge_label.fixed {\r\n background-color: #f5f5f5;\r\n width: auto;\r\n font-size: 14px;\r\n}\r\n\r\n.edge_label .single_value_attribute .value input,\r\n.label .single_value_attribute .value input,\r\n.title .single_value_attribute .value input,\r\n.name .single_value_attribute .value input {\r\n border: 0;\r\n background: none;\r\n width: 100%;\r\n text-align: center;\r\n font-weight: bold;\r\n outline: none;\r\n margin: 2px auto;\r\n display: block;\r\n}\r\n\r\n.edge_label .single_value_attribute .value div.val {\r\n text-align: center;\r\n}\r\n\r\n.attributes .list_attribute .name {\r\n display: none;\r\n}\r\n\r\n.attributes .list_attribute ul.list {\r\n padding: 2px;\r\n margin: 0;\r\n list-style: none;\r\n}\r\n\r\n.attributes .list_attribute ul.list li.key_value_attribute,\r\n.attributes .list_attribute ul.list li.condition_predicate,\r\n.attributes .list_attribute ul.list li.renaming_attr {\r\n overflow: hidden;\r\n}\r\n\r\n.attributes .list_attribute ul.list li.key_value_attribute div.key {\r\n float: left;\r\n width: 50%;\r\n}\r\n\r\n.attributes .list_attribute ul.list li.key_value_attribute div.value {\r\n float: left;\r\n width: 50%;\r\n}\r\n\r\n.attributes .list_attribute ul.list li.condition_predicate div.property,\r\n.attributes .list_attribute ul.list li.condition_predicate div.operator,\r\n.attributes .list_attribute ul.list li.condition_predicate div.val,\r\n.attributes .list_attribute ul.list li.condition_predicate div.operator2 {\r\n float: left;\r\n margin-left: 3px;\r\n}\r\n\r\n.attributes .list_attribute ul.list li.renaming_attr div.val,\r\n.attributes .list_attribute ul.list li.renaming_attr div.ref {\r\n float: left;\r\n margin-left: 3px;\r\n width: 50%;\r\n}\r\n\r\n.attributes .list_attribute ul.list li.renaming_attr div.vis {\r\n float: right;\r\n margin-left: 3px;\r\n}\r\n\r\n.attributes .list_attribute ul.list li.key_value_attribute div.key input,\r\n.attributes .list_attribute ul.list li.key_value_attribute div.value input,\r\n.attributes .list_attribute ul.list li.condition_predicate div.val input,\r\n.attributes .list_attribute ul.list li.renaming_attr div.val input,\r\n.attributes .list_attribute ul.list li.renaming_attr div.ref input {\r\n width: 100%;\r\n border: 0;\r\n outline: none;\r\n background: none;\r\n}\r\n\r\n.attributes .single_value_attribute {\r\n overflow: hidden;\r\n margin-left: 1px;\r\n}\r\n\r\n.attributes .single_value_attribute .name {\r\n width: 50%;\r\n float: left;\r\n margin: 3px 0;\r\n}\r\n\r\n.attributes .single_value_attribute .value {\r\n width: 50%;\r\n float: left;\r\n}\r\n\r\n.attributes .single_value_attribute .value input {\r\n border: 0;\r\n color: #666 !important;\r\n margin: 0;\r\n background: none;\r\n}\r\n\r\n.attributes .value div.val {\r\n text-align: right;\r\n margin: 3px;\r\n}\r\n\r\n.attributes .value input.val {\r\n text-align: right;\r\n float: right;\r\n}\r\n\r\n.size-preview {\r\n z-index: 99;\r\n background-color: #ffffff;\r\n color: #666666;\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n border: 1px dashed black;\r\n}\r\n\r\n#canvas.tool-edge .node.lowlighted,\r\n#canvas.tool-edge .node.target {\r\n opacity: 0.5;\r\n}\r\n\r\n#canvas.tool-edge .node.source {\r\n opacity: 1;\r\n}\r\n\r\n#canvas.tool-edge.dragging .node.source {\r\n opacity: 0.5;\r\n}\r\n\r\n#canvas.tool-edge.dragging .node.source.current,\r\n#canvas.tool-edge.dragging .node.target {\r\n opacity: 1;\r\n}\r\n\r\n#canvas.tool-edge ._jsPlumb_connector {\r\n opacity: 0.5;\r\n}\r\n\r\n#canvas.tool-edge ._jsPlumb_connector._jsPlumb_dragging {\r\n opacity: 1;\r\n}\r\n\r\n/*noinspection CssUnknownProperty*/\r\n.type {\r\n position: absolute;\r\n bottom: 105%;\r\n left: 50%;\r\n transform: translateX(-50%);\r\n -o-transform: translateX(-50%);\r\n -ms-transform: translateX(-50%);\r\n -moz-transform: translateX(-50%);\r\n -webkit-transform: translateX(-50%);\r\n text-align: center;\r\n overflow: visible;\r\n white-space: nowrap;\r\n color: #aaaaaa;\r\n font-size: 0.9em;\r\n}\r\n\r\n#canvas.hide_type .type {\r\n display: none;\r\n}\r\n\r\n#viewsHide {\r\n display: none;\r\n}\r\n\r\n#lblCurrentView {\r\n display: none;\r\n}\r\n\r\n.user_highlight {\r\n position: absolute;\r\n top: 100%;\r\n left: 0;\r\n font-size: 12px;\r\n font-weight: bold;\r\n white-space: nowrap;\r\n text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black;\r\n}\r\n\r\n.jtk-endpoint {\r\n z-index: 300000;\r\n}\r\n\r\n.ghost-edge {\r\n opacity: 0.3;\r\n z-index: 30000;\r\n}\r\n\r\n.ghost-edge-overlay {\r\n z-index: 31000;\r\n}\r\n\r\n/* VML colors */\r\n.object {\r\n background-color: rgb(213, 235, 253);\r\n}\r\n\r\n.nodeshape {\r\n background-color: rgba(213, 235, 253, 0.5);\r\n}\r\n\r\n.enum {\r\n background-color: #f9ffc6;\r\n}\r\n\r\n.relationship {\r\n background-color: #ffcece;\r\n}\r\n\r\n.edgeshape {\r\n background-color: rgba(255, 206, 206, 0.5);\r\n}\r\n\r\n.relation {\r\n background-color: #d5f5d5;\r\n}\r\n\r\n.abstractclass {\r\n background-color: #ffffff;\r\n}\r\n\r\n.main-container {\r\n position: relative;\r\n}');for(var C=[],D=0;D<256;D++)C[D]=(D<16?"0":"")+D.toString(16);function Y(){var t=4294967295*Math.random()|0,e=4294967295*Math.random()|0,n=4294967295*Math.random()|0,r=4294967295*Math.random()|0;return C[255&t]+C[t>>8&255]+C[t>>16&255]+C[t>>24&255]+"-"+C[255&e]+C[e>>8&255]+"-"+C[e>>16&15|64]+C[e>>24&255]+"-"+C[63&n|128]+C[n>>8&255]+"-"+C[n>>16&255]+C[n>>24&255]+C[255&r]+C[r>>8&255]+C[r>>16&255]+C[r>>24&255]}function L(t,e,n){var r=t.x-e.x,i=t.y-e.y,o=Math.cos(n/360*Math.PI*2),a=Math.sin(n/360*Math.PI*2);return{x:r*o-i*a+e.x,y:i*o+r*a+e.y,cr:o,sr:a}}function R(t){if(null==t)return null;for(var e=t.replace(/^\s\s*/,""),n=/\s/,r=e.length;n.test(e.charAt(--r)););return e.slice(0,r+1)}function z(t,e){for(var n=[],r=0;r0?1:0}function G(t,e,n){return function(){var r=null;try{null!=e&&(r=e.apply(this,arguments))}catch(t){B("jsPlumb function failed : "+t)}if(null!=t&&(null==n||r!==n))try{r=t.apply(this,arguments)}catch(t){B("wrapped function failed : "+t)}return r}}function H(t,e,n){return t.has(e)||t.set(e,n()),t.get(e)}function V(t,e){for(var n=t.__proto__;null!=n;){if(n instanceof e)return!0;n=n.__proto__}return!1}function F(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function J(t,e){for(var n=0;nt.y?1/0:-1/0:e.y===t.y?e.x>t.x?0:-0:(e.y-t.y)/(e.x-t.x)}function st(t,e){return Math.sqrt(Math.pow(e.y-t.y,2)+Math.pow(e.x-t.x,2))}function lt(t,e){return e.x>t.x||e.x==t.x?e.y>t.y?2:1:e.y>t.y?3:4}function ut(t,e){var n=t.x,r=t.x+t.w,i=t.y,o=t.y+t.h,a=e.x,s=e.x+e.w,l=e.y,u=e.y+e.h;return n<=a&&a<=r&&i<=l&&l<=o||n<=s&&s<=r&&i<=l&&l<=o||n<=a&&a<=r&&i<=u&&u<=o||n<=s&&a<=r&&i<=u&&u<=o||a<=n&&n<=s&&l<=i&&i<=u||a<=r&&r<=s&&l<=i&&i<=u||a<=n&&n<=s&&l<=o&&o<=u||a<=r&&n<=s&&l<=o&&o<=u}function ct(t,e,n){var r=at(t,e),i=lt(t,e),o=n>0?rt[i]:it[i],a=Math.atan(r),s=Math.abs(n*Math.sin(a))*o[1],l=Math.abs(n*Math.cos(a))*o[0];return{x:t.x+l,y:t.y+s}}function dt(t,e){for(var n=0;nt.length)&&(e=t.length);for(var n=0,r=new Array(e);n0?t/this.totalLength:(this.totalLength+t)/this.totalLength),1===t)n=this.segments.length-1,i=1;else if(0===t)i=0,n=0;else if(t>=.5){for(n=0,i=0,r=this.segmentProportions.length-1;r>-1;r--)if(this.segmentProportions[r][1]>=t&&this.segmentProportions[r][0]<=t){n=r,i=(t-this.segmentProportions[r][0])/this.segmentProportionalLengths[r];break}}else for(n=this.segmentProportions.length-1,i=1,r=0;r=t){n=r,i=(t-this.segmentProportions[r][0])/this.segmentProportionalLengths[r];break}return{segment:this.segments[n],proportion:i,index:n}}},{key:"_addSegment",value:function(t,e){if(e.x1!==e.x2||e.y1!==e.y2){var n=new t(e);this.segments.push(n),this.totalLength+=n.getLength(),this.updateBounds(n)}}},{key:"_clearSegments",value:function(){this.totalLength=0,this.segments.length=0,this.segmentProportions.length=0,this.segmentProportionalLengths.length=0}},{key:"getLength",value:function(){return this.totalLength}},{key:"_prepareCompute",value:function(t){this.strokeWidth=t.strokeWidth;var e=t.sourcePos.curX,n=t.targetPos.curX,r=t.sourcePos.curY,i=t.targetPos.curY,o=lt({x:e,y:r},{x:n,y:i}),a=np?0:1,y=[1,0][v],b=0===v?e:r,m=0===v?n:i;h&&(l[v]=b>m?-1:1,l[y]=0),g&&(u[v]=b>m?1:-1,u[y]=0)}var w=a?f+this.sourceGap*l[0]:this.sourceGap*l[0],E=s?p+this.sourceGap*l[1]:this.sourceGap*l[1],O=a?this.targetGap*u[0]:f+this.targetGap*u[0],T=s?this.targetGap*u[1]:p+this.targetGap*u[1],x=l[0]*u[0]+l[1]*u[1],A={sx:w,sy:E,tx:O,ty:T,xSpan:Math.abs(O-w),ySpan:Math.abs(T-E),mx:(w+O)/2,my:(E+T)/2,so:l,to:u,x:c,y:d,w:f,h:p,segment:o,startStubX:w+l[0]*this.sourceStub,startStubY:E+l[1]*this.sourceStub,endStubX:O+u[0]*this.targetStub,endStubY:T+u[1]*this.targetStub,isXGreaterThanStubTimes2:Math.abs(w-O)>this.sourceStub+this.targetStub,isYGreaterThanStubTimes2:Math.abs(E-T)>this.sourceStub+this.targetStub,opposite:-1===x,perpendicular:0===x,orthogonal:1===x,sourceAxis:0===l[0]?"y":"x",points:[c,d,f,p,w,E,O,T],stubs:[this.sourceStub,this.targetStub]};return A.anchorOrientation=A.opposite?"opposite":A.orthogonal?"orthogonal":"perpendicular",A}},{key:"updateBounds",value:function(t){var e=t.extents;this.bounds.xmin=Math.min(this.bounds.xmin,e.xmin),this.bounds.xmax=Math.max(this.bounds.xmax,e.xmax),this.bounds.ymin=Math.min(this.bounds.ymin,e.ymin),this.bounds.ymax=Math.max(this.bounds.ymax,e.ymax)}},{key:"dumpSegmentsToConsole",value:function(){B("SEGMENTS:");for(var t=0;t0?t:this.length+t:t*this.length;return ct({x:this.x1,y:this.y1},{x:this.x2,y:this.y2},n)}return{x:this.x2,y:this.y2}}return{x:this.x1,y:this.y1}}},{key:"gradientAtPoint",value:function(t,e){return this.m}},{key:"pointAlongPathFrom",value:function(t,e,n){var r=this.pointOnPath(t,n),i=e<=0?{x:this.x1,y:this.y1}:{x:this.x2,y:this.y2};return e<=0&&Math.abs(e)>1&&(e*=-1),ct(r,i,e)}},{key:"within",value:function(t,e,n){return n>=Math.min(t,e)&&n<=Math.max(t,e)}},{key:"closest",value:function(t,e,n){return Math.abs(n-t)e?e<=t&&t<=n:e>=t&&t>=n}},{key:"lineIntersection",value:function(t,e,n,r){var i=Math.abs(at({x:t,y:e},{x:n,y:r})),o=Math.abs(this.m),a=o===1/0?this.x1:this.y1-o*this.x1,s=[],l=i===1/0?t:e-i*t;if(i!==o)if(i===1/0&&0===o)this._pointLiesBetween(t,this.x1,this.x2)&&this._pointLiesBetween(this.y1,e,r)&&s.push({x:t,y:this.y1});else if(0===i&&o===1/0)this._pointLiesBetween(e,this.y1,this.y2)&&this._pointLiesBetween(this.x1,t,n)&&s.push({x:this.x1,y:e});else{var u,c;i===1/0?(u=t,this._pointLiesBetween(u,this.x1,this.x2)&&(c=o*t+a,this._pointLiesBetween(c,e,r)&&s.push({x:u,y:c}))):0===i?(c=e,this._pointLiesBetween(c,this.y1,this.y2)&&(u=(e-a)/o,this._pointLiesBetween(u,t,n)&&s.push({x:u,y:c}))):(c=o*(u=(l-a)/(o-i))+a,this._pointLiesBetween(u,this.x1,this.x2)&&this._pointLiesBetween(c,this.y1,this.y2)&&s.push({x:u,y:c}))}return s}},{key:"boxIntersection",value:function(t,e,n,r){var i=[];return i.push.apply(i,this.lineIntersection(t,e,t+n,e)),i.push.apply(i,this.lineIntersection(t+n,e,t+n,e+r)),i.push.apply(i,this.lineIntersection(t+n,e+r,t,e+r)),i.push.apply(i,this.lineIntersection(t,e+r,t,e)),i}}]),n}();Ot(Ft,"segmentType","Straight");var Jt=function(t){Tt(n,Vt);var e=kt(n);function n(){var t;mt(this,n);for(var r=arguments.length,i=new Array(r),o=0;o0}))}function Ce(t,e,n){for(var r in e)t[r]=n}Ot(Ne,"type","Label"),je.register(Ne.type,Ne);var De="connector",Ye="override",Le="cssClass",Re="__default",ze="anchor",Be="anchors",_e="__label",Ze="overlay",Ge="remove";function He(t,e){if(t.getDefaultType){var n=t.getTypeDescriptor(),r={},i=t.getDefaultType(),o=p({},i);Ce(r,i,Re),t._types.forEach((function(e){if(e!==Re){var i=t.instance.getType(e,n);if(null!=i){var a=new Set([De,ze,Be]);if(i.mergeStrategy===Ye)for(var s in i)a.add(s);o=E(o,i,[Le],(l=[],a.forEach((function(t){l.push(t)})),l)),Ce(r,i,e)}}var l})),e&&(o=T(o,e,"_")),t.applyType(o,r)}}function Ve(t,e){var n=t.instance.getType(e,t.getTypeDescriptor());null!=n&&n.cssClass&&t.removeClass(n.cssClass)}function Fe(t){if(t.paintStyle&&t.hoverPaintStyle){var e={};p(e,t.paintStyle),p(e,t.hoverPaintStyle),t.hoverPaintStyle=e}}var Je,Xe,We,qe,Ue=function(t){Tt(n,tt);var e=kt(n);function n(t,r){var i;if(mt(this,n),(i=e.call(this)).instance=t,Ot(Pt(i),"defaultLabelLocation",.5),Ot(Pt(i),"overlays",{}),Ot(Pt(i),"overlayPositions",{}),Ot(Pt(i),"overlayPlacements",{}),Ot(Pt(i),"clone",void 0),Ot(Pt(i),"deleted",void 0),Ot(Pt(i),"segment",void 0),Ot(Pt(i),"x",void 0),Ot(Pt(i),"y",void 0),Ot(Pt(i),"w",void 0),Ot(Pt(i),"h",void 0),Ot(Pt(i),"id",void 0),Ot(Pt(i),"visible",!0),Ot(Pt(i),"typeId",void 0),Ot(Pt(i),"params",{}),Ot(Pt(i),"paintStyle",void 0),Ot(Pt(i),"hoverPaintStyle",void 0),Ot(Pt(i),"paintStyleInUse",void 0),Ot(Pt(i),"_hover",!1),Ot(Pt(i),"lastPaintedAt",void 0),Ot(Pt(i),"data",void 0),Ot(Pt(i),"_defaultType",void 0),Ot(Pt(i),"events",void 0),Ot(Pt(i),"parameters",void 0),Ot(Pt(i),"_types",void 0),Ot(Pt(i),"_typeCache",void 0),Ot(Pt(i),"cssClass",void 0),Ot(Pt(i),"hoverClass",void 0),Ot(Pt(i),"beforeDetach",void 0),Ot(Pt(i),"beforeDrop",void 0),r=r||{},i.cssClass=r.cssClass||"",i.hoverClass=r.hoverClass||t.defaults.hoverClass,i.beforeDetach=r.beforeDetach,i.beforeDrop=r.beforeDrop,i._types=new Set,i._typeCache={},i.parameters=w(r.parameters||{}),i.id=r.id||i.getIdPrefix()+(new Date).getTime(),i._defaultType={parameters:i.parameters,scope:r.scope||i.instance.defaultScope,overlays:{}},r.events)for(var o in r.events)i.bind(o,r.events[o]);i.clone=function(){var e=Object.create(i.constructor.prototype);return i.constructor.apply(e,[t,r]),e},i.overlays={},i.overlayPositions={};var a=r.overlays||[],s={},l=i.getDefaultOverlayKey();if(l){var u=i.instance.defaults[l];u&&a.push.apply(a,Nt(u));for(var c=0;c1,timestamp:null,cssClass:n.cssClass||""}}var wn="currentFace";function En(t){return t.length<7&&t.every(h)||7===t.length&&t.slice(0,5).every(h)&&g(t[6])}function On(t){if(g(t))return bn(t,null);if(Array.isArray(t)){if(En(t)){var e=t;return mn(null,[{x:e[0],y:e[1],ox:e[2],oy:e[3],offx:null==e[4]?0:e[4],offy:null==e[5]?0:e[5],iox:e[2],ioy:e[3],cls:e[6]||""}],{cssClass:e[6]||""})}return mn("Dynamic",z(t,(function(t){if(g(t)){var e=vn[t];return null!=e?p({iox:e[0].ox,ioy:e[0].oy,cls:""},e[0]):null}if(En(t))return{x:t[0],y:t[1],ox:t[2],oy:t[3],offx:null==t[4]?0:t[4],offy:null==t[5]?0:t[5],iox:t[2],ioy:t[3],cls:t[6]||""}})).filter((function(t){return null!=t})),{})}var n=t;return bn(n.type,n.options)}function Tn(t){for(var e=.5,n=2*Math.PI/t,r=[],i=0,o=0;o0){var e=this.instance.endpointAnchorClassPrefix+"-"+this.currentAnchorClass;this.currentAnchorClass=t;var n=this.instance.endpointAnchorClassPrefix+(this.currentAnchorClass?"-"+this.currentAnchorClass:"");e!==n&&(this.removeClass(e),this.addClass(n),this.instance.removeClass(this.element,e),this.instance.addClass(this.element,n))}}},{key:"setPreparedAnchor",value:function(t){return this.instance.router.setAnchor(this,t),this._updateAnchorClass(),this}},{key:"_anchorLocationChanged",value:function(t){this.fire("anchor:changed",{endpoint:this,anchor:t}),this._updateAnchorClass()}},{key:"setAnchor",value:function(t){var e=this.instance.router.prepareAnchor(t);return this.setPreparedAnchor(e),this}},{key:"addConnection",value:function(t){this.connections.push(t),this.instance._refreshEndpoint(this)}},{key:"detachFromConnection",value:function(t,e,n){(e=null==e?this.connections.indexOf(t):e)>=0&&(this.connections.splice(e,1),this.instance._refreshEndpoint(this)),!n&&this.deleteOnEmpty&&0===this.connections.length&&this.instance.deleteEndpoint(this)}},{key:"deleteEveryConnection",value:function(t){for(var e=this.connections.length,n=0;n0){var i,o,a=this.instance.getConnections({source:n,scope:bt},!0),s=this.instance.getConnections({target:n,scope:bt},!0),l={},u=function(n){for(var r=0;r2?o-2:0),s=2;s2?i-2:0),a=2;at[1]?n=-1:e[1]o;)n(t,e[s])*i<0?a=s:o=s+1,s=Math.floor((o+a)/2);e.splice(s,0,t)}}([t,e],n,Zn,r)}function Vn(t,e){var n=A(e,(function(e){return e[0]===t}));n>-1&&e.splice(n,1)}var Fn,Jn=function(t){Tt(n,tt);var e=kt(n);function n(t){var r;return mt(this,n),(r=e.call(this)).instance=t,Ot(Pt(r),"_currentTransaction",null),Ot(Pt(r),"_sortedElements",{xmin:[],xmax:[],ymin:[],ymax:[]}),Ot(Pt(r),"_elementMap",new Map),Ot(Pt(r),"_transformedElementMap",new Map),Ot(Pt(r),"_bounds",{minx:0,maxx:0,miny:0,maxy:0}),r}return Et(n,[{key:"_updateBounds",value:function(t,e,n){null!=e&&(Vn(t,this._sortedElements.xmin),Vn(t,this._sortedElements.xmax),Vn(t,this._sortedElements.ymin),Vn(t,this._sortedElements.ymax),Hn(t,e.t.x,this._sortedElements.xmin,!1),Hn(t,e.t.x+e.t.w,this._sortedElements.xmax,!0),Hn(t,e.t.y,this._sortedElements.ymin,!1),Hn(t,e.t.y+e.t.h,this._sortedElements.ymax,!0),!0!==n&&this._recalculateBounds())}},{key:"_recalculateBounds",value:function(){this._bounds.minx=this._sortedElements.xmin.length>0?this._sortedElements.xmin[0][1]:0,this._bounds.maxx=this._sortedElements.xmax.length>0?this._sortedElements.xmax[0][1]:0,this._bounds.miny=this._sortedElements.ymin.length>0?this._sortedElements.ymin[0][1]:0,this._bounds.maxy=this._sortedElements.ymax.length>0?this._sortedElements.ymax[0][1]:0}},{key:"recomputeBounds",value:function(){var t=this;this._sortedElements.xmin.length=0,this._sortedElements.xmax.length=0,this._sortedElements.ymin.length=0,this._sortedElements.ymax.length=0,this._elementMap.forEach((function(e,n){t._sortedElements.xmin.push([n,e.t.x]),t._sortedElements.xmax.push([n,e.t.x+e.t.w]),t._sortedElements.ymin.push([n,e.t.y]),t._sortedElements.ymax.push([n,e.t.y+e.t.h])})),this._sortedElements.xmin.sort(Zn),this._sortedElements.ymin.sort(Zn),this._sortedElements.xmax.sort(Gn),this._sortedElements.ymax.sort(Gn),this._recalculateBounds()}},{key:"_finaliseUpdate",value:function(t,e,n){e.t=function(t,e,n,r,i){var o=t+n/2,a=e+r/2,s=Math.cos(i/360*Math.PI*2),l=Math.sin(i/360*Math.PI*2),u=function(t,e){return{x:o+Math.round((t-o)*s-(e-a)*l),y:a+Math.round((e-a)*s-(t-o)*l)}},c=u(t,e),d=u(t+n,e),f=u(t+n,e+r),p=u(t,e+r),h=u(t+n/2,e+r/2),g=Math.min(c.x,d.x,f.x,p.x),v=Math.max(c.x,d.x,f.x,p.x),y=Math.min(c.y,d.y,f.y,p.y),b=Math.max(c.y,d.y,f.y,p.y);return{x:g,y:y,w:v-g,h:b-y,c:h,r:i,x2:v,y2:b,cr:s,sr:l}}(e.x,e.y,e.w,e.h,e.r),this._transformedElementMap.set(t,e.t),!0!==n&&this._updateBounds(t,e,n)}},{key:"shouldFireEvent",value:function(t,e,n){return!0}},{key:"startTransaction",value:function(){if(null!=this._currentTransaction)throw new Error("Viewport: cannot start transaction; a transaction is currently active.");this._currentTransaction=new Bn}},{key:"endTransaction",value:function(){var t=this;null!=this._currentTransaction&&(this._currentTransaction.affectedElements.forEach((function(e){var n=t.getPosition(e);t._finaliseUpdate(e,n,!0)})),this.recomputeBounds(),this._currentTransaction=null)}},{key:"updateElements",value:function(t){var e=this;x(t,(function(t){return e.updateElement(t.id,t.x,t.y,t.width,t.height,t.rotation)}))}},{key:"updateElement",value:function(t,e,n,r,i,o,a){var s=H(this._elementMap,t,_n);return s.dirty=null==e&&null==s.x||null==n&&null==s.y||null==r&&null==s.w||null==i&&null==s.h,null!=e&&(s.x=e),null!=n&&(s.y=n),null!=r&&(s.w=r),null!=i&&(s.h=i),null!=o&&(s.r=o||0),s.c.x=s.x+s.w/2,s.c.y=s.y+s.h/2,s.x2=s.x+s.w,s.y2=s.y+s.h,null==this._currentTransaction?this._finaliseUpdate(t,s,a):this._currentTransaction.affectedElements.add(t),s}},{key:"refreshElement",value:function(t,e){var n=this.instance.getManagedElements(),r=n[t]?n[t].el:null;if(null!=r){var i=this.getSize(r),o=this.getOffset(r);return this.updateElement(t,o.x,o.y,i.w,i.h,null,e)}return null}},{key:"getSize",value:function(t){return this.instance.getSize(t)}},{key:"getOffset",value:function(t){return this.instance.getOffset(t)}},{key:"registerElement",value:function(t,e){return this.updateElement(t,0,0,0,0,0,e)}},{key:"addElement",value:function(t,e,n,r,i,o){return this.updateElement(t,e,n,r,i,o)}},{key:"rotateElement",value:function(t,e){var n=H(this._elementMap,t,_n);return n.r=e||0,this._finaliseUpdate(t,n),n}},{key:"getBoundsWidth",value:function(){return this._bounds.maxx-this._bounds.minx}},{key:"getBoundsHeight",value:function(){return this._bounds.maxy-this._bounds.miny}},{key:"getX",value:function(){return this._bounds.minx}},{key:"getY",value:function(){return this._bounds.miny}},{key:"setSize",value:function(t,e,n){if(this._elementMap.has(t))return this.updateElement(t,null,null,e,n,null)}},{key:"setPosition",value:function(t,e,n){if(this._elementMap.has(t))return this.updateElement(t,e,n,null,null,null)}},{key:"reset",value:function(){this._sortedElements.xmin.length=0,this._sortedElements.xmax.length=0,this._sortedElements.ymin.length=0,this._sortedElements.ymax.length=0,this._elementMap.clear(),this._transformedElementMap.clear(),this._recalculateBounds()}},{key:"remove",value:function(t){Vn(t,this._sortedElements.xmin),Vn(t,this._sortedElements.xmax),Vn(t,this._sortedElements.ymin),Vn(t,this._sortedElements.ymax),this._elementMap.delete(t),this._transformedElementMap.delete(t),this._recalculateBounds()}},{key:"getPosition",value:function(t){return this._elementMap.get(t)}},{key:"getElements",value:function(){return this._elementMap}},{key:"isEmpty",value:function(){return 0===this._elementMap.size}}]),n}();function Xn(t,e){return e.theta-t.theta}function Wn(t,e){return(t.theta<0?-Math.PI-t.theta:Math.PI-t.theta)-(e.theta<0?-Math.PI-e.theta:Math.PI-e.theta)}var qn=(Ot(Fn={},Ke,Wn),Ot(Fn,$e,Xn),Ot(Fn,tn,Xn),Ot(Fn,Qe,Wn),Fn);function Un(t){return!0===t.isContinuous}function Kn(t){return!0===t.isContinuous}function Qn(t){return t.locations.length>1}function $n(t){return[t.currentLocation,t.locations[t.currentLocation]]}var tr=function(){function t(e){var n=this;mt(this,t),this.instance=e,Ot(this,"anchorLists",new Map),Ot(this,"anchorLocations",new Map),e.bind(me,(function(t){t.sourceEndpoint._anchor.isContinuous&&n._removeEndpointFromAnchorLists(t.sourceEndpoint),t.targetEndpoint._anchor.isContinuous&&n._removeEndpointFromAnchorLists(t.targetEndpoint)})),e.bind(be,(function(t){n._removeEndpointFromAnchorLists(t)}))}return Et(t,[{key:"getAnchorOrientation",value:function(t){var e=this.anchorLocations.get(t.id);return e?[e.ox,e.oy]:[0,0]}},{key:"_distance",value:function(t,e,n,r,i,o,a){var s=r.x+t.x*i.w,l=r.y+t.y*i.h,u=r.x+i.w/2,c=r.y+i.h/2;if(null!=o&&o.length>0){var d=this.instance._applyRotations([s,l,0,0],o);s=d.x,l=d.y}return Math.sqrt(Math.pow(e-s,2)+Math.pow(n-l,2))+Math.sqrt(Math.pow(u-s,2)+Math.pow(c-l,2))}},{key:"_anchorSelector",value:function(t,e,n,r,i,o,a){for(var s=n.x+r.w/2,l=n.y+r.h/2,u=-1,c=1/0,d=0;d0){var s=[t.iox,t.ioy],l={x:a.curX,y:a.curY,cr:0,sr:0};x(o,(function(t){l=L(l,t.c,t.r);var e=[Math.round(s[0]*l.cr-s[1]*l.sr),Math.round(s[1]*l.cr+s[0]*l.sr)];s=e.slice()})),t.ox=s[0],t.oy=s[1],i={curX:l.x,curY:l.y,x:t.x,y:t.y,ox:s[0],oy:s[1]}}else t.ox=t.iox,t.oy=t.ioy,i=p({ox:t.iox,oy:t.ioy},a);return i}},{key:"_singleAnchorCompute",value:function(t,e){var n=e.xy,r=e.wh,i=e.timestamp,o=this.anchorLocations.get(t.id);if(null!=o&&i&&i===t.timestamp)return o;var a=jt($n(t),2);a[0];var s=a[1];return o=this._computeSingleLocation(s,n,r,e),this._setComputedPosition(t,o,i)}},{key:"_defaultAnchorCompute",value:function(t,e){var n;if(1===t.locations.length)return this._singleAnchorCompute(t,e);var r=e.xy,i=e.wh,o=e.txy,a=e.twh,s=jt($n(t),2),l=s[0],u=s[1];if(t.locked||null==o||null==a)n=this._computeSingleLocation(u,r,i,e);else{var c=jt(this._anchorSelector(r,i,o,a,e.rotation,e.tRotation,t.locations),2),d=c[0],f=c[1];t.currentLocation=d,d!==l&&(t.cssClass=f.cls||t.cssClass,e.element._anchorLocationChanged(t)),n=this._computeSingleLocation(f,r,i,e)}return this._setComputedPosition(t,n,e.timestamp)}},{key:"_placeAnchors",value:function(t,e){var n=this,r=this.instance.viewport.getPosition(t),i=function(e,i,o,a,s,l){if(o.length>0)for(var u=o.sort(qn[e]),c=function(t,e,n,r,i){for(var o=n?t.w:t.h,a=n?t.h:t.w,s=[],l=o/(e.length+1),u=0;u1)}},{key:"isFloating",value:function(t){return!!t._anchor&&Kn(t._anchor)}},{key:"prepareAnchor",value:function(t){return On(t)}},{key:"redraw",value:function(t,e,n){var r=this,i=new Set,o=new Set,a=new Set;if(!this.instance._suspendDrawing){var s=this.instance.endpointsByElement[t]||[];e=e||Y();for(var l,u,c={},d=0;d0)for(var i in f[t[n]])f[t[n]][i]=l.instance._applyRotationsXY(f[t[n]][i],e[n][1])}}([Qt,$t],[[n,a],[r,s]]);for(var p=[Ke,Qe,$e,tn],h=0;h2&&void 0!==arguments[2]&&arguments[2];mt(this,t),this.selector=e,this.def=n,this.exclude=r,Ot(this,"id",void 0),Ot(this,"redrop",void 0),this.id=Y(),this.redrop=n.def.redrop||nr}return Et(t,[{key:"setEnabled",value:function(t){this.def.enabled=t}},{key:"isEnabled",value:function(){return!1!==this.def.enabled}}]),t}(),nr="strict";function rr(t,e,n){var r=[],i=function(e){return g(e)?e:t.getId(e)};if(e)if("string"==typeof e){if("*"===e)return e;r.push(e)}else{var o;if(n)r=e;else if(null!=e.length)(o=r).push.apply(o,Nt(Nt(e).map(i)));else r.push(i(e))}return r}function ir(t,e,n){null!=e&&(e.connections.push(t),1===e.connections.length&&t.instance.addClass(t.source,t.instance.connectedClass)),null!=n&&(null!=e&&t.sourceId===t.targetId||(n.connections.push(t),1===n.connections.length&&t.instance.addClass(t.target,t.instance.connectedClass)))}function or(t,e,n){if(null!=e){var r=e.connections.length;I(e.connections,(function(e){return t.id===e.id})),r>0&&0===e.connections.length&&t.instance.removeClass(t.source,t.instance.connectedClass)}if(null!=n){var i=n.connections.length;null!=e&&t.sourceId===t.targetId||I(n.connections,(function(e){return t.id===e.id})),i>0&&0===n.connections.length&&t.instance.removeClass(t.target,t.instance.connectedClass)}}var ar=function(t){Tt(n,tt);var e=kt(n);function n(t,r){var i;return mt(this,n),(i=e.call(this))._instanceIndex=t,Ot(Pt(i),"defaults",void 0),Ot(Pt(i),"_initialDefaults",{}),Ot(Pt(i),"isConnectionBeingDragged",!1),Ot(Pt(i),"currentlyDragging",!1),Ot(Pt(i),"hoverSuspended",!1),Ot(Pt(i),"_suspendDrawing",!1),Ot(Pt(i),"_suspendedAt",null),Ot(Pt(i),"connectorClass",ce),Ot(Pt(i),"connectorOutlineClass","jtk-connector-outline"),Ot(Pt(i),"connectedClass","jtk-connected"),Ot(Pt(i),"endpointClass",de),Ot(Pt(i),"endpointConnectedClass","jtk-endpoint-connected"),Ot(Pt(i),"endpointFullClass","jtk-endpoint-full"),Ot(Pt(i),"endpointFloatingClass",fe),Ot(Pt(i),"endpointDropAllowedClass","jtk-endpoint-drop-allowed"),Ot(Pt(i),"endpointDropForbiddenClass","jtk-endpoint-drop-forbidden"),Ot(Pt(i),"endpointAnchorClassPrefix","jtk-endpoint-anchor"),Ot(Pt(i),"overlayClass",ge),Ot(Pt(i),"connections",[]),Ot(Pt(i),"endpointsByElement",{}),Ot(Pt(i),"endpointsByUUID",new Map),Ot(Pt(i),"sourceSelectors",[]),Ot(Pt(i),"targetSelectors",[]),Ot(Pt(i),"allowNestedGroups",void 0),Ot(Pt(i),"_curIdStamp",1),Ot(Pt(i),"viewport",new Jn(Pt(i))),Ot(Pt(i),"router",void 0),Ot(Pt(i),"groupManager",void 0),Ot(Pt(i),"_connectionTypes",new Map),Ot(Pt(i),"_endpointTypes",new Map),Ot(Pt(i),"_container",void 0),Ot(Pt(i),"_managedElements",{}),Ot(Pt(i),"DEFAULT_SCOPE",void 0),Ot(Pt(i),"_zoom",1),i.defaults={anchor:nt.Bottom,anchors:[null,null],connectionsDetachable:!0,connectionOverlays:[],connector:Jt.type,container:null,endpoint:zt.type,endpointOverlays:[],endpoints:[null,null],endpointStyle:{fill:"#456"},endpointStyles:[null,null],endpointHoverStyle:null,endpointHoverStyles:[null,null],hoverPaintStyle:null,listStyle:{},maxConnections:1,paintStyle:{strokeWidth:2,stroke:"#456"},reattachConnections:!1,scope:"jsplumb_defaultscope",allowNestedGroups:!0},r&&p(i.defaults,r),p(i._initialDefaults,i.defaults),null!=i._initialDefaults[Ae]&&(i._initialDefaults[Ae].strokeWidth=i._initialDefaults[Ae].strokeWidth||2),i.DEFAULT_SCOPE=i.defaults.scope,i.allowNestedGroups=!1!==i._initialDefaults.allowNestedGroups,i.router=new tr(Pt(i)),i.groupManager=new Yn(Pt(i)),i.setContainer(i._initialDefaults.container),i}return Et(n,[{key:"defaultScope",get:function(){return this.DEFAULT_SCOPE}},{key:"currentZoom",get:function(){return this._zoom}},{key:"areDefaultAnchorsSet",value:function(){return this.validAnchorsSpec(this.defaults.anchors)}},{key:"validAnchorsSpec",value:function(t){return null!=t&&null!=t[0]&&null!=t[1]}},{key:"getContainer",value:function(){return this._container}},{key:"setZoom",value:function(t,e){return this._zoom=t,this.fire(Ee,this._zoom),e&&this.repaintEverything(),!0}},{key:"_idstamp",value:function(){return""+this._curIdStamp++}},{key:"checkCondition",value:function(t,e){var n=this.getListener(t),r=!0;if(n&&n.length>0){var i=Array.prototype.slice.call(arguments,1);try{for(var o=0,a=n.length;o1?{}:[],a=function(t,r){if(!e&&n.length>1){var i=o[t];null==i&&(i=o[t]=[]),i.push(r)}else o.push(r)},s=0,l=this.connections.length;s0&&!v.isSource,b=p&&i.length>0&&!v.isTarget;if(y||b)continue t;a.push(v)}}}return new Rn(this,a)}},{key:"setContainer",value:function(t){this._container=t,this.fire("container:change",this._container)}},{key:"_set",value:function(t,e,n){var r,i,o=[{el:"source",elId:"sourceId"},{el:"target",elId:"targetId"}][n],a=t[o.elId],s=t.endpoints[n],l={index:n,originalEndpoint:s,originalSourceId:0===n?a:t.sourceId,newSourceId:t.sourceId,originalTargetId:1===n?a:t.targetId,newTargetId:t.targetId,connection:t,newEndpoint:s};return e instanceof Mn?(r=e).addConnection(t):r=(i=this.getId(e))===t[o.elId]?null:t.makeEndpoint(0===n,e,i),null!=r&&(l.newEndpoint=r,s.detachFromConnection(t),t.endpoints[n]=r,t[o.el]=r.element,t[o.elId]=r.elementId,l[0===n?"newSourceId":"newTargetId"]=r.elementId,this.fireMoveEvent(l),this._paintConnection(t)),l}},{key:"setSource",value:function(t,e){or(t,this._managedElements[t.sourceId]);var n=this._set(t,e,0);ir(t,this._managedElements[n.newSourceId])}},{key:"setTarget",value:function(t,e){or(t,this._managedElements[t.targetId]);var n=this._set(t,e,1);ir(t,this._managedElements[n.newTargetId])}},{key:"setConnectionType",value:function(t,e,n){t.setType(e,n),this._paintConnection(t)}},{key:"isHoverSuspended",value:function(){return this.hoverSuspended}},{key:"setSuspendDrawing",value:function(t,e){var n=this._suspendDrawing;return this._suspendDrawing=t,t?this._suspendedAt=""+(new Date).getTime():(this._suspendedAt=null,this.viewport.recomputeBounds()),e&&this.repaintEverything(),n}},{key:"getSuspendedAt",value:function(){return this._suspendedAt}},{key:"batch",value:function(t,e){var n=!0===this._suspendDrawing;n||this.setSuspendDrawing(!0),t(),n||this.setSuspendDrawing(!1,!e)}},{key:"each",value:function(t,e){if(null!=t){if(null!=t.length)for(var n=0;n0)for(var l=0;l2&&void 0!==arguments[2]&&arguments[2],r=this._createSourceDefinition(e),i=new er(t,r,n);return this.sourceSelectors.push(i),i}},{key:"removeSourceSelector",value:function(t){I(this.sourceSelectors,(function(e){return e===t}))}},{key:"removeTargetSelector",value:function(t){I(this.targetSelectors,(function(e){return e===t}))}},{key:"addTargetSelector",value:function(t,e){var n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],r=this._createTargetDefinition(e),i=new er(t,r,n);return this.targetSelectors.push(i),i}},{key:"_createTargetDefinition",value:function(t,e){var n=p({},e);p(n,t),n.edgeType=n.edgeType||gt;var r=n.maxConnections||-1;return{def:p({},n),uniqueEndpoint:n.uniqueEndpoint,maxConnections:r,enabled:!0,endpoint:null}}},{key:"show",value:function(t,e){return this._setVisible(t,te,e)}},{key:"hide",value:function(t,e){return this._setVisible(t,ee,e)}},{key:"_setVisible",value:function(t,e,n){var r=e===te,i=null;n&&(i=function(t){t.setVisible(r,!0,!0)});var o=this.getId(t);return this._operation(t,(function(t){if(r&&n){var e=t.sourceId===o?1:0;t.endpoints[e].isVisible()&&t.setVisible(!0)}else t.setVisible(r)}),i),this}},{key:"toggleVisible",value:function(t,e){var n=null;e&&(n=function(t){var e=t.isVisible();t.setVisible(!e)}),this._operation(t,(function(t){var e=t.isVisible();t.setVisible(!e)}),n)}},{key:"_operation",value:function(t,e,n){var r=this.getId(t),i=this.endpointsByElement[r];if(i&&i.length)for(var o=0,a=i.length;o1?n-1:0),i=1;i0){var l=function(t){var n=0;if(null!=e.elementWithPrecedence)for(var r=0;r0&&(s.connection=t.connections[0]);s.rotation=this._getRotations(t.elementId),a=this.router.computeAnchorLocation(t._anchor,s)}for(var f in t.endpoint.compute(a,this.router.getEndpointOrientation(t),t.paintStyleInUse),this.renderEndpoint(t,t.paintStyleInUse),t.timestamp=n,t.overlays)if(t.overlays.hasOwnProperty(f)){var p=t.overlays[f];p.isVisible()&&(t.overlayPlacements[f]=this.drawOverlay(p,t.endpoint,t.paintStyleInUse,t.getAbsoluteOverlayPosition(p)),this._paintOverlay(p,t.overlayPlacements[f],{xmin:0,ymin:0}))}}}}},{key:"_paintConnection",value:function(t,e){if(!this._suspendDrawing&&!1!==t.visible){var n=(e=e||{}).timestamp;if(null!=n&&n===t.lastPaintedAt)return;if(null==n||n!==t.lastPaintedAt){this.router.computePath(t,n);var r={xmin:1/0,ymin:1/0,xmax:-1/0,ymax:-1/0};for(var i in t.overlays)if(t.overlays.hasOwnProperty(i)){var o=t.overlays[i];o.isVisible()&&(t.overlayPlacements[i]=this.drawOverlay(o,t.connector,t.paintStyleInUse,t.getAbsoluteOverlayPosition(o)),r.xmin=Math.min(r.xmin,t.overlayPlacements[i].xmin),r.xmax=Math.max(r.xmax,t.overlayPlacements[i].xmax),r.ymin=Math.min(r.ymin,t.overlayPlacements[i].ymin),r.ymax=Math.max(r.ymax,t.overlayPlacements[i].ymax))}var a=parseFloat(""+t.paintStyleInUse.strokeWidth||"1")/2,s=parseFloat(""+t.paintStyleInUse.strokeWidth||"0"),l={xmin:Math.min(t.connector.bounds.xmin-(a+s),r.xmin),ymin:Math.min(t.connector.bounds.ymin-(a+s),r.ymin),xmax:Math.max(t.connector.bounds.xmax+(a+s),r.xmax),ymax:Math.max(t.connector.bounds.ymax+(a+s),r.ymax)};for(var u in this.paintConnector(t.connector,t.paintStyleInUse,l),t.overlays)if(t.overlays.hasOwnProperty(u)){var c=t.overlays[u];c.isVisible()&&this._paintOverlay(c,t.overlayPlacements[u],l)}}t.lastPaintedAt=n}}},{key:"_refreshEndpoint",value:function(t){t._anchor.isFloating||(t.connections.length>0?this.addEndpointClass(t,this.endpointConnectedClass):this.removeEndpointClass(t,this.endpointConnectedClass),t.isFull()?this.addEndpointClass(t,this.endpointFullClass):this.removeEndpointClass(t,this.endpointFullClass))}},{key:"_makeConnector",value:function(t,e,n){return Wt(t,e,n)}},{key:"addOverlay",value:function(t,e,n){if(t.addOverlay(e),!n){var r=t instanceof Mn?t.element:t.source;this.revalidate(r)}}},{key:"removeOverlay",value:function(t,e){t.removeOverlay(e);var n=t instanceof Mn?t.element:t.source;this.revalidate(n)}},{key:"setOutlineColor",value:function(t,e){t.paintStyleInUse.outlineStroke=e,this._paintConnection(t)}},{key:"setOutlineWidth",value:function(t,e){t.paintStyleInUse.outlineWidth=e,this._paintConnection(t)}},{key:"setColor",value:function(t,e){t.paintStyleInUse.stroke=e,this._paintConnection(t)}},{key:"setLineWidth",value:function(t,e){t.paintStyleInUse.strokeWidth=e,this._paintConnection(t)}},{key:"setLineStyle",value:function(t,e){null!=e.lineWidth&&(t.paintStyleInUse.strokeWidth=e.lineWidth),null!=e.outlineWidth&&(t.paintStyleInUse.outlineWidth=e.outlineWidth),null!=e.color&&(t.paintStyleInUse.stroke=e.color),null!=e.outlineColor&&(t.paintStyleInUse.outlineStroke=e.outlineColor),this._paintConnection(t)}},{key:"getPathData",value:function(t){for(var e="",n=0;nMath.PI?1:0,n=this.anticlockwise?0:1;return(t?"M"+this.x1+" "+this.y1+" ":"")+"A "+this.radius+" "+this.radius+" 0 "+e+","+n+" "+this.x2+" "+this.y2}},{key:"getLength",value:function(){return this.length}},{key:"pointOnPath",value:function(t,e){if(0===t)return{x:this.x1,y:this.y1,theta:this.startAngle};if(1===t)return{x:this.x2,y:this.y2,theta:this.endAngle};e&&(t/=length);var n=this._calcAngleForLocation(this,t),r=this.cx+this.radius*Math.cos(n),i=this.cy+this.radius*Math.sin(n);return{x:lr(r),y:lr(i),theta:n}}},{key:"gradientAtPoint",value:function(t,e){var n=this.pointOnPath(t,e),r=-1/at({x:this.cx,y:this.cy},n);return this.anticlockwise||r!==1/0&&r!==-1/0||(r*=-1),r}},{key:"pointAlongPathFrom",value:function(t,e,n){var r=this.pointOnPath(t,n),i=e/this.circumference*2*Math.PI,o=this.anticlockwise?-1:1,a=r.theta+o*i;return{x:this.cx+this.radius*Math.cos(a),y:this.cy+this.radius*Math.sin(a)}}}]),n}();Ot(ur,"segmentType","Arc");var cr=function(t){Tt(n,ke);var e=kt(n);function n(t,r,i){var o;return mt(this,n),(o=e.call(this,t,r,i)).instance=t,o.component=r,Ot(Pt(o),"width",void 0),Ot(Pt(o),"length",void 0),Ot(Pt(o),"foldback",void 0),Ot(Pt(o),"direction",void 0),Ot(Pt(o),"location",.5),Ot(Pt(o),"paintStyle",void 0),Ot(Pt(o),"type",n.type),Ot(Pt(o),"cachedDimensions",void 0),i=i||{},o.width=i.width||20,o.length=i.length||20,o.direction=(i.direction||1)<0?-1:1,o.foldback=i.foldback||.623,o.paintStyle=i.paintStyle||{strokeWidth:1},o.location=null==i.location?o.location:Array.isArray(i.location)?i.location[0]:i.location,o}return Et(n,[{key:"draw",value:function(t,e,n){if(t instanceof Vt){var r,i,o,a=t;if(this.location>1||this.location<0){var s=this.location<0?1:0;i=ct(r=a.pointAlongPathFrom(s,this.location,!1),a.pointAlongPathFrom(s,this.location-this.direction*this.length/2,!1),this.length)}else if(1===this.location){if(i=ct(r=a.pointOnPath(this.location),a.pointAlongPathFrom(this.location,-this.length),this.length),-1===this.direction){var l=i;i=r,r=l}}else if(0===this.location){if(r=ct(i=a.pointOnPath(this.location),a.pointAlongPathFrom(this.location,this.length),this.length),-1===this.direction){var u=i;i=r,r=u}}else i=ct(r=a.pointAlongPathFrom(this.location,this.direction*this.length/2),a.pointOnPath(this.location),this.length);var c={hxy:r,tail:o=function(t,e,n){var r=at(t,e),i=Math.atan(-1/r),o=n/2*Math.sin(i),a=n/2*Math.cos(i);return[{x:e.x+a,y:e.y+o},{x:e.x-a,y:e.y-o}]}(r,i,this.width),cxy:ct(r,i,this.foldback*this.length)},d=this.paintStyle.stroke||e.stroke,f=this.paintStyle.fill||e.stroke;return{component:t,d:c,"stroke-width":this.paintStyle.strokeWidth||e.strokeWidth,stroke:d,fill:f,xmin:Math.min(r.x,o[0].x,o[1].x),xmax:Math.max(r.x,o[0].x,o[1].x),ymin:Math.min(r.y,o[0].y,o[1].y),ymax:Math.max(r.y,o[0].y,o[1].y)}}}},{key:"updateFrom",value:function(t){}}]),n}();function dr(t){return t.type===cr.type}Ot(cr,"type","Arrow"),je.register(cr.type,cr);var fr=function(t){Tt(n,cr);var e=kt(n);function n(t,r,i){var o;return mt(this,n),(o=e.call(this,t,r,i)).instance=t,Ot(Pt(o),"type",n.type),o.foldback=1,o}return n}();function pr(t){return t.type===fr.type}Ot(fr,"type","PlainArrow"),je.register("PlainArrow",fr);var hr=function(t){Tt(n,cr);var e=kt(n);function n(t,r,i){var o;return mt(this,n),(o=e.call(this,t,r,i)).instance=t,Ot(Pt(o),"type",n.type),o.length=o.length/2,o.foldback=2,o}return n}();function gr(t){return t.type===hr.type}Ot(hr,"type","Diamond"),je.register(hr.type,hr);var vr,yr=function(t){Tt(n,ke);var e=kt(n);function n(t,r,i){var o;return mt(this,n),(o=e.call(this,t,r,i)).instance=t,o.component=r,Ot(Pt(o),"create",void 0),Ot(Pt(o),"type",n.type),o.create=i.create,o}return Et(n,[{key:"updateFrom",value:function(t){}}]),n}();function br(t){return t.type===yr.type}function mr(t){return mr="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},mr(t)}function wr(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function Er(t,e){for(var n=0;nt.length)&&(e=t.length);for(var n=0,r=new Array(e);n0;)r.remove(r.item(0));for(var i=0;i0&&(t.classList?x(R(e).split(/\s+/),(function(e){t.classList.add(e)})):Br(t,e))};_r(t)?x(t,(function(t){return n(t,e)})):n(t,e)}function Gr(t,e){var n=function(t,e){null!=t&&null!=e&&e.length>0&&(t.classList?R(e).split(/\s+/).forEach((function(e){t.classList.remove(e)})):Br(t,null,e))};_r(t)?x(t,(function(t){return n(t,e)})):n(t,e)}function Hr(t,e,n,r){return Vr(null,t,e,n,r)}function Vr(t,e,n,r,i){var o,a=null==t?document.createElement(e):document.createElementNS(t,e);for(o in n=n||{})a.style[o]=n[o];for(o in r&&(a.className=r),i=i||{})a.setAttribute(o,""+i[o]);return a}function Fr(t){var e=t.getBoundingClientRect(),n=document.body,r=document.documentElement,i=window.pageYOffset||r.scrollTop||n.scrollTop,o=window.pageXOffset||r.scrollLeft||n.scrollLeft,a=r.clientTop||n.clientTop||0,s=r.clientLeft||n.clientLeft||0,l=e.top+i-a,u=e.left+o-s;return{x:Math.round(u),y:Math.round(l)}}function Jr(t,e){var n=e.getContainer().getBoundingClientRect(),r=t.getBoundingClientRect(),i=e.currentZoom;return{x:(r.left-n.left)/i,y:(r.top-n.top)/i}}function Xr(t,e){var n=t.getBoundingClientRect(),r=e.currentZoom;return{w:n.width/r,h:n.height/r}}function Wr(t){return t instanceof SVGElement?vr.SVG:vr.HTML}Ot(yr,"type","Custom"),je.register(yr.type,yr),Lt.registerHandler(Bt),Lt.registerHandler(Ht),Lt.registerHandler(Zt),qt(Jt.type,Jt),function(t){t.SVG="SVG",t.HTML="HTML"}(vr||(vr={}));var qr={"stroke-linejoin":"stroke-linejoin","stroke-dashoffset":"stroke-dashoffset","stroke-linecap":"stroke-linecap"},Ur="stroke-dasharray",Kr="dashstyle",Qr="fill",$r="stroke",ti="stroke-width",ei="strokeWidth",ni="svg",ri="path",ii={svg:"http://www.w3.org/2000/svg"};function oi(t,e){for(var n in e)t.setAttribute(n,""+e[n])}function ai(t,e){return(e=e||{}).version="1.1",e.xmlns=ii.svg,Vr(ii.svg,t,null,null,e)}function si(t){return"position:absolute;left:"+t[0]+"px;top:"+t[1]+"px"}function li(t,e,n){if(e.setAttribute(Qr,n.fill?n.fill:ee),e.setAttribute($r,n.stroke?n.stroke:ee),n.strokeWidth&&e.setAttribute(ti,n.strokeWidth),n[Kr]&&n[ei]&&!n[Ur]){var r=-1===n[Kr].indexOf(",")?" ":",",i=n[Kr].split(r),o="";x(i,(function(t){o+=Math.floor(t*n.strokeWidth)+r})),e.setAttribute(Ur,o)}else n[Ur]&&e.setAttribute(Ur,n[Ur]);for(var a in qr)n[a]&&e.setAttribute(qr[a],n[a])}function ui(t,e,n){t.childNodes.length>n?t.insertBefore(e,t.childNodes[n]):t.appendChild(e)}function ci(t,e,n){var r=[t,e];return n&&r.push(n),r.join(":")}var di="data-jtk-container",fi="data-jtk-enabled",pi="data-jtk-scope",hi="endpoint",gi="element",vi="connection",yi="click",bi="contextmenu",mi="dblclick",wi="dbltap",Ei="mousedown",Oi="mouseenter",Ti="mouseexit",xi="mousemove",Ai="mouseup",Pi="mouseout",ki="mouseover",Ii="tap",ji="drag:stop",Ni="drag:start",Si="revert",Mi="connection:drag",Ci=ci(gi,yi),Di=ci(gi,mi),Yi=ci(gi,wi),Li=ci(gi,Pi),Ri=ci(gi,ki),zi=ci(gi,xi),Bi=ci(gi,Ai),_i=ci(gi,Ei),Zi=ci(gi,bi),Gi=ci(gi,Ii),Hi=ci(hi,yi),Vi=ci(hi,mi);ci(hi,wi);var Fi=ci(hi,Pi),Ji=ci(hi,ki),Xi=ci(hi,Ai),Wi=ci(hi,Ei);ci(hi,Ii);var qi,Ui,Ki=ci(vi,yi),Qi=ci(vi,mi),$i=ci(vi,wi),to=ci(vi,Pi),eo=ci(vi,ki),no=ci(vi,Ai),ro=ci(vi,Ei),io=ci(vi,bi),oo=ci(vi,Ii),ao="position",so=Ut(ce),lo=Ut(de),uo=Kt(ie),co=Kt("data-jtk-group-content"),fo=Ut(ge);function po(t,e,n,r,i,o,a){return function(){var t=[];return t.push.apply(t,arguments),t.item=function(t){return this[t]},t}(function(t,e,n,r,i,o,a){return new Touch({target:t,identifier:Y(),pageX:e,pageY:n,screenX:r,screenY:i,clientX:o||r,clientY:a||i})}(t,e,n,r,i,o,a))}function ho(t,e,n){for(var r=(n=n||t.parentNode).querySelectorAll(e),i=0;i0}function mo(){return"onmousedown"in document.documentElement}var wo=(Tr(qi={},Ei,"touchstart"),Tr(qi,Ai,"touchend"),Tr(qi,xi,"touchmove"),qi),Eo="page",Oo="screen",To="client";function xo(t,e){if(null==t)return{x:0,y:0};var n=function(t,e){return t.item?t.item(e):t[e]}(Po(t),0);return{x:n[e+"X"],y:n[e+"Y"]}}function Ao(t){return xo(t,Eo)}function Po(t){return t.touches&&t.touches.length>0?t.touches:t.changedTouches&&t.changedTouches.length>0?t.changedTouches:t.targetTouches&&t.targetTouches.length>0?t.targetTouches:[t]}function ko(t,e,n,r,i){if(No(t,e,n),r.__tauid=n.__tauid,t.addEventListener)t.addEventListener(e,n,!1,i);else if(t.attachEvent){var o=e+n.__tauid;t["e"+o]=n,t[o]=function(){t["e"+o]&&t["e"+o](window.event)},t.attachEvent("on"+e,t[o])}}function Io(t,e,n){var r=this;null!=n&&jo(t,(function(i){if(function(t,e,n){if(t.__ta&&t.__ta[e]&&delete t.__ta[e][n.__tauid],n.__taExtra){for(var r=0;r0&&0===o.length&&o.push(bt);var s=function r(i){r.__tauid=n.__tauid;var s=go(i),l=!1,u=s,c=vo(i,s,e,null!=t);if(-1!=c.end)for(var d=0;!l&&d0&&a0&&ln.w-o?n.w-o:t.x,y:t.y<0?0:t.y>n.h-o?n.h-o:t.y}};break;case ra.parentEnclosed:r.constrainFunction=function(t,e,n,r){return{x:t.x<0?0:t.x+r.w>n.w?n.w-r.w:t.x,y:t.y<0?0:t.y+r.h>n.h?n.h-r.h:t.y}}}null==this.drag?(r.trackScroll=this._trackScroll,this.drag=this.collicat.draggable(this.instance.getContainer(),r),x(this._filtersToAdd,(function(t){return n.drag.addFilter(t[0],t[1])})),this.drag.on(Si,(function(t){n.instance.revalidate(t)}))):this.drag.addSelector(r),this.handlers.push({handler:t,options:r}),t.init(this.drag)}},{key:"addSelector",value:function(t,e){this.drag&&this.drag.addSelector(t,e)}},{key:"addFilter",value:function(t,e){null==this.drag?this._filtersToAdd.push([t,!0===e]):this.drag.addFilter(t,e)}},{key:"removeFilter",value:function(t){null!=this.drag&&this.drag.removeFilter(t)}},{key:"setFilters",value:function(t){var e=this;x(t,(function(t){e.drag.addFilter(t[0],t[1])}))}},{key:"reset",value:function(){var t=[];if(x(this.handlers,(function(t){t.handler.reset()})),this.handlers.length=0,null!=this.drag){var e=this.drag._filters;for(var n in e)t.push([n,e[n][1]]);this.collicat.destroyDraggable(this.instance.getContainer())}return delete this.drag,t}},{key:"setOption",value:function(t,e){var n=P(this.handlers,(function(e){return e.handler===t}));null!=n&&p(n.options,e||{})}}]),t}();var va=function(){function t(e,n){wr(this,t),this.instance=e,this._dragSelection=n,Tr(this,"selector","> "+xe+":not("+Ut(ge)+")"),Tr(this,"_dragOffset",null),Tr(this,"_groupLocations",[]),Tr(this,"_intersectingGroups",[]),Tr(this,"_currentDragParentGroup",null),Tr(this,"_dragGroupByElementIdMap",{}),Tr(this,"_dragGroupMap",{}),Tr(this,"_currentDragGroup",null),Tr(this,"_currentDragGroupOffsets",new Map),Tr(this,"_currentDragGroupSizes",new Map),Tr(this,"_currentDragGroupOriginalPositions",new Map),Tr(this,"_dragPayload",null),Tr(this,"drag",void 0),Tr(this,"originalPosition",void 0)}return Or(t,[{key:"onDragInit",value:function(t){return null}},{key:"onDragAbort",value:function(t){return null}},{key:"getDropGroup",value:function(){var t=null;if(this._intersectingGroups.length>0){var e=this._intersectingGroups[0].groupLoc.group,n=this._intersectingGroups[0].intersectingElement,r=n._jsPlumbParentGroup;r!==e&&(null!=r&&r.overrideDrop(n,e)||(t=this._intersectingGroups[0]))}return t}},{key:"onStop",value:function(t){var e,n=this,r=t.drag.getDragElement(),i=this.getDropGroup(),o=[];function a(t,e,n,r,a){var s=n.x,l=n.y;if(t._jsPlumbParentGroup&&t._jsPlumbParentGroup.constrain){var u={w:t.parentNode.offsetWidth+t.parentNode.scrollLeft,h:t.parentNode.offsetHeight+t.parentNode.scrollTop};s=Math.max(s,0),l=Math.max(l,0),s=Math.min(s,u.w-r.w),l=Math.min(l,u.h-r.h),n.x=s,n.y=l}o.push({el:t,id:e,pos:n,originalPos:a,originalGroup:t._jsPlumbParentGroup,redrawResult:null,reverted:!1,dropGroup:null==i?void 0:i.groupLoc.group})}if(o.push({el:r,id:this.instance.getId(r),pos:t.finalPos,originalGroup:r._jsPlumbParentGroup,redrawResult:null,originalPos:t.originalPos,reverted:!1,dropGroup:null!=i?i.groupLoc.group:null}),this._dragSelection.each((function(e,n,r,i,o){e!==t.el&&a(e,n,{x:r.x,y:r.y},i,o)})),null===(e=this._currentDragGroup)||void 0===e||e.members.forEach((function(e){if(e.el!==t.el){var r=n._currentDragGroupOffsets.get(e.elId),i=n._currentDragGroupSizes.get(e.elId),o={x:t.finalPos.x+r[0].x,y:t.finalPos.y+r[0].y};a(e.el,e.elId,o,i,n._currentDragGroupOriginalPositions.get(e.elId))}})),x(o,(function(t){var e=null!=t.originalGroup,r=e&&_o(n.instance,t.el,t.pos),o={x:0,y:0};if(e&&!r){if(null==i){var a=n._pruneOrOrphan(t,!0,!0);null!=a.pos?t.pos=a.pos.pos:!a.pruned&&t.originalGroup.revert&&(t.pos=t.originalPos,t.reverted=!0)}}else e&&r&&(o=n._computeOffsetByParentGroup(t.originalGroup));null==i||r?t.dropGroup=null:n.instance.groupManager.addToGroup(i.groupLoc.group,!1,t.el),t.reverted&&n.instance.setPosition(t.el,t.pos),t.redrawResult=n.instance.setElementPosition(t.el,t.pos.x+o.x,t.pos.y+o.y),n.instance.removeClass(t.el,"jtk-dragged"),n.instance.select({source:t.el}).removeClass(n.instance.elementDraggingClass+" "+n.instance.sourceElementDraggingClass,!0),n.instance.select({target:t.el}).removeClass(n.instance.elementDraggingClass+" "+n.instance.targetElementDraggingClass,!0)})),null!=o[0].originalGroup){var s=r._jsPlumbParentGroup;if(s!==o[0].originalGroup){var l=t.drag.getDragElement(!0);if(o[0].originalGroup.ghost){var u=this.instance.getPosition(this.instance.getGroupContentArea(s)),c=this.instance.getPosition(this.instance.getGroupContentArea(o[0].originalGroup)),d={x:c.x+t.pos.x-u.x,y:c.y+t.pos.y-u.y};l.style.left=d.x+"px",l.style.top=d.y+"px",this.instance.revalidate(l)}}}this.instance.fire(ji,{elements:o,e:t.e,el:r,payload:this._dragPayload}),this._cleanup()}},{key:"_cleanup",value:function(){var t=this;x(this._groupLocations,(function(e){t.instance.removeClass(e.el,pa),t.instance.removeClass(e.el,ha)})),this._currentDragParentGroup=null,this._groupLocations.length=0,this.instance.hoverSuspended=!1,this._dragOffset=null,this._dragSelection.reset(),this._dragPayload=null,this._currentDragGroupOffsets.clear(),this._currentDragGroupSizes.clear(),this._currentDragGroupOriginalPositions.clear(),this._currentDragGroup=null}},{key:"reset",value:function(){}},{key:"init",value:function(t){this.drag=t}},{key:"onDrag",value:function(t){var e=this,n=t.drag.getDragElement(),r=this.instance.getId(n),i=t.pos,o=this.instance.viewport.getPosition(r),a={x:i.x,y:i.y};this._intersectingGroups.length=0,null!=this._dragOffset&&(a.x+=this._dragOffset.x,a.y+=this._dragOffset.y);var s=function(n,r,i){if(i){var o=new Set;x(e._groupLocations,(function(n){!o.has(n.group.id)&&ut(r,n.r)?(n.group!==e._currentDragParentGroup&&e.instance.addClass(n.el,ha),e._intersectingGroups.push({groupLoc:n,intersectingElement:t.drag.getDragElement(!0),d:0}),x(e.instance.groupManager.getAncestors(n.group),(function(t){return o.add(t.id)}))):e.instance.removeClass(n.el,ha)}))}e.instance.setElementPosition(n,r.x,r.y),e.instance.fire("drag:move",{el:n,e:t.e,pos:{x:r.x,y:r.y},originalPosition:e.originalPosition,payload:e._dragPayload})},l={x:a.x,y:a.y,w:o.w,h:o.h};s(n,l,!0),this._dragSelection.updatePositions(i,this.originalPosition,(function(t,e,n,r){s(t,r,!1)})),this._currentDragGroupOffsets.forEach((function(t,n){var r=e._currentDragGroupSizes.get(n),i={x:l.x+t[0].x,y:l.y+t[0].y,w:r.w,h:r.h};t[1].style.left=i.x+"px",t[1].style.top=i.y+"px",s(t[1],i,!1)}))}},{key:"_computeOffsetByParentGroup",value:function(t){var e=this.instance.getPosition(t.el),n=t.contentArea;if(n!==t.el){var r=this.instance.getPosition(n);e.x+=r.x,e.y+=r.y}if(t.el._jsPlumbParentGroup){var i=this._computeOffsetByParentGroup(t.el._jsPlumbParentGroup);e.x+=i.x,e.y+=i.y}return e}},{key:"onStart",value:function(t){var e=this,n=t.drag.getDragElement(),r=this.instance.getPosition(n);this.originalPosition={x:t.pos.x,y:t.pos.y},n._jsPlumbParentGroup&&(this._dragOffset=this._computeOffsetByParentGroup(n._jsPlumbParentGroup),this._currentDragParentGroup=n._jsPlumbParentGroup);var i=!0,o=n.getAttribute(ae);if((!1===this.instance.elementsDraggable||null!=o&&o!==yt)&&(i=!1),i){this._groupLocations.length=0,this._intersectingGroups.length=0,this.instance.hoverSuspended=!0;var a=t.drag.getDragElement(!0),s=a.querySelectorAll(xe),l=function(t){for(var e=[],n=t._jsPlumbParentGroup;null!=n;)e.push(n.el),n=n.group;return e}(a),u=[];Array.prototype.push.apply(u,s),Array.prototype.push.apply(u,l),this._dragSelection.filterActiveSet((function(t){return-1===u.indexOf(t.jel)})),this._dragSelection.initialisePositions();var c=function(n,r,i){if(!n._isJsPlumbGroup||e.instance.allowNestedGroups){var o=!n._jsPlumbParentGroup,a=o||!0!==n._jsPlumbParentGroup.dropOverride,s=!o&&(n._jsPlumbParentGroup.ghost||!0!==n._jsPlumbParentGroup.constrain);(o||a&&s)&&(x(e.instance.groupManager.getGroups(),(function(t){var r=n._jsPlumbGroup;if(!1!==t.droppable&&!1!==t.enabled&&n._jsPlumbGroup!==t&&!e.instance.groupManager.isDescendant(t,r)){var i=t.el,o=e.instance.getId(i),a=e.instance.viewport.getPosition(o),s={el:i,r:{x:a.x,y:a.y,w:a.w,h:a.h},group:t};e._groupLocations.push(s),t!==e._currentDragParentGroup&&e.instance.addClass(i,pa)}})),e._groupLocations.sort((function(t,n){return e.instance.groupManager.isDescendant(t.group,n.group)?-1:e.instance.groupManager.isAncestor(n.group,t.group)?1:0})))}return e.instance.select({source:n}).addClass(e.instance.elementDraggingClass+" "+e.instance.sourceElementDraggingClass,!0),e.instance.select({target:n}).addClass(e.instance.elementDraggingClass+" "+e.instance.targetElementDraggingClass,!0),e.instance.fire(Ni,{el:n,e:t.e,originalPosition:e.originalPosition,pos:e.originalPosition,dragGroup:r,dragGroupMemberSpec:i})},d=this.instance.getId(n);this._currentDragGroup=this._dragGroupByElementIdMap[d],this._currentDragGroup&&!function(t,e){var n=k(t.members,(function(t){return t.el===e}));return null!==n&&!0===n.active}(this._currentDragGroup,n)&&(this._currentDragGroup=null);var f=c(n);if(!1===f)return this._cleanup(),!1;this._dragPayload=f,null!=this._currentDragGroup&&(this._currentDragGroupOffsets.clear(),this._currentDragGroupSizes.clear(),this._currentDragGroup.members.forEach((function(t){var n=e.instance.viewport.getPosition(t.elId);e._currentDragGroupOffsets.set(t.elId,[{x:n.x-r.x,y:n.y-r.y},t.el]),e._currentDragGroupSizes.set(t.elId,n),e._currentDragGroupOriginalPositions.set(t.elId,{x:n.x,y:n.y}),c(t.el,e._currentDragGroup,t)})))}return i}},{key:"addToDragGroup",value:function(t){var e=this,n=function(t,e){return g(e)?{id:e,active:!0}:{id:e.id,active:e.active}}(this.instance,t),r=this._dragGroupMap[n.id];null==r&&(r={id:n.id,members:new Set},this._dragGroupMap[n.id]=r);for(var i=arguments.length,o=new Array(i>1?i-1:0),a=1;a1?n-1:0),i=1;i=0)if(this.instance.select({source:e}).length>=s.maxConnections)return Yr(t),i.onMaxConnections&&i.onMaxConnections({element:e,maxConnections:s.maxConnections},t),t.stopImmediatePropagation&&t.stopImmediatePropagation(),!1;if(i.anchorPositionFinder){var u=i.anchorPositionFinder(e,a,i,t);null!=u&&(s.anchor=u)}this._originalAnchorSpec=s.anchor||(this.instance.areDefaultAnchorsSet()?this.instance.defaults.anchors[0]:this.instance.defaults.anchor);var c=this.instance.router.prepareAnchor(this._originalAnchorSpec),d=[a.x,a.y,0,0];if(c.locations.length>0)d[2]=c.locations[0].ox,d[3]=c.locations[0].oy;else if(c.isContinuous){var f=a.x<.5?a.x:1-a.x,h=a.y<.5?a.y:1-a.y;d[2]=f=a)return;var s=Jr(n,o.instance),l=Xr(n,o.instance);i.r={x:s.x,y:s.y,w:l.w,h:l.h},i.def=t.def,null!=t.def.def.rank&&(i.rank=t.def.def.rank),o.endpointDropTargets.push(i),o.instance.addClass(i.targetEl,pa)}}))}))}this.endpointDropTargets.sort((function(t,e){if(t.targetEl._isJsPlumbGroup&&!e.targetEl._isJsPlumbGroup)return 1;if(!t.targetEl._isJsPlumbGroup&&e.targetEl._isJsPlumbGroup)return-1;if(t.targetEl._isJsPlumbGroup&&e.targetEl._isJsPlumbGroup){if(o.instance.groupManager.isAncestor(t.targetEl._jsPlumbGroup,e.targetEl._jsPlumbGroup))return-1;if(o.instance.groupManager.isAncestor(e.targetEl._jsPlumbGroup,t.targetEl._jsPlumbGroup))return 1}else{if(null==t.rank||null==e.rank)return 0;if(t.rank>e.rank)return-1;if(t.rank",uo,xe].join(" ")),Tr(kr(i),"doRevalidate",void 0),i.doRevalidate=i._revalidate.bind(kr(i)),i}return Or(n,[{key:"reset",value:function(){this.drag.off(Si,this.doRevalidate)}},{key:"_revalidate",value:function(t){this.instance.revalidate(t)}},{key:"init",value:function(t){this.drag=t,t.on(Si,this.doRevalidate)}},{key:"useGhostProxy",value:function(t,e){var n=e._jsPlumbParentGroup;return null!=n&&!0===n.ghost}},{key:"makeGhostProxy",value:function(t){var e=t,n=e.cloneNode(!0);return n._jsPlumbParentGroup=e._jsPlumbParentGroup,n}}]),n}(),Ta=function(){function t(e,n){wr(this,t),this.instance=e,this.overlay=n,Tr(this,"htmlElementOverlay",void 0),this.htmlElementOverlay=n}return Or(t,null,[{key:"getElement",value:function(t,e,n){if(null==t.canvas){if(n&&e){t.canvas=n(e);var r=t.instance.overlayClass+" "+(t.cssClass?t.cssClass:"");t.instance.addClass(t.canvas,r)}else t.canvas=Hr("div",{},t.instance.overlayClass+" "+(t.cssClass?t.cssClass:""));for(var i in t.instance.setAttribute(t.canvas,"jtk-overlay-id",t.id),t.attributes)t.instance.setAttribute(t.canvas,i,t.attributes[i]);t.canvas.style.position=ne,t.instance._appendElement(t.canvas,t.instance.getContainer()),t.instance.getId(t.canvas);var o="translate(-50%, -50%)";t.canvas.style.webkitTransform=o,t.canvas.style.mozTransform=o,t.canvas.style.msTransform=o,t.canvas.style.oTransform=o,t.canvas.style.transform=o,t.isVisible()||(t.canvas.style.display=ee),t.canvas.jtk={overlay:t}}return t.canvas}},{key:"destroy",value:function(t){t.canvas&&t.canvas.parentNode&&t.canvas.parentNode.removeChild(t.canvas),delete t.canvas,delete t.cachedDimensions}},{key:"_getDimensions",value:function(t,e){return(null==t.cachedDimensions||e)&&(t.cachedDimensions={w:1,h:1}),t.cachedDimensions}}]),t}();function xa(t){if(null==t.path){var e=p({"jtk-overlay-id":t.id},t.attributes);t.path=ai(ri,e);var n=t.instance.overlayClass+" "+(t.cssClass?t.cssClass:"");t.instance.addClass(t.path,n),t.path.jtk={overlay:t}}var r=t.path.parentNode;if(null==r){if(t.component instanceof Nn){var i=t.component.connector;r=null!=i?i.canvas:null}else if(t.component instanceof Mn){var o=t.component.endpoint;r=null!=o?o.canvas:o}null!=r&&ui(r,t.path,1)}return t.path}!function(t){xr(n,ke);var e=Ir(n);function n(){var t;wr(this,n);for(var r=arguments.length,i=new Array(r),o=0;o0){var o={d:t.getPathData(e),transform:"translate("+i[0]+","+i[1]+")","pointer-events":"visibleStroke"},a=null;if(n.outlineStroke){var s=n.outlineWidth||1,l=n.strokeWidth+2*s;(a=p({},n)).stroke=n.outlineStroke,a.strokeWidth=l,null==e.bgPath?(e.bgPath=ai(ri,o),t.addClass(e.bgPath,t.connectorOutlineClass),ui(e.canvas,e.bgPath,0)):oi(e.bgPath,o),li(e.canvas,e.bgPath,a)}var u=e;null==u.path?(u.path=ai(ri,o),ui(u.canvas,u.path,n.outlineStroke?1:0)):(u.path.parentNode!==u.canvas&&ui(u.canvas,u.path,n.outlineStroke?1:0),oi(e.path,o)),li(e.canvas,e.path,n)}}var ka=function(){function t(){wr(this,t)}return Or(t,null,[{key:"getEndpointElement",value:function(t){if(null!=t.canvas)return t.canvas;var e=ai(ni,{style:"",width:"0",height:"0","pointer-events":"all",position:ne});t.canvas=e;var n=t.classes.join(" ");t.instance.addClass(e,n);for(var r=t.endpoint.scope.split(/\s/),i=0;i0&&(t.classList?t.classList.toggle(e):n.hasClass(t,e)?n.removeClass(t,e):n.addClass(t,e))};_r(t)?x(t,(function(t){return r(t,e)})):r(t,e)}(t,e)}},{key:"setAttribute",value:function(t,e,n){t.setAttribute(e,n)}},{key:"getAttribute",value:function(t,e){return t.getAttribute(e)}},{key:"setAttributes",value:function(t,e){for(var n in e)t.setAttribute(n,e[n])}},{key:"removeAttribute",value:function(t,e){t.removeAttribute&&t.removeAttribute(e)}},{key:"on",value:function(t,e,n,r){var i=this,o=function(t){null==r?i.eventManager.on(t,e,n):i.eventManager.on(t,e,n,r)};return _r(t)?x(t,(function(t){return o(t)})):o(t),this}},{key:"off",value:function(t,e,n){var r=this;return _r(t)?x(t,(function(t){return r.eventManager.off(t,e,n)})):this.eventManager.off(t,e,n),this}},{key:"trigger",value:function(t,e,n,r,i){this.eventManager.trigger(t,e,n,r,i)}},{key:"getOffsetRelativeToRoot",value:function(t){return Fr(t)}},{key:"getOffset",value:function(t){for(var e,n=t,r=this.getContainer(),i=this.getPosition(n),o=t!==r&&n.offsetParent!==r?n.offsetParent:null;null!=o;)i.x+=o.offsetLeft,i.y+=o.offsetTop,null!=(e=o)&&e!==document.body&&(e.scrollTop>0||e.scrollLeft>0)&&(i.x-=e.scrollLeft,i.y-=e.scrollTop),o=o.offsetParent===r?null:o.offsetParent;if(null!=r&&(r.scrollTop>0||r.scrollLeft>0)){var a=null!=n.offsetParent?this.getStyle(n.offsetParent,ao):"static",s=this.getStyle(n,ao);s!==ne&&s!==re&&a!==ne&&a!==re&&(i.x-=r.scrollLeft,i.y-=r.scrollTop)}return i}},{key:"getSize",value:function(t){var e=t;return null!=e.offsetWidth?function(t){return{w:t.offsetWidth,h:t.offsetHeight}}(t):e.width&&e.width.baseVal?function(t){try{return{w:parseFloat(t.width.baseVal.value),h:parseFloat(t.height.baseVal.value)}}catch(t){return{w:0,h:0}}}(e):void 0}},{key:"getPosition",value:function(t){var e=t;return null!=e.offsetLeft?{x:parseFloat(e.offsetLeft),y:parseFloat(e.offsetTop)}:e.x&&e.x.baseVal?function(t){try{return{x:parseFloat(t.x.baseVal.value),y:parseFloat(t.y.baseVal.value)}}catch(t){return{x:0,y:0}}}(e):void 0}},{key:"getStyle",value:function(t,e){return mr(window.getComputedStyle)!==ht?getComputedStyle(t,null).getPropertyValue(e):t.currentStyle[e]}},{key:"getGroupContentArea",value:function(t){var e=this.getSelector(t.el,co);return e&&e.length>0?e[0]:t.el}},{key:"getSelector",value:function(t,e){var n=null;if(1===arguments.length){if(!g(t)){var r=document.createDocumentFragment();return r.appendChild(t),j(r.childNodes)}n=j(document.querySelectorAll(t))}else n=j(t.querySelectorAll(e));return n}},{key:"setPosition",value:function(t,e){var n=t;n.style.left=e.x+"px",n.style.top=e.y+"px"}},{key:"setDraggable",value:function(t,e){e?this.removeAttribute(t,ae):this.setAttribute(t,ae,vt)}},{key:"isDraggable",value:function(t){var e=this.getAttribute(t,ae);return null==e||e===yt}},{key:"toggleDraggable",value:function(t){var e=this.isDraggable(t);return this.setDraggable(t,!e),!e}},{key:"_createEventListeners",value:function(){var t=function(t,e){if(!e.defaultPrevented&&null==e._jsPlumbOverlay){var n=Lr(Rr(e),so,this.getContainer(),!0);this.fire(t,n.jtk.connector.connection,e)}};this._connectorClick=t.bind(this,Ki),this._connectorDblClick=t.bind(this,Qi),this._connectorTap=t.bind(this,oo),this._connectorDblTap=t.bind(this,$i);var e=function(t,e){var n=Rr(e).parentNode;if(n.jtk&&n.jtk.connector){var r=n.jtk.connector,i=r.connection;this.setConnectorHover(r,t),t?(this.addClass(i.source,this.hoverSourceClass),this.addClass(i.target,this.hoverTargetClass)):(this.removeClass(i.source,this.hoverSourceClass),this.removeClass(i.target,this.hoverTargetClass)),this.fire(t?eo:to,n.jtk.connector.connection,e)}};this._connectorMouseover=e.bind(this,!0),this._connectorMouseout=e.bind(this,!1);var n=function(t,e){var n=Rr(e).parentNode;n.jtk&&n.jtk.connector&&this.fire(t?no:ro,n.jtk.connector.connection,e)};this._connectorMouseup=n.bind(this,!0),this._connectorMousedown=n.bind(this,!1),this._connectorContextmenu=function(t){var e=Rr(t).parentNode;e.jtk&&e.jtk.connector&&this.fire(io,e.jtk.connector.connection,t)}.bind(this);var r=function(t,e,n){e.defaultPrevented||null!=e._jsPlumbOverlay||this.fire(t,n.jtk.endpoint,e)};this._endpointClick=r.bind(this,Hi),this._endpointDblClick=r.bind(this,Vi);var i=function(t,e){var n=Rr(e);n.jtk&&n.jtk.endpoint&&(this.setEndpointHover(n.jtk.endpoint,t),this.fire(t?Ji:Fi,n.jtk.endpoint,e))};this._endpointMouseover=i.bind(this,!0),this._endpointMouseout=i.bind(this,!1);var o=function(t,e){var n=Rr(e);n.jtk&&n.jtk.endpoint&&this.fire(t?Xi:Wi,n.jtk.endpoint,e)};this._endpointMouseup=o.bind(this,!0),this._endpointMousedown=o.bind(this,!1);var a=function(t,e){var n=Lr(Rr(e),fo,this.getContainer(),!0).jtk.overlay;n&&this.fireOverlayMethod(n,t,e)}.bind(this);this._overlayClick=a.bind(this,yi),this._overlayDblClick=a.bind(this,mi),this._overlayTap=a.bind(this,Ii),this._overlayDblTap=a.bind(this,wi);var s=function(t,e){var n=Lr(Rr(e),fo,this.getContainer(),!0).jtk.overlay;n&&this.setOverlayHover(n,t)};this._overlayMouseover=s.bind(this,!0),this._overlayMouseout=s.bind(this,!1);this._elementClick=function(t,e,n){e.defaultPrevented||this.fire(1===e.detail?Ci:Di,n,e)}.bind(this,Ci);this._elementTap=function(t,e,n){e.defaultPrevented||this.fire(Gi,n,e)}.bind(this,Gi);this._elementDblTap=function(t,e,n){e.defaultPrevented||this.fire(Yi,n,e)}.bind(this,Yi);var l=function(t,e){this.fire(t?Ri:Li,Rr(e),e)};this._elementMouseenter=l.bind(this,!0),this._elementMouseexit=l.bind(this,!1),this._elementMousemove=function(t){this.fire(zi,Rr(t),t)}.bind(this),this._elementMouseup=function(t){this.fire(Bi,Rr(t),t)}.bind(this),this._elementMousedown=function(t){this.fire(_i,Rr(t),t)}.bind(this),this._elementContextmenu=function(t){this.fire(Zi,Rr(t),t)}.bind(this)}},{key:"_attachEventDelegates",value:function(){var t=this.getContainer();this.eventManager.on(t,yi,fo,this._overlayClick),this.eventManager.on(t,mi,fo,this._overlayDblClick),this.eventManager.on(t,Ii,fo,this._overlayTap),this.eventManager.on(t,wi,fo,this._overlayDblTap),this.eventManager.on(t,yi,so,this._connectorClick),this.eventManager.on(t,mi,so,this._connectorDblClick),this.eventManager.on(t,Ii,so,this._connectorTap),this.eventManager.on(t,wi,so,this._connectorDblTap),this.eventManager.on(t,yi,lo,this._endpointClick),this.eventManager.on(t,mi,lo,this._endpointDblClick),this.eventManager.on(t,yi,this.managedElementsSelector,this._elementClick),this.eventManager.on(t,Ii,this.managedElementsSelector,this._elementTap),this.eventManager.on(t,wi,this.managedElementsSelector,this._elementDblTap),this.eventManager.on(t,ki,so,this._connectorMouseover),this.eventManager.on(t,Pi,so,this._connectorMouseout),this.eventManager.on(t,bi,so,this._connectorContextmenu),this.eventManager.on(t,Ai,so,this._connectorMouseup),this.eventManager.on(t,Ei,so,this._connectorMousedown),this.eventManager.on(t,ki,lo,this._endpointMouseover),this.eventManager.on(t,Pi,lo,this._endpointMouseout),this.eventManager.on(t,Ai,lo,this._endpointMouseup),this.eventManager.on(t,Ei,lo,this._endpointMousedown),this.eventManager.on(t,ki,fo,this._overlayMouseover),this.eventManager.on(t,Pi,fo,this._overlayMouseout),this.eventManager.on(t,ki,xe,this._elementMouseenter),this.eventManager.on(t,Pi,xe,this._elementMouseexit),this.eventManager.on(t,xi,xe,this._elementMousemove),this.eventManager.on(t,Ai,xe,this._elementMouseup),this.eventManager.on(t,Ei,xe,this._elementMousedown),this.eventManager.on(t,bi,xe,this._elementContextmenu)}},{key:"_detachEventDelegates",value:function(){var t=this.getContainer();t&&(this.eventManager.off(t,yi,this._connectorClick),this.eventManager.off(t,mi,this._connectorDblClick),this.eventManager.off(t,Ii,this._connectorTap),this.eventManager.off(t,wi,this._connectorDblTap),this.eventManager.off(t,yi,this._endpointClick),this.eventManager.off(t,mi,this._endpointDblClick),this.eventManager.off(t,yi,this._overlayClick),this.eventManager.off(t,mi,this._overlayDblClick),this.eventManager.off(t,Ii,this._overlayTap),this.eventManager.off(t,wi,this._overlayDblTap),this.eventManager.off(t,yi,this._elementClick),this.eventManager.off(t,Ii,this._elementTap),this.eventManager.off(t,wi,this._elementDblTap),this.eventManager.off(t,ki,this._connectorMouseover),this.eventManager.off(t,Pi,this._connectorMouseout),this.eventManager.off(t,bi,this._connectorContextmenu),this.eventManager.off(t,Ai,this._connectorMouseup),this.eventManager.off(t,Ei,this._connectorMousedown),this.eventManager.off(t,ki,this._endpointMouseover),this.eventManager.off(t,Pi,this._endpointMouseout),this.eventManager.off(t,Ai,this._endpointMouseup),this.eventManager.off(t,Ei,this._endpointMousedown),this.eventManager.off(t,ki,this._overlayMouseover),this.eventManager.off(t,Pi,this._overlayMouseout),this.eventManager.off(t,Oi,this._elementMouseenter),this.eventManager.off(t,Ti,this._elementMouseexit),this.eventManager.off(t,xi,this._elementMousemove),this.eventManager.off(t,Ai,this._elementMouseup),this.eventManager.off(t,Ei,this._elementMousedown),this.eventManager.off(t,bi,this._elementContextmenu))}},{key:"setContainer",value:function(t){var e,r=this;if(t===document||t===document.body)throw new Error("Cannot set document or document.body as container element");this._detachEventDelegates(),null!=this.dragManager&&(e=this.dragManager.reset()),this.setAttribute(t,di,Y().replace("-",""));var i=this.getContainer();null!=i&&(i.removeAttribute(di),x(j(i.childNodes).filter((function(t){return null!=t&&(r.hasClass(t,ce)||r.hasClass(t,de)||r.hasClass(t,ge)||t.getAttribute&&null!=t.getAttribute(oe))})),(function(e){t.appendChild(e)})));jr(Ar(n.prototype),"setContainer",this).call(this,t),this.containerType=Wr(t),null!=this.eventManager&&this._attachEventDelegates(),null!=this.dragManager&&(this.dragManager.addHandler(new Ea(this)),this.dragManager.addHandler(new Oa(this,this.dragSelection),this.groupDragOptions),this.elementDragHandler=new va(this,this.dragSelection),this.dragManager.addHandler(this.elementDragHandler,this.elementDragOptions),null!=e&&this.dragManager.setFilters(e))}},{key:"reset",value:function(){jr(Ar(n.prototype),"reset",this).call(this),this._resizeObserver&&this._resizeObserver.disconnect(),x(this.getContainer().querySelectorAll([xe,lo,so,fo].join(",")),(function(t){return t.parentNode&&t.parentNode.removeChild(t)}))}},{key:"destroy",value:function(){this._detachEventDelegates(),null!=this.dragManager&&this.dragManager.reset(),this.clearDragSelection(),jr(Ar(n.prototype),"destroy",this).call(this)}},{key:"unmanage",value:function(t,e){null!=this._resizeObserver&&this._resizeObserver.unobserve(t),this.removeFromDragSelection(t),jr(Ar(n.prototype),"unmanage",this).call(this,t,e)}},{key:"addToDragSelection",value:function(){for(var t=this,e=arguments.length,n=new Array(e),r=0;r1?n-1:0),i=1;i1?n-1:0),i=1;i1)&&(s=parseInt(""+t.location,10),l=!0),o=e.pointOnPath(s,l)}var u=o.x-i.w/2,c=o.y-i.h/2;return{component:t,d:{minx:u,miny:c,td:i,cxy:o},xmin:u,xmax:u+i.w,ymin:c,ymax:c+i.h}}return{xmin:0,xmax:0,ymin:0,ymax:0}}if(dr(t)||gr(t)||pr(t))return t.draw(e,n,r);throw"Could not draw overlay of type ["+t.type+"]"}},{key:"updateLabel",value:function(t){if(m(t.label)){var e=t.label(this);Ya(t).innerText=null!=e?e:""}else null==t.labelText&&(t.labelText=t.label,null!=t.labelText?Ya(t).innerText=t.labelText:Ya(t).innerText="")}},{key:"setHover",value:function(t,e){t._hover=e,t instanceof Mn&&null!=t.endpoint?this.setEndpointHover(t,e,-1):t instanceof Nn&&null!=t.connector&&this.setConnectorHover(t.connector,e)}},{key:"paintConnector",value:function(t,e,n){Pa(this,t,e,n)}},{key:"setConnectorHover",value:function(t,e,n){if(!1===e||!this.currentlyDragging&&!this.isHoverSuspended()){var r=t.canvas;null!=r&&(null!=t.hoverClass&&(e?this.addClass(r,t.hoverClass):this.removeClass(r,t.hoverClass)),e?this.addClass(r,this.hoverClass):this.removeClass(r,this.hoverClass)),null!=t.connection.hoverPaintStyle&&(t.connection.paintStyleInUse=e?t.connection.hoverPaintStyle:t.connection.paintStyle,this._suspendDrawing||this._paintConnection(t.connection)),t.connection.endpoints[0]!==n&&this.setEndpointHover(t.connection.endpoints[0],e,0,!0),t.connection.endpoints[1]!==n&&this.setEndpointHover(t.connection.endpoints[1],e,1,!0)}}},{key:"destroyConnector",value:function(t){null!=t.connector&&Ca(t.connector)}},{key:"addConnectorClass",value:function(t,e){t.canvas&&this.addClass(t.canvas,e)}},{key:"removeConnectorClass",value:function(t,e){t.canvas&&this.removeClass(t.canvas,e)}},{key:"getConnectorClass",value:function(t){return t.canvas?t.canvas.className.baseVal:""}},{key:"setConnectorVisible",value:function(t,e){Ma(t,e)}},{key:"applyConnectorType",value:function(t,e){if(t.canvas&&e.cssClass){var n=Array.isArray(e.cssClass)?e.cssClass:[e.cssClass];this.addClass(t.canvas,n.join(" "))}}},{key:"addEndpointClass",value:function(t,e){var n=Da(t.endpoint);null!=n&&this.addClass(n,e)}},{key:"applyEndpointType",value:function(t,e){if(e.cssClass){var n=Da(t.endpoint);if(n){var r=Array.isArray(e.cssClass)?e.cssClass:[e.cssClass];this.addClass(n,r.join(" "))}}}},{key:"destroyEndpoint",value:function(t){var e=this.endpointAnchorClassPrefix+(t.currentAnchorClass?"-"+t.currentAnchorClass:"");this.removeClass(t.element,e),Ca(t.endpoint)}},{key:"renderEndpoint",value:function(t,e){var n=Ia[t.endpoint.type];null!=n?ka.paint(t.endpoint,n,e):B("jsPlumb: no endpoint renderer found for type ["+t.endpoint.type+"]")}},{key:"removeEndpointClass",value:function(t,e){var n=Da(t.endpoint);null!=n&&this.removeClass(n,e)}},{key:"getEndpointClass",value:function(t){var e=Da(t.endpoint);return null!=e?e.className:""}},{key:"setEndpointHover",value:function(t,e,n,r){if(null!=t&&(!1===e||!this.currentlyDragging&&!this.isHoverSuspended())){var i=Da(t.endpoint);if(null!=i&&(null!=t.hoverClass&&(e?this.addClass(i,t.hoverClass):this.removeClass(i,t.hoverClass)),0===n||1===n)){var o=0===n?this.hoverSourceClass:this.hoverTargetClass;e?this.addClass(i,o):this.removeClass(i,o)}if(null!=t.hoverPaintStyle&&(t.paintStyleInUse=e?t.hoverPaintStyle:t.paintStyle,this._suspendDrawing||this.renderEndpoint(t,t.paintStyleInUse)),!r)for(var a=0;a=$a)return n[0]=(t[0].x+t[e].x)/2,1;if(function(t,e){var n,r,i,o,a,s,l,u,c,d,f,p,h;a=t[0].y-t[e].y,s=t[e].x-t[0].x,l=t[0].x*t[e].y-t[e].x*t[0].y,p=h=0;for(var g=1;gp?p=v:vr){var a,s,l,u=o*o,c=t*t,d=0;return 2===r?(i=[i[0],i[1],i[2],n],a=u,s=o*t*2,l=c):3===r&&(a=u*o,s=u*t*3,l=o*c*3,d=t*c),{x:a*i[0].x+s*i[1].x+l*i[2].x+d*i[3].x,y:a*i[0].y+s*i[1].y+l*i[2].y+d*i[3].y}}return n}function os(t){var e=0;if(!us(t))for(var n=function(t,e){var n=[];t--;for(var r=0;r<=t;r++)n.push(is(r/t,e));return n}(16,t),r=0;r<15;r++){e+=ls(n[r],n[r+1])}return e}var as=new Map;function ss(t,e){for(var n=function(t){var e=as.get(t);if(!e){var n=function(t){return function(e){return t}},r=function(t){return function(e){for(var n=1,r=0;r0?1:-1,s=null;i=0&&p<=1&&y>=0&&y<=1&&d.push(v)}return d}function fs(t,e){return[-t[0][e]+3*t[1][e]+-3*t[2][e]+t[3][e],3*t[0][e]-6*t[1][e]+3*t[2][e],-3*t[0][e]+3*t[1][e],t[0][e]]}function ps(t,e,n,r){var i,o,a=e/t,s=n/t,l=r/t,u=(3*s-Math.pow(a,2))/9,c=(9*a*s-27*l-2*Math.pow(a,3))/54,d=Math.pow(u,3)+Math.pow(c,2),f=[0,0,0];if(d>=0)i=Z(c+Math.sqrt(d))*Math.pow(Math.abs(c+Math.sqrt(d)),1/3),o=Z(c-Math.sqrt(d))*Math.pow(Math.abs(c-Math.sqrt(d)),1/3),f[0]=-a/3+(i+o),f[1]=-a/3-(i+o)/2,f[2]=-a/3-(i+o)/2,0!==Math.abs(Math.sqrt(3)*(i-o)/2)&&(f[1]=-1,f[2]=-1);else{var p=Math.acos(c/Math.sqrt(-Math.pow(u,3)));f[0]=2*Math.sqrt(-u)*Math.cos(p/3)-a/3,f[1]=2*Math.sqrt(-u)*Math.cos((p+2*Math.PI)/3)-a/3,f[2]=2*Math.sqrt(-u)*Math.cos((p+4*Math.PI)/3)-a/3}for(var h=0;h<3;h++)(f[h]<0||f[h]>1)&&(f[h]=-1);return f}var hs=function(t){Ja(n,pt);var e=Ua(n);function n(t){var r;return Ga(this,n),Fa(qa(r=e.call(this,t)),"curve",void 0),Fa(qa(r),"cp1x",void 0),Fa(qa(r),"cp1y",void 0),Fa(qa(r),"cp2x",void 0),Fa(qa(r),"cp2y",void 0),Fa(qa(r),"length",0),Fa(qa(r),"type",n.segmentType),r.cp1x=t.cp1x,r.cp1y=t.cp1y,r.cp2x=t.cp2x,r.cp2y=t.cp2y,r.x1=t.x1,r.x2=t.x2,r.y1=t.y1,r.y2=t.y2,r.curve=[{x:r.x1,y:r.y1},{x:r.cp1x,y:r.cp1y},{x:r.cp2x,y:r.cp2y},{x:r.x2,y:r.y2}],r.extents={xmin:Math.min(r.x1,r.x2,r.cp1x,r.cp2x),ymin:Math.min(r.y1,r.y2,r.cp1y,r.cp2y),xmax:Math.max(r.x1,r.x2,r.cp1x,r.cp2x),ymax:Math.max(r.y1,r.y2,r.cp1y,r.cp2y)},r}return Va(n,[{key:"getPath",value:function(t){return(t?"M "+this.x2+" "+this.y2+" ":"")+"C "+this.cp2x+" "+this.cp2y+" "+this.cp1x+" "+this.cp1y+" "+this.x1+" "+this.y1}},{key:"pointOnPath",value:function(t,e){return t=n._translateLocation(this.curve,t,e),ss(this.curve,t)}},{key:"gradientAtPoint",value:function(t,e){return t=n._translateLocation(this.curve,t,e),function(t,e){var n=ss(t,e),r=ss(t.slice(0,t.length-1),e),i=r.y-n.y,o=r.x-n.x;return 0===i?1/0:Math.atan(i/o)}(this.curve,t)}},{key:"pointAlongPathFrom",value:function(t,e,r){return t=n._translateLocation(this.curve,t,r),function(t,e,n){return cs(t,e,n).point}(this.curve,t,e)}},{key:"getLength",value:function(){return null!=this.length&&0!==this.length||(this.length=os(this.curve)),this.length}},{key:"findClosestPointOnPath",value:function(t,e){var n,r,i,o=(n={x:t,y:e},r=this.curve,i=es(n,r),{point:rs(r,r.length-1,i.location,null,null),location:i.location});return{d:Math.sqrt(Math.pow(o.point.x-t,2)+Math.pow(o.point.y-e,2)),x:o.point.x,y:o.point.y,l:1-o.location,s:this,x1:null,y1:null,x2:null,y2:null}}},{key:"lineIntersection",value:function(t,e,n,r){return ds(t,e,n,r,this.curve)}}],[{key:"_translateLocation",value:function(t,e,n){return n&&(e=function(t,e,n){return cs(t,e,n).location}(t,e>0?0:1,e)),e}}]),n}();Fa(hs,"segmentType","Bezier");var gs=function(t){Ja(n,Ka);var e=Ua(n);function n(t,r){var i;return Ga(this,n),(i=e.call(this,t,r)).connection=t,Fa(qa(i),"type",n.type),Fa(qa(i),"majorAnchor",void 0),Fa(qa(i),"minorAnchor",void 0),r=r||{},i.majorAnchor=r.curviness||150,i.minorAnchor=10,i}return Va(n,[{key:"getCurviness",value:function(){return this.majorAnchor}},{key:"_findControlPoint",value:function(t,e,n,r,i){var o={x:0,y:0};return r[0]!==i[0]||r[1]===i[1]?(0===i[0]?o.x=n.curX=s?3:4),E=Math.sqrt(Math.pow(v-h,2)+Math.pow(y-g,2));this._controlPoint=function(t,e,n,r,i,o,a,s,l){return s<=l?{x:t,y:e}:1===n?r.curY<=0&&i.curY>=1?{x:t+(r.x<.5?-1*o:o),y:e}:r.curX>=1&&i.curX<=0?{x:t,y:e+(r.y<.5?-1*a:a)}:{x:t+-1*o,y:e+-1*a}:2===n?r.curY>=1&&i.curY<=0?{x:t+(r.x<.5?-1*o:o),y:e}:r.curX>=1&&i.curX<=0?{x:t,y:e+(r.y<.5?-1*a:a)}:{x:t+o,y:e+-1*a}:3===n?r.curY>=1&&i.curY<=0?{x:t+(r.x<.5?-1*o:o),y:e}:r.curX<=0&&i.curX>=1?{x:t,y:e+(r.y<.5?-1*a:a)}:{x:t+-1*o,y:e+-1*a}:4===n?r.curY<=0&&i.curY>=1?{x:t+(r.x<.5?-1*o:o),y:e}:r.curX<=0&&i.curX>=1?{x:t,y:e+(r.y<.5?-1*a:a)}:{x:t+o,y:e+-1*a}:void 0}(b,m,w,e.sourcePos,e.targetPos,this.curviness,this.curviness,E,this.proximityLimit)}else this._controlPoint=this.geometry.controlPoints[0];c=this._controlPoint.x,d=this._controlPoint.x,f=this._controlPoint.y,p=this._controlPoint.y,this.geometry={controlPoints:[this._controlPoint,this._controlPoint],source:e.sourcePos,target:e.targetPos},this._addSegment(hs,{x1:v,y1:y,x2:h,y2:g,cp1x:c,cp1y:f,cp2x:d,cp2y:p})}}]),n}();function ys(t,e){for(var n=0;n0&&i[4]!==e[4]){var a=Math.min(As(i),As(e)),s=Math.min(this.cornerRadius,a/2);i[2]-=n[0]*s,i[3]-=n[1]*s,e[0]+=r[0]*s,e[1]+=r[1]*s;var l=n[1]===r[0]&&1===r[0]||n[1]===r[0]&&0===r[0]&&n[0]!==r[1]||n[1]===r[0]&&-1===r[0],u=(e[1]>i[3]?1:-1)==(e[0]>i[2]?1:-1),c=u&&l||!u&&!l?e[0]:i[2],d=u&&l||!u&&!l?i[3]:e[1];this._addSegment(Ft,{x1:i[0],y1:i[1],x2:i[2],y2:i[3]}),this._addSegment(ur,{r:s,x1:i[2],y1:i[3],x2:e[0],y2:e[1],cx:c,cy:d,ac:l})}else this._addSegment(Ft,{x1:i[0],y1:i[1],x2:i[2],y2:i[3]});i=e}null!=e&&this._addSegment(Ft,{x1:e[0],y1:e[1],x2:e[2],y2:e[3]})}},{key:"_compute",value:function(t,e){var n=this;this.internalSegments.length=0,this.lastx=null,this.lasty=null,this.lastOrientation=null;var r=function(e){return[t.startStubX,t.startStubY,t.endStubX,t.endStubY]},i={perpendicular:r,orthogonal:r,opposite:function(e){var r=t,i="x"===e?0:1,o={x:function(){return 1===r.so[i]&&(r.startStubX>r.endStubX&&r.tx>r.startStubX||r.sx>r.endStubX&&r.tx>r.sx)||-1===r.so[i]&&(r.startStubXr.endStubY&&r.ty>r.startStubY||r.sy>r.endStubY&&r.ty>r.sy)||-1===r.so[i]&&(r.startStubYg[e][0],E=s[e][b][0],O=s[e][b][1],T={x:[[[1,2,3,4],null,[2,1,4,3]],null,[[4,3,2,1],null,[3,4,1,2]]],y:[[[3,2,1,4],null,[2,3,4,1]],null,[[4,1,2,3],null,[1,4,3,2]]]}[e][b][m];return a.segment===T[3]||a.segment===T[2]&&w?l[e]:a.segment===T[2]&&O=E||a.segment===T[1]&&!w?d[e]:a.segment===T[0]||a.segment===T[1]&&w?c[e]:void 0},orthogonal:function(e,n,r,i,o){var a=t,s={x:-1===a.so[0]?Math.min(n,i):Math.max(n,i),y:-1===a.so[1]?Math.min(n,i):Math.max(n,i)}[e];return{x:[[s,r],[s,o],[i,o]],y:[[r,s],[o,s],[o,i]]}[e]},opposite:function(r,i,o,s,l){var u=t,c={x:"y",y:"x"}[r],d={x:"h",y:"w"}[r],h=u["is"+r.toUpperCase()+"GreaterThanStubTimes2"];if(e.sourceEndpoint.elementId===e.targetEndpoint.elementId){var g=o+(1-e.sourceEndpoint._anchor.computedPosition[c])*e.sourceInfo[d]+n.maxStub;return{x:[[i,g],[s,g]],y:[[g,i],[g,s]]}[r]}return!h||1===u.so[a]&&i>s||-1===u.so[a]&&is?{x:[[f,u.sy],[f,u.ty]],y:[[u.sx,p],[u.tx,p]]}[r]:void 0}},v=g[t.anchorOrientation](t.sourceAxis,l,u,c,d);if(v)for(var y=0;y=(parseInt(e.getWindow(v).getComputedStyle(v).zIndex,10)||0)&&(n=i);else n=i}else n=i}var h,v;return n},O.matchesSelector=x,O.matchesUpTo=function(t,e,n){for(;o.default.element(t);){if(x(t,e))return!0;if((t=T(t))===n)return x(t,e)}return!1},O.nodeContains=function(t,e){if(t.contains)return t.contains(e);for(;e;){if(e===t)return!0;e=e.parentNode}return!1},O.parentNode=T,O.trySelector=function(t){return!!o.default.string(t)&&(g.default.document.querySelector(t),!0)};var A=function(t){return t.parentNode||t.host};function P(t,e){for(var n,r=[],i=t;(n=A(i))&&i!==e&&n!==i.ownerDocument;)r.unshift(i),i=n;return r}function k(t){return{x:(t=t||e.window).scrollX||t.document.documentElement.scrollLeft,y:t.scrollY||t.document.documentElement.scrollTop}}function I(t){var e=t instanceof g.default.SVGElement?t.getBoundingClientRect():t.getClientRects()[0];return e&&{left:e.left,right:e.right,top:e.top,bottom:e.bottom,width:e.width||e.right-e.left,height:e.height||e.bottom-e.top}}var j={};Object.defineProperty(j,"__esModule",{value:!0}),j.default=function(t,e){for(var n in e)t[n]=e[n];return t};var N={};function S(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,r=Array(e);n1?V(e):e[0];Z(r,t.page),G(r,t.client),t.timeStamp=n},z.setZeroCoords=function(t){t.page.x=0,t.page.y=0,t.client.x=0,t.client.y=0},z.touchAngle=function(t,e){var n=e+"X",r=e+"Y",i=H(t),o=i[1][n]-i[0][n],a=i[1][r]-i[0][r];return 180*Math.atan2(a,o)/Math.PI},z.touchBBox=function(t){if(!t.length)return null;var e=H(t),n=Math.min(e[0].pageX,e[1].pageX),r=Math.min(e[0].pageY,e[1].pageY),i=Math.max(e[0].pageX,e[1].pageX),o=Math.max(e[0].pageY,e[1].pageY);return{x:n,y:r,left:n,top:r,right:i,bottom:o,width:i-n,height:o-r}},z.touchDistance=function(t,e){var n=e+"X",r=e+"Y",i=H(t),o=i[0][n]-i[1][n],a=i[0][r]-i[1][r];return(0,L.default)(o,a)};var F={};function J(t,e){for(var n=0;ns.left&&d.xs.top&&d.y=s.left&&g<=s.right&&v>=s.top&&v<=s.bottom}return h&&o.default.number(u)&&(l=Math.max(0,Math.min(s.right,h.right)-Math.max(s.left,h.left))*Math.max(0,Math.min(s.bottom,h.bottom)-Math.max(s.top,h.top))/(h.width*h.height)>=u),t.options.drop.checker&&(l=t.options.drop.checker(e,n,l,t,a,r,i)),l}(this,t,e,n,r,i,a)},n.dynamicDrop=function(e){return o.default.bool(e)?(t.dynamicDrop=e,n):t.dynamicDrop},(0,j.default)(e.phaselessTypes,{dragenter:!0,dragleave:!0,dropactivate:!0,dropdeactivate:!0,dropmove:!0,drop:!0}),e.methodDict.drop="dropzone",t.dynamicDrop=!1,i.actions.drop=ht.defaults},listeners:{"interactions:before-action-start":function(t){var e=t.interaction;"drag"===e.prepared.name&&(e.dropState={cur:{dropzone:null,element:null},prev:{dropzone:null,element:null},rejected:null,events:null,activeDrops:[]})},"interactions:after-action-start":function(t,e){var n=t.interaction,r=(t.event,t.iEvent);if("drag"===n.prepared.name){var i=n.dropState;i.activeDrops=null,i.events=null,i.activeDrops=ut(e,n.element),i.events=dt(n,0,r),i.events.activate&&(lt(i.activeDrops,i.events.activate),e.fire("actions/drop:start",{interaction:n,dragEvent:r}))}},"interactions:action-move":pt,"interactions:after-action-move":function(t,e){var n=t.interaction,r=t.iEvent;"drag"===n.prepared.name&&(ft(n,n.dropState.events),e.fire("actions/drop:move",{interaction:n,dragEvent:r}),n.dropState.events={})},"interactions:action-end":function(t,e){if("drag"===t.interaction.prepared.name){var n=t.interaction,r=t.iEvent;pt(t,e),ft(n,n.dropState.events),e.fire("actions/drop:end",{interaction:n,dragEvent:r})}},"interactions:stop":function(t){var e=t.interaction;if("drag"===e.prepared.name){var n=e.dropState;n&&(n.activeDrops=null,n.events=null,n.cur.dropzone=null,n.cur.element=null,n.prev.dropzone=null,n.prev.element=null,n.rejected=!1)}}},getActiveDrops:ut,getDrop:ct,getDropEvents:dt,fireDropEvents:ft,defaults:{enabled:!1,accept:null,overlap:"pointer"}},gt=ht;st.default=gt;var vt={};function yt(t){var e=t.interaction,n=t.iEvent,r=t.phase;if("gesture"===e.prepared.name){var i=e.pointers.map((function(t){return t.pointer})),a="start"===r,s="end"===r,l=e.interactable.options.deltaSource;if(n.touches=[i[0],i[1]],a)n.distance=z.touchDistance(i,l),n.box=z.touchBBox(i),n.scale=1,n.ds=0,n.angle=z.touchAngle(i,l),n.da=0,e.gesture.startDistance=n.distance,e.gesture.startAngle=n.angle;else if(s){var u=e.prevEvent;n.distance=u.distance,n.box=u.box,n.scale=u.scale,n.ds=0,n.angle=u.angle,n.da=0}else n.distance=z.touchDistance(i,l),n.box=z.touchBBox(i),n.scale=n.distance/e.gesture.startDistance,n.angle=z.touchAngle(i,l),n.ds=n.scale-e.gesture.scale,n.da=n.angle-e.gesture.angle;e.gesture.distance=n.distance,e.gesture.angle=n.angle,o.default.number(n.scale)&&n.scale!==1/0&&!isNaN(n.scale)&&(e.gesture.scale=n.scale)}}Object.defineProperty(vt,"__esModule",{value:!0}),vt.default=void 0;var bt={id:"actions/gesture",before:["actions/drag","actions/resize"],install:function(t){var e=t.actions,n=t.Interactable,r=t.defaults;n.prototype.gesturable=function(t){return o.default.object(t)?(this.options.gesture.enabled=!1!==t.enabled,this.setPerAction("gesture",t),this.setOnEvents("gesture",t),this):o.default.bool(t)?(this.options.gesture.enabled=t,this):this.options.gesture},e.map.gesture=bt,e.methodDict.gesture="gesturable",r.actions.gesture=bt.defaults},listeners:{"interactions:action-start":yt,"interactions:action-move":yt,"interactions:action-end":yt,"interactions:new":function(t){t.interaction.gesture={angle:0,distance:0,scale:1,startAngle:0,startDistance:0}},"auto-start:check":function(t){if(!(t.interaction.pointers.length<2)){var e=t.interactable.options.gesture;if(e&&e.enabled)return t.action={name:"gesture"},!1}}},defaults:{},getCursor:function(){return""}},mt=bt;vt.default=mt;var wt={};function Et(t,e,n,r,i,a,s){if(!e)return!1;if(!0===e){var l=o.default.number(a.width)?a.width:a.right-a.left,u=o.default.number(a.height)?a.height:a.bottom-a.top;if(s=Math.min(s,Math.abs(("left"===t||"right"===t?l:u)/2)),l<0&&("left"===t?t="right":"right"===t&&(t="left")),u<0&&("top"===t?t="bottom":"bottom"===t&&(t="top")),"left"===t){var c=l>=0?a.left:a.right;return n.x=0?a.top:a.bottom;return n.y(l>=0?a.right:a.left)-s;if("bottom"===t)return n.y>(u>=0?a.bottom:a.top)-s}return!!o.default.element(r)&&(o.default.element(e)?e===r:O.matchesUpTo(r,e,i))}function Ot(t){var e=t.iEvent,n=t.interaction;if("resize"===n.prepared.name&&n.resizeAxes){var r=e;n.interactable.options.resize.square?("y"===n.resizeAxes?r.delta.x=r.delta.y:r.delta.y=r.delta.x,r.axes="xy"):(r.axes=n.resizeAxes,"x"===n.resizeAxes?r.delta.y=0:"y"===n.resizeAxes&&(r.delta.x=0))}}Object.defineProperty(wt,"__esModule",{value:!0}),wt.default=void 0;var Tt={id:"actions/resize",before:["actions/drag"],install:function(t){var e=t.actions,n=t.browser,r=t.Interactable,i=t.defaults;Tt.cursors=function(t){return t.isIe9?{x:"e-resize",y:"s-resize",xy:"se-resize",top:"n-resize",left:"w-resize",bottom:"s-resize",right:"e-resize",topleft:"se-resize",bottomright:"se-resize",topright:"ne-resize",bottomleft:"ne-resize"}:{x:"ew-resize",y:"ns-resize",xy:"nwse-resize",top:"ns-resize",left:"ew-resize",bottom:"ns-resize",right:"ew-resize",topleft:"nwse-resize",bottomright:"nwse-resize",topright:"nesw-resize",bottomleft:"nesw-resize"}}(n),Tt.defaultMargin=n.supportsTouch||n.supportsPointerEvent?20:10,r.prototype.resizable=function(e){return function(t,e,n){return o.default.object(e)?(t.options.resize.enabled=!1!==e.enabled,t.setPerAction("resize",e),t.setOnEvents("resize",e),o.default.string(e.axis)&&/^x$|^y$|^xy$/.test(e.axis)?t.options.resize.axis=e.axis:null===e.axis&&(t.options.resize.axis=n.defaults.actions.resize.axis),o.default.bool(e.preserveAspectRatio)?t.options.resize.preserveAspectRatio=e.preserveAspectRatio:o.default.bool(e.square)&&(t.options.resize.square=e.square),t):o.default.bool(e)?(t.options.resize.enabled=e,t):t.options.resize}(this,e,t)},e.map.resize=Tt,e.methodDict.resize="resizable",i.actions.resize=Tt.defaults},listeners:{"interactions:new":function(t){t.interaction.resizeAxes="xy"},"interactions:action-start":function(t){!function(t){var e=t.iEvent,n=t.interaction;if("resize"===n.prepared.name&&n.prepared.edges){var r=e,i=n.rect;n._rects={start:(0,j.default)({},i),corrected:(0,j.default)({},i),previous:(0,j.default)({},i),delta:{left:0,right:0,width:0,top:0,bottom:0,height:0}},r.edges=n.prepared.edges,r.rect=n._rects.corrected,r.deltaRect=n._rects.delta}}(t),Ot(t)},"interactions:action-move":function(t){!function(t){var e=t.iEvent,n=t.interaction;if("resize"===n.prepared.name&&n.prepared.edges){var r=e,i=n.interactable.options.resize.invert,o="reposition"===i||"negate"===i,a=n.rect,s=n._rects,l=s.start,u=s.corrected,c=s.delta,d=s.previous;if((0,j.default)(d,u),o){if((0,j.default)(u,a),"reposition"===i){if(u.top>u.bottom){var f=u.top;u.top=u.bottom,u.bottom=f}if(u.left>u.right){var p=u.left;u.left=u.right,u.right=p}}}else u.top=Math.min(a.top,l.bottom),u.bottom=Math.max(a.bottom,l.top),u.left=Math.min(a.left,l.right),u.right=Math.max(a.right,l.left);for(var h in u.width=u.right-u.left,u.height=u.bottom-u.top,u)c[h]=u[h]-d[h];r.edges=n.prepared.edges,r.rect=u,r.deltaRect=c}}(t),Ot(t)},"interactions:action-end":function(t){var e=t.iEvent,n=t.interaction;if("resize"===n.prepared.name&&n.prepared.edges){var r=e;r.edges=n.prepared.edges,r.rect=n._rects.corrected,r.deltaRect=n._rects.delta}},"auto-start:check":function(t){var e=t.interaction,n=t.interactable,r=t.element,i=t.rect,a=t.buttons;if(i){var s=(0,j.default)({},e.coords.cur.page),l=n.options.resize;if(l&&l.enabled&&(!e.pointerIsDown||!/mouse|pointer/.test(e.pointerType)||0!=(a&l.mouseButtons))){if(o.default.object(l.edges)){var u={left:!1,right:!1,top:!1,bottom:!1};for(var c in u)u[c]=Et(c,l.edges[c],s,e._latestPointer.eventTarget,r,i,l.margin||Tt.defaultMargin);u.left=u.left&&!u.right,u.top=u.top&&!u.bottom,(u.left||u.right||u.top||u.bottom)&&(t.action={name:"resize",edges:u})}else{var d="y"!==l.axis&&s.x>i.right-Tt.defaultMargin,f="x"!==l.axis&&s.y>i.bottom-Tt.defaultMargin;(d||f)&&(t.action={name:"resize",axes:(d?"x":"")+(f?"y":"")})}return!t.action&&void 0}}}},defaults:{square:!1,preserveAspectRatio:!1,axis:"xy",margin:NaN,edges:null,invert:"none"},cursors:null,getCursor:function(t){var e=t.edges,n=t.axis,r=t.name,i=Tt.cursors,o=null;if(n)o=i[r+n];else if(e){for(var a="",s=["top","bottom","left","right"],l=0;l=1){var c={x:Ct.x*u,y:Ct.y*u};if(c.x||c.y){var d=Yt(a);o.default.window(a)?a.scrollBy(c.x,c.y):a&&(a.scrollLeft+=c.x,a.scrollTop+=c.y);var f=Yt(a),p={x:f.x-d.x,y:f.y-d.y};(p.x||p.y)&&e.fire({type:"autoscroll",target:n,interactable:e,delta:p,interaction:t,container:a})}Ct.prevTime=s}Ct.isScrolling&&(kt.default.cancel(Ct.i),Ct.i=kt.default.request(Ct.scroll))},check:function(t,e){var n;return null==(n=t.options[e].autoScroll)?void 0:n.enabled},onInteractionMove:function(t){var e=t.interaction,n=t.pointer;if(e.interacting()&&Ct.check(e.interactable,e.prepared.name))if(e.simulation)Ct.x=Ct.y=0;else{var r,i,a,s,l=e.interactable,u=e.element,c=e.prepared.name,d=l.options[c].autoScroll,f=Dt(d.container,l,u);if(o.default.window(f))s=n.clientXf.innerWidth-Ct.margin,a=n.clientY>f.innerHeight-Ct.margin;else{var p=O.getElementClientRect(f);s=n.clientXp.right-Ct.margin,a=n.clientY>p.bottom-Ct.margin}Ct.x=i?1:s?-1:0,Ct.y=a?1:r?-1:0,Ct.isScrolling||(Ct.margin=d.margin,Ct.speed=d.speed,Ct.start(e))}}};function Dt(t,n,r){return(o.default.string(t)?(0,N.getStringOptionResult)(t,n,r):t)||(0,e.getWindow)(r)}function Yt(t){return o.default.window(t)&&(t=window.document.body),{x:t.scrollLeft,y:t.scrollTop}}var Lt={id:"auto-scroll",install:function(t){var e=t.defaults,n=t.actions;t.autoScroll=Ct,Ct.now=function(){return t.now()},n.phaselessTypes.autoscroll=!0,e.perAction.autoScroll=Ct.defaults},listeners:{"interactions:new":function(t){t.interaction.autoScroll=null},"interactions:destroy":function(t){t.interaction.autoScroll=null,Ct.stop(),Ct.interaction&&(Ct.interaction=null)},"interactions:stop":Ct.stop,"interactions:action-move":function(t){return Ct.onInteractionMove(t)}}},Rt=Lt;Mt.default=Rt;var zt={};Object.defineProperty(zt,"__esModule",{value:!0}),zt.copyAction=function(t,e){return t.name=e.name,t.axis=e.axis,t.edges=e.edges,t},zt.sign=void 0,zt.warnOnce=function(t,n){var r=!1;return function(){return r||(e.window.console.warn(n),r=!0),t.apply(this,arguments)}},zt.sign=function(t){return t>=0?1:-1};var Bt={};function _t(t){return o.default.bool(t)?(this.options.styleCursor=t,this):null===t?(delete this.options.styleCursor,this):this.options.styleCursor}function Zt(t){return o.default.func(t)?(this.options.actionChecker=t,this):null===t?(delete this.options.actionChecker,this):this.options.actionChecker}Object.defineProperty(Bt,"__esModule",{value:!0}),Bt.default=void 0;var Gt={id:"auto-start/interactableMethods",install:function(t){var e=t.Interactable;e.prototype.getAction=function(e,n,r,i){var o=function(t,e,n,r,i){var o=t.getRect(r),a={action:null,interactable:t,interaction:n,element:r,rect:o,buttons:e.buttons||{0:1,1:4,3:8,4:16}[e.button]};return i.fire("auto-start:check",a),a.action}(this,n,r,i,t);return this.options.actionChecker?this.options.actionChecker(e,n,o,this,i,r):o},e.prototype.ignoreFrom=(0,zt.warnOnce)((function(t){return this._backCompatOption("ignoreFrom",t)}),"Interactable.ignoreFrom() has been deprecated. Use Interactble.draggable({ignoreFrom: newValue})."),e.prototype.allowFrom=(0,zt.warnOnce)((function(t){return this._backCompatOption("allowFrom",t)}),"Interactable.allowFrom() has been deprecated. Use Interactble.draggable({allowFrom: newValue})."),e.prototype.actionChecker=Zt,e.prototype.styleCursor=_t}};Bt.default=Gt;var Ht={};function Vt(t,e,n,r,i){return e.testIgnoreAllow(e.options[t.name],n,r)&&e.options[t.name].enabled&&Wt(e,n,t,i)?t:null}function Ft(t,e,n,r,i,o,a){for(var s=0,l=r.length;s=s)return!1;if(f.interactable===t){if((u+=p===n.name?1:0)>=o)return!1;if(f.element===e&&(c++,p===n.name&&c>=a))return!1}}}return s>0}function qt(t,e){return o.default.number(t)?(e.autoStart.maxInteractions=t,this):e.autoStart.maxInteractions}function Ut(t,e,n){var r=n.autoStart.cursorElement;r&&r!==t&&(r.style.cursor=""),t.ownerDocument.documentElement.style.cursor=e,t.style.cursor=e,n.autoStart.cursorElement=e?t:null}function Kt(t,e){var n=t.interactable,r=t.element,i=t.prepared;if("mouse"===t.pointerType&&n&&n.options.styleCursor){var a="";if(i.name){var s=n.options[i.name].cursorChecker;a=o.default.func(s)?s(i,n,r,t._interacting):e.actions.map[i.name].getCursor(i)}Ut(t.element,a||"",e)}else e.autoStart.cursorElement&&Ut(e.autoStart.cursorElement,"",e)}Object.defineProperty(Ht,"__esModule",{value:!0}),Ht.default=void 0;var Qt={id:"auto-start/base",before:["actions"],install:function(t){var e=t.interactStatic,n=t.defaults;t.usePlugin(Bt.default),n.base.actionChecker=null,n.base.styleCursor=!0,(0,j.default)(n.perAction,{manualStart:!1,max:1/0,maxPerElement:1,allowFrom:null,ignoreFrom:null,mouseButtons:1}),e.maxInteractions=function(e){return qt(e,t)},t.autoStart={maxInteractions:1/0,withinInteractionLimit:Wt,cursorElement:null}},listeners:{"interactions:down":function(t,e){var n=t.interaction,r=t.pointer,i=t.event,o=t.eventTarget;n.interacting()||Xt(n,Jt(n,r,i,o,e),e)},"interactions:move":function(t,e){!function(t,e){var n=t.interaction,r=t.pointer,i=t.event,o=t.eventTarget;"mouse"!==n.pointerType||n.pointerIsDown||n.interacting()||Xt(n,Jt(n,r,i,o,e),e)}(t,e),function(t,e){var n=t.interaction;if(n.pointerIsDown&&!n.interacting()&&n.pointerWasMoved&&n.prepared.name){e.fire("autoStart:before-start",t);var r=n.interactable,i=n.prepared.name;i&&r&&(r.options[i].manualStart||!Wt(r,n.element,n.prepared,e)?n.stop():(n.start(n.prepared,r,n.element),Kt(n,e)))}}(t,e)},"interactions:stop":function(t,e){var n=t.interaction,r=n.interactable;r&&r.options.styleCursor&&Ut(n.element,"",e)}},maxInteractions:qt,withinInteractionLimit:Wt,validateAction:Vt},$t=Qt;Ht.default=$t;var te={};Object.defineProperty(te,"__esModule",{value:!0}),te.default=void 0;var ee={id:"auto-start/dragAxis",listeners:{"autoStart:before-start":function(t,e){var n=t.interaction,r=t.eventTarget,i=t.dx,a=t.dy;if("drag"===n.prepared.name){var s=Math.abs(i),l=Math.abs(a),u=n.interactable.options.drag,c=u.startAxis,d=s>l?"x":s0&&(e.autoStartHoldTimer=setTimeout((function(){e.start(e.prepared,e.interactable,e.element)}),n))},"interactions:move":function(t){var e=t.interaction,n=t.duplicate;e.autoStartHoldTimer&&e.pointerWasMoved&&!n&&(clearTimeout(e.autoStartHoldTimer),e.autoStartHoldTimer=null)},"autoStart:before-start":function(t){var e=t.interaction;re(e)>0&&(e.prepared.name=null)}},getHoldDuration:re},oe=ie;ne.default=oe;var ae={};Object.defineProperty(ae,"__esModule",{value:!0}),ae.default=void 0;var se={id:"auto-start",install:function(t){t.usePlugin(Ht.default),t.usePlugin(ne.default),t.usePlugin(te.default)}};ae.default=se;var le={};function ue(t){return/^(always|never|auto)$/.test(t)?(this.options.preventDefault=t,this):o.default.bool(t)?(this.options.preventDefault=t?"always":"never",this):this.options.preventDefault}function ce(t){var e=t.interaction,n=t.event;e.interactable&&e.interactable.checkAndPreventDefault(n)}function de(t){var n=t.Interactable;n.prototype.preventDefault=ue,n.prototype.checkAndPreventDefault=function(n){return function(t,n,r){var i=t.options.preventDefault;if("never"!==i)if("always"!==i){if(n.events.supportsPassive&&/^touch(start|move)$/.test(r.type)){var a=(0,e.getWindow)(r.target).document,s=n.getDocOptions(a);if(!s||!s.events||!1!==s.events.passive)return}/^(mouse|pointer|touch)*(down|start)/i.test(r.type)||o.default.element(r.target)&&(0,O.matchesSelector)(r.target,"input,select,textarea,[contenteditable=true],[contenteditable=true] *")||r.preventDefault()}else r.preventDefault()}(this,t,n)},t.interactions.docEvents.push({type:"dragstart",listener:function(e){for(var n=0;nt.length)&&(e=t.length);for(var n=0,r=Array(e);n150)return null;var e=180*Math.atan2(t.prevEvent.velocityY,t.prevEvent.velocityX)/Math.PI;e<0&&(e+=360);var n=112.5<=e&&e<247.5,r=202.5<=e&&e<337.5;return{up:r,down:!r&&22.5<=e&&e<157.5,left:n,right:!n&&(292.5<=e||e<67.5),angle:e,speed:t.prevEvent.speed,velocity:{x:t.prevEvent.velocityX,y:t.prevEvent.velocityY}}}},{key:"preventDefault",value:function(){}},{key:"stopImmediatePropagation",value:function(){this.immediatePropagationStopped=this.propagationStopped=!0}},{key:"stopPropagation",value:function(){this.propagationStopped=!0}}])&&Ce(e.prototype,n),Object.defineProperty(e,"prototype",{writable:!1}),a}(F.BaseEvent);Se.InteractEvent=Be,Object.defineProperties(Be.prototype,{pageX:{get:function(){return this.page.x},set:function(t){this.page.x=t}},pageY:{get:function(){return this.page.y},set:function(t){this.page.y=t}},clientX:{get:function(){return this.client.x},set:function(t){this.client.x=t}},clientY:{get:function(){return this.client.y},set:function(t){this.client.y=t}},dx:{get:function(){return this.delta.x},set:function(t){this.delta.x=t}},dy:{get:function(){return this.delta.y},set:function(t){this.delta.y=t}},velocityX:{get:function(){return this.velocity.x},set:function(t){this.velocity.x=t}},velocityY:{get:function(){return this.velocity.y},set:function(t){this.velocity.y=t}}});var _e={};function Ze(t,e){for(var n=0;nthis.pointerMoveTolerance);var a=this.getPointerIndex(t),s={pointer:t,pointerIndex:a,pointerInfo:this.pointers[a],event:e,type:"move",eventTarget:n,dx:r,dy:i,duplicate:o,interaction:this};o||z.setCoordVelocity(this.coords.velocity,this.coords.delta),this._scopeFire("interactions:move",s),o||this.simulation||(this.interacting()&&(s.type=null,this.move(s)),this.pointerWasMoved&&z.copyCoords(this.coords.prev,this.coords.cur))}},{key:"move",value:function(t){t&&t.event||z.setZeroCoords(this.coords.delta),(t=(0,j.default)({pointer:this._latestPointer.pointer,event:this._latestPointer.event,eventTarget:this._latestPointer.eventTarget,interaction:this},t||{})).phase="move",this._doPhase(t)}},{key:"pointerUp",value:function(t,e,n,r){var i=this.getPointerIndex(t);-1===i&&(i=this.updatePointer(t,e,n,!1));var o=/cancel$/i.test(e.type)?"cancel":"up";this._scopeFire("interactions:".concat(o),{pointer:t,pointerIndex:i,pointerInfo:this.pointers[i],event:e,eventTarget:n,type:o,curEventTarget:r,interaction:this}),this.simulation||this.end(e),this.removePointer(t,e)}},{key:"documentBlur",value:function(t){this.end(t),this._scopeFire("interactions:blur",{event:t,type:"blur",interaction:this})}},{key:"end",value:function(t){var e;this._ending=!0,t=t||this._latestPointer.event,this.interacting()&&(e=this._doPhase({event:t,interaction:this,phase:"end"})),this._ending=!1,!0===e&&this.stop()}},{key:"currentAction",value:function(){return this._interacting?this.prepared.name:null}},{key:"interacting",value:function(){return this._interacting}},{key:"stop",value:function(){this._scopeFire("interactions:stop",{interaction:this}),this.interactable=this.element=null,this._interacting=!1,this._stopped=!0,this.prepared.name=this.prevEvent=null}},{key:"getPointerIndex",value:function(t){var e=z.getPointerId(t);return"mouse"===this.pointerType||"pen"===this.pointerType?this.pointers.length-1:q.findIndex(this.pointers,(function(t){return t.id===e}))}},{key:"getPointerInfo",value:function(t){return this.pointers[this.getPointerIndex(t)]}},{key:"updatePointer",value:function(t,e,n,r){var i=z.getPointerId(t),o=this.getPointerIndex(t),a=this.pointers[o];return r=!1!==r&&(r||/(down|start)$/i.test(e.type)),a?a.pointer=t:(a=new _e.PointerInfo(i,t,e,null,null),o=this.pointers.length,this.pointers.push(a)),z.setCoords(this.coords.cur,this.pointers.map((function(t){return t.pointer})),this._now()),z.setCoordDeltas(this.coords.delta,this.coords.prev,this.coords.cur),r&&(this.pointerIsDown=!0,a.downTime=this.coords.cur.timeStamp,a.downTarget=n,z.pointerExtend(this.downPointer,t),this.interacting()||(z.copyCoords(this.coords.start,this.coords.cur),z.copyCoords(this.coords.prev,this.coords.cur),this.downEvent=e,this.pointerWasMoved=!1)),this._updateLatestPointer(t,e,n),this._scopeFire("interactions:update-pointer",{pointer:t,event:e,eventTarget:n,down:r,pointerInfo:a,pointerIndex:o,interaction:this}),o}},{key:"removePointer",value:function(t,e){var n=this.getPointerIndex(t);if(-1!==n){var r=this.pointers[n];this._scopeFire("interactions:remove-pointer",{pointer:t,event:e,eventTarget:null,pointerIndex:n,pointerInfo:r,interaction:this}),this.pointers.splice(n,1),this.pointerIsDown=!1}}},{key:"_updateLatestPointer",value:function(t,e,n){this._latestPointer.pointer=t,this._latestPointer.event=e,this._latestPointer.eventTarget=n}},{key:"destroy",value:function(){this._latestPointer.pointer=null,this._latestPointer.event=null,this._latestPointer.eventTarget=null}},{key:"_createPreparedEvent",value:function(t,e,n,r){return new Se.InteractEvent(this,t,this.prepared.name,e,this.element,n,r)}},{key:"_fireEvent",value:function(t){var e;null==(e=this.interactable)||e.fire(t),(!this.prevEvent||t.timeStamp>=this.prevEvent.timeStamp)&&(this.prevEvent=t)}},{key:"_doPhase",value:function(t){var e=t.event,n=t.phase,r=t.preEnd,i=t.type,o=this.rect;if(o&&"move"===n&&(N.addEdges(this.edges,o,this.coords.delta[this.interactable.options.deltaSource]),o.width=o.right-o.left,o.height=o.bottom-o.top),!1===this._scopeFire("interactions:before-action-".concat(n),t))return!1;var a=t.iEvent=this._createPreparedEvent(e,n,r,i);return this._scopeFire("interactions:action-".concat(n),t),"start"===n&&(this.prevEvent=a),this._fireEvent(a),this._scopeFire("interactions:after-action-".concat(n),t),!0}},{key:"_now",value:function(){return Date.now()}}],n&&We(e.prototype,n),Object.defineProperty(e,"prototype",{writable:!1}),t}();Xe.Interaction=Ke;var Qe=Ke;Xe.default=Qe;var $e={};function tn(t){t.pointerIsDown&&(on(t.coords.cur,t.offset.total),t.offset.pending.x=0,t.offset.pending.y=0)}function en(t){nn(t.interaction)}function nn(t){if(!function(t){return!(!t.offset.pending.x&&!t.offset.pending.y)}(t))return!1;var e=t.offset.pending;return on(t.coords.cur,e),on(t.coords.delta,e),N.addEdges(t.edges,t.rect,e),e.x=0,e.y=0,!0}function rn(t){var e=t.x,n=t.y;this.offset.pending.x+=e,this.offset.pending.y+=n,this.offset.total.x+=e,this.offset.total.y+=n}function on(t,e){var n=t.page,r=t.client,i=e.x,o=e.y;n.x+=i,n.y+=o,r.x+=i,r.y+=o}Object.defineProperty($e,"__esModule",{value:!0}),$e.addTotal=tn,$e.applyPending=nn,$e.default=void 0,Xe._ProxyMethods.offsetBy="";var an={id:"offset",before:["modifiers","pointer-events","actions","inertia"],install:function(t){t.Interaction.prototype.offsetBy=rn},listeners:{"interactions:new":function(t){t.interaction.offset={total:{x:0,y:0},pending:{x:0,y:0}}},"interactions:update-pointer":function(t){return tn(t.interaction)},"interactions:before-action-start":en,"interactions:before-action-move":en,"interactions:before-action-end":function(t){var e=t.interaction;if(nn(e))return e.move({offset:!0}),e.end(),!1},"interactions:stop":function(t){var e=t.interaction;e.offset.total.x=0,e.offset.total.y=0,e.offset.pending.x=0,e.offset.pending.y=0}}},sn=an;$e.default=sn;var ln={};function un(t,e){for(var n=0;nn.minSpeed&&i>n.endSpeed)this.startInertia();else{if(o.result=o.setAll(this.modifierArg),!o.result.changed)return!1;this.startSmoothEnd()}return e.modification.result.rect=null,e.offsetBy(this.targetOffset),e._doPhase({interaction:e,event:t,phase:"inertiastart"}),e.offsetBy({x:-this.targetOffset.x,y:-this.targetOffset.y}),e.modification.result.rect=null,this.active=!0,e.simulation=this,!0}},{key:"startInertia",value:function(){var t=this,e=this.interaction.coords.velocity.client,n=fn(this.interaction),r=n.resistance,i=-Math.log(n.endSpeed/this.v0)/r;this.targetOffset={x:(e.x-i)/r,y:(e.y-i)/r},this.te=i,this.lambda_v0=r/this.v0,this.one_ve_v0=1-n.endSpeed/this.v0;var o=this.modification,a=this.modifierArg;a.pageCoords={x:this.startCoords.x+this.targetOffset.x,y:this.startCoords.y+this.targetOffset.y},o.result=o.setAll(a),o.result.changed&&(this.isModified=!0,this.modifiedOffset={x:this.targetOffset.x+o.result.delta.x,y:this.targetOffset.y+o.result.delta.y}),this.onNextFrame((function(){return t.inertiaTick()}))}},{key:"startSmoothEnd",value:function(){var t=this;this.smoothEnd=!0,this.isModified=!0,this.targetOffset={x:this.modification.result.delta.x,y:this.modification.result.delta.y},this.onNextFrame((function(){return t.smoothEndTick()}))}},{key:"onNextFrame",value:function(t){var e=this;this.timeout=kt.default.request((function(){e.active&&t()}))}},{key:"inertiaTick",value:function(){var t,e,n,r,i,o=this,a=this.interaction,s=fn(a).resistance,l=(a._now()-this.t0)/1e3;if(l=0;n--){var r=e[n],i=r.selector,a=r.context,s=r.listeners;i===this.target&&a===this._context&&e.splice(n,1);for(var l=s.length-1;l>=0;l--)this._scopeEvents.removeDelegate(this.target,this._context,t,s[l][0],s[l][1])}else this._scopeEvents.remove(this.target,"all")}}])&&An(n.prototype,r),Object.defineProperty(n,"prototype",{writable:!1}),t}();xn.Interactable=kn;var In={};function jn(t,e){for(var n=0;nt.length)&&(e=t.length);for(var n=0,r=Array(e);n=0;a--){var p=d[a];if(p.selector===t&&p.context===e){for(var h=p.listeners,g=h.length-1;g>=0;g--){var v=Yn(h[g],2),y=v[0],b=v[1],m=b.capture,w=b.passive;if(y===i&&m===s.capture&&w===s.passive){h.splice(g,1),h.length||(d.splice(a,1),l(e,n,u),l(e,n,c,!0)),f=!0;break}}if(f)break}}},delegateListener:u,delegateUseCapture:c,delegatedEvents:r,documents:i,targets:n,supportsOptions:!1,supportsPassive:!1};function s(t,e,r,i){var o=zn(i),s=q.find(n,(function(e){return e.eventTarget===t}));s||(s={eventTarget:t,events:{}},n.push(s)),s.events[e]||(s.events[e]=[]),t.addEventListener&&!q.contains(s.events[e],r)&&(t.addEventListener(e,r,a.supportsOptions?o:o.capture),s.events[e].push(r))}function l(t,e,r,i){var o=zn(i),s=q.findIndex(n,(function(e){return e.eventTarget===t})),u=n[s];if(u&&u.events)if("all"!==e){var c=!1,d=u.events[e];if(d){if("all"===r){for(var f=d.length-1;f>=0;f--)l(t,e,d[f],o);return}for(var p=0;p=2)continue;if(!i.interacting()&&e===i.pointerType)return i}return null}};function Gn(t,e){return t.pointers.some((function(t){return t.id===e}))}var Hn=Zn;_n.default=Hn;var Vn={};function Fn(t){return Fn="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},Fn(t)}function Jn(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var n=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=n){var r,i,o=[],a=!0,s=!1;try{for(n=n.call(t);!(a=(r=n.next()).done)&&(o.push(r.value),!e||o.length!==e);a=!0);}catch(t){s=!0,i=t}finally{try{a||null==n.return||n.return()}finally{if(s)throw i}}return o}}(t,e)||function(t,e){if(t){if("string"==typeof t)return Xn(t,e);var n=Object.prototype.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?Xn(t,e):void 0}}(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Xn(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,r=Array(e);n=0;r--){var i=e.interactions.list[r];i.interactable===n&&(i.stop(),e.fire("interactions:destroy",{interaction:i}),i.destroy(),e.interactions.list.length>2&&e.interactions.list.splice(r,1))}}},onDocSignal:nr,doOnInteractions:tr,methodNames:$n},ir=rr;Vn.default=ir;var or={};function ar(t){return ar="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},ar(t)}function sr(){return sr="undefined"!=typeof Reflect&&Reflect.get?Reflect.get.bind():function(t,e,n){var r=lr(t,e);if(r){var i=Object.getOwnPropertyDescriptor(r,e);return i.get?i.get.call(arguments.length<3?t:n):i.value}},sr.apply(this,arguments)}function lr(t,e){for(;!Object.prototype.hasOwnProperty.call(t,e)&&null!==(t=dr(t)););return t}function ur(t,e){return ur=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(t,e){return t.__proto__=e,t},ur(t,e)}function cr(t,e){if(e&&("object"===ar(e)||"function"==typeof e))return e;if(void 0!==e)throw new TypeError("Derived constructors may only return object or undefined");return function(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}(t)}function dr(t){return dr=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(t){return t.__proto__||Object.getPrototypeOf(t)},dr(t)}function fr(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function pr(t,e){for(var n=0;nt.length)&&(e=t.length);for(var n=0,r=Array(e);nMath.abs(l.y),s.coords,s.rect),(0,j.default)(r,s.coords)),s.eventProps},defaults:{ratio:"preserve",equalDelta:!1,modifiers:[],enabled:!1}};function Rr(t,e,n){var r=t.startCoords,i=t.edgeSign;e?n.y=r.y+(n.x-r.x)*i.y:n.x=r.x+(n.y-r.y)*i.x}function zr(t,e,n,r){var i=t.startRect,o=t.startCoords,a=t.ratio,s=t.edgeSign;if(e){var l=r.width/a;n.y=o.y+(l-i.height)*s.y}else{var u=r.height*a;n.x=o.x+(u-i.width)*s.x}}Mr.aspectRatio=Lr;var Br=(0,Pe.makeModifier)(Lr,"aspectRatio");Mr.default=Br;var _r={};Object.defineProperty(_r,"__esModule",{value:!0}),_r.default=void 0;var Zr=function(){};Zr._defaults={};var Gr=Zr;_r.default=Gr;var Hr={};Object.defineProperty(Hr,"__esModule",{value:!0}),Object.defineProperty(Hr,"default",{enumerable:!0,get:function(){return _r.default}});var Vr={};function Fr(t,e,n){return o.default.func(t)?N.resolveRectLike(t,e.interactable,e.element,[n.x,n.y,e]):N.resolveRectLike(t,e.interactable,e.element)}Object.defineProperty(Vr,"__esModule",{value:!0}),Vr.default=void 0,Vr.getRestrictionRect=Fr,Vr.restrict=void 0;var Jr={start:function(t){var e=t.rect,n=t.startOffset,r=t.state,i=t.interaction,o=t.pageCoords,a=r.options,s=a.elementRect,l=(0,j.default)({left:0,top:0,right:0,bottom:0},a.offset||{});if(e&&s){var u=Fr(a.restriction,i,o);if(u){var c=u.right-u.left-e.width,d=u.bottom-u.top-e.height;c<0&&(l.left+=c,l.right+=c),d<0&&(l.top+=d,l.bottom+=d)}l.left+=n.left-e.width*s.left,l.top+=n.top-e.height*s.top,l.right+=n.right-e.width*(1-s.right),l.bottom+=n.bottom-e.height*(1-s.bottom)}r.offset=l},set:function(t){var e=t.coords,n=t.interaction,r=t.state,i=r.options,o=r.offset,a=Fr(i.restriction,n,e);if(a){var s=N.xywhToTlbr(a);e.x=Math.max(Math.min(s.right-o.right,e.x),s.left+o.left),e.y=Math.max(Math.min(s.bottom-o.bottom,e.y),s.top+o.top)}},defaults:{restriction:null,elementRect:null,offset:null,endOnly:!1,enabled:!1}};Vr.restrict=Jr;var Xr=(0,Pe.makeModifier)(Jr,"restrict");Vr.default=Xr;var Wr={};Object.defineProperty(Wr,"__esModule",{value:!0}),Wr.restrictEdges=Wr.default=void 0;var qr={top:1/0,left:1/0,bottom:-1/0,right:-1/0},Ur={top:-1/0,left:-1/0,bottom:1/0,right:1/0};function Kr(t,e){for(var n=["top","left","bottom","right"],r=0;rt.length)&&(e=t.length);for(var n=0,r=Array(e);n0){if(++e>=cu)return arguments[0]}else e=0;return t.apply(void 0,arguments)}}var hu=pu(_l),gu=/\{\n\/\* \[wrapped with (.+)\] \*/,vu=/,? & /;var yu=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/;function bu(t){return function(){return t}}var mu=function(){try{var t=Rl(Object,"defineProperty");return t({},"",{}),t}catch(t){}}(),wu=mu?function(t,e){return mu(t,"toString",{configurable:!0,enumerable:!1,value:bu(e),writable:!0})}:ml,Eu=pu(wu);function Ou(t,e){for(var n=-1,r=null==t?0:t.length;++n-1}var ku=[["ary",128],["bind",1],["bindKey",2],["curry",8],["curryRight",16],["flip",512],["partial",32],["partialRight",64],["rearg",256]];function Iu(t,e,n){var r=e+"";return Eu(t,function(t,e){var n=e.length;if(!n)return t;var r=n-1;return e[r]=(n>1?"& ":"")+e[r],e=e.join(n>2?", ":" "),t.replace(yu,"{\n/* [wrapped with "+e+"] */\n")}(r,function(t,e){return Ou(ku,(function(n){var r="_."+n[0];e&n[1]&&!Pu(t,r)&&t.push(r)})),t.sort()}(function(t){var e=t.match(gu);return e?e[1].split(vu):[]}(r),n)))}var ju=1,Nu=2,Su=4,Mu=8,Cu=32,Du=64;function Yu(t,e,n,r,i,o,a,s,l,u){var c=eΜe|=c?Cu:Du,(e&=~(c?Du:Cu))&Su||(e&=~(ju|Nu));var d=[t,e,i,c?o:void 0,c?a:void 0,c?void 0:o,c?void 0:a,s,l,u],f=n.apply(void 0,d);return uu(t)&&hu(f,d),f.placeholder=r,Iu(f,t,e)}function Lu(t){return t.placeholder}var Ru=9007199254740991,zu=/^(?:0|[1-9]\d*)$/;function Bu(t,e){var n=typeof t;return!!(e=null==e?Ru:e)&&("number"==n||"symbol"!=n&&zu.test(t))&&t>-1&&t%1==0&&t1&&b.reverse(),c&&l-1&&t%1==0&&t<=xc}function Pc(t){return null!=t&&Ac(t.length)&&!xl(t)}function kc(t,e,n){if(!sl(n))return!1;var r=typeof e;return!!("number"==r?Pc(n)&&Bu(e,n.length):"string"==r&&e in n)&&yc(n[e],t)}function Ic(t){return Tc((function(e,n){var r=-1,i=n.length,o=i>1?n[i-1]:void 0,a=i>2?n[2]:void 0;for(o=t.length>3&&"function"==typeof o?(i--,o):void 0,a&&kc(n[0],n[1],a)&&(o=i<3?void 0:o,i=1),e=Object(e);++r-1},Td.prototype.set=function(t,e){var n=this.__data__,r=Ed(n,t);return r<0?(++this.size,n.push([t,e])):n[r][1]=e,this};var xd=Rl(Cs,"Map");function Ad(t,e){var n,r,i=t.__data__;return("string"==(r=typeof(n=e))||"number"==r||"symbol"==r||"boolean"==r?"__proto__"!==n:null===n)?i["string"==typeof e?"string":"hash"]:i.map}function Pd(t){var e=-1,n=null==t?0:t.length;for(this.clear();++e0&&n(s)?e>1?Hd(s,e-1,n,r,i):_d(i,s):r||(i[i.length]=s)}return i}function Vd(t){return(null==t?0:t.length)?Hd(t,1):[]}function Fd(t){return Eu(Oc(t,void 0,Vd),t+"")}var Jd=Fd(Bd),Xd=$c(Object.getPrototypeOf,Object),Wd="[object Object]",qd=Function.prototype,Ud=Object.prototype,Kd=qd.toString,Qd=Ud.hasOwnProperty,$d=Kd.call(Object);function tf(t){if(!Vs(t)||Hs(t)!=Wd)return!1;var e=Xd(t);if(null===e)return!0;var n=Qd.call(e,"constructor")&&e.constructor;return"function"==typeof n&&n instanceof n&&Kd.call(n)==$d}var ef="[object DOMException]",nf="[object Error]";function rf(t){if(!Vs(t))return!1;var e=Hs(t);return e==nf||e==ef||"string"==typeof t.message&&"string"==typeof t.name&&!tf(t)}var of=Tc((function(t,e){try{return Fl(t,void 0,e)}catch(t){return rf(t)?t:new Error(t)}})),af="Expected a function";function sf(t,e){var n;if("function"!=typeof e)throw new TypeError(af);return t=yl(t),function(){return--t>0&&(n=e.apply(this,arguments)),t<=1&&(e=void 0),n}}var lf=Tc((function(t,e,n){var r=1;if(n.length){var i=Gu(n,Lu(lf));r|=32}return pc(t,r,e,n,i)}));lf.placeholder={};var uf=Fd((function(t,e){return Ou(e,(function(e){e=Ld(e),vc(t,e,lf(t[e],t))})),t})),cf=Tc((function(t,e,n){var r=3;if(n.length){var i=Gu(n,Lu(cf));r|=32}return pc(e,r,t,n,i)}));function df(t,e,n){var r=-1,i=t.length;e<0&&(e=-e>i?0:i+e),(n=n>i?i:n)<0&&(n+=i),i=e>n?0:n-e>>>0,e>>>=0;for(var o=Array(i);++r=r?t:df(t,e,n)}cf.placeholder={};var pf=RegExp("[\\u200d\\ud800-\\udfff\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff\\ufe0e\\ufe0f]");function hf(t){return pf.test(t)}var gf="\\ud800-\\udfff",vf="["+gf+"]",yf="[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]",bf="\\ud83c[\\udffb-\\udfff]",mf="[^"+gf+"]",wf="(?:\\ud83c[\\udde6-\\uddff]){2}",Ef="[\\ud800-\\udbff][\\udc00-\\udfff]",Of="(?:"+yf+"|"+bf+")"+"?",Tf="[\\ufe0e\\ufe0f]?",xf=Tf+Of+("(?:\\u200d(?:"+[mf,wf,Ef].join("|")+")"+Tf+Of+")*"),Af="(?:"+[mf+yf+"?",yf,wf,Ef,vf].join("|")+")",Pf=RegExp(bf+"(?="+bf+")|"+Af+xf,"g");function kf(t){return hf(t)?function(t){return t.match(Pf)||[]}(t):function(t){return t.split("")}(t)}function If(t){return function(e){var n=hf(e=Cd(e))?kf(e):void 0,r=n?n[0]:e.charAt(0),i=n?ff(n,1).join(""):e.slice(1);return r[t]()+i}}var jf=If("toUpperCase");function Nf(t){return jf(Cd(t).toLowerCase())}function Sf(t,e,n,r){var i=-1,o=null==t?0:t.length;for(r&&o&&(n=t[++i]);++i=e?t:e)),t}var mp=200;function wp(t){var e=this.__data__=new Td(t);this.size=e.size}function Ep(t,e){return t&&wc(e,rd(e),t)}wp.prototype.clear=function(){this.__data__=new Td,this.size=0},wp.prototype.delete=function(t){var e=this.__data__,n=e.delete(t);return this.size=e.size,n},wp.prototype.get=function(t){return this.__data__.get(t)},wp.prototype.has=function(t){return this.__data__.has(t)},wp.prototype.set=function(t,e){var n=this.__data__;if(n instanceof Td){var r=n.__data__;if(!xd||r.lengths))return!1;var u=o.get(t),c=o.get(e);if(u&&c)return u==e&&c==t;var d=-1,f=!0,p=n&Kh?new Xh:void 0;for(o.set(t,e),o.set(e,t);++d=e||n<0||d&&t-u>=o}function g(){var t=iv();if(h(t))return v(t);s=setTimeout(g,function(t){var n=e-(t-l);return d?sv(n,o-(t-u)):n}(t))}function v(t){return s=void 0,f&&r?p(t):(r=i=void 0,a)}function y(){var t=iv(),n=h(t);if(r=arguments,i=this,l=t,n){if(void 0===s)return function(t){return u=t,s=setTimeout(g,e),c?p(t):a}(l);if(d)return clearTimeout(s),s=setTimeout(g,e),p(l)}return void 0===s&&(s=setTimeout(g,e)),a}return e=pl(e)||0,sl(n)&&(c=!!n.leading,o=(d="maxWait"in n)?av(pl(n.maxWait)||0,e):o,f="trailing"in n?!!n.trailing:f),y.cancel=function(){void 0!==s&&clearTimeout(s),u=0,r=l=i=s=void 0},y.flush=function(){return void 0===s?a:v(iv())},y}var uv=Object.prototype,cv=uv.hasOwnProperty,dv=Tc((function(t,e){t=Object(t);var n=-1,r=e.length,i=r>2?e[2]:void 0;for(i&&kc(e[0],e[1],i)&&(r=1);++n=Av&&(o=qh,a=!1,e=new Xh(e));t:for(;++i":">",'"':""","'":"'"}),Jv=/[&<>"']/g,Xv=RegExp(Jv.source);function Wv(t){return(t=Cd(t))&&Xv.test(t)?t.replace(Jv,Fv):t}var qv=/[\\^$.*+?()[\]{}|]/g,Uv=RegExp(qv.source);function Kv(t,e){for(var n=-1,r=null==t?0:t.length;++n-1?i[o?e[a]:a]:void 0}}var ry=Math.max;function iy(t,e,n){var r=null==t?0:t.length;if(!r)return-1;var i=null==n?0:yl(n);return i<0&&(i=ry(r+i,0)),Tu(t,_g(e),i)}var oy=ny(iy);function ay(t,e,n){var r;return n(t,(function(t,n,i){if(e(t,n,i))return r=n,!1})),r}var sy=Math.max,ly=Math.min;function uy(t,e,n){var r=null==t?0:t.length;if(!r)return-1;var i=r-1;return void 0!==n&&(i=yl(n),i=n<0?sy(r+i,0):ly(i,r-1)),Tu(t,_g(e),i,!0)}var cy=ny(uy);function dy(t){return t&&t.length?t[0]:void 0}function fy(t,e){var n=-1,r=Pc(t)?Array(t.length):[];return qg(t,(function(t,i,o){r[++n]=e(t,i,o)})),r}function py(t,e){return(Us(t)?qs:fy)(t,_g(e))}var hy=1/0;var gy=1/0;var vy=512;var yy=pp("floor"),by="Expected a function",my=8,wy=32,Ey=128,Oy=256;function Ty(t){return Fd((function(e){var n=e.length,r=n,i=iu.prototype.thru;for(t&&e.reverse();r--;){var o=e[r];if("function"!=typeof o)throw new TypeError(by);if(i&&!a&&"wrapper"==ru(o))var a=new iu([],!0)}for(r=a?r:n;++re}function Ny(t){return function(e,n){return"string"==typeof e&&"string"==typeof n||(e=pl(e),n=pl(n)),t(e,n)}}var Sy=Ny(jy),My=Ny((function(t,e){return t>=e})),Cy=Object.prototype.hasOwnProperty;function Dy(t,e){return null!=t&&Cy.call(t,e)}var Yy=Math.max,Ly=Math.min;var Ry="[object String]";function zy(t){return"string"==typeof t||!Us(t)&&Vs(t)&&Hs(t)==Ry}function By(t,e){return qs(e,(function(e){return t[e]}))}function _y(t){return null==t?[]:By(t,rd(t))}var Zy=Math.max;var Gy=Math.max;var Hy=Math.min;function Vy(t,e,n){for(var r=n?xv:Pu,i=t[0].length,o=t.length,a=o,s=Array(o),l=1/0,u=[];a--;){var c=t[a];a&&e&&(c=qs(c,Vc(e))),l=Hy(c.length,l),s[a]=!n&&(e||i>=120&&c.length>=120)?new Xh(a&&c):void 0}c=t[0];var d=-1,f=s[0];t:for(;++d1),e})),wc(t,Yp(t),n),r&&(n=Bh(n,7,im));for(var i=e.length;i--;)rm(n,e[i]);return n}));function am(t,e,n,r){if(!sl(t))return t;for(var i=-1,o=(e=Dd(e,t)).length,a=o-1,s=t;null!=s&&++ie||o&&a&&l&&!s&&!u||r&&a&&l||!n&&l||!i)return 1;if(!r&&!o&&!u&&t=s?l:l*("desc"==n[r]?-1:1)}return t.index-e.index}(t,e,n)}))}function dm(t){return Fd((function(e){return e=qs(e,Vc(_g)),Tc((function(n){var r=this;return t(e,(function(t){return Fl(t,r,n)}))}))}))}var fm=dm(qs),pm=Tc,hm=Math.min,gm=pm((function(t,e){var n=(e=1==e.length&&Us(e[0])?qs(e[0],Vc(_g)):qs(Hd(e,1),Vc(_g))).length;return Tc((function(r){for(var i=-1,o=hm(r.length,n);++ibm)return n;do{e%2&&(n+=t),(e=mm(e/2))&&(t+=t)}while(e);return n}var Em=zg("length"),Om="\\ud800-\\udfff",Tm="["+Om+"]",xm="[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]",Am="\\ud83c[\\udffb-\\udfff]",Pm="[^"+Om+"]",km="(?:\\ud83c[\\udde6-\\uddff]){2}",Im="[\\ud800-\\udbff][\\udc00-\\udfff]",jm="(?:"+xm+"|"+Am+")"+"?",Nm="[\\ufe0e\\ufe0f]?",Sm=Nm+jm+("(?:\\u200d(?:"+[Pm,km,Im].join("|")+")"+Nm+jm+")*"),Mm="(?:"+[Pm+xm+"?",xm,km,Im,Tm].join("|")+")",Cm=RegExp(Am+"(?="+Am+")|"+Mm+Sm,"g");function Dm(t){return hf(t)?function(t){for(var e=Cm.lastIndex=0;Cm.test(t);)++e;return e}(t):Em(t)}var Ym=Math.ceil;function Lm(t,e){var n=(e=void 0===e?" ":tl(e)).length;if(n<2)return n?wm(e,t):e;var r=wm(e,Ym(t/Dm(e)));return hf(e)?ff(kf(r),0,t).join(""):r.slice(0,t)}var Rm=Math.ceil,zm=Math.floor;var Bm=/^\s+/,_m=Cs.parseInt;var Zm=Tc((function(t,e){return pc(t,32,void 0,e,Gu(e,Lu(Zm)))}));Zm.placeholder={};var Gm=Tc((function(t,e){return pc(t,64,void 0,e,Gu(e,Lu(Gm)))}));Gm.placeholder={};var Hm=Kg((function(t,e,n){t[n?0:1].push(e)}),(function(){return[[],[]]}));var Vm=Fd((function(t,e){return null==t?{}:function(t,e){return sm(t,e,(function(e,n){return Dg(t,n)}))}(t,e)}));function Fm(t,e,n,r){for(var i=n-1,o=t.length;++i-1;)s!==t&&Jm.call(s,l,1),Jm.call(t,l,1);return t}function Wm(t,e){return t&&t.length&&e&&e.length?Xm(t,e):t}var qm=Tc(Wm);var Um=Array.prototype.splice;function Km(t,e){for(var n=t?e.length:0,r=n-1;n--;){var i=e[n];if(n==r||i!==o){var o=i;Bu(i)?Um.call(t,i,1):rm(t,i)}}return t}var Qm=Fd((function(t,e){var n=null==t?0:t.length,r=Bd(t,e);return Km(t,qs(e,(function(t){return Bu(t,n)?+t:t})).sort(um)),r})),$m=Math.floor,tw=Math.random;function ew(t,e){return t+$m(tw()*(e-t+1))}var nw=parseFloat,rw=Math.min,iw=Math.random;var ow=Math.ceil,aw=Math.max;function sw(t){return function(e,n,r){return r&&"number"!=typeof r&&kc(e,n,r)&&(n=r=void 0),e=vl(e),void 0===n?(n=e,e=0):n=vl(n),function(t,e,n,r){for(var i=-1,o=aw(ow((e-t)/(n||1)),0),a=Array(o);o--;)a[r?o:++i]=t,t+=n;return a}(e,n,r=void 0===r?e1&&kc(t,e[0],e[1])?e=[]:n>2&&kc(e[0],e[1],e[2])&&(e=[e[0]]),cm(t,Hd(e,1),[])})),jw=4294967294,Nw=Math.floor,Sw=Math.min;function Mw(t,e,n,r){var i=0,o=null==t?0:t.length;if(0===o)return 0;for(var a=(e=n(e))!=e,s=null===e,l=Js(e),u=void 0===e;i>>1,a=t[o];null!==a&&!Js(a)&&(n?a<=e:a/g,Xw={escape:/<%-([\s\S]+?)%>/g,evaluate:/<%([\s\S]+?)%>/g,interpolate:Jw,variable:"",imports:{_:{escape:Wv}}},Ww="Invalid `variable` option passed into `_.template`",qw=/\b__p \+= '';/g,Uw=/\b(__p \+=) '' \+/g,Kw=/(__e\(.*?\)|\b__t\)) \+\n'';/g,Qw=/[()=,{}\[\]\/\s]/,$w=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,tE=/($^)/,eE=/['\n\r\u2028\u2029\\]/g,nE=Object.prototype.hasOwnProperty;var rE="Expected a function";function iE(t,e){return e(t)}var oE=9007199254740991,aE=4294967295,sE=Math.min;function lE(t,e){var n=t;return n instanceof Ql&&(n=n.value()),Sf(e,(function(t,e){return e.func.apply(e.thisArg,_d([t],e.args))}),n)}function uE(){return lE(this.__wrapped__,this.__actions__)}var cE=9007199254740991;function dE(t,e){for(var n=t.length;n--&&Au(e,t[n],0)>-1;);return n}function fE(t,e){for(var n=-1,r=t.length;++n-1;);return n}var pE=/^\s+/;var hE=30,gE="...",vE=/\w*$/;var yE=Mf({"&":"&","<":"<",">":">",""":'"',"'":"'"}),bE=/&(?:amp|lt|gt|quot|#39);/g,mE=RegExp(bE.source);var wE=zp&&1/tg(new zp([,-0]))[1]==1/0?function(t){return new zp(t)}:$l,EE=200;function OE(t,e,n){var r=-1,i=Pu,o=t.length,a=!0,s=[],l=s;if(n)a=!1,i=xv;else if(o>=EE){var u=e?null:wE(t);if(u)return tg(u);a=!1,i=qh,l=new Xh}else l=e?[]:s;t:for(;++r1||this.__actions__.length)&&r instanceof Ql&&Bu(n)?((r=r.slice(n,+n+(e?1:0))).__actions__.push({func:iE,args:[i],thisArg:void 0}),new iu(r,this.__chain__).thru((function(t){return e&&!t.length&&t.push(void 0),t}))):this.thru(i)}));function DE(t,e,n){var r=t.length;if(r<2)return r?OE(t[0]):[];for(var i=-1,o=Array(r);++i1?t[e-1]:void 0;return n="function"==typeof n?(t.pop(),n):void 0,jE(t,n)})),ZE={chunk:function(t,e,n){e=(n?kc(t,e,n):void 0===e)?1:yp(yl(e),0);var r=null==t?0:t.length;if(!r||e<1)return[];for(var i=0,o=0,a=Array(vp(r/e));ii?0:i+n),(r=void 0===r||r>i?i:yl(r))<0&&(r+=i),r=n>r?0:ty(r);n-1:!!i&&Au(t,e,n)>-1},invokeMap:ob,keyBy:Sb,map:py,orderBy:function(t,e,n,r){return null==t?[]:(Us(e)||(e=null==e?[]:[e]),Us(n=r?void 0:n)||(n=null==n?[]:[n]),cm(t,e,n))},partition:Hm,reduce:function(t,e,n){var r=Us(t)?Sf:dw,i=arguments.length<3;return r(t,_g(e),n,i,qg)},reduceRight:function(t,e,n){var r=Us(t)?fw:dw,i=arguments.length<3;return r(t,_g(e),n,i,zv)},reject:function(t,e){return(Us(t)?kp:ey)(t,Kb(_g(e)))},sample:function(t){return(Us(t)?yw:bw)(t)},sampleSize:function(t,e,n){return e=(n?kc(t,e,n):void 0===e)?1:yl(e),(Us(t)?ww:Ew)(t,e)},shuffle:function(t){return(Us(t)?Ow:Tw)(t)},size:function(t){if(null==t)return 0;if(Pc(t))return zy(t)?Dm(t):t.length;var e=Up(t);return e==xw||e==Aw?t.size:nd(t).length},some:function(t,e,n){var r=Us(t)?Wh:kw;return n&&kc(t,e,n)&&(e=void 0),r(t,_g(e))},sortBy:Iw},HE={now:iv},VE={after:function(t,e){if("function"!=typeof e)throw new TypeError(bl);return t=yl(t),function(){if(--t<1)return e.apply(this,arguments)}},ary:gc,before:sf,bind:lf,bindKey:cf,curry:ev,curryRight:rv,debounce:lv,defer:Ov,delay:Tv,flip:function(t){return pc(t,vy)},memoize:Id,negate:Kb,once:function(t){return sf(2,t)},overArgs:gm,partial:Zm,partialRight:Gm,rearg:cw,rest:function(t,e){if("function"!=typeof t)throw new TypeError(pw);return Tc(t,e=void 0===e?e:yl(e))},spread:function(t,e){if("function"!=typeof t)throw new TypeError(Rw);return e=null==e?0:zw(yl(e),0),Tc((function(n){var r=n[e],i=ff(n,0,e);return r&&_d(i,r),Fl(t,this,i)}))},throttle:function(t,e,n){var r=!0,i=!0;if("function"!=typeof t)throw new TypeError(rE);return sl(n)&&(r="leading"in n?!!n.leading:r,i="trailing"in n?!!n.trailing:i),lv(t,e,{leading:r,maxWait:e,trailing:i})},unary:function(t){return gc(t,1)},wrap:function(t,e){return Zm(Cv(e),t)}},FE={castArray:function(){if(!arguments.length)return[];var t=arguments[0];return Us(t)?t:[t]},clone:function(t){return Bh(t,_h)},cloneDeep:function(t){return Bh(t,Zh|Gh)},cloneDeepWith:function(t,e){return Bh(t,Hh|Vh,e="function"==typeof e?e:void 0)},cloneWith:function(t,e){return Bh(t,Fh,e="function"==typeof e?e:void 0)},conformsTo:function(t,e){return null==e||Gg(t,e,rd(e))},eq:yc,gt:Sy,gte:My,isArguments:Rc,isArray:Us,isArrayBuffer:lb,isArrayLike:Pc,isArrayLikeObject:pv,isBoolean:function(t){return!0===t||!1===t||Vs(t)&&Hs(t)==ub},isBuffer:Gc,isDate:fb,isElement:function(t){return Vs(t)&&1===t.nodeType&&!tf(t)},isEmpty:function(t){if(null==t)return!0;if(Pc(t)&&(Us(t)||"string"==typeof t||"function"==typeof t.splice||Gc(t)||Uc(t)||Rc(t)))return!t.length;var e=Up(t);if(e==pb||e==hb)return!t.size;if(Nc(t))return!nd(t).length;for(var n in t)if(gb.call(t,n))return!1;return!0},isEqual:function(t,e){return xg(t,e)},isEqualWith:function(t,e,n){var r=(n="function"==typeof n?n:void 0)?n(t,e):void 0;return void 0===r?xg(t,e,void 0,n):!!r},isError:rf,isFinite:function(t){return"number"==typeof t&&vb(t)},isFunction:xl,isInteger:yb,isLength:Ac,isMap:kh,isMatch:function(t,e){return t===e||kg(t,e,jg(e))},isMatchWith:function(t,e,n){return n="function"==typeof n?n:void 0,kg(t,e,jg(e),n)},isNaN:function(t){return mb(t)&&t!=+t},isNative:function(t){if(wb(t))throw new Error(Eb);return Ll(t)},isNil:function(t){return null==t},isNull:function(t){return null===t},isNumber:mb,isObject:sl,isObjectLike:Vs,isPlainObject:tf,isRegExp:xb,isSafeInteger:function(t){return yb(t)&&t>=-Ab&&t<=Ab},isSet:Nh,isString:zy,isSymbol:Js,isTypedArray:Uc,isUndefined:function(t){return void 0===t},isWeakMap:function(t){return Vs(t)&&Up(t)==Pb},isWeakSet:function(t){return Vs(t)&&Hs(t)==kb},lt:Rb,lte:zb,toArray:em,toFinite:vl,toInteger:yl,toLength:ty,toNumber:pl,toPlainObject:gv,toSafeInteger:function(t){return t?bp(yl(t),-cE,cE):0===t?t:0},toString:Cd},JE={add:nl,ceil:hp,divide:Sv,floor:yy,max:function(t){return t&&t.length?Zb(t,ml,jy):void 0},maxBy:function(t,e){return t&&t.length?Zb(t,_g(e),jy):void 0},mean:function(t){return Vb(t,ml)},meanBy:function(t,e){return Vb(t,_g(e))},min:function(t){return t&&t.length?Zb(t,ml,Lb):void 0},minBy:function(t,e){return t&&t.length?Zb(t,_g(e),Lb):void 0},multiply:qb,round:vw,subtract:_w,sum:function(t){return t&&t.length?Gb(t,ml):0},sumBy:function(t,e){return t&&t.length?Gb(t,_g(e)):0}},XE=function(t,e,n){return void 0===n&&(n=e,e=void 0),void 0!==n&&(n=(n=pl(n))==n?n:0),void 0!==e&&(e=(e=pl(e))==e?e:0),bp(pl(t),e,n)},WE=function(t,e,n){return e=vl(e),void 0===n?(n=e,e=0):n=vl(n),function(t,e,n){return t>=Ly(e,n)&&te){var r=t;t=e,e=r}if(n||t%1||e%1){var i=iw();return rw(t+i*(e-t+nw("1e-"+((i+"").length-1))),e)}return ew(t,e)},UE={assign:od,assignIn:ud,assignInWith:cd,assignWith:dd,at:Jd,create:function(t,e){var n=Gl(t);return null==e?n:Ep(n,e)},defaults:dv,defaultsDeep:mv,entries:Hv,entriesIn:Vv,extend:ud,extendWith:cd,findKey:function(t,e){return ay(t,_g(e),Xg)},findLastKey:function(t,e){return ay(t,_g(e),Rv)},forIn:function(t,e){return null==t?t:Jg(t,Cv(e),ld)},forInRight:function(t,e){return null==t?t:Lv(t,Cv(e),ld)},forOwn:function(t,e){return t&&Xg(t,Cv(e))},forOwnRight:function(t,e){return t&&Rv(t,Cv(e))},functions:function(t){return null==t?[]:Py(t,rd(t))},functionsIn:function(t){return null==t?[]:Py(t,ld(t))},get:zd,has:function(t,e){return null!=t&&Cg(t,e,Dy)},hasIn:Dg,invert:Ky,invertBy:eb,invoke:ib,keys:rd,keysIn:ld,mapKeys:function(t,e){var n={};return e=_g(e),Xg(t,(function(t,r,i){vc(n,e(t,r,i),t)})),n},mapValues:function(t,e){var n={};return e=_g(e),Xg(t,(function(t,r,i){vc(n,r,e(t,r,i))})),n},merge:Fb,mergeWith:bv,omit:om,omitBy:function(t,e){return lm(t,Kb(_g(e)))},pick:Vm,pickBy:lm,result:function(t,e,n){var r=-1,i=(e=Dd(e,t)).length;for(i||(i=1,t=void 0);++r=this.__values__.length;return{done:t,value:t?void 0:this.__values__[this.__index__++]}},plant:function(t){for(var e,n=this;n instanceof Ul;){var r=au(n);r.__index__=0,r.__values__=void 0,e?i.__wrapped__=r:e=r;var i=r;n=n.__wrapped__}return i.__wrapped__=t,e},reverse:function(){var t=this.__wrapped__;if(t instanceof Ql){var e=t;return this.__actions__.length&&(e=new Ql(this)),(e=e.reverse()).__actions__.push({func:iE,args:[gw],thisArg:void 0}),new iu(e,this.__chain__)}return this.thru(gw)},tap:function(t,e){return e(t),t},thru:iE,toIterator:function(){return this},toJSON:uE,value:uE,valueOf:uE,wrapperChain:function(){return gp(this)}},QE={camelCase:cp,capitalize:Nf,deburr:Lf,endsWith:function(t,e,n){t=Cd(t),e=tl(e);var r=t.length,i=n=void 0===n?r:bp(yl(n),0,r);return(n-=e.length)>=0&&t.slice(n,i)==e},escape:Wv,escapeRegExp:function(t){return(t=Cd(t))&&Uv.test(t)?t.replace(qv,"\\$&"):t},kebabCase:Nb,lowerCase:Db,lowerFirst:Yb,pad:function(t,e,n){t=Cd(t);var r=(e=yl(e))?Dm(t):0;if(!e||r>=e)return t;var i=(e-r)/2;return Lm(zm(i),n)+t+Lm(Rm(i),n)},padEnd:function(t,e,n){t=Cd(t);var r=(e=yl(e))?Dm(t):0;return e&&r>>0)?(t=Cd(t))&&("string"==typeof e||null!=e&&!xb(e))&&!(e=tl(e))&&hf(t)?ff(kf(t),0,n):t.split(e,n):[]},startCase:Bw,startsWith:function(t,e,n){return t=Cd(t),n=null==n?0:bp(yl(n),0,t.length),e=tl(e),t.slice(n,n+e.length)==e},template:function(t,e,n){var r=Xw.imports._.templateSettings||Xw;n&&kc(t,e,n)&&(e=void 0),t=Cd(t),e=cd({},e,r,Hw);var i,o,a=cd({},e.imports,r.imports,Hw),s=rd(a),l=By(a,s),u=0,c=e.interpolate||tE,d="__p += '",f=RegExp((e.escape||tE).source+"|"+c.source+"|"+(c===Jw?$w:tE).source+"|"+(e.evaluate||tE).source+"|$","g"),p=nE.call(e,"sourceURL")?"//# sourceURL="+(e.sourceURL+"").replace(/\s/g," ")+"\n":"";t.replace(f,(function(e,n,r,a,s,l){return r||(r=a),d+=t.slice(u,l).replace(eE,Fw),n&&(i=!0,d+="' +\n__e("+n+") +\n'"),s&&(o=!0,d+="';\n"+s+";\n__p += '"),r&&(d+="' +\n((__t = ("+r+")) == null ? '' : __t) +\n'"),u=l+e.length,e})),d+="';\n";var h=nE.call(e,"variable")&&e.variable;if(h){if(Qw.test(h))throw new Error(Ww)}else d="with (obj) {\n"+d+"\n}\n";d=(o?d.replace(qw,""):d).replace(Uw,"$1").replace(Kw,"$1;"),d="function("+(h||"obj")+") {\n"+(h?"":"obj || (obj = {});\n")+"var __t, __p = ''"+(i?", __e = _.escape":"")+(o?", __j = Array.prototype.join;\nfunction print() { __p += __j.call(arguments, '') }\n":";\n")+d+"return __p\n}";var g=of((function(){return Function(s,p+"return "+d).apply(void 0,l)}));if(g.source=d,rf(g))throw g;return g},templateSettings:Xw,toLower:function(t){return Cd(t).toLowerCase()},toUpper:function(t){return Cd(t).toUpperCase()},trim:function(t,e,n){if((t=Cd(t))&&(n||void 0===e))return al(t);if(!t||!(e=tl(e)))return t;var r=kf(t),i=kf(e);return ff(r,fE(r,i),dE(r,i)+1).join("")},trimEnd:function(t,e,n){if((t=Cd(t))&&(n||void 0===e))return t.slice(0,il(t)+1);if(!t||!(e=tl(e)))return t;var r=kf(t);return ff(r,0,dE(r,kf(e))+1).join("")},trimStart:function(t,e,n){if((t=Cd(t))&&(n||void 0===e))return t.replace(pE,"");if(!t||!(e=tl(e)))return t;var r=kf(t);return ff(r,fE(r,kf(e))).join("")},truncate:function(t,e){var n=hE,r=gE;if(sl(e)){var i="separator"in e?e.separator:i;n="length"in e?yl(e.length):n,r="omission"in e?tl(e.omission):r}var o=(t=Cd(t)).length;if(hf(t)){var a=kf(t);o=a.length}if(n>=o)return t;var s=n-Dm(r);if(s<1)return r;var l=a?ff(a,0,s).join(""):t.slice(0,s);if(void 0===i)return l+r;if(a&&(s+=l.length-s),xb(i)){if(t.slice(s).search(i)){var u,c=l;for(i.global||(i=RegExp(i.source,Cd(vE.exec(i))+"g")),i.lastIndex=0;u=i.exec(c);)var d=u.index;l=l.slice(0,void 0===d?s:d)}}else if(t.indexOf(tl(i),s)!=s){var f=l.lastIndexOf(i);f>-1&&(l=l.slice(0,f))}return l+r},unescape:function(t){return(t=Cd(t))&&mE.test(t)?t.replace(bE,yE):t},upperCase:SE,upperFirst:jf,words:sp},$E={attempt:of,bindAll:uf,cond:function(t){var e=null==t?0:t.length,n=_g;return t=e?qs(t,(function(t){if("function"!=typeof t[1])throw new TypeError(Zg);return[n(t[0]),t[1]]})):[],Tc((function(n){for(var r=-1;++roE)return[];var n=aE,r=sE(t,aE);e=Cv(e),t-=aE;for(var i=Sc(r,e);++n