Showing
6 changed files
with
140 additions
and
87 deletions
@@ -18,17 +18,17 @@ export default angular.module('thingsboard.directives.confirmOnExit', []) | @@ -18,17 +18,17 @@ export default angular.module('thingsboard.directives.confirmOnExit', []) | ||
18 | .name; | 18 | .name; |
19 | 19 | ||
20 | /*@ngInject*/ | 20 | /*@ngInject*/ |
21 | -function ConfirmOnExit($state, $mdDialog, $window, $filter, userService) { | 21 | +function ConfirmOnExit($state, $mdDialog, $window, $filter, $parse, userService) { |
22 | return { | 22 | return { |
23 | - link: function ($scope) { | ||
24 | - | 23 | + link: function ($scope, $element, $attributes) { |
24 | + $scope.confirmForm = $scope.$eval($attributes.confirmForm); | ||
25 | $window.onbeforeunload = function () { | 25 | $window.onbeforeunload = function () { |
26 | - if (userService.isAuthenticated() && (($scope.confirmForm && $scope.confirmForm.$dirty) || $scope.isDirty)) { | 26 | + if (userService.isAuthenticated() && (($scope.confirmForm && $scope.confirmForm.$dirty) || $scope.$eval($attributes.isDirty))) { |
27 | return $filter('translate')('confirm-on-exit.message'); | 27 | return $filter('translate')('confirm-on-exit.message'); |
28 | } | 28 | } |
29 | } | 29 | } |
30 | $scope.$on('$stateChangeStart', function (event, next, current, params) { | 30 | $scope.$on('$stateChangeStart', function (event, next, current, params) { |
31 | - if (userService.isAuthenticated() && (($scope.confirmForm && $scope.confirmForm.$dirty) || $scope.isDirty)) { | 31 | + if (userService.isAuthenticated() && (($scope.confirmForm && $scope.confirmForm.$dirty) || $scope.$eval($attributes.isDirty))) { |
32 | event.preventDefault(); | 32 | event.preventDefault(); |
33 | var confirm = $mdDialog.confirm() | 33 | var confirm = $mdDialog.confirm() |
34 | .title($filter('translate')('confirm-on-exit.title')) | 34 | .title($filter('translate')('confirm-on-exit.title')) |
@@ -40,7 +40,9 @@ function ConfirmOnExit($state, $mdDialog, $window, $filter, userService) { | @@ -40,7 +40,9 @@ function ConfirmOnExit($state, $mdDialog, $window, $filter, userService) { | ||
40 | if ($scope.confirmForm) { | 40 | if ($scope.confirmForm) { |
41 | $scope.confirmForm.$setPristine(); | 41 | $scope.confirmForm.$setPristine(); |
42 | } else { | 42 | } else { |
43 | - $scope.isDirty = false; | 43 | + var remoteSetter = $parse($attributes.isDirty).assign; |
44 | + remoteSetter($scope, false); | ||
45 | + //$scope.isDirty = false; | ||
44 | } | 46 | } |
45 | $state.go(next.name, params); | 47 | $state.go(next.name, params); |
46 | }, function () { | 48 | }, function () { |
@@ -48,9 +50,6 @@ function ConfirmOnExit($state, $mdDialog, $window, $filter, userService) { | @@ -48,9 +50,6 @@ function ConfirmOnExit($state, $mdDialog, $window, $filter, userService) { | ||
48 | } | 50 | } |
49 | }); | 51 | }); |
50 | }, | 52 | }, |
51 | - scope: { | ||
52 | - confirmForm: '=', | ||
53 | - isDirty: '=' | ||
54 | - } | 53 | + scope: false |
55 | }; | 54 | }; |
56 | } | 55 | } |
@@ -1177,6 +1177,8 @@ export default angular.module('thingsboard.locale', []) | @@ -1177,6 +1177,8 @@ export default angular.module('thingsboard.locale', []) | ||
1177 | "type": "Type", | 1177 | "type": "Type", |
1178 | "description": "Description", | 1178 | "description": "Description", |
1179 | "delete": "Delete rule node", | 1179 | "delete": "Delete rule node", |
1180 | + "select-all": "Select all nodes and connections", | ||
1181 | + "deselect-all": "Deselect all nodes and connections", | ||
1180 | "delete-selected-objects": "Delete selected nodes and connections", | 1182 | "delete-selected-objects": "Delete selected nodes and connections", |
1181 | "rulenode-details": "Rule node details", | 1183 | "rulenode-details": "Rule node details", |
1182 | "debug-mode": "Debug mode", | 1184 | "debug-mode": "Debug mode", |
@@ -27,15 +27,10 @@ import addRuleNodeLinkTemplate from './add-link.tpl.html'; | @@ -27,15 +27,10 @@ import addRuleNodeLinkTemplate from './add-link.tpl.html'; | ||
27 | 27 | ||
28 | /* eslint-enable import/no-unresolved, import/default */ | 28 | /* eslint-enable import/no-unresolved, import/default */ |
29 | 29 | ||
30 | - | ||
31 | -const deleteKeyCode = 46; | ||
32 | -const ctrlKeyCode = 17; | ||
33 | -const aKeyCode = 65; | ||
34 | -const escKeyCode = 27; | ||
35 | - | ||
36 | /*@ngInject*/ | 30 | /*@ngInject*/ |
37 | export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, $timeout, $mdExpansionPanel, $document, $mdDialog, | 31 | export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, $timeout, $mdExpansionPanel, $document, $mdDialog, |
38 | - $filter, $translate, types, ruleChainService, Modelfactory, flowchartConstants, ruleChain, ruleChainMetaData) { | 32 | + $filter, $translate, hotkeys, types, ruleChainService, Modelfactory, flowchartConstants, |
33 | + ruleChain, ruleChainMetaData, ruleNodeComponents) { | ||
39 | 34 | ||
40 | var vm = this; | 35 | var vm = this; |
41 | 36 | ||
@@ -76,42 +71,62 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, | @@ -76,42 +71,62 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, | ||
76 | 71 | ||
77 | vm.modelservice = Modelfactory(vm.ruleChainModel, vm.selectedObjects); | 72 | vm.modelservice = Modelfactory(vm.ruleChainModel, vm.selectedObjects); |
78 | 73 | ||
79 | - vm.ctrlDown = false; | ||
80 | - | ||
81 | vm.saveRuleChain = saveRuleChain; | 74 | vm.saveRuleChain = saveRuleChain; |
82 | vm.revertRuleChain = revertRuleChain; | 75 | vm.revertRuleChain = revertRuleChain; |
83 | 76 | ||
84 | vm.objectsSelected = objectsSelected; | 77 | vm.objectsSelected = objectsSelected; |
85 | vm.deleteSelected = deleteSelected; | 78 | vm.deleteSelected = deleteSelected; |
86 | 79 | ||
87 | - vm.keyDown = function (evt) { | ||
88 | - if (evt.keyCode === ctrlKeyCode) { | ||
89 | - vm.ctrlDown = true; | ||
90 | - evt.stopPropagation(); | ||
91 | - evt.preventDefault(); | ||
92 | - } | ||
93 | - }; | ||
94 | - | ||
95 | - vm.keyUp = function (evt) { | ||
96 | - | ||
97 | - if (evt.keyCode === deleteKeyCode) { | ||
98 | - vm.modelservice.deleteSelected(); | ||
99 | - } | ||
100 | - | ||
101 | - if (evt.keyCode == aKeyCode && vm.ctrlDown) { | ||
102 | - vm.modelservice.selectAll(); | ||
103 | - } | ||
104 | - | ||
105 | - if (evt.keyCode == escKeyCode) { | ||
106 | - vm.modelservice.deselectAll(); | ||
107 | - } | ||
108 | - | ||
109 | - if (evt.keyCode === ctrlKeyCode) { | ||
110 | - vm.ctrlDown = false; | ||
111 | - evt.stopPropagation(); | ||
112 | - evt.preventDefault(); | ||
113 | - } | ||
114 | - }; | 80 | + initHotKeys(); |
81 | + | ||
82 | + function initHotKeys() { | ||
83 | + hotkeys.bindTo($scope) | ||
84 | + .add({ | ||
85 | + combo: 'ctrl+a', | ||
86 | + description: $translate.instant('rulenode.select-all'), | ||
87 | + allowIn: ['INPUT', 'SELECT', 'TEXTAREA'], | ||
88 | + callback: function (event) { | ||
89 | + event.preventDefault(); | ||
90 | + vm.modelservice.selectAll(); | ||
91 | + } | ||
92 | + }) | ||
93 | + .add({ | ||
94 | + combo: 'esc', | ||
95 | + description: $translate.instant('rulenode.deselect-all'), | ||
96 | + allowIn: ['INPUT', 'SELECT', 'TEXTAREA'], | ||
97 | + callback: function (event) { | ||
98 | + event.preventDefault(); | ||
99 | + vm.modelservice.deselectAll(); | ||
100 | + } | ||
101 | + }) | ||
102 | + .add({ | ||
103 | + combo: 'ctrl+s', | ||
104 | + description: $translate.instant('action.apply'), | ||
105 | + allowIn: ['INPUT', 'SELECT', 'TEXTAREA'], | ||
106 | + callback: function (event) { | ||
107 | + event.preventDefault(); | ||
108 | + vm.saveRuleChain(); | ||
109 | + } | ||
110 | + }) | ||
111 | + .add({ | ||
112 | + combo: 'ctrl+z', | ||
113 | + description: $translate.instant('action.decline-changes'), | ||
114 | + allowIn: ['INPUT', 'SELECT', 'TEXTAREA'], | ||
115 | + callback: function (event) { | ||
116 | + event.preventDefault(); | ||
117 | + vm.revertRuleChain(); | ||
118 | + } | ||
119 | + }) | ||
120 | + .add({ | ||
121 | + combo: 'del', | ||
122 | + description: $translate.instant('rulenode.delete-selected-objects'), | ||
123 | + allowIn: ['INPUT', 'SELECT', 'TEXTAREA'], | ||
124 | + callback: function (event) { | ||
125 | + event.preventDefault(); | ||
126 | + vm.modelservice.deleteSelected(); | ||
127 | + } | ||
128 | + }) | ||
129 | + } | ||
115 | 130 | ||
116 | vm.onEditRuleNodeClosed = function() { | 131 | vm.onEditRuleNodeClosed = function() { |
117 | vm.editingRuleNode = null; | 132 | vm.editingRuleNode = null; |
@@ -289,44 +304,40 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, | @@ -289,44 +304,40 @@ export function RuleChainController($stateParams, $scope, $compile, $q, $mdUtil, | ||
289 | loadRuleChainLibrary(); | 304 | loadRuleChainLibrary(); |
290 | 305 | ||
291 | function loadRuleChainLibrary() { | 306 | function loadRuleChainLibrary() { |
292 | - ruleChainService.getRuleNodeComponents().then( | ||
293 | - (ruleNodeComponents) => { | ||
294 | - for (var i=0;i<ruleNodeComponents.length;i++) { | ||
295 | - var ruleNodeComponent = ruleNodeComponents[i]; | ||
296 | - var componentType = ruleNodeComponent.type; | ||
297 | - var model = vm.ruleNodeTypesModel[componentType].model; | ||
298 | - var node = { | ||
299 | - id: model.nodes.length, | ||
300 | - component: ruleNodeComponent, | ||
301 | - name: '', | ||
302 | - nodeClass: vm.types.ruleNodeType[componentType].nodeClass, | ||
303 | - icon: vm.types.ruleNodeType[componentType].icon, | ||
304 | - x: 30, | ||
305 | - y: 10+50*model.nodes.length, | ||
306 | - connectors: [] | ||
307 | - }; | ||
308 | - if (ruleNodeComponent.configurationDescriptor.nodeDefinition.inEnabled) { | ||
309 | - node.connectors.push( | ||
310 | - { | ||
311 | - type: flowchartConstants.leftConnectorType, | ||
312 | - id: model.nodes.length * 2 | ||
313 | - } | ||
314 | - ); | 307 | + for (var i=0;i<ruleNodeComponents.length;i++) { |
308 | + var ruleNodeComponent = ruleNodeComponents[i]; | ||
309 | + var componentType = ruleNodeComponent.type; | ||
310 | + var model = vm.ruleNodeTypesModel[componentType].model; | ||
311 | + var node = { | ||
312 | + id: model.nodes.length, | ||
313 | + component: ruleNodeComponent, | ||
314 | + name: '', | ||
315 | + nodeClass: vm.types.ruleNodeType[componentType].nodeClass, | ||
316 | + icon: vm.types.ruleNodeType[componentType].icon, | ||
317 | + x: 30, | ||
318 | + y: 10+50*model.nodes.length, | ||
319 | + connectors: [] | ||
320 | + }; | ||
321 | + if (ruleNodeComponent.configurationDescriptor.nodeDefinition.inEnabled) { | ||
322 | + node.connectors.push( | ||
323 | + { | ||
324 | + type: flowchartConstants.leftConnectorType, | ||
325 | + id: model.nodes.length * 2 | ||
315 | } | 326 | } |
316 | - if (ruleNodeComponent.configurationDescriptor.nodeDefinition.outEnabled) { | ||
317 | - node.connectors.push( | ||
318 | - { | ||
319 | - type: flowchartConstants.rightConnectorType, | ||
320 | - id: model.nodes.length * 2 + 1 | ||
321 | - } | ||
322 | - ); | 327 | + ); |
328 | + } | ||
329 | + if (ruleNodeComponent.configurationDescriptor.nodeDefinition.outEnabled) { | ||
330 | + node.connectors.push( | ||
331 | + { | ||
332 | + type: flowchartConstants.rightConnectorType, | ||
333 | + id: model.nodes.length * 2 + 1 | ||
323 | } | 334 | } |
324 | - model.nodes.push(node); | ||
325 | - } | ||
326 | - vm.ruleChainLibraryLoaded = true; | ||
327 | - prepareRuleChain(); | 335 | + ); |
328 | } | 336 | } |
329 | - ); | 337 | + model.nodes.push(node); |
338 | + } | ||
339 | + vm.ruleChainLibraryLoaded = true; | ||
340 | + prepareRuleChain(); | ||
330 | } | 341 | } |
331 | 342 | ||
332 | function prepareRuleChain() { | 343 | function prepareRuleChain() { |
@@ -68,6 +68,11 @@ export default function RuleChainRoutes($stateProvider, NodeTemplatePathProvider | @@ -68,6 +68,11 @@ export default function RuleChainRoutes($stateProvider, NodeTemplatePathProvider | ||
68 | /*@ngInject*/ | 68 | /*@ngInject*/ |
69 | function($stateParams, ruleChainService) { | 69 | function($stateParams, ruleChainService) { |
70 | return ruleChainService.getRuleChainMetaData($stateParams.ruleChainId); | 70 | return ruleChainService.getRuleChainMetaData($stateParams.ruleChainId); |
71 | + }, | ||
72 | + ruleNodeComponents: | ||
73 | + /*@ngInject*/ | ||
74 | + function($stateParams, ruleChainService) { | ||
75 | + return ruleChainService.getRuleNodeComponents(); | ||
71 | } | 76 | } |
72 | }, | 77 | }, |
73 | data: { | 78 | data: { |
@@ -75,6 +75,7 @@ | @@ -75,6 +75,7 @@ | ||
75 | padding: 5px 10px; | 75 | padding: 5px 10px; |
76 | border-radius: 5px; | 76 | border-radius: 5px; |
77 | background-color: #F15B26; | 77 | background-color: #F15B26; |
78 | + pointer-events: none; | ||
78 | color: #333; | 79 | color: #333; |
79 | border: solid 1px #777; | 80 | border: solid 1px #777; |
80 | font-size: 12px; | 81 | font-size: 12px; |
@@ -186,12 +187,27 @@ | @@ -186,12 +187,27 @@ | ||
186 | margin: 10px; | 187 | margin: 10px; |
187 | border-radius: 5px; | 188 | border-radius: 5px; |
188 | background-color: #ccc; | 189 | background-color: #ccc; |
190 | + pointer-events: all; | ||
189 | } | 191 | } |
190 | 192 | ||
191 | .fc-connector.fc-hover { | 193 | .fc-connector.fc-hover { |
192 | background-color: #000; | 194 | background-color: #000; |
193 | } | 195 | } |
194 | 196 | ||
197 | +.fc-arrow-marker { | ||
198 | + polygon { | ||
199 | + stroke: gray; | ||
200 | + fill: gray; | ||
201 | + } | ||
202 | +} | ||
203 | + | ||
204 | +.fc-arrow-marker-selected { | ||
205 | + polygon { | ||
206 | + stroke: red; | ||
207 | + fill: red; | ||
208 | + } | ||
209 | +} | ||
210 | + | ||
195 | .fc-edge { | 211 | .fc-edge { |
196 | outline: none; | 212 | outline: none; |
197 | stroke: gray; | 213 | stroke: gray; |
@@ -246,11 +262,23 @@ | @@ -246,11 +262,23 @@ | ||
246 | cursor: pointer; | 262 | cursor: pointer; |
247 | } | 263 | } |
248 | 264 | ||
265 | +.fc-noselect { | ||
266 | + -webkit-touch-callout: none; /* iOS Safari */ | ||
267 | + -webkit-user-select: none; /* Safari */ | ||
268 | + -khtml-user-select: none; /* Konqueror HTML */ | ||
269 | + -moz-user-select: none; /* Firefox */ | ||
270 | + -ms-user-select: none; /* Internet Explorer/Edge */ | ||
271 | + user-select: none; /* Non-prefixed version, currently | ||
272 | + supported by Chrome and Opera */ | ||
273 | +} | ||
274 | + | ||
249 | .fc-edge-label { | 275 | .fc-edge-label { |
250 | position: absolute; | 276 | position: absolute; |
251 | - user-select: none; | ||
252 | transition: transform .2s; | 277 | transition: transform .2s; |
253 | opacity: 0.8; | 278 | opacity: 0.8; |
279 | + &.ng-leave { | ||
280 | + transition: 0s none; | ||
281 | + } | ||
254 | &.fc-hover { | 282 | &.fc-hover { |
255 | transform: scale(1.25); | 283 | transform: scale(1.25); |
256 | } | 284 | } |
@@ -262,6 +290,13 @@ | @@ -262,6 +290,13 @@ | ||
262 | } | 290 | } |
263 | } | 291 | } |
264 | } | 292 | } |
293 | + .fc-nodedelete { | ||
294 | + right: -13px; | ||
295 | + top: -30px; | ||
296 | + } | ||
297 | + &:focus { | ||
298 | + outline: 0; | ||
299 | + } | ||
265 | } | 300 | } |
266 | 301 | ||
267 | .fc-edge-label-text { | 302 | .fc-edge-label-text { |
@@ -273,6 +308,7 @@ | @@ -273,6 +308,7 @@ | ||
273 | font-size: 14px; | 308 | font-size: 14px; |
274 | font-weight: 600; | 309 | font-weight: 600; |
275 | span { | 310 | span { |
311 | + cursor: default; | ||
276 | border: solid 2px #003a79; | 312 | border: solid 2px #003a79; |
277 | border-radius: 10px; | 313 | border-radius: 10px; |
278 | color: #003a79; | 314 | color: #003a79; |
@@ -16,8 +16,10 @@ | @@ -16,8 +16,10 @@ | ||
16 | 16 | ||
17 | --> | 17 | --> |
18 | 18 | ||
19 | -<md-content flex tb-expand-fullscreen | ||
20 | - expand-tooltip-direction="bottom" layout="column" class="tb-rulechain"> | 19 | +<md-content flex tb-expand-fullscreen tb-confirm-on-exit is-dirty="vm.isDirty" |
20 | + expand-tooltip-direction="bottom" layout="column" class="tb-rulechain" | ||
21 | + ng-keydown="vm.keyDown($event)" | ||
22 | + ng-keyup="vm.keyUp($event)"> | ||
21 | <section class="tb-rulechain-container" flex layout="column"> | 23 | <section class="tb-rulechain-container" flex layout="column"> |
22 | <div class="tb-rulechain-layout" flex layout="row"> | 24 | <div class="tb-rulechain-layout" flex layout="row"> |
23 | <div class="tb-rulechain-library"> | 25 | <div class="tb-rulechain-library"> |
@@ -50,8 +52,6 @@ | @@ -50,8 +52,6 @@ | ||
50 | </div> | 52 | </div> |
51 | <div flex class="tb-rulechain-graph"> | 53 | <div flex class="tb-rulechain-graph"> |
52 | <fc-canvas id="tb-rulchain-canvas" | 54 | <fc-canvas id="tb-rulchain-canvas" |
53 | - ng-keydown="vm.keyDown($event)" | ||
54 | - ng-keyup="vm.keyUp($event)" | ||
55 | model="vm.ruleChainModel" | 55 | model="vm.ruleChainModel" |
56 | selected-objects="vm.selectedObjects" | 56 | selected-objects="vm.selectedObjects" |
57 | edge-style="curved" | 57 | edge-style="curved" |