angular_ui_tree_rails 0.0.1 → 0.0.5

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 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
+ })();