/* * Copyright © 2016-2018 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import './rulechain.scss'; import 'tooltipster/dist/css/tooltipster.bundle.min.css'; import 'tooltipster/dist/js/tooltipster.bundle.min.js'; import 'tooltipster/dist/css/plugins/tooltipster/sideTip/themes/tooltipster-sideTip-shadow.min.css'; /* eslint-disable import/no-unresolved, import/default */ import addRuleNodeTemplate from './add-rulenode.tpl.html'; import addRuleNodeLinkTemplate from './add-link.tpl.html'; /* eslint-enable import/no-unresolved, import/default */ /*@ngInject*/ export function RuleChainController($state, $scope, $compile, $q, $mdUtil, $timeout, $mdExpansionPanel, $window, $document, $mdDialog, $filter, $translate, hotkeys, types, ruleChainService, itembuffer, Modelfactory, flowchartConstants, ruleChain, ruleChainMetaData, ruleNodeComponents) { var vm = this; vm.$mdExpansionPanel = $mdExpansionPanel; vm.types = types; if ($state.current.data.import && !ruleChain) { $state.go('home.ruleChains'); return; } vm.isImport = $state.current.data.import; vm.isConfirmOnExit = false; $scope.$watch(function() { return vm.isDirty || vm.isImport; }, (val) => { vm.isConfirmOnExit = val; }); vm.errorTooltips = {}; vm.isFullscreen = false; vm.editingRuleNode = null; vm.isEditingRuleNode = false; vm.editingRuleNodeLink = null; vm.isEditingRuleNodeLink = false; vm.isLibraryOpen = true; vm.enableHotKeys = true; Object.defineProperty(vm, 'isLibraryOpenReadonly', { get: function() { return vm.isLibraryOpen }, set: function() {} }); vm.ruleNodeSearch = ''; vm.ruleChain = ruleChain; vm.ruleChainMetaData = ruleChainMetaData; vm.canvasControl = {}; vm.ruleChainModel = { nodes: [], edges: [] }; vm.ruleNodeTypesModel = {}; vm.ruleNodeTypesCanvasControl = {}; vm.ruleChainLibraryLoaded = false; for (var type in types.ruleNodeType) { if (!types.ruleNodeType[type].special) { vm.ruleNodeTypesModel[type] = { model: { nodes: [], edges: [] }, selectedObjects: [] }; vm.ruleNodeTypesCanvasControl[type] = {}; } } vm.selectedObjects = []; vm.modelservice = Modelfactory(vm.ruleChainModel, vm.selectedObjects); vm.saveRuleChain = saveRuleChain; vm.revertRuleChain = revertRuleChain; vm.objectsSelected = objectsSelected; vm.deleteSelected = deleteSelected; vm.triggerResize = triggerResize; vm.openRuleChainContextMenu = openRuleChainContextMenu; initHotKeys(); function openRuleChainContextMenu($event, $mdOpenMousepointMenu) { if (vm.canvasControl.modelservice && !$event.ctrlKey && !$event.metaKey) { var x = $event.clientX; var y = $event.clientY; var item = vm.canvasControl.modelservice.getItemInfoAtPoint(x, y); vm.contextInfo = prepareContextMenu(item); if (vm.contextInfo.items && vm.contextInfo.items.length > 0) { vm.contextMenuEvent = $event; $mdOpenMousepointMenu($event); return false; } } } function prepareContextMenu(item) { if (objectsSelected() || (!item.node && !item.edge)) { return prepareRuleChainContextMenu(); } else if (item.node) { return prepareRuleNodeContextMenu(item.node); } else if (item.edge) { return prepareEdgeContextMenu(item.edge); } } function prepareRuleChainContextMenu() { var contextInfo = { headerClass: 'tb-rulechain', icon: 'settings_ethernet', title: vm.ruleChain.name, subtitle: $translate.instant('rulechain.rulechain') }; contextInfo.items = []; if (vm.modelservice.nodes.getSelectedNodes().length) { contextInfo.items.push( { action: function () { copyRuleNodes(); }, enabled: true, value: "rulenode.copy-selected", icon: "content_copy", shortcut: "M-C" } ); } contextInfo.items.push( { action: function ($event) { pasteRuleNodes($event); }, enabled: itembuffer.hasRuleNodes(), value: "action.paste", icon: "content_paste", shortcut: "M-V" } ); contextInfo.items.push( { divider: true } ); if (objectsSelected()) { contextInfo.items.push( { action: function () { vm.modelservice.deselectAll(); }, enabled: true, value: "rulenode.deselect-all", icon: "tab_unselected", shortcut: "Esc" } ); contextInfo.items.push( { action: function () { vm.modelservice.deleteSelected(); }, enabled: true, value: "rulenode.delete-selected", icon: "clear", shortcut: "Del" } ); } else { contextInfo.items.push( { action: function () { vm.modelservice.selectAll(); }, enabled: true, value: "rulenode.select-all", icon: "select_all", shortcut: "M-A" } ); } contextInfo.items.push( { divider: true } ); contextInfo.items.push( { action: function () { vm.saveRuleChain(); }, enabled: !(vm.isInvalid || (!vm.isDirty && !vm.isImport)), value: "action.apply-changes", icon: "done", shortcut: "M-S" } ); contextInfo.items.push( { action: function () { vm.revertRuleChain(); }, enabled: vm.isDirty, value: "action.decline-changes", icon: "close", shortcut: "M-Z" } ); return contextInfo; } function prepareRuleNodeContextMenu(node) { var contextInfo = { headerClass: node.nodeClass, icon: node.icon, iconUrl: node.iconUrl, title: node.name, subtitle: node.component.name }; contextInfo.items = []; if (!node.readonly) { contextInfo.items.push( { action: function () { openNodeDetails(node); }, enabled: true, value: "rulenode.details", icon: "menu" } ); contextInfo.items.push( { action: function () { copyNode(node); }, enabled: true, value: "action.copy", icon: "content_copy" } ); contextInfo.items.push( { action: function () { vm.canvasControl.modelservice.nodes.delete(node); }, enabled: true, value: "action.delete", icon: "clear", shortcut: "M-X" } ); } return contextInfo; } function prepareEdgeContextMenu(edge) { var contextInfo = { headerClass: 'tb-link', icon: 'trending_flat', title: edge.label, subtitle: $translate.instant('rulenode.link') }; contextInfo.items = []; var sourceNode = vm.modelservice.nodes.getNodeByConnectorId(edge.source); if (sourceNode.component.type != types.ruleNodeType.INPUT.value) { contextInfo.items.push( { action: function () { openLinkDetails(edge); }, enabled: true, value: "rulenode.details", icon: "menu" } ); } contextInfo.items.push( { action: function () { vm.canvasControl.modelservice.edges.delete(edge); }, enabled: true, value: "action.delete", icon: "clear", shortcut: "M-X" } ); return contextInfo; } function initHotKeys() { hotkeys.bindTo($scope) .add({ combo: 'ctrl+a', description: $translate.instant('rulenode.select-all-objects'), allowIn: ['INPUT', 'SELECT', 'TEXTAREA'], callback: function (event) { if (vm.enableHotKeys) { event.preventDefault(); vm.modelservice.selectAll(); } } }) .add({ combo: 'ctrl+c', description: $translate.instant('rulenode.copy-selected'), allowIn: ['INPUT', 'SELECT', 'TEXTAREA'], callback: function (event) { if (vm.enableHotKeys) { event.preventDefault(); copyRuleNodes(); } } }) .add({ combo: 'ctrl+v', description: $translate.instant('action.paste'), allowIn: ['INPUT', 'SELECT', 'TEXTAREA'], callback: function (event) { if (vm.enableHotKeys) { event.preventDefault(); if (itembuffer.hasRuleNodes()) { pasteRuleNodes(); } } } }) .add({ combo: 'esc', description: $translate.instant('rulenode.deselect-all-objects'), allowIn: ['INPUT', 'SELECT', 'TEXTAREA'], callback: function (event) { if (vm.enableHotKeys) { event.preventDefault(); event.stopPropagation(); vm.modelservice.deselectAll(); } } }) .add({ combo: 'ctrl+s', description: $translate.instant('action.apply'), allowIn: ['INPUT', 'SELECT', 'TEXTAREA'], callback: function (event) { if (vm.enableHotKeys) { event.preventDefault(); vm.saveRuleChain(); } } }) .add({ combo: 'ctrl+z', description: $translate.instant('action.decline-changes'), allowIn: ['INPUT', 'SELECT', 'TEXTAREA'], callback: function (event) { if (vm.enableHotKeys) { event.preventDefault(); vm.revertRuleChain(); } } }) .add({ combo: 'del', description: $translate.instant('rulenode.delete-selected-objects'), allowIn: ['INPUT', 'SELECT', 'TEXTAREA'], callback: function (event) { if (vm.enableHotKeys) { event.preventDefault(); vm.modelservice.deleteSelected(); } } }) } vm.onEditRuleNodeClosed = function() { vm.editingRuleNode = null; }; vm.onEditRuleNodeLinkClosed = function() { vm.editingRuleNodeLink = null; }; vm.saveRuleNode = function(theForm) { $scope.$broadcast('form-submit'); if (theForm.$valid) { theForm.$setPristine(); if (vm.editingRuleNode.error) { delete vm.editingRuleNode.error; } vm.ruleChainModel.nodes[vm.editingRuleNodeIndex] = vm.editingRuleNode; vm.editingRuleNode = angular.copy(vm.editingRuleNode); updateRuleNodesHighlight(); } }; vm.saveRuleNodeLink = function(theForm) { theForm.$setPristine(); vm.ruleChainModel.edges[vm.editingRuleNodeLinkIndex] = vm.editingRuleNodeLink; vm.editingRuleNodeLink = angular.copy(vm.editingRuleNodeLink); }; vm.onRevertRuleNodeEdit = function(theForm) { theForm.$setPristine(); var node = vm.ruleChainModel.nodes[vm.editingRuleNodeIndex]; vm.editingRuleNode = angular.copy(node); }; vm.onRevertRuleNodeLinkEdit = function(theForm) { theForm.$setPristine(); var edge = vm.ruleChainModel.edges[vm.editingRuleNodeLinkIndex]; vm.editingRuleNodeLink = angular.copy(edge); }; vm.nodeLibCallbacks = { nodeCallbacks: { 'mouseEnter': function (event, node) { displayNodeDescriptionTooltip(event, node); }, 'mouseLeave': function () { destroyTooltips(); }, 'mouseDown': function () { destroyTooltips(); } } }; vm.typeHeaderMouseEnter = function(event, typeId) { var ruleNodeType = types.ruleNodeType[typeId]; displayTooltip(event, '
' + '
' + '
' + $translate.instant(ruleNodeType.name) + '
' + '
' + $translate.instant(ruleNodeType.details) + '
' + '
' + '
' ); }; vm.destroyTooltips = destroyTooltips; function destroyTooltips() { if (vm.tooltipTimeout) { $timeout.cancel(vm.tooltipTimeout); vm.tooltipTimeout = null; } var instances = angular.element.tooltipster.instances(); instances.forEach((instance) => { if (!instance.isErrorTooltip) { instance.destroy(); } }); } function displayNodeDescriptionTooltip(event, node) { displayTooltip(event, '
' + '
' + '
' + node.component.name + '
' + '
' + node.component.configurationDescriptor.nodeDefinition.description + '
' + '
' + node.component.configurationDescriptor.nodeDefinition.details + '
' + '
' + '
' ); } function displayTooltip(event, content) { destroyTooltips(); vm.tooltipTimeout = $timeout(() => { var element = angular.element(event.target); element.tooltipster( { theme: 'tooltipster-shadow', delay: 100, trigger: 'custom', triggerOpen: { click: false, tap: false }, triggerClose: { click: true, tap: true, scroll: true }, side: 'right', trackOrigin: true } ); var contentElement = angular.element(content); $compile(contentElement)($scope); var tooltip = element.tooltipster('instance'); tooltip.content(contentElement); tooltip.open(); }, 500); } function updateNodeErrorTooltip(node) { if (node.error) { var element = angular.element('#' + node.id); var tooltip = vm.errorTooltips[node.id]; if (!tooltip || !element.hasClass("tooltipstered")) { element.tooltipster( { theme: 'tooltipster-shadow', delay: 0, animationDuration: 0, trigger: 'custom', triggerOpen: { click: false, tap: false }, triggerClose: { click: false, tap: false, scroll: false }, side: 'top', trackOrigin: true } ); var content = '
' + '
' + '
' + node.error + '
' + '
' + '
'; var contentElement = angular.element(content); $compile(contentElement)($scope); tooltip = element.tooltipster('instance'); tooltip.isErrorTooltip = true; tooltip.content(contentElement); vm.errorTooltips[node.id] = tooltip; } $mdUtil.nextTick(() => { tooltip.open(); }); } else { if (vm.errorTooltips[node.id]) { tooltip = vm.errorTooltips[node.id]; tooltip.destroy(); delete vm.errorTooltips[node.id]; } } } function updateErrorTooltips(hide) { for (var nodeId in vm.errorTooltips) { var tooltip = vm.errorTooltips[nodeId]; if (hide) { tooltip.close(); } else { tooltip.open(); } } } $scope.$watch(function() { return vm.isEditingRuleNode || vm.isEditingRuleNodeLink; }, (val) => { vm.enableHotKeys = !val; updateErrorTooltips(val); }); vm.editCallbacks = { edgeDoubleClick: function (event, edge) { openLinkDetails(edge); }, edgeEdit: function(event, edge) { openLinkDetails(edge); }, nodeCallbacks: { 'doubleClick': function (event, node) { openNodeDetails(node); }, 'nodeEdit': function (event, node) { openNodeDetails(node); } }, isValidEdge: function (source, destination) { return source.type === flowchartConstants.rightConnectorType && destination.type === flowchartConstants.leftConnectorType; }, createEdge: function (event, edge) { var deferred = $q.defer(); var sourceNode = vm.modelservice.nodes.getNodeByConnectorId(edge.source); if (sourceNode.component.type == types.ruleNodeType.INPUT.value) { var destNode = vm.modelservice.nodes.getNodeByConnectorId(edge.destination); if (destNode.component.type == types.ruleNodeType.RULE_CHAIN.value) { deferred.reject(); } else { var res = $filter('filter')(vm.ruleChainModel.edges, {source: vm.inputConnectorId}, true); if (res && res.length) { vm.modelservice.edges.delete(res[0]); } deferred.resolve(edge); } } else { var labels = ruleChainService.getRuleNodeSupportedLinks(sourceNode.component); vm.enableHotKeys = false; addRuleNodeLink(event, edge, labels).then( (link) => { deferred.resolve(link); vm.enableHotKeys = true; }, () => { deferred.reject(); vm.enableHotKeys = true; } ); } return deferred.promise; }, dropNode: function (event, node) { addRuleNode(event, node); } }; function openNodeDetails(node) { if (node.component.type != types.ruleNodeType.INPUT.value) { vm.isEditingRuleNodeLink = false; vm.editingRuleNodeLink = null; vm.isEditingRuleNode = true; vm.editingRuleNodeIndex = vm.ruleChainModel.nodes.indexOf(node); vm.editingRuleNode = angular.copy(node); $mdUtil.nextTick(() => { if (vm.ruleNodeForm) { vm.ruleNodeForm.$setPristine(); } }); } } function openLinkDetails(edge) { var sourceNode = vm.modelservice.nodes.getNodeByConnectorId(edge.source); if (sourceNode.component.type != types.ruleNodeType.INPUT.value) { vm.isEditingRuleNode = false; vm.editingRuleNode = null; vm.editingRuleNodeLinkLabels = ruleChainService.getRuleNodeSupportedLinks(sourceNode.component); vm.isEditingRuleNodeLink = true; vm.editingRuleNodeLinkIndex = vm.ruleChainModel.edges.indexOf(edge); vm.editingRuleNodeLink = angular.copy(edge); $mdUtil.nextTick(() => { if (vm.ruleNodeLinkForm) { vm.ruleNodeLinkForm.$setPristine(); } }); } } function copyNode(node) { itembuffer.copyRuleNodes([node], []); } function copyRuleNodes() { var nodes = vm.modelservice.nodes.getSelectedNodes(); var edges = vm.modelservice.edges.getSelectedEdges(); var connections = []; for (var i=0;i -1) && toIndex > -1 ) { var connection = { isInputSource: isInputSource, fromIndex: fromIndex, toIndex: toIndex, label: edge.label }; connections.push(connection); } } itembuffer.copyRuleNodes(nodes, connections); } function pasteRuleNodes(event) { var canvas = angular.element(vm.canvasControl.modelservice.getCanvasHtmlElement()); var x,y; if (event) { var offset = canvas.offset(); x = Math.round(event.clientX - offset.left); y = Math.round(event.clientY - offset.top); } else { var scrollParent = canvas.parent(); var scrollTop = scrollParent.scrollTop(); var scrollLeft = scrollParent.scrollLeft(); x = scrollLeft + scrollParent.width()/2; y = scrollTop + scrollParent.height()/2; } var ruleNodes = itembuffer.pasteRuleNodes(x, y, event); if (ruleNodes) { vm.modelservice.deselectAll(); var nodes = []; for (var i=0;i { for (componentType in vm.ruleNodeTypesCanvasControl) { if (vm.ruleNodeTypesCanvasControl[componentType].adjustCanvasSize) { vm.ruleNodeTypesCanvasControl[componentType].adjustCanvasSize(true); } } for (componentType in vm.ruleNodeTypesModel) { var panel = vm.$mdExpansionPanel(componentType); if (panel) { if (!vm.ruleNodeTypesModel[componentType].model.nodes.length) { panel.collapse(); } else { panel.expand(); } } } }); } function prepareRuleChain() { if (vm.ruleChainWatch) { vm.ruleChainWatch(); vm.ruleChainWatch = null; } vm.nextNodeID = 1; vm.nextConnectorID = 1; vm.selectedObjects.length = 0; vm.ruleChainModel.nodes.length = 0; vm.ruleChainModel.edges.length = 0; vm.inputConnectorId = vm.nextConnectorID++; vm.ruleChainModel.nodes.push( { id: 'rule-chain-node-' + vm.nextNodeID++, component: types.inputNodeComponent, name: "", nodeClass: types.ruleNodeType.INPUT.nodeClass, icon: types.ruleNodeType.INPUT.icon, readonly: true, x: 50, y: 150, connectors: [ { type: flowchartConstants.rightConnectorType, id: vm.inputConnectorId }, ] } ); ruleChainService.resolveTargetRuleChains(vm.ruleChainMetaData.ruleChainConnections) .then((ruleChainsMap) => { createRuleChainModel(ruleChainsMap); } ); } function createRuleChainModel(ruleChainsMap) { var nodes = []; for (var i=0;i -1) { var destNode = nodes[vm.ruleChainMetaData.firstNodeIndex]; if (destNode) { var connectors = vm.modelservice.nodes.getConnectorsByType(destNode, flowchartConstants.leftConnectorType); if (connectors && connectors.length) { var edge = { source: vm.inputConnectorId, destination: connectors[0].id }; vm.ruleChainModel.edges.push(edge); } } } if (vm.ruleChainMetaData.connections) { for (i = 0; i < vm.ruleChainMetaData.connections.length; i++) { var connection = vm.ruleChainMetaData.connections[i]; var sourceNode = nodes[connection.fromIndex]; destNode = nodes[connection.toIndex]; if (sourceNode && destNode) { var sourceConnectors = vm.modelservice.nodes.getConnectorsByType(sourceNode, flowchartConstants.rightConnectorType); var destConnectors = vm.modelservice.nodes.getConnectorsByType(destNode, flowchartConstants.leftConnectorType); if (sourceConnectors && sourceConnectors.length && destConnectors && destConnectors.length) { edge = { source: sourceConnectors[0].id, destination: destConnectors[0].id, label: connection.type }; vm.ruleChainModel.edges.push(edge); } } } } if (vm.ruleChainMetaData.ruleChainConnections) { var ruleChainNodesMap = {}; for (i = 0; i < vm.ruleChainMetaData.ruleChainConnections.length; i++) { var ruleChainConnection = vm.ruleChainMetaData.ruleChainConnections[i]; var ruleChain = ruleChainsMap[ruleChainConnection.targetRuleChainId.id]; if (ruleChainConnection.additionalInfo && ruleChainConnection.additionalInfo.ruleChainNodeId) { var ruleChainNode = ruleChainNodesMap[ruleChainConnection.additionalInfo.ruleChainNodeId]; if (!ruleChainNode) { ruleChainNode = { id: 'rule-chain-node-' + vm.nextNodeID++, additionalInfo: ruleChainConnection.additionalInfo, x: ruleChainConnection.additionalInfo.layoutX, y: ruleChainConnection.additionalInfo.layoutY, component: types.ruleChainNodeComponent, nodeClass: vm.types.ruleNodeType.RULE_CHAIN.nodeClass, icon: vm.types.ruleNodeType.RULE_CHAIN.icon, connectors: [ { type: flowchartConstants.leftConnectorType, id: vm.nextConnectorID++ } ] }; if (ruleChain.name) { ruleChainNode.name = ruleChain.name; ruleChainNode.targetRuleChainId = ruleChainConnection.targetRuleChainId.id; } else { ruleChainNode.name = "Unresolved"; ruleChainNode.targetRuleChainId = null; ruleChainNode.error = $translate.instant('rulenode.invalid-target-rulechain'); } ruleChainNodesMap[ruleChainConnection.additionalInfo.ruleChainNodeId] = ruleChainNode; vm.ruleChainModel.nodes.push(ruleChainNode); } sourceNode = nodes[ruleChainConnection.fromIndex]; if (sourceNode) { connectors = vm.modelservice.nodes.getConnectorsByType(sourceNode, flowchartConstants.rightConnectorType); if (connectors && connectors.length) { var ruleChainEdge = { source: connectors[0].id, destination: ruleChainNode.connectors[0].id, label: ruleChainConnection.type }; vm.ruleChainModel.edges.push(ruleChainEdge); } } } } } if (vm.canvasControl.adjustCanvasSize) { vm.canvasControl.adjustCanvasSize(true); } vm.isDirty = false; updateRuleNodesHighlight(); validate(); $mdUtil.nextTick(() => { vm.ruleChainWatch = $scope.$watch('vm.ruleChainModel', function (newVal, oldVal) { if (!angular.equals(newVal, oldVal)) { validate(); if (!vm.isDirty) { vm.isDirty = true; } } }, true ); }); } function updateRuleNodesHighlight() { for (var i = 0; i < vm.ruleChainModel.nodes.length; i++) { vm.ruleChainModel.nodes[i].highlighted = false; } if ($scope.searchConfig.searchText) { var res = $filter('filter')(vm.ruleChainModel.nodes, {name: $scope.searchConfig.searchText}); if (res) { for (i = 0; i < res.length; i++) { res[i].highlighted = true; } } } } function validate() { $mdUtil.nextTick(() => { vm.isInvalid = false; for (var i = 0; i < vm.ruleChainModel.nodes.length; i++) { if (vm.ruleChainModel.nodes[i].error) { vm.isInvalid = true; } updateNodeErrorTooltip(vm.ruleChainModel.nodes[i]); } }); } function saveRuleChain() { var saveRuleChainPromise; if (vm.isImport) { saveRuleChainPromise = ruleChainService.saveRuleChain(vm.ruleChain); } else { saveRuleChainPromise = $q.when(vm.ruleChain); } saveRuleChainPromise.then( (ruleChain) => { vm.ruleChain = ruleChain; var ruleChainMetaData = { ruleChainId: vm.ruleChain.id, nodes: [], connections: [], ruleChainConnections: [] }; var nodes = []; for (var i=0;i { vm.ruleChainMetaData = ruleChainMetaData; if (vm.isImport) { vm.isDirty = false; vm.isImport = false; $mdUtil.nextTick(() => { $state.go('home.ruleChains.ruleChain', {ruleChainId: vm.ruleChain.id.id}); }); } else { prepareRuleChain(); } } ); } ); } function revertRuleChain() { prepareRuleChain(); } function addRuleNode($event, ruleNode) { ruleNode.configuration = angular.copy(ruleNode.component.configurationDescriptor.nodeDefinition.defaultConfiguration); var ruleChainId = vm.ruleChain.id ? vm.ruleChain.id.id : null; vm.enableHotKeys = false; $mdDialog.show({ controller: 'AddRuleNodeController', controllerAs: 'vm', templateUrl: addRuleNodeTemplate, parent: angular.element($document[0].body), locals: {ruleNode: ruleNode, ruleChainId: ruleChainId}, fullscreen: true, targetEvent: $event }).then(function (ruleNode) { ruleNode.id = 'rule-chain-node-' + vm.nextNodeID++; ruleNode.connectors = []; if (ruleNode.component.configurationDescriptor.nodeDefinition.inEnabled) { ruleNode.connectors.push( { id: vm.nextConnectorID++, type: flowchartConstants.leftConnectorType } ); } if (ruleNode.component.configurationDescriptor.nodeDefinition.outEnabled) { ruleNode.connectors.push( { id: vm.nextConnectorID++, type: flowchartConstants.rightConnectorType } ); } vm.ruleChainModel.nodes.push(ruleNode); updateRuleNodesHighlight(); vm.enableHotKeys = true; }, function () { vm.enableHotKeys = true; }); } function addRuleNodeLink($event, link, labels) { return $mdDialog.show({ controller: 'AddRuleNodeLinkController', controllerAs: 'vm', templateUrl: addRuleNodeLinkTemplate, parent: angular.element($document[0].body), locals: {link: link, labels: labels}, fullscreen: true, targetEvent: $event }); } function objectsSelected() { return vm.modelservice.nodes.getSelectedNodes().length > 0 || vm.modelservice.edges.getSelectedEdges().length > 0 } function deleteSelected() { vm.modelservice.deleteSelected(); } function triggerResize() { var w = angular.element($window); w.triggerHandler('resize'); } } /*@ngInject*/ export function AddRuleNodeController($scope, $mdDialog, ruleNode, ruleChainId, helpLinks) { var vm = this; vm.helpLinks = helpLinks; vm.ruleNode = ruleNode; vm.ruleChainId = ruleChainId; vm.add = add; vm.cancel = cancel; function cancel() { $mdDialog.cancel(); } function add() { $scope.theForm.$setPristine(); $mdDialog.hide(vm.ruleNode); } } /*@ngInject*/ export function AddRuleNodeLinkController($scope, $mdDialog, link, labels, helpLinks) { var vm = this; vm.helpLinks = helpLinks; vm.link = link; vm.labels = labels; vm.add = add; vm.cancel = cancel; function cancel() { $mdDialog.cancel(); } function add() { $scope.theForm.$setPristine(); $mdDialog.hide(vm.link); } }