angular_ui_tree_rails 0.0.1 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ad043fd34b83cb86a7ccd3333400ee49be57869e
4
- data.tar.gz: 980af9a9859a8da237dd841d21d8adcb2cfd1022
3
+ metadata.gz: e977635ef5a14d7181a0663865914513d0400483
4
+ data.tar.gz: 7c966188eb155837a470c236c34160b7a24e9ff8
5
5
  SHA512:
6
- metadata.gz: 200f14d9177c3b5fea072a083698eba7c5c2212654ffa496393ebe2f2ec39502bc61e40fb1acdfefeebd3397c7afffeba9fba80a9237408ccb60acba445585dc
7
- data.tar.gz: 269e0ca4ec1ad3c756931f702d2466737d06a70da93ab20aef3e93a42e211c1570e37fa0f0061bd6349901fa637540e6e9ad421ffd33f89f23dd03405572766a
6
+ metadata.gz: c99575754ddb92ae812c3d1e03c86c5a3c505bff8c43747a22333d7ec8fb2c7da976f3e842de282e25dc906eb6517104f43aad89612c9d392828db60d5efe790
7
+ data.tar.gz: 0ad0b5c3141b45c9c3cdb01045e9752b64e000894ef8ca1827dcd88db6d65551447d30da9788ded7a4c391ffc8aa0065c1a1b8d7632fe7d04d545f4620f34f51
@@ -1,3 +1,3 @@
1
1
  module AngularUiTreeRails
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.5"
3
3
  end
@@ -0,0 +1,1247 @@
1
+ /**
2
+ * @license Angular UI Tree v2.1.5
3
+ * (c) 2010-2014. https://github.com/JimLiu/angular-ui-tree
4
+ * License: MIT
5
+ */
6
+ (function () {
7
+ 'use strict';
8
+
9
+ angular.module('ui.tree', [])
10
+ .constant('treeConfig', {
11
+ treeClass: 'angular-ui-tree',
12
+ emptyTreeClass: 'angular-ui-tree-empty',
13
+ hiddenClass: 'angular-ui-tree-hidden',
14
+ nodesClass: 'angular-ui-tree-nodes',
15
+ nodeClass: 'angular-ui-tree-node',
16
+ handleClass: 'angular-ui-tree-handle',
17
+ placeHolderClass: 'angular-ui-tree-placeholder',
18
+ dragClass: 'angular-ui-tree-drag',
19
+ dragThreshold: 3,
20
+ levelThreshold: 30
21
+ });
22
+
23
+ })();
24
+
25
+ (function () {
26
+ 'use strict';
27
+
28
+ angular.module('ui.tree')
29
+
30
+ /**
31
+ * @ngdoc service
32
+ * @name ui.tree.service:$helper
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
+ if (!scope.$modelValue) return null;
52
+ var data = this.nodesData[scope.$modelValue.$$hashKey];
53
+ if (!data) {
54
+ data = {};
55
+ this.nodesData[scope.$modelValue.$$hashKey] = data;
56
+ }
57
+ data[attrName] = val;
58
+ },
59
+
60
+ getNodeAttribute: function(scope, attrName) {
61
+ if (!scope.$modelValue) return null;
62
+ var data = this.nodesData[scope.$modelValue.$$hashKey];
63
+ if (data) {
64
+ return data[attrName];
65
+ }
66
+ return null;
67
+ },
68
+
69
+ /**
70
+ * @ngdoc method
71
+ * @methodOf ui.tree.service:$nodrag
72
+ * @param {Object} targetElm angular element
73
+ * @return {Bool} check if the node can be dragged.
74
+ */
75
+ nodrag: function (targetElm) {
76
+ return (typeof targetElm.attr('data-nodrag')) != "undefined";
77
+ },
78
+
79
+ /**
80
+ * get the event object for touchs
81
+ * @param {[type]} e [description]
82
+ * @return {[type]} [description]
83
+ */
84
+ eventObj: function(e) {
85
+ var obj = e;
86
+ if (e.targetTouches !== undefined) {
87
+ obj = e.targetTouches.item(0);
88
+ } else if (e.originalEvent !== undefined && e.originalEvent.targetTouches !== undefined) {
89
+ obj = e.originalEvent.targetTouches.item(0);
90
+ }
91
+ return obj;
92
+ },
93
+
94
+ dragInfo: function(node) {
95
+ return {
96
+ source: node,
97
+ sourceInfo: {
98
+ nodeScope: node,
99
+ index: node.index(),
100
+ nodesScope: node.$parentNodesScope
101
+ },
102
+ index: node.index(),
103
+ siblings: node.siblings().slice(0),
104
+ parent: node.$parentNodesScope,
105
+
106
+ moveTo: function(parent, siblings, index) { // Move the node to a new position
107
+ this.parent = parent;
108
+ this.siblings = siblings.slice(0);
109
+ var i = this.siblings.indexOf(this.source); // If source node is in the target nodes
110
+ if (i > -1) {
111
+ this.siblings.splice(i, 1);
112
+ if (this.source.index() < index) {
113
+ index--;
114
+ }
115
+ }
116
+ this.siblings.splice(index, 0, this.source);
117
+ this.index = index;
118
+ },
119
+
120
+ parentNode: function() {
121
+ return this.parent.$nodeScope;
122
+ },
123
+
124
+ prev: function() {
125
+ if (this.index > 0) {
126
+ return this.siblings[this.index - 1];
127
+ }
128
+ return null;
129
+ },
130
+
131
+ next: function() {
132
+ if (this.index < this.siblings.length - 1) {
133
+ return this.siblings[this.index + 1];
134
+ }
135
+ return null;
136
+ },
137
+
138
+ isDirty: function() {
139
+ return this.source.$parentNodesScope != this.parent ||
140
+ this.source.index() != this.index;
141
+ },
142
+
143
+ eventArgs: function(elements, pos) {
144
+ return {
145
+ source: this.sourceInfo,
146
+ dest: {
147
+ index: this.index,
148
+ nodesScope: this.parent
149
+ },
150
+ elements: elements,
151
+ pos: pos
152
+ };
153
+ },
154
+
155
+ apply: function() {
156
+ var nodeData = this.source.$modelValue;
157
+ this.source.remove();
158
+ this.parent.insertNode(this.index, nodeData);
159
+ }
160
+ };
161
+ },
162
+
163
+ /**
164
+ * @ngdoc method
165
+ * @name hippo.theme#height
166
+ * @methodOf ui.tree.service:$helper
167
+ *
168
+ * @description
169
+ * Get the height of an element.
170
+ *
171
+ * @param {Object} element Angular element.
172
+ * @returns {String} Height
173
+ */
174
+ height: function (element) {
175
+ return element.prop('scrollHeight');
176
+ },
177
+
178
+ /**
179
+ * @ngdoc method
180
+ * @name hippo.theme#width
181
+ * @methodOf ui.tree.service:$helper
182
+ *
183
+ * @description
184
+ * Get the width of an element.
185
+ *
186
+ * @param {Object} element Angular element.
187
+ * @returns {String} Width
188
+ */
189
+ width: function (element) {
190
+ return element.prop('scrollWidth');
191
+ },
192
+
193
+ /**
194
+ * @ngdoc method
195
+ * @name hippo.theme#offset
196
+ * @methodOf ui.nestedSortable.service:$helper
197
+ *
198
+ * @description
199
+ * Get the offset values of an element.
200
+ *
201
+ * @param {Object} element Angular element.
202
+ * @returns {Object} Object with properties width, height, top and left
203
+ */
204
+ offset: function (element) {
205
+ var boundingClientRect = element[0].getBoundingClientRect();
206
+
207
+ return {
208
+ width: element.prop('offsetWidth'),
209
+ height: element.prop('offsetHeight'),
210
+ top: boundingClientRect.top + ($window.pageYOffset || $document[0].body.scrollTop || $document[0].documentElement.scrollTop),
211
+ left: boundingClientRect.left + ($window.pageXOffset || $document[0].body.scrollLeft || $document[0].documentElement.scrollLeft)
212
+ };
213
+ },
214
+
215
+ /**
216
+ * @ngdoc method
217
+ * @name hippo.theme#positionStarted
218
+ * @methodOf ui.tree.service:$helper
219
+ *
220
+ * @description
221
+ * Get the start position of the target element according to the provided event properties.
222
+ *
223
+ * @param {Object} e Event
224
+ * @param {Object} target Target element
225
+ * @returns {Object} Object with properties offsetX, offsetY, startX, startY, nowX and dirX.
226
+ */
227
+ positionStarted: function (e, target) {
228
+ var pos = {};
229
+ pos.offsetX = e.pageX - this.offset(target).left;
230
+ pos.offsetY = e.pageY - this.offset(target).top;
231
+ pos.startX = pos.lastX = e.pageX;
232
+ pos.startY = pos.lastY = e.pageY;
233
+ pos.nowX = pos.nowY = pos.distX = pos.distY = pos.dirAx = 0;
234
+ pos.dirX = pos.dirY = pos.lastDirX = pos.lastDirY = pos.distAxX = pos.distAxY = 0;
235
+ return pos;
236
+ },
237
+
238
+ positionMoved: function (e, pos, firstMoving) {
239
+ // mouse position last events
240
+ pos.lastX = pos.nowX;
241
+ pos.lastY = pos.nowY;
242
+
243
+ // mouse position this events
244
+ pos.nowX = e.pageX;
245
+ pos.nowY = e.pageY;
246
+
247
+ // distance mouse moved between events
248
+ pos.distX = pos.nowX - pos.lastX;
249
+ pos.distY = pos.nowY - pos.lastY;
250
+
251
+ // direction mouse was moving
252
+ pos.lastDirX = pos.dirX;
253
+ pos.lastDirY = pos.dirY;
254
+
255
+ // direction mouse is now moving (on both axis)
256
+ pos.dirX = pos.distX === 0 ? 0 : pos.distX > 0 ? 1 : -1;
257
+ pos.dirY = pos.distY === 0 ? 0 : pos.distY > 0 ? 1 : -1;
258
+
259
+ // axis mouse is now moving on
260
+ var newAx = Math.abs(pos.distX) > Math.abs(pos.distY) ? 1 : 0;
261
+
262
+ // do nothing on first move
263
+ if (firstMoving) {
264
+ pos.dirAx = newAx;
265
+ pos.moving = true;
266
+ return;
267
+ }
268
+
269
+ // calc distance moved on this axis (and direction)
270
+ if (pos.dirAx !== newAx) {
271
+ pos.distAxX = 0;
272
+ pos.distAxY = 0;
273
+ } else {
274
+ pos.distAxX += Math.abs(pos.distX);
275
+ if (pos.dirX !== 0 && pos.dirX !== pos.lastDirX) {
276
+ pos.distAxX = 0;
277
+ }
278
+
279
+ pos.distAxY += Math.abs(pos.distY);
280
+ if (pos.dirY !== 0 && pos.dirY !== pos.lastDirY) {
281
+ pos.distAxY = 0;
282
+ }
283
+ }
284
+
285
+ pos.dirAx = newAx;
286
+ }
287
+ };
288
+ }
289
+ ]);
290
+
291
+ })();
292
+ (function () {
293
+ 'use strict';
294
+
295
+ angular.module('ui.tree')
296
+
297
+ .controller('TreeController', ['$scope', '$element', '$attrs', 'treeConfig',
298
+ function ($scope, $element, $attrs, treeConfig) {
299
+ this.scope = $scope;
300
+
301
+ $scope.$element = $element;
302
+ $scope.$nodesScope = null; // root nodes
303
+ $scope.$type = 'uiTree';
304
+ $scope.$emptyElm = null;
305
+ $scope.$callbacks = null;
306
+
307
+ $scope.dragEnabled = true;
308
+ $scope.emptyPlaceHolderEnabled = true;
309
+ $scope.maxDepth = 0;
310
+ $scope.dragDelay = 0;
311
+
312
+ // Check if it's a empty tree
313
+ $scope.isEmpty = function() {
314
+ return ($scope.$nodesScope && $scope.$nodesScope.$modelValue
315
+ && $scope.$nodesScope.$modelValue.length === 0);
316
+ };
317
+
318
+ // add placeholder to empty tree
319
+ $scope.place = function(placeElm) {
320
+ $scope.$nodesScope.$element.append(placeElm);
321
+ $scope.$emptyElm.remove();
322
+ };
323
+
324
+ $scope.resetEmptyElement = function() {
325
+ if ($scope.$nodesScope.$modelValue.length === 0 &&
326
+ $scope.emptyPlaceHolderEnabled) {
327
+ $element.append($scope.$emptyElm);
328
+ } else {
329
+ $scope.$emptyElm.remove();
330
+ }
331
+ };
332
+
333
+ var collapseOrExpand = function(scope, collapsed) {
334
+ var nodes = scope.childNodes();
335
+ for (var i = 0; i < nodes.length; i++) {
336
+ collapsed ? nodes[i].collapse() : nodes[i].expand();
337
+ var subScope = nodes[i].$childNodesScope;
338
+ if (subScope) {
339
+ collapseOrExpand(subScope, collapsed);
340
+ }
341
+ }
342
+ };
343
+
344
+ $scope.collapseAll = function() {
345
+ collapseOrExpand($scope.$nodesScope, true);
346
+ };
347
+
348
+ $scope.expandAll = function() {
349
+ collapseOrExpand($scope.$nodesScope, false);
350
+ };
351
+
352
+ }
353
+ ]);
354
+ })();
355
+
356
+ (function () {
357
+ 'use strict';
358
+
359
+ angular.module('ui.tree')
360
+
361
+ .controller('TreeNodesController', ['$scope', '$element', 'treeConfig',
362
+ function ($scope, $element, treeConfig) {
363
+ this.scope = $scope;
364
+
365
+ $scope.$element = $element;
366
+ $scope.$modelValue = null;
367
+ $scope.$nodeScope = null; // the scope of node which the nodes belongs to
368
+ $scope.$treeScope = null;
369
+ $scope.$type = 'uiTreeNodes';
370
+ $scope.$nodesMap = {};
371
+
372
+ $scope.nodrop = false;
373
+ $scope.maxDepth = 0;
374
+
375
+ $scope.initSubNode = function(subNode) {
376
+ if(!subNode.$modelValue) return null;
377
+ $scope.$nodesMap[subNode.$modelValue.$$hashKey] = subNode;
378
+ };
379
+
380
+ $scope.destroySubNode = function(subNode) {
381
+ if(!subNode.$modelValue) return null;
382
+ $scope.$nodesMap[subNode.$modelValue.$$hashKey] = null;
383
+ };
384
+
385
+ $scope.accept = function(sourceNode, destIndex) {
386
+ return $scope.$treeScope.$callbacks.accept(sourceNode, $scope, destIndex);
387
+ };
388
+
389
+ $scope.beforeDrag = function(sourceNode) {
390
+ return $scope.$treeScope.$callbacks.beforeDrag(sourceNode);
391
+ };
392
+
393
+ $scope.isParent = function(node) {
394
+ return node.$parentNodesScope == $scope;
395
+ };
396
+
397
+ $scope.hasChild = function() {
398
+ return $scope.$modelValue.length > 0;
399
+ };
400
+
401
+ $scope.safeApply = function(fn) {
402
+ var phase = this.$root.$$phase;
403
+ if(phase == '$apply' || phase == '$digest') {
404
+ if(fn && (typeof(fn) === 'function')) {
405
+ fn();
406
+ }
407
+ } else {
408
+ this.$apply(fn);
409
+ }
410
+ };
411
+
412
+ $scope.removeNode = function(node) {
413
+ var index = $scope.$modelValue.indexOf(node.$modelValue);
414
+ if (index > -1) {
415
+ $scope.safeApply(function() {
416
+ $scope.$modelValue.splice(index, 1)[0];
417
+ });
418
+ return node;
419
+ }
420
+ return null;
421
+ };
422
+
423
+ $scope.insertNode = function(index, nodeData) {
424
+ $scope.safeApply(function() {
425
+ $scope.$modelValue.splice(index, 0, nodeData);
426
+ });
427
+ };
428
+
429
+ $scope.childNodes = function() {
430
+ var nodes = [];
431
+ if ($scope.$modelValue) {
432
+ for (var i = 0; i < $scope.$modelValue.length; i++) {
433
+ nodes.push($scope.$nodesMap[$scope.$modelValue[i].$$hashKey]);
434
+ }
435
+ }
436
+ return nodes;
437
+ };
438
+
439
+ $scope.depth = function() {
440
+ if ($scope.$nodeScope) {
441
+ return $scope.$nodeScope.depth();
442
+ }
443
+ return 0; // if it has no $nodeScope, it's root
444
+ };
445
+
446
+ // check if depth limit has reached
447
+ $scope.outOfDepth = function(sourceNode) {
448
+ var maxDepth = $scope.maxDepth || $scope.$treeScope.maxDepth;
449
+ if (maxDepth > 0) {
450
+ return $scope.depth() + sourceNode.maxSubDepth() + 1 > maxDepth;
451
+ }
452
+ return false;
453
+ };
454
+
455
+ }
456
+ ]);
457
+ })();
458
+ (function () {
459
+ 'use strict';
460
+
461
+ angular.module('ui.tree')
462
+
463
+ .controller('TreeNodeController', ['$scope', '$element', '$attrs', 'treeConfig',
464
+ function ($scope, $element, $attrs, treeConfig) {
465
+ this.scope = $scope;
466
+
467
+ $scope.$element = $element;
468
+ $scope.$modelValue = null; // Model value for node;
469
+ $scope.$parentNodeScope = null; // uiTreeNode Scope of parent node;
470
+ $scope.$childNodesScope = null; // uiTreeNodes Scope of child nodes.
471
+ $scope.$parentNodesScope = null; // uiTreeNodes Scope of parent nodes.
472
+ $scope.$treeScope = null; // uiTree scope
473
+ $scope.$handleScope = null; // it's handle scope
474
+ $scope.$type = 'uiTreeNode';
475
+ $scope.$$apply = false; //
476
+
477
+ $scope.collapsed = false;
478
+
479
+ $scope.init = function(controllersArr) {
480
+ var treeNodesCtrl = controllersArr[0];
481
+ $scope.$treeScope = controllersArr[1] ? controllersArr[1].scope : null;
482
+
483
+ // find the scope of it's parent node
484
+ $scope.$parentNodeScope = treeNodesCtrl.scope.$nodeScope;
485
+ // modelValue for current node
486
+ $scope.$modelValue = treeNodesCtrl.scope.$modelValue[$scope.$index];
487
+ $scope.$parentNodesScope = treeNodesCtrl.scope;
488
+ treeNodesCtrl.scope.initSubNode($scope); // init sub nodes
489
+
490
+ $element.on('$destroy', function() {
491
+ treeNodesCtrl.scope.destroySubNode($scope); // destroy sub nodes
492
+ });
493
+ };
494
+
495
+ $scope.index = function() {
496
+ return $scope.$parentNodesScope.$modelValue.indexOf($scope.$modelValue);
497
+ };
498
+
499
+ $scope.dragEnabled = function() {
500
+ return !($scope.$treeScope && !$scope.$treeScope.dragEnabled);
501
+ };
502
+
503
+ $scope.isSibling = function(targetNode) {
504
+ return $scope.$parentNodesScope == targetNode.$parentNodesScope;
505
+ };
506
+
507
+ $scope.isChild = function(targetNode) {
508
+ var nodes = $scope.childNodes();
509
+ return nodes && nodes.indexOf(targetNode) > -1;
510
+ };
511
+
512
+ $scope.prev = function() {
513
+ var index = $scope.index();
514
+ if (index > 0) {
515
+ return $scope.siblings()[index - 1];
516
+ }
517
+ return null;
518
+ };
519
+
520
+ $scope.siblings = function() {
521
+ return $scope.$parentNodesScope.childNodes();
522
+ };
523
+
524
+ $scope.childNodesCount = function() {
525
+ return $scope.childNodes() ? $scope.childNodes().length : 0;
526
+ };
527
+
528
+ $scope.hasChild = function() {
529
+ return $scope.childNodesCount() > 0;
530
+ };
531
+
532
+ $scope.childNodes = function() {
533
+ return $scope.$childNodesScope && $scope.$childNodesScope.$modelValue ?
534
+ $scope.$childNodesScope.childNodes() :
535
+ null;
536
+ };
537
+
538
+ $scope.accept = function(sourceNode, destIndex) {
539
+ return $scope.$childNodesScope &&
540
+ $scope.$childNodesScope.$modelValue &&
541
+ $scope.$childNodesScope.accept(sourceNode, destIndex);
542
+ };
543
+
544
+ $scope.removeNode = function(){
545
+ var node = $scope.remove();
546
+ $scope.$callbacks.removed(node);
547
+ return node;
548
+ };
549
+
550
+ $scope.remove = function() {
551
+ return $scope.$parentNodesScope.removeNode($scope);
552
+ };
553
+
554
+ $scope.toggle = function() {
555
+ $scope.collapsed = !$scope.collapsed;
556
+ };
557
+
558
+ $scope.collapse = function() {
559
+ $scope.collapsed = true;
560
+ };
561
+
562
+ $scope.expand = function() {
563
+ $scope.collapsed = false;
564
+ };
565
+
566
+ $scope.depth = function() {
567
+ var parentNode = $scope.$parentNodeScope;
568
+ if (parentNode) {
569
+ return parentNode.depth() + 1;
570
+ }
571
+ return 1;
572
+ };
573
+
574
+ var subDepth = 0;
575
+ var countSubDepth = function(scope) {
576
+ var count = 0;
577
+ var nodes = scope.childNodes();
578
+ for (var i = 0; i < nodes.length; i++) {
579
+ var childNodes = nodes[i].$childNodesScope;
580
+ if (childNodes) {
581
+ count = 1;
582
+ countSubDepth(childNodes);
583
+ }
584
+ }
585
+ subDepth += count;
586
+ };
587
+
588
+ $scope.maxSubDepth = function() {
589
+ subDepth = 0;
590
+ if ($scope.$childNodesScope) {
591
+ countSubDepth($scope.$childNodesScope);
592
+ }
593
+ return subDepth;
594
+ };
595
+
596
+ }
597
+ ]);
598
+ })();
599
+
600
+ (function () {
601
+ 'use strict';
602
+
603
+ angular.module('ui.tree')
604
+
605
+ .controller('TreeHandleController', ['$scope', '$element', '$attrs', 'treeConfig',
606
+ function ($scope, $element, $attrs, treeConfig) {
607
+ this.scope = $scope;
608
+
609
+ $scope.$element = $element;
610
+ $scope.$nodeScope = null;
611
+ $scope.$type = 'uiTreeHandle';
612
+
613
+ }
614
+ ]);
615
+ })();
616
+
617
+ (function () {
618
+ 'use strict';
619
+
620
+ angular.module('ui.tree')
621
+ .directive('uiTree', [ 'treeConfig', '$window',
622
+ function(treeConfig, $window) {
623
+ return {
624
+ restrict: 'A',
625
+ scope: true,
626
+ controller: 'TreeController',
627
+ link: function(scope, element, attrs) {
628
+ var callbacks = {
629
+ accept: null,
630
+ beforeDrag: null
631
+ };
632
+
633
+ var config = {};
634
+ angular.extend(config, treeConfig);
635
+ if (config.treeClass) {
636
+ element.addClass(config.treeClass);
637
+ }
638
+
639
+ scope.$emptyElm = angular.element($window.document.createElement('div'));
640
+ if (config.emptyTreeClass) {
641
+ scope.$emptyElm.addClass(config.emptyTreeClass);
642
+ }
643
+
644
+ scope.$watch('$nodesScope.$modelValue.length', function() {
645
+ if (scope.$nodesScope.$modelValue) {
646
+ scope.resetEmptyElement();
647
+ }
648
+ }, true);
649
+
650
+ scope.$watch(attrs.dragEnabled, function(val) {
651
+ if((typeof val) == "boolean") {
652
+ scope.dragEnabled = val;
653
+ }
654
+ });
655
+
656
+ scope.$watch(attrs.emptyPlaceHolderEnabled, function(val) {
657
+ if((typeof val) == "boolean") {
658
+ scope.emptyPlaceHolderEnabled = val;
659
+ }
660
+ });
661
+
662
+ scope.$watch(attrs.maxDepth, function(val) {
663
+ if((typeof val) == "number") {
664
+ scope.maxDepth = val;
665
+ }
666
+ });
667
+
668
+ scope.$watch(attrs.dragDelay, function(val) {
669
+ if((typeof val) == "number") {
670
+ scope.dragDelay = val;
671
+ }
672
+ });
673
+
674
+ // check if the dest node can accept the dragging node
675
+ // by default, we check the 'data-nodrop' attribute in `ui-tree-nodes`
676
+ // and the 'max-depth' attribute in `ui-tree` or `ui-tree-nodes`.
677
+ // the method can be overrided
678
+ callbacks.accept = function(sourceNodeScope, destNodesScope, destIndex) {
679
+ if (destNodesScope.nodrop || destNodesScope.outOfDepth(sourceNodeScope)) {
680
+ return false;
681
+ }
682
+ return true;
683
+ };
684
+
685
+ callbacks.beforeDrag = function(sourceNodeScope) {
686
+ return true;
687
+ };
688
+
689
+ callbacks.removed = function(node){
690
+
691
+ };
692
+
693
+ callbacks.dropped = function(event) {
694
+
695
+ };
696
+
697
+ //
698
+ callbacks.dragStart = function(event) {
699
+
700
+ };
701
+
702
+ callbacks.dragMove = function(event) {
703
+
704
+ };
705
+
706
+ callbacks.dragStop = function(event) {
707
+
708
+ };
709
+
710
+ callbacks.beforeDrop = function(event) {
711
+
712
+ };
713
+
714
+ scope.$watch(attrs.uiTree, function(newVal, oldVal){
715
+ angular.forEach(newVal, function(value, key){
716
+ if (callbacks[key]) {
717
+ if (typeof value === "function") {
718
+ callbacks[key] = value;
719
+ }
720
+ }
721
+ });
722
+
723
+ scope.$callbacks = callbacks;
724
+ }, true);
725
+
726
+
727
+ }
728
+ };
729
+ }
730
+ ]);
731
+ })();
732
+
733
+ (function () {
734
+ 'use strict';
735
+
736
+ angular.module('ui.tree')
737
+ .directive('uiTreeNodes', [ 'treeConfig', '$window',
738
+ function(treeConfig) {
739
+ return {
740
+ require: ['ngModel', '?^uiTreeNode', '^uiTree'],
741
+ restrict: 'A',
742
+ scope: true,
743
+ controller: 'TreeNodesController',
744
+ link: function(scope, element, attrs, controllersArr) {
745
+
746
+ var config = {};
747
+ angular.extend(config, treeConfig);
748
+ if (config.nodesClass) {
749
+ element.addClass(config.nodesClass);
750
+ }
751
+
752
+ var ngModel = controllersArr[0];
753
+ var treeNodeCtrl = controllersArr[1];
754
+ var treeCtrl = controllersArr[2];
755
+ if (treeNodeCtrl) {
756
+ treeNodeCtrl.scope.$childNodesScope = scope;
757
+ scope.$nodeScope = treeNodeCtrl.scope;
758
+ }
759
+ else { // find the root nodes if there is no parent node and have a parent ui-tree
760
+ treeCtrl.scope.$nodesScope = scope;
761
+ }
762
+ scope.$treeScope = treeCtrl.scope;
763
+
764
+ if (ngModel) {
765
+ ngModel.$render = function() {
766
+ if (!ngModel.$modelValue || !angular.isArray(ngModel.$modelValue)) {
767
+ scope.$modelValue = [];
768
+ }
769
+ scope.$modelValue = ngModel.$modelValue;
770
+ };
771
+ }
772
+
773
+ scope.$watch(attrs.maxDepth, function(val) {
774
+ if((typeof val) == "number") {
775
+ scope.maxDepth = val;
776
+ }
777
+ });
778
+
779
+ attrs.$observe('nodrop', function(val) {
780
+ scope.nodrop = ((typeof val) != "undefined");
781
+ });
782
+
783
+ attrs.$observe('horizontal', function(val) {
784
+ scope.horizontal = ((typeof val) != "undefined");
785
+ });
786
+
787
+ }
788
+ };
789
+ }
790
+ ]);
791
+ })();
792
+
793
+ (function () {
794
+ 'use strict';
795
+
796
+ angular.module('ui.tree')
797
+
798
+ .directive('uiTreeNode', ['treeConfig', '$uiTreeHelper', '$window', '$document','$timeout',
799
+ function (treeConfig, $uiTreeHelper, $window, $document, $timeout) {
800
+ return {
801
+ require: ['^uiTreeNodes', '^uiTree'],
802
+ restrict: 'A',
803
+ controller: 'TreeNodeController',
804
+ link: function(scope, element, attrs, controllersArr) {
805
+ var config = {};
806
+ angular.extend(config, treeConfig);
807
+ if (config.nodeClass) {
808
+ element.addClass(config.nodeClass);
809
+ }
810
+ scope.init(controllersArr);
811
+
812
+ scope.collapsed = !!$uiTreeHelper.getNodeAttribute(scope, 'collapsed');
813
+
814
+ scope.$watch(attrs.collapsed, function(val) {
815
+ if((typeof val) == "boolean") {
816
+ scope.collapsed = val;
817
+ }
818
+ });
819
+
820
+ scope.$watch('collapsed', function(val) {
821
+ $uiTreeHelper.setNodeAttribute(scope, 'collapsed', val);
822
+ attrs.$set('collapsed', val);
823
+ });
824
+
825
+ var hasTouch = 'ontouchstart' in window;
826
+ // todo startPos is unused
827
+ var startPos, firstMoving, dragInfo, pos;
828
+ var placeElm, hiddenPlaceElm, dragElm;
829
+ var treeScope = null;
830
+ var elements; // As a parameter for callbacks
831
+ var dragDelaying = true;
832
+ var dragStarted = false;
833
+ var dragTimer = null;
834
+ var body = document.body,
835
+ html = document.documentElement,
836
+ document_height,
837
+ document_width;
838
+
839
+ var dragStart = function(e) {
840
+ if (!hasTouch && (e.button == 2 || e.which == 3)) {
841
+ // disable right click
842
+ return;
843
+ }
844
+ if (e.uiTreeDragging || (e.originalEvent && e.originalEvent.uiTreeDragging)) { // event has already fired in other scope.
845
+ return;
846
+ }
847
+
848
+ // the element which is clicked.
849
+ var eventElm = angular.element(e.target);
850
+ var eventScope = eventElm.scope();
851
+ if (!eventScope || !eventScope.$type) {
852
+ return;
853
+ }
854
+ if (eventScope.$type != 'uiTreeNode'
855
+ && eventScope.$type != 'uiTreeHandle') { // Check if it is a node or a handle
856
+ return;
857
+ }
858
+ if (eventScope.$type == 'uiTreeNode'
859
+ && eventScope.$handleScope) { // If the node has a handle, then it should be clicked by the handle
860
+ return;
861
+ }
862
+
863
+ var eventElmTagName = eventElm.prop('tagName').toLowerCase();
864
+ if (eventElmTagName == 'input' ||
865
+ eventElmTagName == 'textarea' ||
866
+ eventElmTagName == 'button' ||
867
+ eventElmTagName == 'select') { // if it's a input or button, ignore it
868
+ return;
869
+ }
870
+
871
+ // check if it or it's parents has a 'data-nodrag' attribute
872
+ while (eventElm && eventElm[0] && eventElm[0] != element) {
873
+ if ($uiTreeHelper.nodrag(eventElm)) { // if the node mark as `nodrag`, DONOT drag it.
874
+ return;
875
+ }
876
+ eventElm = eventElm.parent();
877
+ }
878
+
879
+ if (!scope.beforeDrag(scope)){
880
+ return;
881
+ }
882
+
883
+ e.uiTreeDragging = true; // stop event bubbling
884
+ if (e.originalEvent) {
885
+ e.originalEvent.uiTreeDragging = true;
886
+ }
887
+ e.preventDefault();
888
+ var eventObj = $uiTreeHelper.eventObj(e);
889
+
890
+ firstMoving = true;
891
+ dragInfo = $uiTreeHelper.dragInfo(scope);
892
+
893
+ var tagName = scope.$element.prop('tagName');
894
+ if (tagName.toLowerCase() === 'tr') {
895
+ placeElm = angular.element($window.document.createElement(tagName));
896
+ var tdElm = angular.element($window.document.createElement('td'))
897
+ .addClass(config.placeHolderClass);
898
+ placeElm.append(tdElm);
899
+ } else {
900
+ placeElm = angular.element($window.document.createElement(tagName))
901
+ .addClass(config.placeHolderClass);
902
+ }
903
+ hiddenPlaceElm = angular.element($window.document.createElement(tagName));
904
+ if (config.hiddenClass) {
905
+ hiddenPlaceElm.addClass(config.hiddenClass);
906
+ }
907
+ pos = $uiTreeHelper.positionStarted(eventObj, scope.$element);
908
+ placeElm.css('height', $uiTreeHelper.height(scope.$element) + 'px');
909
+ placeElm.css('width', $uiTreeHelper.width(scope.$element) + 'px');
910
+ dragElm = angular.element($window.document.createElement(scope.$parentNodesScope.$element.prop('tagName')))
911
+ .addClass(scope.$parentNodesScope.$element.attr('class')).addClass(config.dragClass);
912
+ dragElm.css('width', $uiTreeHelper.width(scope.$element) + 'px');
913
+ dragElm.css('z-index', 9999);
914
+
915
+ // Prevents cursor to change rapidly in Opera 12.16 and IE when dragging an element
916
+ var hStyle = (scope.$element[0].querySelector('.angular-ui-tree-handle') || scope.$element[0]).currentStyle;
917
+ if (hStyle) {
918
+ document.body.setAttribute('ui-tree-cursor', $document.find('body').css('cursor') || '');
919
+ $document.find('body').css({'cursor': hStyle.cursor + '!important'});
920
+ }
921
+
922
+ scope.$element.after(placeElm);
923
+ scope.$element.after(hiddenPlaceElm);
924
+ dragElm.append(scope.$element);
925
+ $document.find('body').append(dragElm);
926
+ dragElm.css({
927
+ 'left' : eventObj.pageX - pos.offsetX + 'px',
928
+ 'top' : eventObj.pageY - pos.offsetY + 'px'
929
+ });
930
+ elements = {
931
+ placeholder: placeElm,
932
+ dragging: dragElm
933
+ };
934
+
935
+ angular.element($document).bind('touchend', dragEndEvent);
936
+ angular.element($document).bind('touchcancel', dragEndEvent);
937
+ angular.element($document).bind('touchmove', dragMoveEvent);
938
+ angular.element($document).bind('mouseup', dragEndEvent);
939
+ angular.element($document).bind('mousemove', dragMoveEvent);
940
+ angular.element($document).bind('mouseleave', dragCancelEvent);
941
+
942
+ document_height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight);
943
+ document_width = Math.max(body.scrollWidth, body.offsetWidth, html.clientWidth, html.scrollWidth, html.offsetWidth);
944
+ };
945
+
946
+ var dragMove = function(e) {
947
+ if (!dragStarted) {
948
+ if (!dragDelaying) {
949
+ dragStarted = true;
950
+ scope.$apply(function() {
951
+ scope.$callbacks.dragStart(dragInfo.eventArgs(elements, pos));
952
+ });
953
+ }
954
+ return;
955
+ }
956
+
957
+ var eventObj = $uiTreeHelper.eventObj(e);
958
+ var prev, leftElmPos, topElmPos;
959
+
960
+ if (dragElm) {
961
+ e.preventDefault();
962
+
963
+ if ($window.getSelection) {
964
+ $window.getSelection().removeAllRanges();
965
+ } else if ($window.document.selection) {
966
+ $window.document.selection.empty();
967
+ }
968
+
969
+ leftElmPos = eventObj.pageX - pos.offsetX;
970
+ topElmPos = eventObj.pageY - pos.offsetY;
971
+
972
+ //dragElm can't leave the screen on the left
973
+ if(leftElmPos < 0){
974
+ leftElmPos = 0;
975
+ }
976
+
977
+ //dragElm can't leave the screen on the top
978
+ if(topElmPos < 0){
979
+ topElmPos = 0;
980
+ }
981
+
982
+ //dragElm can't leave the screen on the bottom
983
+ if ((topElmPos + 10) > document_height){
984
+ topElmPos = document_height - 10;
985
+ }
986
+
987
+ //dragElm can't leave the screen on the right
988
+ if((leftElmPos + 10) > document_width) {
989
+ leftElmPos = document_width - 10;
990
+ }
991
+
992
+ dragElm.css({
993
+ 'left': leftElmPos + 'px',
994
+ 'top': topElmPos + 'px'
995
+ });
996
+
997
+ var top_scroll = window.pageYOffset || $window.document.documentElement.scrollTop;
998
+ var bottom_scroll = top_scroll + (window.innerHeight || $window.document.clientHeight || $window.document.clientHeight);
999
+
1000
+ // to scroll down if cursor y-position is greater than the bottom position the vertical scroll
1001
+ if (bottom_scroll < eventObj.pageY && bottom_scroll <= document_height) {
1002
+ window.scrollBy(0, 10);
1003
+ }
1004
+
1005
+ // to scroll top if cursor y-position is less than the top position the vertical scroll
1006
+ if (top_scroll > eventObj.pageY) {
1007
+ window.scrollBy(0, -10);
1008
+ }
1009
+
1010
+ $uiTreeHelper.positionMoved(e, pos, firstMoving);
1011
+ if (firstMoving) {
1012
+ firstMoving = false;
1013
+ return;
1014
+ }
1015
+
1016
+ // move horizontal
1017
+ if (pos.dirAx && pos.distAxX >= config.levelThreshold) {
1018
+ pos.distAxX = 0;
1019
+
1020
+ // increase horizontal level if previous sibling exists and is not collapsed
1021
+ if (pos.distX > 0) {
1022
+ prev = dragInfo.prev();
1023
+ if (prev && !prev.collapsed
1024
+ && prev.accept(scope, prev.childNodesCount())) {
1025
+ prev.$childNodesScope.$element.append(placeElm);
1026
+ dragInfo.moveTo(prev.$childNodesScope, prev.childNodes(), prev.childNodesCount());
1027
+ }
1028
+ }
1029
+
1030
+ // decrease horizontal level
1031
+ if (pos.distX < 0) {
1032
+ // we can't decrease a level if an item preceeds the current one
1033
+ var next = dragInfo.next();
1034
+ if (!next) {
1035
+ var target = dragInfo.parentNode(); // As a sibling of it's parent node
1036
+ if (target
1037
+ && target.$parentNodesScope.accept(scope, target.index() + 1)) {
1038
+ target.$element.after(placeElm);
1039
+ dragInfo.moveTo(target.$parentNodesScope, target.siblings(), target.index() + 1);
1040
+ }
1041
+ }
1042
+ }
1043
+ }
1044
+
1045
+ // check if add it as a child node first
1046
+ // todo decrease is unused
1047
+ var decrease = ($uiTreeHelper.offset(dragElm).left - $uiTreeHelper.offset(placeElm).left) >= config.threshold;
1048
+ var targetX = eventObj.pageX - $window.document.body.scrollLeft;
1049
+ var targetY = eventObj.pageY - (window.pageYOffset || $window.document.documentElement.scrollTop);
1050
+
1051
+ // Select the drag target. Because IE does not support CSS 'pointer-events: none', it will always
1052
+ // pick the drag element itself as the target. To prevent this, we hide the drag element while
1053
+ // selecting the target.
1054
+ var displayElm;
1055
+ if (angular.isFunction(dragElm.hide)) {
1056
+ dragElm.hide();
1057
+ }else{
1058
+ displayElm = dragElm[0].style.display;
1059
+ dragElm[0].style.display = "none";
1060
+ }
1061
+
1062
+ // when using elementFromPoint() inside an iframe, you have to call
1063
+ // elementFromPoint() twice to make sure IE8 returns the correct value
1064
+ $window.document.elementFromPoint(targetX, targetY);
1065
+
1066
+ var targetElm = angular.element($window.document.elementFromPoint(targetX, targetY));
1067
+ if (angular.isFunction(dragElm.show)) {
1068
+ dragElm.show();
1069
+ }else{
1070
+ dragElm[0].style.display = displayElm;
1071
+ }
1072
+
1073
+ // move vertical
1074
+ if (!pos.dirAx) {
1075
+ var targetBefore, targetNode;
1076
+ // check it's new position
1077
+ targetNode = targetElm.scope();
1078
+ var isEmpty = false;
1079
+ if (!targetNode) {
1080
+ return;
1081
+ }
1082
+ if (targetNode.$type == 'uiTree' && targetNode.dragEnabled) {
1083
+ isEmpty = targetNode.isEmpty(); // Check if it's empty tree
1084
+ }
1085
+ if (targetNode.$type == 'uiTreeHandle') {
1086
+ targetNode = targetNode.$nodeScope;
1087
+ }
1088
+ if (targetNode.$type != 'uiTreeNode'
1089
+ && !isEmpty) { // Check if it is a uiTreeNode or it's an empty tree
1090
+ return;
1091
+ }
1092
+
1093
+ // if placeholder move from empty tree, reset it.
1094
+ if (treeScope && placeElm.parent()[0] != treeScope.$element[0]) {
1095
+ treeScope.resetEmptyElement();
1096
+ treeScope = null;
1097
+ }
1098
+
1099
+ if (isEmpty) { // it's an empty tree
1100
+ treeScope = targetNode;
1101
+ if (targetNode.$nodesScope.accept(scope, 0)) {
1102
+ targetNode.place(placeElm);
1103
+ dragInfo.moveTo(targetNode.$nodesScope, targetNode.$nodesScope.childNodes(), 0);
1104
+ }
1105
+ } else if (targetNode.dragEnabled()){ // drag enabled
1106
+ targetElm = targetNode.$element; // Get the element of ui-tree-node
1107
+ var targetOffset = $uiTreeHelper.offset(targetElm);
1108
+ targetBefore = targetNode.horizontal ? eventObj.pageX < (targetOffset.left + $uiTreeHelper.width(targetElm) / 2)
1109
+ : eventObj.pageY < (targetOffset.top + $uiTreeHelper.height(targetElm) / 2);
1110
+
1111
+ if (targetNode.$parentNodesScope.accept(scope, targetNode.index())) {
1112
+ if (targetBefore) {
1113
+ targetElm[0].parentNode.insertBefore(placeElm[0], targetElm[0]);
1114
+ dragInfo.moveTo(targetNode.$parentNodesScope, targetNode.siblings(), targetNode.index());
1115
+ } else {
1116
+ targetElm.after(placeElm);
1117
+ dragInfo.moveTo(targetNode.$parentNodesScope, targetNode.siblings(), targetNode.index() + 1);
1118
+ }
1119
+ }
1120
+ else if (!targetBefore && targetNode.accept(scope, targetNode.childNodesCount())) { // we have to check if it can add the dragging node as a child
1121
+ targetNode.$childNodesScope.$element.append(placeElm);
1122
+ dragInfo.moveTo(targetNode.$childNodesScope, targetNode.childNodes(), targetNode.childNodesCount());
1123
+ }
1124
+ }
1125
+
1126
+ }
1127
+
1128
+ scope.$apply(function() {
1129
+ scope.$callbacks.dragMove(dragInfo.eventArgs(elements, pos));
1130
+ });
1131
+ }
1132
+ };
1133
+
1134
+ var dragEnd = function(e) {
1135
+ e.preventDefault();
1136
+
1137
+ if (dragElm) {
1138
+ scope.$treeScope.$apply(function() {
1139
+ scope.$callbacks.beforeDrop(dragInfo.eventArgs(elements, pos));
1140
+ });
1141
+ // roll back elements changed
1142
+ hiddenPlaceElm.replaceWith(scope.$element);
1143
+ placeElm.remove();
1144
+
1145
+ dragElm.remove();
1146
+ dragElm = null;
1147
+ if (scope.$$apply) {
1148
+ dragInfo.apply();
1149
+ scope.$treeScope.$apply(function() {
1150
+ scope.$callbacks.dropped(dragInfo.eventArgs(elements, pos));
1151
+ });
1152
+ } else {
1153
+ bindDrag();
1154
+ }
1155
+ scope.$treeScope.$apply(function() {
1156
+ scope.$callbacks.dragStop(dragInfo.eventArgs(elements, pos));
1157
+ });
1158
+ scope.$$apply = false;
1159
+ dragInfo = null;
1160
+
1161
+ }
1162
+
1163
+ // Restore cursor in Opera 12.16 and IE
1164
+ var oldCur = document.body.getAttribute('ui-tree-cursor');
1165
+ if (oldCur !== null) {
1166
+ $document.find('body').css({'cursor': oldCur});
1167
+ document.body.removeAttribute('ui-tree-cursor');
1168
+ }
1169
+
1170
+ angular.element($document).unbind('touchend', dragEndEvent); // Mobile
1171
+ angular.element($document).unbind('touchcancel', dragEndEvent); // Mobile
1172
+ angular.element($document).unbind('touchmove', dragMoveEvent); // Mobile
1173
+ angular.element($document).unbind('mouseup', dragEndEvent);
1174
+ angular.element($document).unbind('mousemove', dragMoveEvent);
1175
+ angular.element($window.document.body).unbind('mouseleave', dragCancelEvent);
1176
+ };
1177
+
1178
+ var dragStartEvent = function(e) {
1179
+ if (scope.dragEnabled()) {
1180
+ dragStart(e);
1181
+ }
1182
+ };
1183
+
1184
+ var dragMoveEvent = function(e) {
1185
+ dragMove(e);
1186
+ };
1187
+
1188
+ var dragEndEvent = function(e) {
1189
+ scope.$$apply = true;
1190
+ dragEnd(e);
1191
+ };
1192
+
1193
+ var dragCancelEvent = function(e) {
1194
+ dragEnd(e);
1195
+ };
1196
+
1197
+ var bindDrag = function() {
1198
+ element.bind('touchstart mousedown', function (e) {
1199
+ dragDelaying = true;
1200
+ dragStarted = false;
1201
+ dragStartEvent(e);
1202
+ dragTimer = $timeout(function(){dragDelaying = false;}, scope.dragDelay);
1203
+ });
1204
+ element.bind('touchend touchcancel mouseup',function(){$timeout.cancel(dragTimer);});
1205
+ };
1206
+ bindDrag();
1207
+
1208
+ angular.element($window.document.body).bind("keydown", function(e) {
1209
+ if (e.keyCode == 27) {
1210
+ scope.$$apply = false;
1211
+ dragEnd(e);
1212
+ }
1213
+ });
1214
+ }
1215
+ };
1216
+ }
1217
+ ]);
1218
+
1219
+ })();
1220
+
1221
+ (function () {
1222
+ 'use strict';
1223
+
1224
+ angular.module('ui.tree')
1225
+ .directive('uiTreeHandle', [ 'treeConfig', '$window',
1226
+ function(treeConfig) {
1227
+ return {
1228
+ require: '^uiTreeNode',
1229
+ restrict: 'A',
1230
+ scope: true,
1231
+ controller: 'TreeHandleController',
1232
+ link: function(scope, element, attrs, treeNodeCtrl) {
1233
+ var config = {};
1234
+ angular.extend(config, treeConfig);
1235
+ if (config.handleClass) {
1236
+ element.addClass(config.handleClass);
1237
+ }
1238
+ // connect with the tree node.
1239
+ if (scope != treeNodeCtrl.scope) {
1240
+ scope.$nodeScope = treeNodeCtrl.scope;
1241
+ treeNodeCtrl.scope.$handleScope = scope;
1242
+ }
1243
+ }
1244
+ };
1245
+ }
1246
+ ]);
1247
+ })();