kms 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/javascripts/kms/application/controllers/pages_controller.coffee.erb +1 -2
- data/app/assets/javascripts/templates/assets/index.html.slim +4 -12
- data/app/assets/javascripts/templates/help/scopes.html.slim +74 -0
- data/app/assets/javascripts/templates/pages/index.html.slim +4 -3
- data/app/assets/javascripts/templates/snippets/index.html.slim +4 -3
- data/app/assets/javascripts/templates/templates/index.html.slim +4 -3
- data/app/assets/javascripts/templates/users/index.html.slim +3 -2
- data/app/assets/stylesheets/kms/custom.css.scss +3 -0
- data/app/controllers/kms/pages_controller.rb +2 -2
- data/app/models/ability.rb +0 -1
- data/app/models/concerns/kms/positioned.rb +18 -0
- data/app/models/kms/page.rb +2 -12
- data/app/services/kms/functions_registry.rb +11 -0
- data/app/uploaders/kms/asset_uploader.rb +1 -1
- data/config/initializers/help.rb +1 -1
- data/config/initializers/liquor.rb +0 -47
- data/config/locales/en.yml +22 -0
- data/config/locales/ru.yml +22 -0
- data/lib/generators/kms/install/install_generator.rb +2 -0
- data/lib/generators/kms/install/templates/carrierwave.rb +14 -0
- data/lib/kms/dependencies.rb +2 -0
- data/lib/kms/engine.rb +1 -1
- data/lib/kms/version.rb +1 -1
- data/spec/controllers/kms/snippets_controller_spec.rb +6 -6
- data/spec/internal/log/test.log +2439 -0
- data/spec/services/kms/functions_registry_spec.rb +14 -0
- data/spec/spec_helper.rb +1 -1
- data/vendor/assets/bower.json +1 -1
- data/vendor/assets/bower_components/angular-ui-tree/CHANGELOG.md +164 -0
- data/vendor/assets/bower_components/angular-ui-tree/CONTRIBUTING.md +39 -0
- data/vendor/assets/bower_components/angular-ui-tree/README.md +145 -37
- data/vendor/assets/bower_components/angular-ui-tree/bower.json +28 -18
- data/vendor/assets/bower_components/angular-ui-tree/{source → dist}/angular-ui-tree.css +18 -16
- data/vendor/assets/bower_components/angular-ui-tree/dist/angular-ui-tree.js +1408 -822
- data/vendor/assets/bower_components/angular-ui-tree/dist/angular-ui-tree.min.css +1 -2
- data/vendor/assets/bower_components/angular-ui-tree/dist/angular-ui-tree.min.js +3 -3
- data/vendor/assets/bower_components/angular-ui-tree/e2e/basic-example/basic-example.js +81 -0
- data/vendor/assets/bower_components/angular-ui-tree/e2e/basic-example/page.js +42 -0
- data/vendor/assets/bower_components/angular-ui-tree/e2e/table-example/page.js +31 -0
- data/vendor/assets/bower_components/angular-ui-tree/e2e/table-example/table-example.js +34 -0
- data/vendor/assets/bower_components/angular-ui-tree/index.js +2 -0
- data/vendor/assets/bower_components/angular-ui-tree/protractor.conf.js +19 -0
- data/vendor/assets/bower_components/angular/angular.js +4880 -2111
- data/vendor/assets/bower_components/angular/angular.min.js +320 -297
- data/vendor/assets/bower_components/angular/angular.min.js.gzip +0 -0
- data/vendor/assets/bower_components/angular/angular.min.js.map +3 -3
- data/vendor/assets/bower_components/angular/bower.json +1 -1
- data/vendor/assets/bower_components/angular/package.json +1 -1
- metadata +32 -40
- data/vendor/assets/bower_components/angular-ui-tree/Gruntfile.js +0 -229
- data/vendor/assets/bower_components/angular-ui-tree/build/compiler.jar +0 -0
- data/vendor/assets/bower_components/angular-ui-tree/demo/css/demo-horizontal.css +0 -47
- data/vendor/assets/bower_components/angular-ui-tree/demo/css/demo.css +0 -31
- data/vendor/assets/bower_components/angular-ui-tree/demo/css/tree.css +0 -25
- data/vendor/assets/bower_components/angular-ui-tree/demo/dist/angular-ui-tree.js +0 -1243
- data/vendor/assets/bower_components/angular-ui-tree/demo/dist/angular-ui-tree.min.css +0 -2
- data/vendor/assets/bower_components/angular-ui-tree/demo/dist/angular-ui-tree.min.js +0 -6
- data/vendor/assets/bower_components/angular-ui-tree/demo/filter.html +0 -64
- data/vendor/assets/bower_components/angular-ui-tree/demo/groups.html +0 -100
- data/vendor/assets/bower_components/angular-ui-tree/demo/index.html +0 -101
- data/vendor/assets/bower_components/angular-ui-tree/demo/js/demo.js +0 -63
- data/vendor/assets/bower_components/angular-ui-tree/demo/js/filter.js +0 -91
- data/vendor/assets/bower_components/angular-ui-tree/demo/js/groups.js +0 -143
- data/vendor/assets/bower_components/angular-ui-tree/demo/js/tree.js +0 -102
- data/vendor/assets/bower_components/angular-ui-tree/demo/js/trees.js +0 -60
- data/vendor/assets/bower_components/angular-ui-tree/demo/test.html +0 -60
- data/vendor/assets/bower_components/angular-ui-tree/demo/tree-horizontal.html +0 -66
- data/vendor/assets/bower_components/angular-ui-tree/demo/tree.html +0 -66
- data/vendor/assets/bower_components/angular-ui-tree/demo/trees.html +0 -92
- data/vendor/assets/bower_components/angular-ui-tree/guide/00_usage.ngdoc +0 -78
- data/vendor/assets/bower_components/angular-ui-tree/guide/01_development_setup.ngdoc +0 -58
- data/vendor/assets/bower_components/angular-ui-tree/guide/index.ngdoc +0 -33
- data/vendor/assets/bower_components/angular-ui-tree/karma.conf.js +0 -49
- data/vendor/assets/bower_components/angular-ui-tree/package.json +0 -40
- data/vendor/assets/bower_components/angular-ui-tree/source/angular-ui-tree.scss +0 -63
- data/vendor/assets/bower_components/angular-ui-tree/source/controllers/handleCtrl.js +0 -16
- data/vendor/assets/bower_components/angular-ui-tree/source/controllers/nodeCtrl.js +0 -141
- data/vendor/assets/bower_components/angular-ui-tree/source/controllers/nodesCtrl.js +0 -100
- data/vendor/assets/bower_components/angular-ui-tree/source/controllers/treeCtrl.js +0 -63
- data/vendor/assets/bower_components/angular-ui-tree/source/directives/uiTree.js +0 -115
- data/vendor/assets/bower_components/angular-ui-tree/source/directives/uiTreeHandle.js +0 -27
- data/vendor/assets/bower_components/angular-ui-tree/source/directives/uiTreeNode.js +0 -427
- data/vendor/assets/bower_components/angular-ui-tree/source/directives/uiTreeNodes.js +0 -59
- data/vendor/assets/bower_components/angular-ui-tree/source/main.js +0 -23
- data/vendor/assets/bower_components/angular-ui-tree/source/services/helper.js +0 -265
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "angular-ui-tree",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"homepage": "https://github.com/
|
|
3
|
+
"version": "2.22.5",
|
|
4
|
+
"homepage": "https://github.com/angular-ui-tree/angular-ui-tree",
|
|
5
5
|
"authors": [
|
|
6
6
|
"Jim Liu <https://github.com/JimLiu>",
|
|
7
|
-
"Voles <https://github.com/Voles>"
|
|
7
|
+
"Voles <https://github.com/Voles>",
|
|
8
|
+
"Stefan Mohr <https://github.com/StefanCodes>"
|
|
8
9
|
],
|
|
9
|
-
"description": "Tree directive for
|
|
10
|
+
"description": "Tree directive for AngularJS",
|
|
10
11
|
"main": [
|
|
11
12
|
"dist/angular-ui-tree.js",
|
|
12
|
-
"dist/angular-ui-tree.
|
|
13
|
+
"dist/angular-ui-tree.css"
|
|
13
14
|
],
|
|
14
15
|
"keywords": [
|
|
15
16
|
"angular",
|
|
@@ -22,22 +23,31 @@
|
|
|
22
23
|
"node"
|
|
23
24
|
],
|
|
24
25
|
"dependencies": {
|
|
25
|
-
"angular": "
|
|
26
|
-
"es5-shim": "2.3.0"
|
|
26
|
+
"angular": "1.2.x || 1.3.x || 1.4.x || 1.5.x"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"angular": "
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
29
|
+
"angular-bootstrap": "~0.13.4",
|
|
30
|
+
"angular-mocks": "1.2.x || 1.3.x || 1.4.x || 1.5.x",
|
|
31
|
+
"angular-route": "1.2.x || 1.3.x || 1.4.x || 1.5.x",
|
|
32
|
+
"angularfire": "2.0.x",
|
|
33
|
+
"bootstrap-css": "~3.2.0",
|
|
34
|
+
"jasmine-jquery": "2.1.1",
|
|
35
|
+
"jquery": "~2.1.1"
|
|
36
36
|
},
|
|
37
37
|
"ignore": [
|
|
38
|
+
"examples",
|
|
39
|
+
"demo",
|
|
40
|
+
"build",
|
|
41
|
+
"guide",
|
|
38
42
|
"node_modules",
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"tests"
|
|
42
|
-
|
|
43
|
+
"source",
|
|
44
|
+
"tasks",
|
|
45
|
+
"tests",
|
|
46
|
+
"gulpfile.js",
|
|
47
|
+
"karma.conf.js",
|
|
48
|
+
"package.json"
|
|
49
|
+
],
|
|
50
|
+
"resolutions": {
|
|
51
|
+
"angular": "1.2.x || 1.3.x || 1.4.x || 1.5.x"
|
|
52
|
+
}
|
|
43
53
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
.angular-ui-tree {
|
|
2
|
-
|
|
3
2
|
}
|
|
4
3
|
|
|
5
4
|
.angular-ui-tree-empty {
|
|
@@ -11,26 +10,26 @@
|
|
|
11
10
|
background-image: linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff), linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff);
|
|
12
11
|
background-size: 60px 60px;
|
|
13
12
|
background-position: 0 0, 30px 30px;
|
|
13
|
+
pointer-events: none;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
.angular-ui-tree-nodes {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
list-style: none;
|
|
17
|
+
position: relative;
|
|
18
|
+
margin: 0;
|
|
19
|
+
padding: 0;
|
|
20
|
+
list-style: none;
|
|
22
21
|
}
|
|
23
22
|
|
|
24
23
|
.angular-ui-tree-nodes .angular-ui-tree-nodes {
|
|
25
24
|
padding-left: 20px;
|
|
26
25
|
}
|
|
26
|
+
|
|
27
27
|
.angular-ui-tree-node, .angular-ui-tree-placeholder {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
line-height: 20px;
|
|
28
|
+
position: relative;
|
|
29
|
+
margin: 0;
|
|
30
|
+
padding: 0;
|
|
31
|
+
min-height: 20px;
|
|
32
|
+
line-height: 20px;
|
|
34
33
|
}
|
|
35
34
|
|
|
36
35
|
.angular-ui-tree-hidden {
|
|
@@ -38,7 +37,7 @@
|
|
|
38
37
|
}
|
|
39
38
|
|
|
40
39
|
.angular-ui-tree-placeholder {
|
|
41
|
-
margin:
|
|
40
|
+
margin: 10px;
|
|
42
41
|
padding: 0;
|
|
43
42
|
min-height: 30px;
|
|
44
43
|
}
|
|
@@ -54,10 +53,13 @@
|
|
|
54
53
|
line-height: 20px;
|
|
55
54
|
}
|
|
56
55
|
|
|
57
|
-
|
|
58
56
|
.angular-ui-tree-drag {
|
|
59
57
|
position: absolute;
|
|
60
58
|
pointer-events: none;
|
|
61
59
|
z-index: 999;
|
|
62
|
-
opacity: .8;
|
|
63
|
-
}
|
|
60
|
+
opacity: .8;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.angular-ui-tree-drag .tree-node-content {
|
|
64
|
+
margin-top: 0;
|
|
65
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular UI Tree v2.
|
|
3
|
-
* (c) 2010-
|
|
2
|
+
* @license Angular UI Tree v2.22.5
|
|
3
|
+
* (c) 2010-2017. https://github.com/angular-ui-tree/angular-ui-tree
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
6
6
|
(function () {
|
|
@@ -14,10 +14,11 @@
|
|
|
14
14
|
nodesClass: 'angular-ui-tree-nodes',
|
|
15
15
|
nodeClass: 'angular-ui-tree-node',
|
|
16
16
|
handleClass: 'angular-ui-tree-handle',
|
|
17
|
-
|
|
17
|
+
placeholderClass: 'angular-ui-tree-placeholder',
|
|
18
18
|
dragClass: 'angular-ui-tree-drag',
|
|
19
19
|
dragThreshold: 3,
|
|
20
|
-
|
|
20
|
+
defaultCollapsed: false,
|
|
21
|
+
appendChildOnHover: true
|
|
21
22
|
});
|
|
22
23
|
|
|
23
24
|
})();
|
|
@@ -27,326 +28,166 @@
|
|
|
27
28
|
|
|
28
29
|
angular.module('ui.tree')
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
* @requires ng.$document
|
|
34
|
-
* @requires ng.$window
|
|
35
|
-
*
|
|
36
|
-
* @description
|
|
37
|
-
* angular-ui-tree.
|
|
38
|
-
*/
|
|
39
|
-
.factory('$uiTreeHelper', ['$document', '$window',
|
|
40
|
-
function ($document, $window) {
|
|
41
|
-
return {
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* A hashtable used to storage data of nodes
|
|
45
|
-
* @type {Object}
|
|
46
|
-
*/
|
|
47
|
-
nodesData: {
|
|
48
|
-
},
|
|
49
|
-
|
|
50
|
-
setNodeAttribute: function(scope, attrName, val) {
|
|
51
|
-
var data = this.nodesData[scope.$modelValue.$$hashKey];
|
|
52
|
-
if (!data) {
|
|
53
|
-
data = {};
|
|
54
|
-
this.nodesData[scope.$modelValue.$$hashKey] = data;
|
|
55
|
-
}
|
|
56
|
-
data[attrName] = val;
|
|
57
|
-
},
|
|
58
|
-
|
|
59
|
-
getNodeAttribute: function(scope, attrName) {
|
|
60
|
-
var data = this.nodesData[scope.$modelValue.$$hashKey];
|
|
61
|
-
if (data) {
|
|
62
|
-
return data[attrName];
|
|
63
|
-
}
|
|
64
|
-
return null;
|
|
65
|
-
},
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* @ngdoc method
|
|
69
|
-
* @methodOf ui.tree.service:$nodrag
|
|
70
|
-
* @param {Object} targetElm angular element
|
|
71
|
-
* @return {Bool} check if the node can be dragged.
|
|
72
|
-
*/
|
|
73
|
-
nodrag: function (targetElm) {
|
|
74
|
-
return (typeof targetElm.attr('data-nodrag')) != "undefined";
|
|
75
|
-
},
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* get the event object for touchs
|
|
79
|
-
* @param {[type]} e [description]
|
|
80
|
-
* @return {[type]} [description]
|
|
81
|
-
*/
|
|
82
|
-
eventObj: function(e) {
|
|
83
|
-
var obj = e;
|
|
84
|
-
if (e.targetTouches !== undefined) {
|
|
85
|
-
obj = e.targetTouches.item(0);
|
|
86
|
-
} else if (e.originalEvent !== undefined && e.originalEvent.targetTouches !== undefined) {
|
|
87
|
-
obj = e.originalEvent.targetTouches.item(0);
|
|
88
|
-
}
|
|
89
|
-
return obj;
|
|
90
|
-
},
|
|
91
|
-
|
|
92
|
-
dragInfo: function(node) {
|
|
93
|
-
return {
|
|
94
|
-
source: node,
|
|
95
|
-
sourceInfo: {
|
|
96
|
-
nodeScope: node,
|
|
97
|
-
index: node.index(),
|
|
98
|
-
nodesScope: node.$parentNodesScope
|
|
99
|
-
},
|
|
100
|
-
index: node.index(),
|
|
101
|
-
siblings: node.siblings().slice(0),
|
|
102
|
-
parent: node.$parentNodesScope,
|
|
103
|
-
|
|
104
|
-
moveTo: function(parent, siblings, index) { // Move the node to a new position
|
|
105
|
-
this.parent = parent;
|
|
106
|
-
this.siblings = siblings.slice(0);
|
|
107
|
-
var i = this.siblings.indexOf(this.source); // If source node is in the target nodes
|
|
108
|
-
if (i > -1) {
|
|
109
|
-
this.siblings.splice(i, 1);
|
|
110
|
-
if (this.source.index() < index) {
|
|
111
|
-
index--;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
this.siblings.splice(index, 0, this.source);
|
|
115
|
-
this.index = index;
|
|
116
|
-
},
|
|
117
|
-
|
|
118
|
-
parentNode: function() {
|
|
119
|
-
return this.parent.$nodeScope;
|
|
120
|
-
},
|
|
121
|
-
|
|
122
|
-
prev: function() {
|
|
123
|
-
if (this.index > 0) {
|
|
124
|
-
return this.siblings[this.index - 1];
|
|
125
|
-
}
|
|
126
|
-
return null;
|
|
127
|
-
},
|
|
128
|
-
|
|
129
|
-
next: function() {
|
|
130
|
-
if (this.index < this.siblings.length - 1) {
|
|
131
|
-
return this.siblings[this.index + 1];
|
|
132
|
-
}
|
|
133
|
-
return null;
|
|
134
|
-
},
|
|
135
|
-
|
|
136
|
-
isDirty: function() {
|
|
137
|
-
return this.source.$parentNodesScope != this.parent ||
|
|
138
|
-
this.source.index() != this.index;
|
|
139
|
-
},
|
|
140
|
-
|
|
141
|
-
eventArgs: function(elements, pos) {
|
|
142
|
-
return {
|
|
143
|
-
source: this.sourceInfo,
|
|
144
|
-
dest: {
|
|
145
|
-
index: this.index,
|
|
146
|
-
nodesScope: this.parent
|
|
147
|
-
},
|
|
148
|
-
elements: elements,
|
|
149
|
-
pos: pos
|
|
150
|
-
};
|
|
151
|
-
},
|
|
31
|
+
.controller('TreeHandleController', ['$scope', '$element',
|
|
32
|
+
function ($scope, $element) {
|
|
33
|
+
this.scope = $scope;
|
|
152
34
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
this.parent.insertNode(this.index, nodeData);
|
|
157
|
-
}
|
|
158
|
-
};
|
|
159
|
-
},
|
|
35
|
+
$scope.$element = $element;
|
|
36
|
+
$scope.$nodeScope = null;
|
|
37
|
+
$scope.$type = 'uiTreeHandle';
|
|
160
38
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
* @methodOf ui.tree.service:$helper
|
|
165
|
-
*
|
|
166
|
-
* @description
|
|
167
|
-
* Get the height of an element.
|
|
168
|
-
*
|
|
169
|
-
* @param {Object} element Angular element.
|
|
170
|
-
* @returns {String} Height
|
|
171
|
-
*/
|
|
172
|
-
height: function (element) {
|
|
173
|
-
return element.prop('scrollHeight');
|
|
174
|
-
},
|
|
39
|
+
}
|
|
40
|
+
]);
|
|
41
|
+
})();
|
|
175
42
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
* @name hippo.theme#width
|
|
179
|
-
* @methodOf ui.tree.service:$helper
|
|
180
|
-
*
|
|
181
|
-
* @description
|
|
182
|
-
* Get the width of an element.
|
|
183
|
-
*
|
|
184
|
-
* @param {Object} element Angular element.
|
|
185
|
-
* @returns {String} Width
|
|
186
|
-
*/
|
|
187
|
-
width: function (element) {
|
|
188
|
-
return element.prop('scrollWidth');
|
|
189
|
-
},
|
|
43
|
+
(function () {
|
|
44
|
+
'use strict';
|
|
190
45
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
*
|
|
196
|
-
* @description
|
|
197
|
-
* Get the offset values of an element.
|
|
198
|
-
*
|
|
199
|
-
* @param {Object} element Angular element.
|
|
200
|
-
* @returns {Object} Object with properties width, height, top and left
|
|
201
|
-
*/
|
|
202
|
-
offset: function (element) {
|
|
203
|
-
var boundingClientRect = element[0].getBoundingClientRect();
|
|
46
|
+
angular.module('ui.tree')
|
|
47
|
+
.controller('TreeNodeController', ['$scope', '$element',
|
|
48
|
+
function ($scope, $element) {
|
|
49
|
+
this.scope = $scope;
|
|
204
50
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
51
|
+
$scope.$element = $element;
|
|
52
|
+
$scope.$modelValue = null; // Model value for node;
|
|
53
|
+
$scope.$parentNodeScope = null; // uiTreeNode Scope of parent node;
|
|
54
|
+
$scope.$childNodesScope = null; // uiTreeNodes Scope of child nodes.
|
|
55
|
+
$scope.$parentNodesScope = null; // uiTreeNodes Scope of parent nodes.
|
|
56
|
+
$scope.$treeScope = null; // uiTree scope
|
|
57
|
+
$scope.$handleScope = null; // it's handle scope
|
|
58
|
+
$scope.$type = 'uiTreeNode';
|
|
59
|
+
$scope.$$allowNodeDrop = false;
|
|
60
|
+
$scope.collapsed = false;
|
|
61
|
+
$scope.expandOnHover = false;
|
|
212
62
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
*
|
|
218
|
-
* @description
|
|
219
|
-
* Get the start position of the target element according to the provided event properties.
|
|
220
|
-
*
|
|
221
|
-
* @param {Object} e Event
|
|
222
|
-
* @param {Object} target Target element
|
|
223
|
-
* @returns {Object} Object with properties offsetX, offsetY, startX, startY, nowX and dirX.
|
|
224
|
-
*/
|
|
225
|
-
positionStarted: function (e, target) {
|
|
226
|
-
var pos = {};
|
|
227
|
-
pos.offsetX = e.pageX - this.offset(target).left;
|
|
228
|
-
pos.offsetY = e.pageY - this.offset(target).top;
|
|
229
|
-
pos.startX = pos.lastX = e.pageX;
|
|
230
|
-
pos.startY = pos.lastY = e.pageY;
|
|
231
|
-
pos.nowX = pos.nowY = pos.distX = pos.distY = pos.dirAx = 0;
|
|
232
|
-
pos.dirX = pos.dirY = pos.lastDirX = pos.lastDirY = pos.distAxX = pos.distAxY = 0;
|
|
233
|
-
return pos;
|
|
234
|
-
},
|
|
63
|
+
//Called by uiTreeNode Directive on load.
|
|
64
|
+
$scope.init = function (controllersArr) {
|
|
65
|
+
var treeNodesCtrl = controllersArr[0];
|
|
66
|
+
$scope.$treeScope = controllersArr[1] ? controllersArr[1].scope : null;
|
|
235
67
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
pos.lastX = pos.nowX;
|
|
239
|
-
pos.lastY = pos.nowY;
|
|
68
|
+
//Find the scope of it's parent node.
|
|
69
|
+
$scope.$parentNodeScope = treeNodesCtrl.scope.$nodeScope;
|
|
240
70
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
71
|
+
//modelValue for current node.
|
|
72
|
+
$scope.$modelValue = treeNodesCtrl.scope.$modelValue[$scope.$index];
|
|
73
|
+
$scope.$parentNodesScope = treeNodesCtrl.scope;
|
|
244
74
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
pos.distY = pos.nowY - pos.lastY;
|
|
75
|
+
//Init sub nodes.
|
|
76
|
+
treeNodesCtrl.scope.initSubNode($scope);
|
|
248
77
|
|
|
249
|
-
|
|
250
|
-
pos.lastDirX = pos.dirX;
|
|
251
|
-
pos.lastDirY = pos.dirY;
|
|
78
|
+
$element.on('$destroy', function () {
|
|
252
79
|
|
|
253
|
-
//
|
|
254
|
-
|
|
255
|
-
|
|
80
|
+
//Destroy sub nodes.
|
|
81
|
+
treeNodesCtrl.scope.destroySubNode($scope);
|
|
82
|
+
});
|
|
83
|
+
};
|
|
256
84
|
|
|
257
|
-
|
|
258
|
-
|
|
85
|
+
//Return the index of child node in parent node (nodesScope).
|
|
86
|
+
$scope.index = function () {
|
|
87
|
+
return $scope.$parentNodesScope.$modelValue.indexOf($scope.$modelValue);
|
|
88
|
+
};
|
|
259
89
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
pos.moving = true;
|
|
264
|
-
return;
|
|
265
|
-
}
|
|
90
|
+
$scope.dragEnabled = function () {
|
|
91
|
+
return !($scope.$treeScope && !$scope.$treeScope.dragEnabled);
|
|
92
|
+
};
|
|
266
93
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
pos.distAxY = 0;
|
|
271
|
-
} else {
|
|
272
|
-
pos.distAxX += Math.abs(pos.distX);
|
|
273
|
-
if (pos.dirX !== 0 && pos.dirX !== pos.lastDirX) {
|
|
274
|
-
pos.distAxX = 0;
|
|
275
|
-
}
|
|
94
|
+
$scope.isSibling = function (targetNode) {
|
|
95
|
+
return $scope.$parentNodesScope == targetNode.$parentNodesScope;
|
|
96
|
+
};
|
|
276
97
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
}
|
|
98
|
+
$scope.isChild = function (targetNode) {
|
|
99
|
+
var nodes = $scope.childNodes();
|
|
100
|
+
return nodes && nodes.indexOf(targetNode) > -1;
|
|
101
|
+
};
|
|
282
102
|
|
|
283
|
-
|
|
103
|
+
//TODO(jcarter): This method is on uiTreeHelper already.
|
|
104
|
+
$scope.prev = function () {
|
|
105
|
+
var index = $scope.index();
|
|
106
|
+
if (index > 0) {
|
|
107
|
+
return $scope.siblings()[index - 1];
|
|
284
108
|
}
|
|
109
|
+
return null;
|
|
285
110
|
};
|
|
286
|
-
}
|
|
287
|
-
]);
|
|
288
|
-
|
|
289
|
-
})();
|
|
290
|
-
(function () {
|
|
291
|
-
'use strict';
|
|
292
111
|
|
|
293
|
-
|
|
112
|
+
//Calls childNodes on parent.
|
|
113
|
+
$scope.siblings = function () {
|
|
114
|
+
return $scope.$parentNodesScope.childNodes();
|
|
115
|
+
};
|
|
294
116
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
117
|
+
$scope.childNodesCount = function () {
|
|
118
|
+
return $scope.childNodes() ? $scope.childNodes().length : 0;
|
|
119
|
+
};
|
|
298
120
|
|
|
299
|
-
$scope
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
$scope.$emptyElm = null;
|
|
303
|
-
$scope.$callbacks = null;
|
|
121
|
+
$scope.hasChild = function () {
|
|
122
|
+
return $scope.childNodesCount() > 0;
|
|
123
|
+
};
|
|
304
124
|
|
|
305
|
-
$scope.
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
125
|
+
$scope.childNodes = function () {
|
|
126
|
+
return $scope.$childNodesScope && $scope.$childNodesScope.$modelValue ?
|
|
127
|
+
$scope.$childNodesScope.childNodes() :
|
|
128
|
+
null;
|
|
129
|
+
};
|
|
309
130
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
131
|
+
$scope.accept = function (sourceNode, destIndex) {
|
|
132
|
+
return $scope.$childNodesScope &&
|
|
133
|
+
$scope.$childNodesScope.$modelValue &&
|
|
134
|
+
$scope.$childNodesScope.accept(sourceNode, destIndex);
|
|
314
135
|
};
|
|
315
136
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
$scope.$nodesScope.$element.append(placeElm);
|
|
319
|
-
$scope.$emptyElm.remove();
|
|
137
|
+
$scope.remove = function () {
|
|
138
|
+
return $scope.$parentNodesScope.removeNode($scope);
|
|
320
139
|
};
|
|
321
140
|
|
|
322
|
-
$scope.
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
$element.append($scope.$emptyElm);
|
|
326
|
-
} else {
|
|
327
|
-
$scope.$emptyElm.remove();
|
|
328
|
-
}
|
|
141
|
+
$scope.toggle = function () {
|
|
142
|
+
$scope.collapsed = !$scope.collapsed;
|
|
143
|
+
$scope.$treeScope.$callbacks.toggle($scope.collapsed, $scope);
|
|
329
144
|
};
|
|
330
145
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
for (var i = 0; i < nodes.length; i++) {
|
|
334
|
-
collapsed ? nodes[i].collapse() : nodes[i].expand();
|
|
335
|
-
var subScope = nodes[i].$childNodesScope;
|
|
336
|
-
if (subScope) {
|
|
337
|
-
collapseOrExpand(subScope, collapsed);
|
|
338
|
-
}
|
|
339
|
-
}
|
|
146
|
+
$scope.collapse = function () {
|
|
147
|
+
$scope.collapsed = true;
|
|
340
148
|
};
|
|
341
149
|
|
|
342
|
-
$scope.
|
|
343
|
-
|
|
150
|
+
$scope.expand = function () {
|
|
151
|
+
$scope.collapsed = false;
|
|
344
152
|
};
|
|
345
153
|
|
|
346
|
-
$scope.
|
|
347
|
-
|
|
154
|
+
$scope.depth = function () {
|
|
155
|
+
var parentNode = $scope.$parentNodeScope;
|
|
156
|
+
if (parentNode) {
|
|
157
|
+
return parentNode.depth() + 1;
|
|
158
|
+
}
|
|
159
|
+
return 1;
|
|
348
160
|
};
|
|
349
161
|
|
|
162
|
+
/**
|
|
163
|
+
* Returns the depth of the deepest subtree under this node
|
|
164
|
+
* @param scope a TreeNodesController scope object
|
|
165
|
+
* @returns Depth of all nodes *beneath* this node. If scope belongs to a leaf node, the
|
|
166
|
+
* result is 0 (it has no subtree).
|
|
167
|
+
*/
|
|
168
|
+
function countSubTreeDepth(scope) {
|
|
169
|
+
if (!scope) {
|
|
170
|
+
return 0;
|
|
171
|
+
}
|
|
172
|
+
var thisLevelDepth = 0,
|
|
173
|
+
childNodes = scope.childNodes(),
|
|
174
|
+
childNode,
|
|
175
|
+
childDepth,
|
|
176
|
+
i;
|
|
177
|
+
if (!childNodes || childNodes.length === 0) {
|
|
178
|
+
return 0;
|
|
179
|
+
}
|
|
180
|
+
for (i = childNodes.length - 1; i >= 0 ; i--) {
|
|
181
|
+
childNode = childNodes[i],
|
|
182
|
+
childDepth = 1 + countSubTreeDepth(childNode);
|
|
183
|
+
thisLevelDepth = Math.max(thisLevelDepth, childDepth);
|
|
184
|
+
}
|
|
185
|
+
return thisLevelDepth;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
$scope.maxSubDepth = function () {
|
|
189
|
+
return $scope.$childNodesScope ? countSubTreeDepth($scope.$childNodesScope) : 0;
|
|
190
|
+
};
|
|
350
191
|
}
|
|
351
192
|
]);
|
|
352
193
|
})();
|
|
@@ -356,8 +197,8 @@
|
|
|
356
197
|
|
|
357
198
|
angular.module('ui.tree')
|
|
358
199
|
|
|
359
|
-
.controller('TreeNodesController', ['$scope', '$element',
|
|
360
|
-
function ($scope, $element
|
|
200
|
+
.controller('TreeNodesController', ['$scope', '$element',
|
|
201
|
+
function ($scope, $element) {
|
|
361
202
|
this.scope = $scope;
|
|
362
203
|
|
|
363
204
|
$scope.$element = $element;
|
|
@@ -367,37 +208,44 @@
|
|
|
367
208
|
$scope.$type = 'uiTreeNodes';
|
|
368
209
|
$scope.$nodesMap = {};
|
|
369
210
|
|
|
370
|
-
$scope.
|
|
211
|
+
$scope.nodropEnabled = false;
|
|
371
212
|
$scope.maxDepth = 0;
|
|
213
|
+
$scope.cloneEnabled = false;
|
|
372
214
|
|
|
373
|
-
$scope.initSubNode = function(subNode) {
|
|
215
|
+
$scope.initSubNode = function (subNode) {
|
|
216
|
+
if (!subNode.$modelValue) {
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
374
219
|
$scope.$nodesMap[subNode.$modelValue.$$hashKey] = subNode;
|
|
375
220
|
};
|
|
376
221
|
|
|
377
|
-
$scope.destroySubNode = function(subNode) {
|
|
222
|
+
$scope.destroySubNode = function (subNode) {
|
|
223
|
+
if (!subNode.$modelValue) {
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
378
226
|
$scope.$nodesMap[subNode.$modelValue.$$hashKey] = null;
|
|
379
227
|
};
|
|
380
228
|
|
|
381
|
-
$scope.accept = function(sourceNode, destIndex) {
|
|
229
|
+
$scope.accept = function (sourceNode, destIndex) {
|
|
382
230
|
return $scope.$treeScope.$callbacks.accept(sourceNode, $scope, destIndex);
|
|
383
231
|
};
|
|
384
232
|
|
|
385
|
-
$scope.beforeDrag = function(sourceNode) {
|
|
233
|
+
$scope.beforeDrag = function (sourceNode) {
|
|
386
234
|
return $scope.$treeScope.$callbacks.beforeDrag(sourceNode);
|
|
387
235
|
};
|
|
388
236
|
|
|
389
|
-
$scope.isParent = function(node) {
|
|
237
|
+
$scope.isParent = function (node) {
|
|
390
238
|
return node.$parentNodesScope == $scope;
|
|
391
239
|
};
|
|
392
240
|
|
|
393
|
-
$scope.hasChild = function() {
|
|
241
|
+
$scope.hasChild = function () {
|
|
394
242
|
return $scope.$modelValue.length > 0;
|
|
395
243
|
};
|
|
396
244
|
|
|
397
|
-
$scope.safeApply = function(fn) {
|
|
245
|
+
$scope.safeApply = function (fn) {
|
|
398
246
|
var phase = this.$root.$$phase;
|
|
399
|
-
if(phase == '$apply' || phase == '$digest') {
|
|
400
|
-
if(fn && (typeof(fn) === 'function')) {
|
|
247
|
+
if (phase == '$apply' || phase == '$digest') {
|
|
248
|
+
if (fn && (typeof (fn) === 'function')) {
|
|
401
249
|
fn();
|
|
402
250
|
}
|
|
403
251
|
} else {
|
|
@@ -405,34 +253,36 @@
|
|
|
405
253
|
}
|
|
406
254
|
};
|
|
407
255
|
|
|
408
|
-
|
|
256
|
+
//Called in apply method of UiTreeHelper.dragInfo.
|
|
257
|
+
$scope.removeNode = function (node) {
|
|
409
258
|
var index = $scope.$modelValue.indexOf(node.$modelValue);
|
|
410
259
|
if (index > -1) {
|
|
411
|
-
$scope.safeApply(function() {
|
|
260
|
+
$scope.safeApply(function () {
|
|
412
261
|
$scope.$modelValue.splice(index, 1)[0];
|
|
413
262
|
});
|
|
414
|
-
return node;
|
|
263
|
+
return $scope.$treeScope.$callbacks.removed(node);
|
|
415
264
|
}
|
|
416
265
|
return null;
|
|
417
266
|
};
|
|
418
267
|
|
|
419
|
-
|
|
420
|
-
|
|
268
|
+
//Called in apply method of UiTreeHelper.dragInfo.
|
|
269
|
+
$scope.insertNode = function (index, nodeData) {
|
|
270
|
+
$scope.safeApply(function () {
|
|
421
271
|
$scope.$modelValue.splice(index, 0, nodeData);
|
|
422
272
|
});
|
|
423
273
|
};
|
|
424
274
|
|
|
425
|
-
$scope.childNodes = function() {
|
|
426
|
-
var nodes = [];
|
|
275
|
+
$scope.childNodes = function () {
|
|
276
|
+
var i, nodes = [];
|
|
427
277
|
if ($scope.$modelValue) {
|
|
428
|
-
for (
|
|
278
|
+
for (i = 0; i < $scope.$modelValue.length; i++) {
|
|
429
279
|
nodes.push($scope.$nodesMap[$scope.$modelValue[i].$$hashKey]);
|
|
430
280
|
}
|
|
431
281
|
}
|
|
432
282
|
return nodes;
|
|
433
283
|
};
|
|
434
284
|
|
|
435
|
-
$scope.depth = function() {
|
|
285
|
+
$scope.depth = function () {
|
|
436
286
|
if ($scope.$nodeScope) {
|
|
437
287
|
return $scope.$nodeScope.depth();
|
|
438
288
|
}
|
|
@@ -440,7 +290,7 @@
|
|
|
440
290
|
};
|
|
441
291
|
|
|
442
292
|
// check if depth limit has reached
|
|
443
|
-
$scope.outOfDepth = function(sourceNode) {
|
|
293
|
+
$scope.outOfDepth = function (sourceNode) {
|
|
444
294
|
var maxDepth = $scope.maxDepth || $scope.$treeScope.maxDepth;
|
|
445
295
|
if (maxDepth > 0) {
|
|
446
296
|
return $scope.depth() + sourceNode.maxSubDepth() + 1 > maxDepth;
|
|
@@ -451,339 +301,290 @@
|
|
|
451
301
|
}
|
|
452
302
|
]);
|
|
453
303
|
})();
|
|
304
|
+
|
|
454
305
|
(function () {
|
|
455
306
|
'use strict';
|
|
456
307
|
|
|
457
308
|
angular.module('ui.tree')
|
|
458
309
|
|
|
459
|
-
.controller('
|
|
460
|
-
function ($scope, $element
|
|
310
|
+
.controller('TreeController', ['$scope', '$element',
|
|
311
|
+
function ($scope, $element) {
|
|
461
312
|
this.scope = $scope;
|
|
462
313
|
|
|
463
314
|
$scope.$element = $element;
|
|
464
|
-
$scope.$
|
|
465
|
-
$scope.$
|
|
466
|
-
$scope.$
|
|
467
|
-
$scope.$
|
|
468
|
-
$scope.$treeScope = null; // uiTree scope
|
|
469
|
-
$scope.$handleScope = null; // it's handle scope
|
|
470
|
-
$scope.$type = 'uiTreeNode';
|
|
471
|
-
$scope.$$apply = false; //
|
|
315
|
+
$scope.$nodesScope = null; // root nodes
|
|
316
|
+
$scope.$type = 'uiTree';
|
|
317
|
+
$scope.$emptyElm = null;
|
|
318
|
+
$scope.$callbacks = null;
|
|
472
319
|
|
|
473
|
-
$scope.
|
|
320
|
+
$scope.dragEnabled = true;
|
|
321
|
+
$scope.emptyPlaceholderEnabled = true;
|
|
322
|
+
$scope.maxDepth = 0;
|
|
323
|
+
$scope.dragDelay = 0;
|
|
324
|
+
$scope.cloneEnabled = false;
|
|
325
|
+
$scope.nodropEnabled = false;
|
|
474
326
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
$scope.$
|
|
478
|
-
|
|
479
|
-
// find the scope of it's parent node
|
|
480
|
-
$scope.$parentNodeScope = treeNodesCtrl.scope.$nodeScope;
|
|
481
|
-
// modelValue for current node
|
|
482
|
-
$scope.$modelValue = treeNodesCtrl.scope.$modelValue[$scope.$index];
|
|
483
|
-
$scope.$parentNodesScope = treeNodesCtrl.scope;
|
|
484
|
-
treeNodesCtrl.scope.initSubNode($scope); // init sub nodes
|
|
485
|
-
|
|
486
|
-
$element.on('$destroy', function() {
|
|
487
|
-
treeNodesCtrl.scope.destroySubNode($scope); // destroy sub nodes
|
|
488
|
-
});
|
|
489
|
-
};
|
|
490
|
-
|
|
491
|
-
$scope.index = function() {
|
|
492
|
-
return $scope.$parentNodesScope.$modelValue.indexOf($scope.$modelValue);
|
|
493
|
-
};
|
|
494
|
-
|
|
495
|
-
$scope.dragEnabled = function() {
|
|
496
|
-
return !($scope.$treeScope && !$scope.$treeScope.dragEnabled);
|
|
497
|
-
};
|
|
498
|
-
|
|
499
|
-
$scope.isSibling = function(targetNode) {
|
|
500
|
-
return $scope.$parentNodesScope == targetNode.$parentNodesScope;
|
|
327
|
+
// Check if it's a empty tree
|
|
328
|
+
$scope.isEmpty = function () {
|
|
329
|
+
return ($scope.$nodesScope && $scope.$nodesScope.$modelValue
|
|
330
|
+
&& $scope.$nodesScope.$modelValue.length === 0);
|
|
501
331
|
};
|
|
502
332
|
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
333
|
+
// add placeholder to empty tree
|
|
334
|
+
$scope.place = function (placeElm) {
|
|
335
|
+
$scope.$nodesScope.$element.append(placeElm);
|
|
336
|
+
$scope.$emptyElm.remove();
|
|
506
337
|
};
|
|
507
338
|
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
339
|
+
this.resetEmptyElement = function () {
|
|
340
|
+
if ((!$scope.$nodesScope.$modelValue || $scope.$nodesScope.$modelValue.length === 0) &&
|
|
341
|
+
$scope.emptyPlaceholderEnabled) {
|
|
342
|
+
$element.append($scope.$emptyElm);
|
|
343
|
+
} else {
|
|
344
|
+
$scope.$emptyElm.remove();
|
|
512
345
|
}
|
|
513
|
-
return null;
|
|
514
|
-
};
|
|
515
|
-
|
|
516
|
-
$scope.siblings = function() {
|
|
517
|
-
return $scope.$parentNodesScope.childNodes();
|
|
518
|
-
};
|
|
519
|
-
|
|
520
|
-
$scope.childNodesCount = function() {
|
|
521
|
-
return $scope.childNodes() ? $scope.childNodes().length : 0;
|
|
522
|
-
};
|
|
523
|
-
|
|
524
|
-
$scope.hasChild = function() {
|
|
525
|
-
return $scope.childNodesCount() > 0;
|
|
526
346
|
};
|
|
527
347
|
|
|
528
|
-
$scope.
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
};
|
|
533
|
-
|
|
534
|
-
$scope.accept = function(sourceNode, destIndex) {
|
|
535
|
-
return $scope.$childNodesScope &&
|
|
536
|
-
$scope.$childNodesScope.$modelValue &&
|
|
537
|
-
$scope.$childNodesScope.accept(sourceNode, destIndex);
|
|
538
|
-
};
|
|
348
|
+
$scope.resetEmptyElement = this.resetEmptyElement;
|
|
349
|
+
}
|
|
350
|
+
]);
|
|
351
|
+
})();
|
|
539
352
|
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
$scope.$callbacks.removed(node);
|
|
543
|
-
return node;
|
|
544
|
-
};
|
|
353
|
+
(function () {
|
|
354
|
+
'use strict';
|
|
545
355
|
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
356
|
+
angular.module('ui.tree')
|
|
357
|
+
.directive('uiTree', ['treeConfig', '$window',
|
|
358
|
+
function (treeConfig, $window) {
|
|
359
|
+
return {
|
|
360
|
+
restrict: 'A',
|
|
361
|
+
scope: true,
|
|
362
|
+
controller: 'TreeController',
|
|
363
|
+
link: function (scope, element, attrs, ctrl) {
|
|
364
|
+
var callbacks = {
|
|
365
|
+
accept: null,
|
|
366
|
+
beforeDrag: null
|
|
367
|
+
},
|
|
368
|
+
config = {},
|
|
369
|
+
tdElm,
|
|
370
|
+
$trElm,
|
|
371
|
+
emptyElmColspan;
|
|
372
|
+
|
|
373
|
+
//Adding configured class to uiTree.
|
|
374
|
+
angular.extend(config, treeConfig);
|
|
549
375
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
376
|
+
if (config.treeClass) {
|
|
377
|
+
element.addClass(config.treeClass);
|
|
378
|
+
}
|
|
553
379
|
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
380
|
+
//Determining if uiTree is on a table.
|
|
381
|
+
if (element.prop('tagName').toLowerCase() === 'table') {
|
|
382
|
+
scope.$emptyElm = angular.element($window.document.createElement('tr'));
|
|
383
|
+
$trElm = element.find('tr');
|
|
384
|
+
|
|
385
|
+
//If we can find a tr, then we can use its td children as the empty element colspan.
|
|
386
|
+
if ($trElm.length > 0) {
|
|
387
|
+
emptyElmColspan = angular.element($trElm).children().length;
|
|
388
|
+
} else {
|
|
389
|
+
|
|
390
|
+
//If not, by setting a huge colspan we make sure it takes full width.
|
|
391
|
+
//TODO(jcarter): Check for negative side effects.
|
|
392
|
+
emptyElmColspan = 1000000;
|
|
393
|
+
}
|
|
394
|
+
tdElm = angular.element($window.document.createElement('td'))
|
|
395
|
+
.attr('colspan', emptyElmColspan);
|
|
396
|
+
scope.$emptyElm.append(tdElm);
|
|
397
|
+
} else {
|
|
398
|
+
scope.$emptyElm = angular.element($window.document.createElement('div'));
|
|
399
|
+
}
|
|
557
400
|
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
401
|
+
if (config.emptyTreeClass) {
|
|
402
|
+
scope.$emptyElm.addClass(config.emptyTreeClass);
|
|
403
|
+
}
|
|
561
404
|
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
}
|
|
567
|
-
return 1;
|
|
568
|
-
};
|
|
405
|
+
scope.$watch('$nodesScope.$modelValue.length', function (val) {
|
|
406
|
+
if (!angular.isNumber(val)) {
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
569
409
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
var count = 0;
|
|
573
|
-
var nodes = scope.childNodes();
|
|
574
|
-
for (var i = 0; i < nodes.length; i++) {
|
|
575
|
-
var childNodes = nodes[i].$childNodesScope;
|
|
576
|
-
if (childNodes) {
|
|
577
|
-
count = 1;
|
|
578
|
-
countSubDepth(childNodes);
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
subDepth += count;
|
|
582
|
-
};
|
|
410
|
+
ctrl.resetEmptyElement();
|
|
411
|
+
}, true);
|
|
583
412
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
return subDepth;
|
|
590
|
-
};
|
|
413
|
+
scope.$watch(attrs.dragEnabled, function (val) {
|
|
414
|
+
if ((typeof val) == 'boolean') {
|
|
415
|
+
scope.dragEnabled = val;
|
|
416
|
+
}
|
|
417
|
+
});
|
|
591
418
|
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
419
|
+
scope.$watch(attrs.emptyPlaceholderEnabled, function (val) {
|
|
420
|
+
if ((typeof val) == 'boolean') {
|
|
421
|
+
scope.emptyPlaceholderEnabled = val;
|
|
422
|
+
ctrl.resetEmptyElement();
|
|
423
|
+
}
|
|
424
|
+
});
|
|
595
425
|
|
|
596
|
-
(function () {
|
|
597
|
-
|
|
426
|
+
scope.$watch(attrs.nodropEnabled, function (val) {
|
|
427
|
+
if ((typeof val) == 'boolean') {
|
|
428
|
+
scope.nodropEnabled = val;
|
|
429
|
+
}
|
|
430
|
+
});
|
|
598
431
|
|
|
599
|
-
|
|
432
|
+
scope.$watch(attrs.cloneEnabled, function (val) {
|
|
433
|
+
if ((typeof val) == 'boolean') {
|
|
434
|
+
scope.cloneEnabled = val;
|
|
435
|
+
}
|
|
436
|
+
});
|
|
600
437
|
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
438
|
+
scope.$watch(attrs.maxDepth, function (val) {
|
|
439
|
+
if ((typeof val) == 'number') {
|
|
440
|
+
scope.maxDepth = val;
|
|
441
|
+
}
|
|
442
|
+
});
|
|
604
443
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
444
|
+
scope.$watch(attrs.dragDelay, function (val) {
|
|
445
|
+
if ((typeof val) == 'number') {
|
|
446
|
+
scope.dragDelay = val;
|
|
447
|
+
}
|
|
448
|
+
});
|
|
608
449
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
450
|
+
/**
|
|
451
|
+
* Callback checks if the destination node can accept the dragged node.
|
|
452
|
+
* By default, ui-tree will check that 'data-nodrop-enabled' is not set for the
|
|
453
|
+
* destination ui-tree-nodes, and that the 'max-depth' attribute will not be exceeded
|
|
454
|
+
* if it is set on the ui-tree or ui-tree-nodes.
|
|
455
|
+
* This callback can be overridden, but callers must manually enforce nodrop and max-depth
|
|
456
|
+
* themselves if they need those to be enforced.
|
|
457
|
+
* @param sourceNodeScope Scope of the ui-tree-node being dragged
|
|
458
|
+
* @param destNodesScope Scope of the ui-tree-nodes where the node is hovering
|
|
459
|
+
* @param destIndex Index in the destination nodes array where the source node will drop
|
|
460
|
+
* @returns {boolean} True if the node is permitted to be dropped here
|
|
461
|
+
*/
|
|
462
|
+
callbacks.accept = function (sourceNodeScope, destNodesScope, destIndex) {
|
|
463
|
+
return !(destNodesScope.nodropEnabled || destNodesScope.$treeScope.nodropEnabled || destNodesScope.outOfDepth(sourceNodeScope));
|
|
464
|
+
};
|
|
612
465
|
|
|
613
|
-
|
|
614
|
-
|
|
466
|
+
callbacks.beforeDrag = function (sourceNodeScope) {
|
|
467
|
+
return true;
|
|
468
|
+
};
|
|
615
469
|
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
function(treeConfig, $window) {
|
|
619
|
-
return {
|
|
620
|
-
restrict: 'A',
|
|
621
|
-
scope: true,
|
|
622
|
-
controller: 'TreeController',
|
|
623
|
-
link: function(scope, element, attrs) {
|
|
624
|
-
var callbacks = {
|
|
625
|
-
accept: null,
|
|
626
|
-
beforeDrag: null
|
|
627
|
-
};
|
|
628
|
-
|
|
629
|
-
var config = {};
|
|
630
|
-
angular.extend(config, treeConfig);
|
|
631
|
-
if (config.treeClass) {
|
|
632
|
-
element.addClass(config.treeClass);
|
|
633
|
-
}
|
|
470
|
+
callbacks.expandTimeoutStart = function()
|
|
471
|
+
{
|
|
634
472
|
|
|
635
|
-
|
|
636
|
-
if (config.emptyTreeClass) {
|
|
637
|
-
scope.$emptyElm.addClass(config.emptyTreeClass);
|
|
638
|
-
}
|
|
473
|
+
};
|
|
639
474
|
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
scope.resetEmptyElement();
|
|
643
|
-
}
|
|
644
|
-
}, true);
|
|
475
|
+
callbacks.expandTimeoutCancel = function()
|
|
476
|
+
{
|
|
645
477
|
|
|
646
|
-
|
|
647
|
-
if((typeof val) == "boolean") {
|
|
648
|
-
scope.dragEnabled = val;
|
|
649
|
-
}
|
|
650
|
-
});
|
|
478
|
+
};
|
|
651
479
|
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
scope.emptyPlaceHolderEnabled = val;
|
|
655
|
-
}
|
|
656
|
-
});
|
|
480
|
+
callbacks.expandTimeoutEnd = function()
|
|
481
|
+
{
|
|
657
482
|
|
|
658
|
-
|
|
659
|
-
if((typeof val) == "number") {
|
|
660
|
-
scope.maxDepth = val;
|
|
661
|
-
}
|
|
662
|
-
});
|
|
483
|
+
};
|
|
663
484
|
|
|
664
|
-
|
|
665
|
-
if((typeof val) == "number") {
|
|
666
|
-
scope.dragDelay = val;
|
|
667
|
-
}
|
|
668
|
-
});
|
|
485
|
+
callbacks.removed = function (node) {
|
|
669
486
|
|
|
670
|
-
|
|
671
|
-
// by default, we check the 'data-nodrop' attribute in `ui-tree-nodes`
|
|
672
|
-
// and the 'max-depth' attribute in `ui-tree` or `ui-tree-nodes`.
|
|
673
|
-
// the method can be overrided
|
|
674
|
-
callbacks.accept = function(sourceNodeScope, destNodesScope, destIndex) {
|
|
675
|
-
if (destNodesScope.nodrop || destNodesScope.outOfDepth(sourceNodeScope)) {
|
|
676
|
-
return false;
|
|
677
|
-
}
|
|
678
|
-
return true;
|
|
679
|
-
};
|
|
487
|
+
};
|
|
680
488
|
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
489
|
+
/**
|
|
490
|
+
* Callback is fired when a node is successfully dropped in a new location
|
|
491
|
+
* @param event
|
|
492
|
+
*/
|
|
493
|
+
callbacks.dropped = function (event) {
|
|
684
494
|
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
};
|
|
495
|
+
};
|
|
688
496
|
|
|
689
|
-
|
|
497
|
+
/**
|
|
498
|
+
* Callback is fired each time the user starts dragging a node
|
|
499
|
+
* @param event
|
|
500
|
+
*/
|
|
501
|
+
callbacks.dragStart = function (event) {
|
|
690
502
|
|
|
691
|
-
|
|
503
|
+
};
|
|
692
504
|
|
|
693
|
-
|
|
694
|
-
|
|
505
|
+
/**
|
|
506
|
+
* Callback is fired each time a dragged node is moved with the mouse/touch.
|
|
507
|
+
* @param event
|
|
508
|
+
*/
|
|
509
|
+
callbacks.dragMove = function (event) {
|
|
695
510
|
|
|
696
|
-
|
|
511
|
+
};
|
|
697
512
|
|
|
698
|
-
|
|
513
|
+
/**
|
|
514
|
+
* Callback is fired when the tree exits drag mode. If the user dropped a node, the drop may have been
|
|
515
|
+
* accepted or reverted.
|
|
516
|
+
* @param event
|
|
517
|
+
*/
|
|
518
|
+
callbacks.dragStop = function (event) {
|
|
699
519
|
|
|
700
|
-
|
|
520
|
+
};
|
|
701
521
|
|
|
702
|
-
|
|
522
|
+
/**
|
|
523
|
+
* Callback is fired when a user drops a node (but prior to processing the drop action)
|
|
524
|
+
* beforeDrop can return a Promise, truthy, or falsy (returning nothing is falsy).
|
|
525
|
+
* If it returns falsy, or a resolve Promise, the node move is accepted
|
|
526
|
+
* If it returns truthy, or a rejected Promise, the node move is reverted
|
|
527
|
+
* @param event
|
|
528
|
+
* @returns {Boolean|Promise} Truthy (or rejected Promise) to cancel node move; falsy (or resolved promise)
|
|
529
|
+
*/
|
|
530
|
+
callbacks.beforeDrop = function (event) {
|
|
703
531
|
|
|
704
|
-
|
|
532
|
+
};
|
|
705
533
|
|
|
706
|
-
|
|
534
|
+
/**
|
|
535
|
+
* Callback is fired when a user toggles node (but after processing the toggle action)
|
|
536
|
+
* @param sourceNodeScope
|
|
537
|
+
* @param collapsed
|
|
538
|
+
*/
|
|
539
|
+
callbacks.toggle = function (collapsed, sourceNodeScope) {
|
|
707
540
|
|
|
708
|
-
|
|
541
|
+
};
|
|
709
542
|
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
543
|
+
scope.$watch(attrs.uiTree, function (newVal, oldVal) {
|
|
544
|
+
angular.forEach(newVal, function (value, key) {
|
|
545
|
+
if (callbacks[key]) {
|
|
546
|
+
if (typeof value === 'function') {
|
|
547
|
+
callbacks[key] = value;
|
|
548
|
+
}
|
|
715
549
|
}
|
|
716
|
-
}
|
|
717
|
-
});
|
|
550
|
+
});
|
|
718
551
|
|
|
719
|
-
|
|
720
|
-
|
|
552
|
+
scope.$callbacks = callbacks;
|
|
553
|
+
}, true);
|
|
721
554
|
|
|
722
555
|
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
556
|
+
}
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
]);
|
|
727
560
|
})();
|
|
728
561
|
|
|
729
562
|
(function () {
|
|
730
563
|
'use strict';
|
|
731
564
|
|
|
732
565
|
angular.module('ui.tree')
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
element.addClass(config.nodesClass);
|
|
746
|
-
}
|
|
747
|
-
|
|
748
|
-
var ngModel = controllersArr[0];
|
|
749
|
-
var treeNodeCtrl = controllersArr[1];
|
|
750
|
-
var treeCtrl = controllersArr[2];
|
|
751
|
-
if (treeNodeCtrl) {
|
|
752
|
-
treeNodeCtrl.scope.$childNodesScope = scope;
|
|
753
|
-
scope.$nodeScope = treeNodeCtrl.scope;
|
|
754
|
-
}
|
|
755
|
-
else { // find the root nodes if there is no parent node and have a parent ui-tree
|
|
756
|
-
treeCtrl.scope.$nodesScope = scope;
|
|
757
|
-
}
|
|
758
|
-
scope.$treeScope = treeCtrl.scope;
|
|
759
|
-
|
|
760
|
-
if (ngModel) {
|
|
761
|
-
ngModel.$render = function() {
|
|
762
|
-
if (!ngModel.$modelValue || !angular.isArray(ngModel.$modelValue)) {
|
|
763
|
-
scope.$modelValue = [];
|
|
764
|
-
}
|
|
765
|
-
scope.$modelValue = ngModel.$modelValue;
|
|
766
|
-
};
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
scope.$watch(attrs.maxDepth, function(val) {
|
|
770
|
-
if((typeof val) == "number") {
|
|
771
|
-
scope.maxDepth = val;
|
|
566
|
+
.directive('uiTreeHandle', ['treeConfig',
|
|
567
|
+
function (treeConfig) {
|
|
568
|
+
return {
|
|
569
|
+
require: '^uiTreeNode',
|
|
570
|
+
restrict: 'A',
|
|
571
|
+
scope: true,
|
|
572
|
+
controller: 'TreeHandleController',
|
|
573
|
+
link: function (scope, element, attrs, treeNodeCtrl) {
|
|
574
|
+
var config = {};
|
|
575
|
+
angular.extend(config, treeConfig);
|
|
576
|
+
if (config.handleClass) {
|
|
577
|
+
element.addClass(config.handleClass);
|
|
772
578
|
}
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
}
|
|
784
|
-
};
|
|
785
|
-
}
|
|
786
|
-
]);
|
|
579
|
+
// connect with the tree node.
|
|
580
|
+
if (scope != treeNodeCtrl.scope) {
|
|
581
|
+
scope.$nodeScope = treeNodeCtrl.scope;
|
|
582
|
+
treeNodeCtrl.scope.$handleScope = scope;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
]);
|
|
787
588
|
})();
|
|
788
589
|
|
|
789
590
|
(function () {
|
|
@@ -791,453 +592,1238 @@
|
|
|
791
592
|
|
|
792
593
|
angular.module('ui.tree')
|
|
793
594
|
|
|
794
|
-
.directive('uiTreeNode', ['treeConfig', '
|
|
795
|
-
function (treeConfig,
|
|
595
|
+
.directive('uiTreeNode', ['treeConfig', 'UiTreeHelper', '$window', '$document', '$timeout', '$q',
|
|
596
|
+
function (treeConfig, UiTreeHelper, $window, $document, $timeout, $q) {
|
|
796
597
|
return {
|
|
797
598
|
require: ['^uiTreeNodes', '^uiTree'],
|
|
798
599
|
restrict: 'A',
|
|
799
600
|
controller: 'TreeNodeController',
|
|
800
|
-
link: function(scope, element, attrs, controllersArr) {
|
|
801
|
-
var config = {}
|
|
601
|
+
link: function (scope, element, attrs, controllersArr) {
|
|
602
|
+
var config = {},
|
|
603
|
+
hasTouch = 'ontouchstart' in window,
|
|
604
|
+
firstMoving,
|
|
605
|
+
dragInfo,
|
|
606
|
+
pos,
|
|
607
|
+
placeElm,
|
|
608
|
+
hiddenPlaceElm,
|
|
609
|
+
dragElm,
|
|
610
|
+
scrollContainerElm,
|
|
611
|
+
unhover,
|
|
612
|
+
treeScope = null,
|
|
613
|
+
elements, // As a parameter for callbacks
|
|
614
|
+
dragDelaying = true,
|
|
615
|
+
dragStarted = false,
|
|
616
|
+
dragTimer = null,
|
|
617
|
+
body = document.body,
|
|
618
|
+
html = document.documentElement,
|
|
619
|
+
document_height,
|
|
620
|
+
document_width,
|
|
621
|
+
dragStart,
|
|
622
|
+
tagName,
|
|
623
|
+
dragMove,
|
|
624
|
+
dragEnd,
|
|
625
|
+
dragStartEvent,
|
|
626
|
+
dragMoveEvent,
|
|
627
|
+
dragEndEvent,
|
|
628
|
+
dragCancelEvent,
|
|
629
|
+
dragDelay,
|
|
630
|
+
bindDragStartEvents,
|
|
631
|
+
bindDragMoveEvents,
|
|
632
|
+
unbindDragMoveEvents,
|
|
633
|
+
keydownHandler,
|
|
634
|
+
isHandleChild,
|
|
635
|
+
el,
|
|
636
|
+
isUiTreeRoot,
|
|
637
|
+
treeOfOrigin;
|
|
638
|
+
|
|
639
|
+
//Adding configured class to ui-tree-node.
|
|
802
640
|
angular.extend(config, treeConfig);
|
|
641
|
+
|
|
803
642
|
if (config.nodeClass) {
|
|
804
643
|
element.addClass(config.nodeClass);
|
|
805
644
|
}
|
|
645
|
+
|
|
646
|
+
//Call init function in nodeCtrl, sets parent node and sets up sub nodes.
|
|
806
647
|
scope.init(controllersArr);
|
|
807
648
|
|
|
808
|
-
scope.collapsed =
|
|
649
|
+
scope.collapsed = !!UiTreeHelper.getNodeAttribute(scope, 'collapsed') || treeConfig.defaultCollapsed;
|
|
650
|
+
scope.expandOnHover = !!UiTreeHelper.getNodeAttribute(scope, 'expandOnHover');
|
|
651
|
+
scope.scrollContainer = UiTreeHelper.getNodeAttribute(scope, 'scrollContainer') || attrs.scrollContainer || null;
|
|
652
|
+
scope.sourceOnly = scope.nodropEnabled || scope.$treeScope.nodropEnabled;
|
|
809
653
|
|
|
810
|
-
scope.$watch(attrs.collapsed, function(val) {
|
|
811
|
-
if((typeof val) ==
|
|
654
|
+
scope.$watch(attrs.collapsed, function (val) {
|
|
655
|
+
if ((typeof val) == 'boolean') {
|
|
812
656
|
scope.collapsed = val;
|
|
813
657
|
}
|
|
814
658
|
});
|
|
815
659
|
|
|
816
|
-
|
|
817
|
-
|
|
660
|
+
//Watches to trigger behavior based on actions and settings.
|
|
661
|
+
scope.$watch('collapsed', function (val) {
|
|
662
|
+
UiTreeHelper.setNodeAttribute(scope, 'collapsed', val);
|
|
818
663
|
attrs.$set('collapsed', val);
|
|
819
664
|
});
|
|
820
665
|
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
var dragStart = function(e) {
|
|
836
|
-
if (!hasTouch && (e.button == 2 || e.which == 3)) {
|
|
837
|
-
// disable right click
|
|
838
|
-
return;
|
|
666
|
+
scope.$watch(attrs.expandOnHover, function(val) {
|
|
667
|
+
if ((typeof val) === 'boolean' || (typeof val) === 'number') {
|
|
668
|
+
scope.expandOnHover = val;
|
|
669
|
+
}
|
|
670
|
+
});
|
|
671
|
+
|
|
672
|
+
scope.$watch('expandOnHover', function (val) {
|
|
673
|
+
UiTreeHelper.setNodeAttribute(scope, 'expandOnHover', val);
|
|
674
|
+
attrs.$set('expandOnHover', val);
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
attrs.$observe('scrollContainer', function(val) {
|
|
678
|
+
if ((typeof val) === 'string') {
|
|
679
|
+
scope.scrollContainer = val;
|
|
839
680
|
}
|
|
840
|
-
|
|
681
|
+
});
|
|
682
|
+
|
|
683
|
+
scope.$watch('scrollContainer', function(val) {
|
|
684
|
+
UiTreeHelper.setNodeAttribute(scope, 'scrollContainer', val);
|
|
685
|
+
attrs.$set('scrollContainer', val);
|
|
686
|
+
scrollContainerElm = document.querySelector(val);
|
|
687
|
+
});
|
|
688
|
+
|
|
689
|
+
scope.$on('angular-ui-tree:collapse-all', function () {
|
|
690
|
+
scope.collapsed = true;
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
scope.$on('angular-ui-tree:expand-all', function () {
|
|
694
|
+
scope.collapsed = false;
|
|
695
|
+
});
|
|
696
|
+
|
|
697
|
+
/**
|
|
698
|
+
* Called when the user has grabbed a node and started dragging it.
|
|
699
|
+
*
|
|
700
|
+
* @param {MouseEvent} e event that is triggered by DOM.
|
|
701
|
+
* @return undefined?
|
|
702
|
+
*/
|
|
703
|
+
dragStart = function (e) {
|
|
704
|
+
|
|
705
|
+
//Disable right click.
|
|
706
|
+
if (!hasTouch && (e.button === 2 || e.which === 3)) {
|
|
841
707
|
return;
|
|
842
708
|
}
|
|
843
709
|
|
|
844
|
-
//
|
|
845
|
-
|
|
846
|
-
var eventScope = eventElm.scope();
|
|
847
|
-
if (!eventScope || !eventScope.$type) {
|
|
710
|
+
//Event has already fired in other scope.
|
|
711
|
+
if (e.uiTreeDragging || (e.originalEvent && e.originalEvent.uiTreeDragging)) {
|
|
848
712
|
return;
|
|
849
713
|
}
|
|
850
|
-
|
|
851
|
-
|
|
714
|
+
|
|
715
|
+
//The node being dragged.
|
|
716
|
+
var eventElm = angular.element(e.target),
|
|
717
|
+
isHandleChild,
|
|
718
|
+
cloneElm,
|
|
719
|
+
eventElmTagName,
|
|
720
|
+
tagName,
|
|
721
|
+
eventObj,
|
|
722
|
+
tdElm,
|
|
723
|
+
hStyle,
|
|
724
|
+
isTreeNode,
|
|
725
|
+
isTreeNodeHandle;
|
|
726
|
+
|
|
727
|
+
//If the target element is a child element of a ui-tree-handle,
|
|
728
|
+
// use the containing handle element as target element.
|
|
729
|
+
isHandleChild = UiTreeHelper.treeNodeHandlerContainerOfElement(eventElm);
|
|
730
|
+
if (isHandleChild) {
|
|
731
|
+
eventElm = angular.element(isHandleChild);
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
cloneElm = element.clone();
|
|
735
|
+
isTreeNode = UiTreeHelper.elementIsTreeNode(eventElm);
|
|
736
|
+
isTreeNodeHandle = UiTreeHelper.elementIsTreeNodeHandle(eventElm);
|
|
737
|
+
|
|
738
|
+
//If we are not triggering mousedown on our uiTree or any of it's parts, return.
|
|
739
|
+
if (!isTreeNode && !isTreeNodeHandle) {
|
|
852
740
|
return;
|
|
853
741
|
}
|
|
854
|
-
|
|
855
|
-
|
|
742
|
+
|
|
743
|
+
//If we are not triggering mousedown on our uiTree or any of it's parts, return.
|
|
744
|
+
if (isTreeNode && UiTreeHelper.elementContainsTreeNodeHandler(eventElm)) {
|
|
856
745
|
return;
|
|
857
746
|
}
|
|
858
747
|
|
|
859
|
-
|
|
748
|
+
//Dragging not allowed on inputs or buttons.
|
|
749
|
+
eventElmTagName = eventElm.prop('tagName').toLowerCase();
|
|
860
750
|
if (eventElmTagName == 'input' ||
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
751
|
+
eventElmTagName == 'textarea' ||
|
|
752
|
+
eventElmTagName == 'button' ||
|
|
753
|
+
eventElmTagName == 'select') {
|
|
864
754
|
return;
|
|
865
755
|
}
|
|
866
756
|
|
|
867
|
-
//
|
|
868
|
-
|
|
869
|
-
|
|
757
|
+
//Check if it or it's parents has a 'data-nodrag' attribute
|
|
758
|
+
el = angular.element(e.target);
|
|
759
|
+
isUiTreeRoot = el[0].attributes['ui-tree'];
|
|
760
|
+
while (el && el[0] && el[0] !== element && !isUiTreeRoot) {
|
|
761
|
+
|
|
762
|
+
//Checking that I can access attributes.
|
|
763
|
+
if (el[0].attributes) {
|
|
764
|
+
isUiTreeRoot = el[0].attributes['ui-tree'];
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
//If the node mark as `nodrag`, DONOT drag it.
|
|
768
|
+
if (UiTreeHelper.nodrag(el)) {
|
|
870
769
|
return;
|
|
871
770
|
}
|
|
872
|
-
|
|
771
|
+
el = el.parent();
|
|
873
772
|
}
|
|
874
773
|
|
|
875
|
-
|
|
774
|
+
//If users beforeDrag calback returns falsey, do not initiate.
|
|
775
|
+
if (!scope.beforeDrag(scope)) {
|
|
876
776
|
return;
|
|
877
777
|
}
|
|
878
778
|
|
|
879
|
-
|
|
779
|
+
//Set property checked at start of function to prevent running logic again.
|
|
780
|
+
e.uiTreeDragging = true;
|
|
880
781
|
if (e.originalEvent) {
|
|
881
782
|
e.originalEvent.uiTreeDragging = true;
|
|
882
783
|
}
|
|
883
784
|
e.preventDefault();
|
|
884
|
-
var eventObj = $uiTreeHelper.eventObj(e);
|
|
885
785
|
|
|
786
|
+
//Get original event if TouchEvent.
|
|
787
|
+
eventObj = UiTreeHelper.eventObj(e);
|
|
788
|
+
|
|
789
|
+
//Set boolean used to specify beginning of move.
|
|
886
790
|
firstMoving = true;
|
|
887
|
-
dragInfo = $uiTreeHelper.dragInfo(scope);
|
|
888
791
|
|
|
889
|
-
|
|
792
|
+
//Setting drag info properties and methods in scope of node being moved.
|
|
793
|
+
dragInfo = UiTreeHelper.dragInfo(scope);
|
|
794
|
+
|
|
795
|
+
//Setting original tree to adjust horizontal behavior in drag move.
|
|
796
|
+
treeOfOrigin = dragInfo.source.$treeScope.$id;
|
|
797
|
+
|
|
798
|
+
//Determine tage name of element ui-tree-node is on.
|
|
799
|
+
tagName = element.prop('tagName');
|
|
800
|
+
|
|
890
801
|
if (tagName.toLowerCase() === 'tr') {
|
|
802
|
+
|
|
803
|
+
//Create a new table column as placeholder.
|
|
891
804
|
placeElm = angular.element($window.document.createElement(tagName));
|
|
892
|
-
|
|
893
|
-
|
|
805
|
+
|
|
806
|
+
//Create a column placeholder and set colspan to whole row length.
|
|
807
|
+
tdElm = angular.element($window.document.createElement('td'))
|
|
808
|
+
.addClass(config.placeholderClass)
|
|
809
|
+
.attr('colspan', element[0].children.length);
|
|
894
810
|
placeElm.append(tdElm);
|
|
895
811
|
} else {
|
|
812
|
+
|
|
813
|
+
//If not a table just duplicate element and add placeholder class.
|
|
896
814
|
placeElm = angular.element($window.document.createElement(tagName))
|
|
897
|
-
|
|
815
|
+
.addClass(config.placeholderClass);
|
|
898
816
|
}
|
|
817
|
+
|
|
818
|
+
//Create a hidden placeholder and add class from config.
|
|
899
819
|
hiddenPlaceElm = angular.element($window.document.createElement(tagName));
|
|
900
820
|
if (config.hiddenClass) {
|
|
901
821
|
hiddenPlaceElm.addClass(config.hiddenClass);
|
|
902
822
|
}
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
823
|
+
|
|
824
|
+
//Getting starting position of element being moved.
|
|
825
|
+
pos = UiTreeHelper.positionStarted(eventObj, element);
|
|
826
|
+
placeElm.css('height', element.prop('offsetHeight') + 'px');
|
|
827
|
+
|
|
828
|
+
//Creating drag element to represent node.
|
|
906
829
|
dragElm = angular.element($window.document.createElement(scope.$parentNodesScope.$element.prop('tagName')))
|
|
907
|
-
|
|
908
|
-
dragElm.css('width',
|
|
830
|
+
.addClass(scope.$parentNodesScope.$element.attr('class')).addClass(config.dragClass);
|
|
831
|
+
dragElm.css('width', UiTreeHelper.width(element) + 'px');
|
|
909
832
|
dragElm.css('z-index', 9999);
|
|
910
833
|
|
|
911
|
-
//
|
|
912
|
-
|
|
834
|
+
//Prevents cursor to change rapidly in Opera 12.16 and IE when dragging an element.
|
|
835
|
+
hStyle = (element[0].querySelector('.angular-ui-tree-handle') || element[0]).currentStyle;
|
|
913
836
|
if (hStyle) {
|
|
914
837
|
document.body.setAttribute('ui-tree-cursor', $document.find('body').css('cursor') || '');
|
|
915
838
|
$document.find('body').css({'cursor': hStyle.cursor + '!important'});
|
|
916
839
|
}
|
|
917
840
|
|
|
918
|
-
|
|
919
|
-
scope
|
|
920
|
-
|
|
841
|
+
//If tree is sourceOnly (noDragDrop) don't show placeholder when moving about it.
|
|
842
|
+
if (scope.sourceOnly) {
|
|
843
|
+
placeElm.css('display', 'none');
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
//Insert placeholder.
|
|
847
|
+
element.after(placeElm);
|
|
848
|
+
element.after(hiddenPlaceElm);
|
|
849
|
+
if (dragInfo.isClone() && scope.sourceOnly) {
|
|
850
|
+
dragElm.append(cloneElm);
|
|
851
|
+
} else {
|
|
852
|
+
dragElm.append(element);
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
//Create drag element.
|
|
921
856
|
$document.find('body').append(dragElm);
|
|
857
|
+
|
|
858
|
+
//Set drag elements position on screen.
|
|
922
859
|
dragElm.css({
|
|
923
|
-
'left'
|
|
924
|
-
'top'
|
|
860
|
+
'left': eventObj.pageX - pos.offsetX + 'px',
|
|
861
|
+
'top': eventObj.pageY - pos.offsetY + 'px'
|
|
925
862
|
});
|
|
926
863
|
elements = {
|
|
927
864
|
placeholder: placeElm,
|
|
928
865
|
dragging: dragElm
|
|
929
866
|
};
|
|
930
867
|
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
868
|
+
//Create all drag/move bindings.
|
|
869
|
+
bindDragMoveEvents();
|
|
870
|
+
|
|
871
|
+
//Fire dragStart callback.
|
|
872
|
+
scope.$apply(function () {
|
|
873
|
+
scope.$treeScope.$callbacks.dragStart(dragInfo.eventArgs(elements, pos));
|
|
874
|
+
});
|
|
937
875
|
|
|
876
|
+
//Get bounds of document.
|
|
938
877
|
document_height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight);
|
|
939
878
|
document_width = Math.max(body.scrollWidth, body.offsetWidth, html.clientWidth, html.scrollWidth, html.offsetWidth);
|
|
940
879
|
};
|
|
941
880
|
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
881
|
+
dragMove = function (e) {
|
|
882
|
+
var eventObj = UiTreeHelper.eventObj(e),
|
|
883
|
+
prev,
|
|
884
|
+
next,
|
|
885
|
+
leftElmPos,
|
|
886
|
+
topElmPos,
|
|
887
|
+
top_scroll,
|
|
888
|
+
bottom_scroll,
|
|
889
|
+
scrollContainerElmRect,
|
|
890
|
+
target,
|
|
891
|
+
targetX,
|
|
892
|
+
targetY,
|
|
893
|
+
displayElm,
|
|
894
|
+
targetNode,
|
|
895
|
+
targetElm,
|
|
896
|
+
isEmpty,
|
|
897
|
+
scrollDownBy,
|
|
898
|
+
scrollUpBy,
|
|
899
|
+
targetOffset,
|
|
900
|
+
targetBefore,
|
|
901
|
+
moveWithinTree,
|
|
902
|
+
targetBeforeBuffer,
|
|
903
|
+
targetHeight,
|
|
904
|
+
targetChildElm,
|
|
905
|
+
targetChildHeight;
|
|
906
|
+
|
|
907
|
+
//If check ensures that drag element was created.
|
|
956
908
|
if (dragElm) {
|
|
957
909
|
e.preventDefault();
|
|
958
910
|
|
|
911
|
+
//Deselect anything (text, etc.) that was selected when move began.
|
|
959
912
|
if ($window.getSelection) {
|
|
960
913
|
$window.getSelection().removeAllRanges();
|
|
961
914
|
} else if ($window.document.selection) {
|
|
962
915
|
$window.document.selection.empty();
|
|
963
916
|
}
|
|
964
917
|
|
|
918
|
+
//Get top left positioning of element being moved.
|
|
965
919
|
leftElmPos = eventObj.pageX - pos.offsetX;
|
|
966
920
|
topElmPos = eventObj.pageY - pos.offsetY;
|
|
967
921
|
|
|
968
|
-
//dragElm can't leave the screen on the left
|
|
969
|
-
if(leftElmPos < 0){
|
|
922
|
+
//dragElm can't leave the screen on the left.
|
|
923
|
+
if (leftElmPos < 0) {
|
|
970
924
|
leftElmPos = 0;
|
|
971
925
|
}
|
|
972
926
|
|
|
973
|
-
//dragElm can't leave the screen on the top
|
|
974
|
-
if(topElmPos < 0){
|
|
927
|
+
//dragElm can't leave the screen on the top.
|
|
928
|
+
if (topElmPos < 0) {
|
|
975
929
|
topElmPos = 0;
|
|
976
930
|
}
|
|
977
931
|
|
|
978
|
-
//dragElm can't leave the screen on the bottom
|
|
979
|
-
if ((topElmPos + 10) > document_height){
|
|
932
|
+
//dragElm can't leave the screen on the bottom.
|
|
933
|
+
if ((topElmPos + 10) > document_height) {
|
|
980
934
|
topElmPos = document_height - 10;
|
|
981
935
|
}
|
|
982
936
|
|
|
983
|
-
//dragElm can't leave the screen on the right
|
|
984
|
-
if((leftElmPos + 10) > document_width) {
|
|
937
|
+
//dragElm can't leave the screen on the right.
|
|
938
|
+
if ((leftElmPos + 10) > document_width) {
|
|
985
939
|
leftElmPos = document_width - 10;
|
|
986
940
|
}
|
|
987
941
|
|
|
942
|
+
//Updating element being moved css.
|
|
988
943
|
dragElm.css({
|
|
989
944
|
'left': leftElmPos + 'px',
|
|
990
945
|
'top': topElmPos + 'px'
|
|
991
946
|
});
|
|
992
947
|
|
|
993
|
-
|
|
994
|
-
|
|
948
|
+
if (scrollContainerElm) {
|
|
949
|
+
//Getting position to top and bottom of container element.
|
|
950
|
+
scrollContainerElmRect = scrollContainerElm.getBoundingClientRect();
|
|
951
|
+
top_scroll = scrollContainerElm.scrollTop;
|
|
952
|
+
bottom_scroll = top_scroll + scrollContainerElm.clientHeight;
|
|
995
953
|
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
954
|
+
//To scroll down if cursor y-position is greater than the bottom position of the container vertical scroll
|
|
955
|
+
if (scrollContainerElmRect.bottom < eventObj.clientY && bottom_scroll < scrollContainerElm.scrollHeight) {
|
|
956
|
+
scrollDownBy = Math.min(scrollContainerElm.scrollHeight - bottom_scroll, 10);
|
|
957
|
+
scrollContainerElm.scrollTop += scrollDownBy;
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
//To scroll top if cursor y-position is less than the top position of the container vertical scroll
|
|
961
|
+
if (scrollContainerElmRect.top > eventObj.clientY && top_scroll > 0) {
|
|
962
|
+
scrollUpBy = Math.min(top_scroll, 10);
|
|
963
|
+
scrollContainerElm.scrollTop -= scrollUpBy;
|
|
964
|
+
}
|
|
965
|
+
} else {
|
|
966
|
+
//Getting position to top and bottom of page.
|
|
967
|
+
top_scroll = window.pageYOffset || $window.document.documentElement.scrollTop;
|
|
968
|
+
bottom_scroll = top_scroll + (window.innerHeight || $window.document.clientHeight || $window.document.clientHeight);
|
|
969
|
+
|
|
970
|
+
//To scroll down if cursor y-position is greater than the bottom position of the window vertical scroll
|
|
971
|
+
if (bottom_scroll < eventObj.pageY && bottom_scroll < document_height) {
|
|
972
|
+
scrollDownBy = Math.min(document_height - bottom_scroll, 10);
|
|
973
|
+
window.scrollBy(0, scrollDownBy);
|
|
974
|
+
}
|
|
1000
975
|
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
976
|
+
//To scroll top if cursor y-position is less than the top position of the window vertical scroll
|
|
977
|
+
if (top_scroll > eventObj.pageY) {
|
|
978
|
+
scrollUpBy = Math.min(top_scroll, 10);
|
|
979
|
+
window.scrollBy(0, -scrollUpBy);
|
|
980
|
+
}
|
|
1004
981
|
}
|
|
1005
982
|
|
|
1006
|
-
|
|
983
|
+
//Calling service to update position coordinates based on move.
|
|
984
|
+
UiTreeHelper.positionMoved(e, pos, firstMoving);
|
|
1007
985
|
if (firstMoving) {
|
|
1008
986
|
firstMoving = false;
|
|
1009
987
|
return;
|
|
1010
988
|
}
|
|
1011
989
|
|
|
1012
|
-
//
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
if (pos.distX > 0) {
|
|
1018
|
-
prev = dragInfo.prev();
|
|
1019
|
-
if (prev && !prev.collapsed
|
|
1020
|
-
&& prev.accept(scope, prev.childNodesCount())) {
|
|
1021
|
-
prev.$childNodesScope.$element.append(placeElm);
|
|
1022
|
-
dragInfo.moveTo(prev.$childNodesScope, prev.childNodes(), prev.childNodesCount());
|
|
1023
|
-
}
|
|
1024
|
-
}
|
|
1025
|
-
|
|
1026
|
-
// decrease horizontal level
|
|
1027
|
-
if (pos.distX < 0) {
|
|
1028
|
-
// we can't decrease a level if an item preceeds the current one
|
|
1029
|
-
var next = dragInfo.next();
|
|
1030
|
-
if (!next) {
|
|
1031
|
-
var target = dragInfo.parentNode(); // As a sibling of it's parent node
|
|
1032
|
-
if (target
|
|
1033
|
-
&& target.$parentNodesScope.accept(scope, target.index() + 1)) {
|
|
1034
|
-
target.$element.after(placeElm);
|
|
1035
|
-
dragInfo.moveTo(target.$parentNodesScope, target.siblings(), target.index() + 1);
|
|
1036
|
-
}
|
|
1037
|
-
}
|
|
1038
|
-
}
|
|
1039
|
-
}
|
|
990
|
+
//Setting X point for elementFromPoint.
|
|
991
|
+
targetX = eventObj.pageX - ($window.pageXOffset ||
|
|
992
|
+
$window.document.body.scrollLeft ||
|
|
993
|
+
$window.document.documentElement.scrollLeft) -
|
|
994
|
+
($window.document.documentElement.clientLeft || 0);
|
|
1040
995
|
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
var targetY = eventObj.pageY - (window.pageYOffset || $window.document.documentElement.scrollTop);
|
|
996
|
+
targetY = eventObj.pageY - ($window.pageYOffset ||
|
|
997
|
+
$window.document.body.scrollTop ||
|
|
998
|
+
$window.document.documentElement.scrollTop) -
|
|
999
|
+
($window.document.documentElement.clientTop || 0);
|
|
1046
1000
|
|
|
1047
|
-
//
|
|
1001
|
+
//Select the drag target. Because IE does not support CSS 'pointer-events: none', it will always
|
|
1048
1002
|
// pick the drag element itself as the target. To prevent this, we hide the drag element while
|
|
1049
1003
|
// selecting the target.
|
|
1050
|
-
var displayElm;
|
|
1051
1004
|
if (angular.isFunction(dragElm.hide)) {
|
|
1052
1005
|
dragElm.hide();
|
|
1053
|
-
}else{
|
|
1006
|
+
} else {
|
|
1054
1007
|
displayElm = dragElm[0].style.display;
|
|
1055
|
-
dragElm[0].style.display =
|
|
1008
|
+
dragElm[0].style.display = 'none';
|
|
1056
1009
|
}
|
|
1057
1010
|
|
|
1058
|
-
//
|
|
1011
|
+
//When using elementFromPoint() inside an iframe, you have to call
|
|
1059
1012
|
// elementFromPoint() twice to make sure IE8 returns the correct value
|
|
1013
|
+
//MDN: The elementFromPoint() method of the Document interface returns the topmost element at the specified coordinates.
|
|
1060
1014
|
$window.document.elementFromPoint(targetX, targetY);
|
|
1061
1015
|
|
|
1062
|
-
|
|
1016
|
+
//Set target element (element in specified x/y coordinates).
|
|
1017
|
+
targetElm = angular.element($window.document.elementFromPoint(targetX, targetY));
|
|
1018
|
+
|
|
1019
|
+
//If the target element is a child element of a ui-tree-handle,
|
|
1020
|
+
// use the containing handle element as target element
|
|
1021
|
+
isHandleChild = UiTreeHelper.treeNodeHandlerContainerOfElement(targetElm);
|
|
1022
|
+
if (isHandleChild) {
|
|
1023
|
+
targetElm = angular.element(isHandleChild);
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1063
1026
|
if (angular.isFunction(dragElm.show)) {
|
|
1064
1027
|
dragElm.show();
|
|
1065
|
-
}else{
|
|
1028
|
+
} else {
|
|
1066
1029
|
dragElm[0].style.display = displayElm;
|
|
1067
1030
|
}
|
|
1068
1031
|
|
|
1069
|
-
//
|
|
1070
|
-
if (
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
targetNode = targetElm.
|
|
1074
|
-
|
|
1032
|
+
//Assigning scope to target you are moving draggable over.
|
|
1033
|
+
if (UiTreeHelper.elementIsTree(targetElm)) {
|
|
1034
|
+
targetNode = targetElm.controller('uiTree').scope;
|
|
1035
|
+
} else if (UiTreeHelper.elementIsTreeNodeHandle(targetElm)) {
|
|
1036
|
+
targetNode = targetElm.controller('uiTreeHandle').scope;
|
|
1037
|
+
} else if (UiTreeHelper.elementIsTreeNode(targetElm)) {
|
|
1038
|
+
targetNode = targetElm.controller('uiTreeNode').scope;
|
|
1039
|
+
} else if (UiTreeHelper.elementIsTreeNodes(targetElm)) {
|
|
1040
|
+
targetNode = targetElm.controller('uiTreeNodes').scope;
|
|
1041
|
+
} else if (UiTreeHelper.elementIsPlaceholder(targetElm)) {
|
|
1042
|
+
targetNode = targetElm.controller('uiTreeNodes').scope;
|
|
1043
|
+
} else if (targetElm.controller('uiTreeNode')) {
|
|
1044
|
+
//Is a child element of a node.
|
|
1045
|
+
targetNode = targetElm.controller('uiTreeNode').scope;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
moveWithinTree = (targetNode && targetNode.$treeScope && targetNode.$treeScope.$id && targetNode.$treeScope.$id === treeOfOrigin);
|
|
1049
|
+
|
|
1050
|
+
/* (jcarter) Notes to developers:
|
|
1051
|
+
* pos.dirAx is either 0 or 1
|
|
1052
|
+
* 1 means horizontal movement is happening
|
|
1053
|
+
* 0 means vertical movement is happening
|
|
1054
|
+
*/
|
|
1055
|
+
|
|
1056
|
+
// Move nodes up and down in nesting level.
|
|
1057
|
+
if (moveWithinTree && pos.dirAx) {
|
|
1058
|
+
|
|
1059
|
+
// increase horizontal level if previous sibling exists and is not collapsed
|
|
1060
|
+
// example 1.1.1 becomes 1.2
|
|
1061
|
+
if (pos.distX > 0) {
|
|
1062
|
+
prev = dragInfo.prev();
|
|
1063
|
+
if (prev && !prev.collapsed
|
|
1064
|
+
&& prev.accept(scope, prev.childNodesCount())) {
|
|
1065
|
+
prev.$childNodesScope.$element.append(placeElm);
|
|
1066
|
+
dragInfo.moveTo(prev.$childNodesScope, prev.childNodes(), prev.childNodesCount());
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
// decrease horizontal level
|
|
1071
|
+
// example 1.2 become 1.1.1
|
|
1072
|
+
if (pos.distX < 0) {
|
|
1073
|
+
// we can't decrease a level if an item preceeds the current one
|
|
1074
|
+
next = dragInfo.next();
|
|
1075
|
+
if (!next) {
|
|
1076
|
+
target = dragInfo.parentNode(); // As a sibling of it's parent node
|
|
1077
|
+
if (target
|
|
1078
|
+
&& target.$parentNodesScope.accept(scope, target.index() + 1)) {
|
|
1079
|
+
target.$element.after(placeElm);
|
|
1080
|
+
dragInfo.moveTo(target.$parentNodesScope, target.siblings(), target.index() + 1);
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
} else { //Either in origin tree and moving horizontally OR you are moving within a new tree.
|
|
1085
|
+
|
|
1086
|
+
//Check it's new position.
|
|
1087
|
+
isEmpty = false;
|
|
1088
|
+
|
|
1089
|
+
//Exit if target is not a uiTree or child of one.
|
|
1075
1090
|
if (!targetNode) {
|
|
1076
1091
|
return;
|
|
1077
1092
|
}
|
|
1078
|
-
|
|
1079
|
-
|
|
1093
|
+
|
|
1094
|
+
//Show the placeholder if it was hidden for nodrop-enabled and this is a new tree
|
|
1095
|
+
if (targetNode.$treeScope && !targetNode.$parent.nodropEnabled && !targetNode.$treeScope.nodropEnabled) {
|
|
1096
|
+
placeElm.css('display', '');
|
|
1080
1097
|
}
|
|
1081
|
-
|
|
1098
|
+
|
|
1099
|
+
//Set whether target tree is empty or not.
|
|
1100
|
+
if (targetNode.$type === 'uiTree' && targetNode.dragEnabled) {
|
|
1101
|
+
isEmpty = targetNode.isEmpty();
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
//If target is a handle set new target to handle's node.
|
|
1105
|
+
if (targetNode.$type === 'uiTreeHandle') {
|
|
1082
1106
|
targetNode = targetNode.$nodeScope;
|
|
1083
1107
|
}
|
|
1084
|
-
|
|
1085
|
-
|
|
1108
|
+
|
|
1109
|
+
//Check if it is a uiTreeNode or it's an empty tree.
|
|
1110
|
+
if (targetNode.$type !== 'uiTreeNode' && !isEmpty) {
|
|
1111
|
+
|
|
1112
|
+
// Allow node to return to its original position if no longer hovering over target
|
|
1113
|
+
if (config.appendChildOnHover) {
|
|
1114
|
+
next = dragInfo.next();
|
|
1115
|
+
if (!next && unhover) {
|
|
1116
|
+
target = dragInfo.parentNode();
|
|
1117
|
+
target.$element.after(placeElm);
|
|
1118
|
+
dragInfo.moveTo(target.$parentNodesScope, target.siblings(), target.index() + 1);
|
|
1119
|
+
unhover = false;
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1086
1122
|
return;
|
|
1087
1123
|
}
|
|
1088
1124
|
|
|
1089
|
-
//
|
|
1125
|
+
//If placeholder move from empty tree, reset it.
|
|
1090
1126
|
if (treeScope && placeElm.parent()[0] != treeScope.$element[0]) {
|
|
1091
1127
|
treeScope.resetEmptyElement();
|
|
1092
1128
|
treeScope = null;
|
|
1093
1129
|
}
|
|
1094
1130
|
|
|
1095
|
-
|
|
1131
|
+
//It's an empty tree
|
|
1132
|
+
if (isEmpty) {
|
|
1096
1133
|
treeScope = targetNode;
|
|
1097
1134
|
if (targetNode.$nodesScope.accept(scope, 0)) {
|
|
1098
1135
|
targetNode.place(placeElm);
|
|
1099
1136
|
dragInfo.moveTo(targetNode.$nodesScope, targetNode.$nodesScope.childNodes(), 0);
|
|
1100
1137
|
}
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1138
|
+
//Not empty and drag enabled.
|
|
1139
|
+
} else if (targetNode.dragEnabled()) {
|
|
1140
|
+
|
|
1141
|
+
//Setting/Resetting data for exanding on hover.
|
|
1142
|
+
if (angular.isDefined(scope.expandTimeoutOn) && scope.expandTimeoutOn !== targetNode.id) {
|
|
1143
|
+
$timeout.cancel(scope.expandTimeout);
|
|
1144
|
+
delete scope.expandTimeout;
|
|
1145
|
+
delete scope.expandTimeoutOn;
|
|
1146
|
+
|
|
1147
|
+
scope.$callbacks.expandTimeoutCancel();
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
//Determining if expansion is needed.
|
|
1151
|
+
if (targetNode.collapsed) {
|
|
1152
|
+
if (scope.expandOnHover === true || (angular.isNumber(scope.expandOnHover) && scope.expandOnHover === 0)) {
|
|
1153
|
+
targetNode.collapsed = false;
|
|
1154
|
+
targetNode.$treeScope.$callbacks.toggle(false, targetNode);
|
|
1155
|
+
} else if (scope.expandOnHover !== false && angular.isNumber(scope.expandOnHover) && scope.expandOnHover > 0) {
|
|
1156
|
+
|
|
1157
|
+
//Triggering expansion.
|
|
1158
|
+
if (angular.isUndefined(scope.expandTimeoutOn)) {
|
|
1159
|
+
scope.expandTimeoutOn = targetNode.$id;
|
|
1160
|
+
|
|
1161
|
+
scope.$callbacks.expandTimeoutStart();
|
|
1162
|
+
scope.expandTimeout = $timeout(function()
|
|
1163
|
+
{
|
|
1164
|
+
scope.$callbacks.expandTimeoutEnd();
|
|
1165
|
+
targetNode.collapsed = false;
|
|
1166
|
+
targetNode.$treeScope.$callbacks.toggle(false, targetNode);
|
|
1167
|
+
}, scope.expandOnHover);
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
//Get the element of ui-tree-node
|
|
1173
|
+
targetElm = targetNode.$element;
|
|
1174
|
+
targetOffset = UiTreeHelper.offset(targetElm);
|
|
1175
|
+
targetHeight = UiTreeHelper.height(targetElm);
|
|
1176
|
+
targetChildElm = targetNode.$childNodesScope ? targetNode.$childNodesScope.$element : null;
|
|
1177
|
+
targetChildHeight = targetChildElm ? UiTreeHelper.height(targetChildElm) : 0;
|
|
1178
|
+
targetHeight -= targetChildHeight;
|
|
1179
|
+
targetBeforeBuffer = config.appendChildOnHover ? targetHeight * 0.25 : UiTreeHelper.height(targetElm) / 2;
|
|
1180
|
+
targetBefore = eventObj.pageY < (targetOffset.top + targetBeforeBuffer);
|
|
1106
1181
|
|
|
1107
1182
|
if (targetNode.$parentNodesScope.accept(scope, targetNode.index())) {
|
|
1108
1183
|
if (targetBefore) {
|
|
1109
1184
|
targetElm[0].parentNode.insertBefore(placeElm[0], targetElm[0]);
|
|
1110
1185
|
dragInfo.moveTo(targetNode.$parentNodesScope, targetNode.siblings(), targetNode.index());
|
|
1111
1186
|
} else {
|
|
1112
|
-
|
|
1113
|
-
|
|
1187
|
+
// Try to append as a child if dragged upwards onto targetNode
|
|
1188
|
+
if (config.appendChildOnHover && targetNode.accept(scope, targetNode.childNodesCount())) {
|
|
1189
|
+
targetNode.$childNodesScope.$element.prepend(placeElm);
|
|
1190
|
+
dragInfo.moveTo(targetNode.$childNodesScope, targetNode.childNodes(), 0);
|
|
1191
|
+
unhover = true;
|
|
1192
|
+
} else {
|
|
1193
|
+
targetElm.after(placeElm);
|
|
1194
|
+
dragInfo.moveTo(targetNode.$parentNodesScope, targetNode.siblings(), targetNode.index() + 1);
|
|
1195
|
+
}
|
|
1114
1196
|
}
|
|
1115
|
-
|
|
1116
|
-
|
|
1197
|
+
|
|
1198
|
+
//We have to check if it can add the dragging node as a child.
|
|
1199
|
+
} else if (!targetBefore && targetNode.accept(scope, targetNode.childNodesCount())) {
|
|
1117
1200
|
targetNode.$childNodesScope.$element.append(placeElm);
|
|
1118
1201
|
dragInfo.moveTo(targetNode.$childNodesScope, targetNode.childNodes(), targetNode.childNodesCount());
|
|
1119
1202
|
}
|
|
1120
1203
|
}
|
|
1121
|
-
|
|
1122
1204
|
}
|
|
1123
1205
|
|
|
1124
|
-
|
|
1125
|
-
|
|
1206
|
+
//Triggering dragMove callback.
|
|
1207
|
+
scope.$apply(function () {
|
|
1208
|
+
scope.$treeScope.$callbacks.dragMove(dragInfo.eventArgs(elements, pos));
|
|
1126
1209
|
});
|
|
1127
1210
|
}
|
|
1128
1211
|
};
|
|
1129
1212
|
|
|
1130
|
-
|
|
1213
|
+
dragEnd = function (e) {
|
|
1214
|
+
|
|
1215
|
+
var dragEventArgs = dragInfo.eventArgs(elements, pos);
|
|
1216
|
+
|
|
1131
1217
|
e.preventDefault();
|
|
1132
1218
|
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
scope.$callbacks.beforeDrop(dragInfo.eventArgs(elements, pos));
|
|
1136
|
-
});
|
|
1137
|
-
// roll back elements changed
|
|
1138
|
-
hiddenPlaceElm.replaceWith(scope.$element);
|
|
1139
|
-
placeElm.remove();
|
|
1140
|
-
|
|
1141
|
-
dragElm.remove();
|
|
1142
|
-
dragElm = null;
|
|
1143
|
-
if (scope.$$apply) {
|
|
1144
|
-
dragInfo.apply();
|
|
1145
|
-
scope.$treeScope.$apply(function() {
|
|
1146
|
-
scope.$callbacks.dropped(dragInfo.eventArgs(elements, pos));
|
|
1147
|
-
});
|
|
1148
|
-
} else {
|
|
1149
|
-
bindDrag();
|
|
1150
|
-
}
|
|
1151
|
-
scope.$treeScope.$apply(function() {
|
|
1152
|
-
scope.$callbacks.dragStop(dragInfo.eventArgs(elements, pos));
|
|
1153
|
-
});
|
|
1154
|
-
scope.$$apply = false;
|
|
1155
|
-
dragInfo = null;
|
|
1219
|
+
//TODO(jcarter): Is dragStart need to be unbound?
|
|
1220
|
+
unbindDragMoveEvents();
|
|
1156
1221
|
|
|
1157
|
-
|
|
1222
|
+
//This cancel the collapse/expand login running.
|
|
1223
|
+
$timeout.cancel(scope.expandTimeout);
|
|
1158
1224
|
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
if (oldCur !== null) {
|
|
1162
|
-
$document.find('body').css({'cursor': oldCur});
|
|
1163
|
-
document.body.removeAttribute('ui-tree-cursor');
|
|
1164
|
-
}
|
|
1225
|
+
scope.$treeScope.$apply(function () {
|
|
1226
|
+
$q.when(scope.$treeScope.$callbacks.beforeDrop(dragEventArgs))
|
|
1165
1227
|
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1228
|
+
//Promise resolved (or callback didn't return false)
|
|
1229
|
+
.then(function (allowDrop) {
|
|
1230
|
+
if (allowDrop !== false && scope.$$allowNodeDrop) {
|
|
1231
|
+
//Node drop accepted.
|
|
1232
|
+
dragInfo.apply();
|
|
1233
|
+
|
|
1234
|
+
//Fire the dropped callback only if the move was successful.
|
|
1235
|
+
scope.$treeScope.$callbacks.dropped(dragEventArgs);
|
|
1236
|
+
} else {
|
|
1237
|
+
//Drop canceled - revert the node to its original position.
|
|
1238
|
+
bindDragStartEvents();
|
|
1239
|
+
}
|
|
1240
|
+
})
|
|
1241
|
+
|
|
1242
|
+
//Promise rejected - revert the node to its original position.
|
|
1243
|
+
.catch(function () {
|
|
1244
|
+
bindDragStartEvents();
|
|
1245
|
+
})
|
|
1246
|
+
.finally(function () {
|
|
1247
|
+
|
|
1248
|
+
//Replace placeholder with newly dropped element.
|
|
1249
|
+
hiddenPlaceElm.replaceWith(scope.$element);
|
|
1250
|
+
placeElm.remove();
|
|
1251
|
+
|
|
1252
|
+
//Remove drag element if still in DOM.
|
|
1253
|
+
if (dragElm) {
|
|
1254
|
+
dragElm.remove();
|
|
1255
|
+
dragElm = null;
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
//Fire dragStope callback.
|
|
1259
|
+
scope.$treeScope.$callbacks.dragStop(dragEventArgs);
|
|
1260
|
+
scope.$$allowNodeDrop = false;
|
|
1261
|
+
dragInfo = null;
|
|
1262
|
+
|
|
1263
|
+
//Restore cursor in Opera 12.16 and IE
|
|
1264
|
+
var oldCur = document.body.getAttribute('ui-tree-cursor');
|
|
1265
|
+
if (oldCur !== null) {
|
|
1266
|
+
$document.find('body').css({'cursor': oldCur});
|
|
1267
|
+
document.body.removeAttribute('ui-tree-cursor');
|
|
1268
|
+
}
|
|
1269
|
+
});
|
|
1270
|
+
});
|
|
1172
1271
|
};
|
|
1173
1272
|
|
|
1174
|
-
|
|
1273
|
+
dragStartEvent = function (e) {
|
|
1175
1274
|
if (scope.dragEnabled()) {
|
|
1176
1275
|
dragStart(e);
|
|
1177
1276
|
}
|
|
1178
1277
|
};
|
|
1179
1278
|
|
|
1180
|
-
|
|
1279
|
+
dragMoveEvent = function (e) {
|
|
1181
1280
|
dragMove(e);
|
|
1182
1281
|
};
|
|
1183
1282
|
|
|
1184
|
-
|
|
1185
|
-
scope.$$
|
|
1283
|
+
dragEndEvent = function (e) {
|
|
1284
|
+
scope.$$allowNodeDrop = true;
|
|
1186
1285
|
dragEnd(e);
|
|
1187
1286
|
};
|
|
1188
1287
|
|
|
1189
|
-
|
|
1288
|
+
dragCancelEvent = function (e) {
|
|
1190
1289
|
dragEnd(e);
|
|
1191
1290
|
};
|
|
1192
1291
|
|
|
1193
|
-
|
|
1292
|
+
dragDelay = (function () {
|
|
1293
|
+
var to;
|
|
1294
|
+
|
|
1295
|
+
return {
|
|
1296
|
+
exec: function (fn, ms) {
|
|
1297
|
+
if (!ms) {
|
|
1298
|
+
ms = 0;
|
|
1299
|
+
}
|
|
1300
|
+
this.cancel();
|
|
1301
|
+
to = $timeout(fn, ms);
|
|
1302
|
+
},
|
|
1303
|
+
cancel: function () {
|
|
1304
|
+
$timeout.cancel(to);
|
|
1305
|
+
}
|
|
1306
|
+
};
|
|
1307
|
+
})();
|
|
1308
|
+
|
|
1309
|
+
keydownHandler = function (e) {
|
|
1310
|
+
if (e.keyCode === 27) {
|
|
1311
|
+
dragEndEvent(e);
|
|
1312
|
+
}
|
|
1313
|
+
};
|
|
1314
|
+
|
|
1315
|
+
/**
|
|
1316
|
+
* Binds the mouse/touch events to enable drag start for this node.
|
|
1317
|
+
*/
|
|
1318
|
+
//This is outside of bindDragMoveEvents because of the potential for a delay setting.
|
|
1319
|
+
bindDragStartEvents = function () {
|
|
1194
1320
|
element.bind('touchstart mousedown', function (e) {
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1321
|
+
//Don't call drag delay if no delay was specified.
|
|
1322
|
+
if (scope.dragDelay > 0) {
|
|
1323
|
+
dragDelay.exec(function () {
|
|
1324
|
+
dragStartEvent(e);
|
|
1325
|
+
}, scope.dragDelay);
|
|
1326
|
+
} else {
|
|
1327
|
+
dragStartEvent(e);
|
|
1328
|
+
}
|
|
1199
1329
|
});
|
|
1200
|
-
element.bind('touchend touchcancel mouseup',function(){
|
|
1330
|
+
element.bind('touchend touchcancel mouseup', function () {
|
|
1331
|
+
if (scope.dragDelay > 0) {
|
|
1332
|
+
dragDelay.cancel();
|
|
1333
|
+
}
|
|
1334
|
+
});
|
|
1335
|
+
};
|
|
1336
|
+
bindDragStartEvents();
|
|
1337
|
+
|
|
1338
|
+
/**
|
|
1339
|
+
* Binds mouse/touch events that handle moving/dropping this dragged node
|
|
1340
|
+
*/
|
|
1341
|
+
bindDragMoveEvents = function () {
|
|
1342
|
+
angular.element($document).bind('touchend', dragEndEvent);
|
|
1343
|
+
angular.element($document).bind('touchcancel', dragEndEvent);
|
|
1344
|
+
angular.element($document).bind('touchmove', dragMoveEvent);
|
|
1345
|
+
angular.element($document).bind('mouseup', dragEndEvent);
|
|
1346
|
+
angular.element($document).bind('mousemove', dragMoveEvent);
|
|
1347
|
+
angular.element($document).bind('mouseleave', dragCancelEvent);
|
|
1348
|
+
angular.element($document).bind('keydown', keydownHandler);
|
|
1201
1349
|
};
|
|
1202
|
-
bindDrag();
|
|
1203
1350
|
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1351
|
+
/**
|
|
1352
|
+
* Unbinds mouse/touch events that handle moving/dropping this dragged node.
|
|
1353
|
+
*/
|
|
1354
|
+
unbindDragMoveEvents = function () {
|
|
1355
|
+
angular.element($document).unbind('touchend', dragEndEvent);
|
|
1356
|
+
angular.element($document).unbind('touchcancel', dragEndEvent);
|
|
1357
|
+
angular.element($document).unbind('touchmove', dragMoveEvent);
|
|
1358
|
+
angular.element($document).unbind('mouseup', dragEndEvent);
|
|
1359
|
+
angular.element($document).unbind('mousemove', dragMoveEvent);
|
|
1360
|
+
angular.element($document).unbind('mouseleave', dragCancelEvent);
|
|
1361
|
+
angular.element($document).unbind('keydown', keydownHandler);
|
|
1362
|
+
};
|
|
1363
|
+
}
|
|
1364
|
+
};
|
|
1365
|
+
}
|
|
1366
|
+
]);
|
|
1367
|
+
})();
|
|
1368
|
+
|
|
1369
|
+
(function () {
|
|
1370
|
+
'use strict';
|
|
1371
|
+
|
|
1372
|
+
angular.module('ui.tree')
|
|
1373
|
+
.directive('uiTreeNodes', ['treeConfig', '$window',
|
|
1374
|
+
function (treeConfig) {
|
|
1375
|
+
return {
|
|
1376
|
+
require: ['ngModel', '?^uiTreeNode', '^uiTree'],
|
|
1377
|
+
restrict: 'A',
|
|
1378
|
+
scope: true,
|
|
1379
|
+
controller: 'TreeNodesController',
|
|
1380
|
+
link: function (scope, element, attrs, controllersArr) {
|
|
1381
|
+
|
|
1382
|
+
var config = {},
|
|
1383
|
+
ngModel = controllersArr[0],
|
|
1384
|
+
treeNodeCtrl = controllersArr[1],
|
|
1385
|
+
treeCtrl = controllersArr[2];
|
|
1386
|
+
|
|
1387
|
+
angular.extend(config, treeConfig);
|
|
1388
|
+
if (config.nodesClass) {
|
|
1389
|
+
element.addClass(config.nodesClass);
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
if (treeNodeCtrl) {
|
|
1393
|
+
treeNodeCtrl.scope.$childNodesScope = scope;
|
|
1394
|
+
scope.$nodeScope = treeNodeCtrl.scope;
|
|
1395
|
+
} else {
|
|
1396
|
+
// find the root nodes if there is no parent node and have a parent ui-tree
|
|
1397
|
+
treeCtrl.scope.$nodesScope = scope;
|
|
1398
|
+
}
|
|
1399
|
+
scope.$treeScope = treeCtrl.scope;
|
|
1400
|
+
|
|
1401
|
+
if (ngModel) {
|
|
1402
|
+
ngModel.$render = function () {
|
|
1403
|
+
scope.$modelValue = ngModel.$modelValue;
|
|
1404
|
+
};
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
scope.$watch(function () {
|
|
1408
|
+
return attrs.maxDepth;
|
|
1409
|
+
}, function (val) {
|
|
1410
|
+
if ((typeof val) == 'number') {
|
|
1411
|
+
scope.maxDepth = val;
|
|
1208
1412
|
}
|
|
1209
1413
|
});
|
|
1414
|
+
|
|
1415
|
+
scope.$watch(function () {
|
|
1416
|
+
return attrs.nodropEnabled;
|
|
1417
|
+
}, function (newVal) {
|
|
1418
|
+
if ((typeof newVal) != 'undefined') {
|
|
1419
|
+
scope.nodropEnabled = true;
|
|
1420
|
+
}
|
|
1421
|
+
}, true);
|
|
1422
|
+
|
|
1210
1423
|
}
|
|
1211
1424
|
};
|
|
1212
1425
|
}
|
|
1213
1426
|
]);
|
|
1214
|
-
|
|
1215
1427
|
})();
|
|
1216
1428
|
|
|
1217
1429
|
(function () {
|
|
1218
1430
|
'use strict';
|
|
1219
1431
|
|
|
1220
1432
|
angular.module('ui.tree')
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1433
|
+
|
|
1434
|
+
/**
|
|
1435
|
+
* @ngdoc service
|
|
1436
|
+
* @name ui.tree.service:UiTreeHelper
|
|
1437
|
+
* @requires ng.$document
|
|
1438
|
+
* @requires ng.$window
|
|
1439
|
+
*
|
|
1440
|
+
* @description
|
|
1441
|
+
* angular-ui-tree.
|
|
1442
|
+
*/
|
|
1443
|
+
.factory('UiTreeHelper', ['$document', '$window', 'treeConfig',
|
|
1444
|
+
function ($document, $window, treeConfig) {
|
|
1445
|
+
return {
|
|
1446
|
+
|
|
1447
|
+
/**
|
|
1448
|
+
* A hashtable used to storage data of nodes
|
|
1449
|
+
* @type {Object}
|
|
1450
|
+
*/
|
|
1451
|
+
nodesData: {},
|
|
1452
|
+
|
|
1453
|
+
setNodeAttribute: function (scope, attrName, val) {
|
|
1454
|
+
if (!scope.$modelValue) {
|
|
1455
|
+
return null;
|
|
1456
|
+
}
|
|
1457
|
+
var data = this.nodesData[scope.$modelValue.$$hashKey];
|
|
1458
|
+
if (!data) {
|
|
1459
|
+
data = {};
|
|
1460
|
+
this.nodesData[scope.$modelValue.$$hashKey] = data;
|
|
1461
|
+
}
|
|
1462
|
+
data[attrName] = val;
|
|
1463
|
+
},
|
|
1464
|
+
|
|
1465
|
+
getNodeAttribute: function (scope, attrName) {
|
|
1466
|
+
if (!scope.$modelValue) {
|
|
1467
|
+
return null;
|
|
1468
|
+
}
|
|
1469
|
+
var data = this.nodesData[scope.$modelValue.$$hashKey];
|
|
1470
|
+
if (data) {
|
|
1471
|
+
return data[attrName];
|
|
1472
|
+
}
|
|
1473
|
+
return null;
|
|
1474
|
+
},
|
|
1475
|
+
|
|
1476
|
+
/**
|
|
1477
|
+
* @ngdoc method
|
|
1478
|
+
* @methodOf ui.tree.service:$nodrag
|
|
1479
|
+
* @param {Object} targetElm angular element
|
|
1480
|
+
* @return {Bool} check if the node can be dragged.
|
|
1481
|
+
*/
|
|
1482
|
+
nodrag: function (targetElm) {
|
|
1483
|
+
if (typeof targetElm.attr('data-nodrag') != 'undefined') {
|
|
1484
|
+
return targetElm.attr('data-nodrag') !== 'false';
|
|
1485
|
+
}
|
|
1486
|
+
return false;
|
|
1487
|
+
},
|
|
1488
|
+
|
|
1489
|
+
/**
|
|
1490
|
+
* Get the event object for touches.
|
|
1491
|
+
*
|
|
1492
|
+
* @param {MouseEvent|TouchEvent} e MouseEvent or TouchEvent that kicked off dragX method.
|
|
1493
|
+
* @return {MouseEvent|TouchEvent} Object returned as original event object.
|
|
1494
|
+
*/
|
|
1495
|
+
eventObj: function (e) {
|
|
1496
|
+
var obj = e;
|
|
1497
|
+
if (e.targetTouches !== undefined) {
|
|
1498
|
+
//Set obj equal to the first Touch object in the TouchList.
|
|
1499
|
+
obj = e.targetTouches.item(0);
|
|
1500
|
+
//Logic to set obj to original TouchEvent.
|
|
1501
|
+
} else if (e.originalEvent !== undefined && e.originalEvent.targetTouches !== undefined) {
|
|
1502
|
+
obj = e.originalEvent.targetTouches.item(0);
|
|
1503
|
+
}
|
|
1504
|
+
return obj;
|
|
1505
|
+
},
|
|
1506
|
+
|
|
1507
|
+
/**
|
|
1508
|
+
* Generate object used to store data about node being moved.
|
|
1509
|
+
*
|
|
1510
|
+
* {angular.$scope} node Scope of the node that is being moved.
|
|
1511
|
+
*/
|
|
1512
|
+
dragInfo: function (node) {
|
|
1513
|
+
return {
|
|
1514
|
+
source: node,
|
|
1515
|
+
sourceInfo: {
|
|
1516
|
+
cloneModel: node.$treeScope.cloneEnabled === true ? angular.copy(node.$modelValue) : undefined,
|
|
1517
|
+
nodeScope: node,
|
|
1518
|
+
index: node.index(),
|
|
1519
|
+
nodesScope: node.$parentNodesScope
|
|
1520
|
+
},
|
|
1521
|
+
index: node.index(),
|
|
1522
|
+
|
|
1523
|
+
//Slice(0) just duplicates an array.
|
|
1524
|
+
siblings: node.siblings().slice(0),
|
|
1525
|
+
parent: node.$parentNodesScope,
|
|
1526
|
+
|
|
1527
|
+
//Reset parent to source parent.
|
|
1528
|
+
resetParent: function() {
|
|
1529
|
+
this.parent = node.$parentNodesScope;
|
|
1530
|
+
},
|
|
1531
|
+
|
|
1532
|
+
//Move the node to a new position, determining where the node will be inserted to when dropped happens here.
|
|
1533
|
+
moveTo: function (parent, siblings, index) {
|
|
1534
|
+
this.parent = parent;
|
|
1535
|
+
|
|
1536
|
+
//Duplicate siblings array.
|
|
1537
|
+
this.siblings = siblings.slice(0);
|
|
1538
|
+
|
|
1539
|
+
//If source node is in the target nodes
|
|
1540
|
+
var i = this.siblings.indexOf(this.source);
|
|
1541
|
+
if (i > -1) {
|
|
1542
|
+
this.siblings.splice(i, 1);
|
|
1543
|
+
if (this.source.index() < index) {
|
|
1544
|
+
index--;
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
this.siblings.splice(index, 0, this.source);
|
|
1549
|
+
this.index = index;
|
|
1550
|
+
},
|
|
1551
|
+
|
|
1552
|
+
//Get parent nodes nodeScope.
|
|
1553
|
+
parentNode: function () {
|
|
1554
|
+
return this.parent.$nodeScope;
|
|
1555
|
+
},
|
|
1556
|
+
|
|
1557
|
+
//Get previous sibling node.
|
|
1558
|
+
prev: function () {
|
|
1559
|
+
if (this.index > 0) {
|
|
1560
|
+
return this.siblings[this.index - 1];
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
return null;
|
|
1564
|
+
},
|
|
1565
|
+
|
|
1566
|
+
//Get next sibling node.
|
|
1567
|
+
next: function () {
|
|
1568
|
+
if (this.index < this.siblings.length - 1) {
|
|
1569
|
+
return this.siblings[this.index + 1];
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
return null;
|
|
1573
|
+
},
|
|
1574
|
+
|
|
1575
|
+
//Return what cloneEnabled is set to on uiTree.
|
|
1576
|
+
isClone: function () {
|
|
1577
|
+
return this.source.$treeScope.cloneEnabled === true;
|
|
1578
|
+
},
|
|
1579
|
+
|
|
1580
|
+
//Returns a copy of node passed in.
|
|
1581
|
+
clonedNode: function (node) {
|
|
1582
|
+
return angular.copy(node);
|
|
1583
|
+
},
|
|
1584
|
+
|
|
1585
|
+
//Returns true if parent or index have changed (move happened within any uiTree).
|
|
1586
|
+
isDirty: function () {
|
|
1587
|
+
return this.source.$parentNodesScope != this.parent ||
|
|
1588
|
+
this.source.index() != this.index;
|
|
1589
|
+
},
|
|
1590
|
+
|
|
1591
|
+
//Return whether node has a new parent (set on moveTo method).
|
|
1592
|
+
isForeign: function () {
|
|
1593
|
+
return this.source.$treeScope !== this.parent.$treeScope;
|
|
1594
|
+
},
|
|
1595
|
+
|
|
1596
|
+
//Sets arguments passed to user callbacks.
|
|
1597
|
+
eventArgs: function (elements, pos) {
|
|
1598
|
+
return {
|
|
1599
|
+
source: this.sourceInfo,
|
|
1600
|
+
dest: {
|
|
1601
|
+
index: this.index,
|
|
1602
|
+
nodesScope: this.parent
|
|
1603
|
+
},
|
|
1604
|
+
elements: elements,
|
|
1605
|
+
pos: pos
|
|
1606
|
+
};
|
|
1607
|
+
},
|
|
1608
|
+
|
|
1609
|
+
//Method that actually manipulates the node being moved.
|
|
1610
|
+
apply: function () {
|
|
1611
|
+
|
|
1612
|
+
var nodeData = this.source.$modelValue;
|
|
1613
|
+
|
|
1614
|
+
//Nodrop enabled on tree or parent
|
|
1615
|
+
if (this.parent.nodropEnabled || this.parent.$treeScope.nodropEnabled) {
|
|
1616
|
+
return;
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
//Node was dropped in the same place - do nothing.
|
|
1620
|
+
if (!this.isDirty()) {
|
|
1621
|
+
return;
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
//CloneEnabled and cross-tree so copy and do not remove from source.
|
|
1625
|
+
if (this.isClone() && this.isForeign()) {
|
|
1626
|
+
this.parent.insertNode(this.index, this.sourceInfo.cloneModel);
|
|
1627
|
+
//Any other case, remove and reinsert.
|
|
1628
|
+
} else {
|
|
1629
|
+
this.source.remove();
|
|
1630
|
+
this.parent.insertNode(this.index, nodeData);
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1633
|
+
};
|
|
1634
|
+
},
|
|
1635
|
+
|
|
1636
|
+
/**
|
|
1637
|
+
* @ngdoc method
|
|
1638
|
+
* @name ui.tree#height
|
|
1639
|
+
* @methodOf ui.tree.service:UiTreeHelper
|
|
1640
|
+
*
|
|
1641
|
+
* @description
|
|
1642
|
+
* Get the height of an element.
|
|
1643
|
+
*
|
|
1644
|
+
* @param {Object} element Angular element.
|
|
1645
|
+
* @returns {String} Height
|
|
1646
|
+
*/
|
|
1647
|
+
height: function (element) {
|
|
1648
|
+
return element.prop('scrollHeight');
|
|
1649
|
+
},
|
|
1650
|
+
|
|
1651
|
+
/**
|
|
1652
|
+
* @ngdoc method
|
|
1653
|
+
* @name ui.tree#width
|
|
1654
|
+
* @methodOf ui.tree.service:UiTreeHelper
|
|
1655
|
+
*
|
|
1656
|
+
* @description
|
|
1657
|
+
* Get the width of an element.
|
|
1658
|
+
*
|
|
1659
|
+
* @param {Object} element Angular element.
|
|
1660
|
+
* @returns {String} Width
|
|
1661
|
+
*/
|
|
1662
|
+
width: function (element) {
|
|
1663
|
+
return element.prop('scrollWidth');
|
|
1664
|
+
},
|
|
1665
|
+
|
|
1666
|
+
/**
|
|
1667
|
+
* @ngdoc method
|
|
1668
|
+
* @name ui.tree#offset
|
|
1669
|
+
* @methodOf ui.nestedSortable.service:UiTreeHelper
|
|
1670
|
+
*
|
|
1671
|
+
* @description
|
|
1672
|
+
* Get the offset values of an element.
|
|
1673
|
+
*
|
|
1674
|
+
* @param {Object} element Angular element.
|
|
1675
|
+
* @returns {Object} Object with properties width, height, top and left
|
|
1676
|
+
*/
|
|
1677
|
+
offset: function (element) {
|
|
1678
|
+
var boundingClientRect = element[0].getBoundingClientRect();
|
|
1679
|
+
|
|
1680
|
+
return {
|
|
1681
|
+
width: element.prop('offsetWidth'),
|
|
1682
|
+
height: element.prop('offsetHeight'),
|
|
1683
|
+
top: boundingClientRect.top + ($window.pageYOffset || $document[0].body.scrollTop || $document[0].documentElement.scrollTop),
|
|
1684
|
+
left: boundingClientRect.left + ($window.pageXOffset || $document[0].body.scrollLeft || $document[0].documentElement.scrollLeft)
|
|
1685
|
+
};
|
|
1686
|
+
},
|
|
1687
|
+
|
|
1688
|
+
/**
|
|
1689
|
+
* @ngdoc method
|
|
1690
|
+
* @name ui.tree#positionStarted
|
|
1691
|
+
* @methodOf ui.tree.service:UiTreeHelper
|
|
1692
|
+
*
|
|
1693
|
+
* @description
|
|
1694
|
+
* Get the start position of the target element according to the provided event properties.
|
|
1695
|
+
*
|
|
1696
|
+
* @param {Object} e Event
|
|
1697
|
+
* @param {Object} target Target element
|
|
1698
|
+
* @returns {Object} Object with properties offsetX, offsetY, startX, startY, nowX and dirX.
|
|
1699
|
+
*/
|
|
1700
|
+
positionStarted: function (e, target) {
|
|
1701
|
+
var pos = {},
|
|
1702
|
+
pageX = e.pageX,
|
|
1703
|
+
pageY = e.pageY;
|
|
1704
|
+
|
|
1705
|
+
//Check to set correct data for TouchEvents
|
|
1706
|
+
if (e.originalEvent && e.originalEvent.touches && (e.originalEvent.touches.length > 0)) {
|
|
1707
|
+
pageX = e.originalEvent.touches[0].pageX;
|
|
1708
|
+
pageY = e.originalEvent.touches[0].pageY;
|
|
1709
|
+
}
|
|
1710
|
+
pos.offsetX = pageX - this.offset(target).left;
|
|
1711
|
+
pos.offsetY = pageY - this.offset(target).top;
|
|
1712
|
+
pos.startX = pos.lastX = pageX;
|
|
1713
|
+
pos.startY = pos.lastY = pageY;
|
|
1714
|
+
pos.nowX = pos.nowY = pos.distX = pos.distY = pos.dirAx = 0;
|
|
1715
|
+
pos.dirX = pos.dirY = pos.lastDirX = pos.lastDirY = pos.distAxX = pos.distAxY = 0;
|
|
1716
|
+
return pos;
|
|
1717
|
+
},
|
|
1718
|
+
|
|
1719
|
+
positionMoved: function (e, pos, firstMoving) {
|
|
1720
|
+
|
|
1721
|
+
var pageX = e.pageX,
|
|
1722
|
+
pageY = e.pageY,
|
|
1723
|
+
newAx;
|
|
1724
|
+
|
|
1725
|
+
//If there are multiple touch points, choose one to use as X and Y.
|
|
1726
|
+
if (e.originalEvent && e.originalEvent.touches && (e.originalEvent.touches.length > 0)) {
|
|
1727
|
+
pageX = e.originalEvent.touches[0].pageX;
|
|
1728
|
+
pageY = e.originalEvent.touches[0].pageY;
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1731
|
+
//Mouse position last event.
|
|
1732
|
+
pos.lastX = pos.nowX;
|
|
1733
|
+
pos.lastY = pos.nowY;
|
|
1734
|
+
|
|
1735
|
+
//Mouse position this event.
|
|
1736
|
+
pos.nowX = pageX;
|
|
1737
|
+
pos.nowY = pageY;
|
|
1738
|
+
|
|
1739
|
+
//Distance mouse moved between events.
|
|
1740
|
+
pos.distX = pos.nowX - pos.lastX;
|
|
1741
|
+
pos.distY = pos.nowY - pos.lastY;
|
|
1742
|
+
|
|
1743
|
+
//Direction mouse was moving.
|
|
1744
|
+
pos.lastDirX = pos.dirX;
|
|
1745
|
+
pos.lastDirY = pos.dirY;
|
|
1746
|
+
|
|
1747
|
+
//Direction mouse is now moving (on both axis).
|
|
1748
|
+
pos.dirX = pos.distX === 0 ? 0 : pos.distX > 0 ? 1 : -1;
|
|
1749
|
+
pos.dirY = pos.distY === 0 ? 0 : pos.distY > 0 ? 1 : -1;
|
|
1750
|
+
|
|
1751
|
+
//Axis mouse is now moving on.
|
|
1752
|
+
newAx = Math.abs(pos.distX) > Math.abs(pos.distY) ? 1 : 0;
|
|
1753
|
+
|
|
1754
|
+
//Do nothing on first move.
|
|
1755
|
+
if (firstMoving) {
|
|
1756
|
+
pos.dirAx = newAx;
|
|
1757
|
+
pos.moving = true;
|
|
1758
|
+
return;
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
//Calc distance moved on this axis (and direction).
|
|
1762
|
+
if (pos.dirAx !== newAx) {
|
|
1763
|
+
pos.distAxX = 0;
|
|
1764
|
+
pos.distAxY = 0;
|
|
1765
|
+
} else {
|
|
1766
|
+
pos.distAxX += Math.abs(pos.distX);
|
|
1767
|
+
if (pos.dirX !== 0 && pos.dirX !== pos.lastDirX) {
|
|
1768
|
+
pos.distAxX = 0;
|
|
1769
|
+
}
|
|
1770
|
+
pos.distAxY += Math.abs(pos.distY);
|
|
1771
|
+
if (pos.dirY !== 0 && pos.dirY !== pos.lastDirY) {
|
|
1772
|
+
pos.distAxY = 0;
|
|
1773
|
+
}
|
|
1774
|
+
}
|
|
1775
|
+
pos.dirAx = newAx;
|
|
1776
|
+
},
|
|
1777
|
+
|
|
1778
|
+
elementIsTreeNode: function (element) {
|
|
1779
|
+
return typeof element.attr('ui-tree-node') !== 'undefined';
|
|
1780
|
+
},
|
|
1781
|
+
|
|
1782
|
+
elementIsTreeNodeHandle: function (element) {
|
|
1783
|
+
return typeof element.attr('ui-tree-handle') !== 'undefined';
|
|
1784
|
+
},
|
|
1785
|
+
elementIsTree: function (element) {
|
|
1786
|
+
return typeof element.attr('ui-tree') !== 'undefined';
|
|
1787
|
+
},
|
|
1788
|
+
elementIsTreeNodes: function (element) {
|
|
1789
|
+
return typeof element.attr('ui-tree-nodes') !== 'undefined';
|
|
1790
|
+
},
|
|
1791
|
+
elementIsPlaceholder: function (element) {
|
|
1792
|
+
return element.hasClass(treeConfig.placeholderClass);
|
|
1793
|
+
},
|
|
1794
|
+
elementContainsTreeNodeHandler: function (element) {
|
|
1795
|
+
return element[0].querySelectorAll('[ui-tree-handle]').length >= 1;
|
|
1796
|
+
},
|
|
1797
|
+
treeNodeHandlerContainerOfElement: function (element) {
|
|
1798
|
+
return findFirstParentElementWithAttribute('ui-tree-handle', element[0]);
|
|
1238
1799
|
}
|
|
1239
|
-
}
|
|
1240
|
-
}
|
|
1800
|
+
};
|
|
1801
|
+
}
|
|
1802
|
+
]);
|
|
1803
|
+
|
|
1804
|
+
// TODO: optimize this loop
|
|
1805
|
+
//(Jcarter): Suggest adding a parent element property on uiTree, then all these bubble
|
|
1806
|
+
// to <html> can trigger to stop when they reach the parent.
|
|
1807
|
+
function findFirstParentElementWithAttribute(attributeName, childObj) {
|
|
1808
|
+
//Undefined if the mouse leaves the browser window
|
|
1809
|
+
if (childObj === undefined) {
|
|
1810
|
+
return null;
|
|
1241
1811
|
}
|
|
1242
|
-
|
|
1243
|
-
|
|
1812
|
+
var testObj = childObj.parentNode,
|
|
1813
|
+
count = 1,
|
|
1814
|
+
//Check for setAttribute due to exception thrown by Firefox when a node is dragged outside the browser window
|
|
1815
|
+
res = (typeof testObj.setAttribute === 'function' && testObj.hasAttribute(attributeName)) ? testObj : null;
|
|
1816
|
+
while (testObj && typeof testObj.setAttribute === 'function' && !testObj.hasAttribute(attributeName)) {
|
|
1817
|
+
testObj = testObj.parentNode;
|
|
1818
|
+
res = testObj;
|
|
1819
|
+
//Stop once we reach top of page.
|
|
1820
|
+
if (testObj === document.documentElement) {
|
|
1821
|
+
res = null;
|
|
1822
|
+
break;
|
|
1823
|
+
}
|
|
1824
|
+
count++;
|
|
1825
|
+
}
|
|
1826
|
+
return res;
|
|
1827
|
+
}
|
|
1828
|
+
|
|
1829
|
+
})();
|