Skip to content

Commit 2dbb5a6

Browse files
author
Niels Dequeker
committed
Merge pull request angular-ui-tree#411 from enkodellc/master
Clone and NoDrop.
2 parents e04dfda + 349c6d2 commit 2dbb5a6

16 files changed

+318
-57
lines changed

README.md

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,16 @@ Injecting `ui.tree`, `ui-tree-nodes`, `ui-tree-node`, `ui-tree-handle` to your h
131131
`ui-tree` is the root scope for a tree
132132

133133
#### Attributes
134+
##### data-drop-enabled
135+
Turn on the ability to prevent dropping of nodes into this tree.
136+
- `false` (default): turn off
137+
- `true`: turn on no drop
138+
139+
##### data-clone-enabled
140+
Turn on cloning of nodes. This will clone the source node to the destination when dragging between 2 trees.
141+
- `false` (default): turn off clone
142+
- `true`: turn on clone
143+
134144
##### data-drag-enabled
135145
Turn on dragging and dropping of nodes.
136146
- `true` (default): allow drag and drop
@@ -144,10 +154,10 @@ If you write your own [$callbacks.accept](#accept) method, you have to check `da
144154
##### data-drag-delay
145155
Number of milliseconds a click must be held to start a drag. (default 0)
146156

147-
##### data-empty-place-holder-enabled
148-
If a tree is empty, there will be an empty place hoder which is used to drop node from other trees by default.
149-
- `true` (default): display an empty place holder if the tree is empty
150-
- `false`: do not display an empty place hoder
157+
##### data-empty-placeholder-enabled
158+
If a tree is empty, there will be an empty placeholder which is used to drop node from other trees by default.
159+
- `true` (default): display an empty placeholder if the tree is empty
160+
- `false`: do not display an empty placeholder
151161

152162
##### Example
153163
- turn on/off drag and drop.
@@ -255,16 +265,16 @@ Same as [Parameters](#eventParam) of dropped.
255265
`ui-tree-nodes` is the container of nodes. Every `ui-tree-node` should have a `ui-tree-nodes` as it's container, a `ui-tree-nodes` can have multiple child nodes.
256266

257267
#### Attributes
258-
##### data-nodrop<a name="nodes_attrs_nodrop"></a>
268+
##### data-nodrop-enabled <a name="nodes_attrs_nodrop"></a>
259269
Turn off drop of nodes.
260-
##### data-max-depth<a name="nodes_attrs_maxDepth"></a>
270+
##### data-max-depth <a name="nodes_attrs_maxDepth"></a>
261271
Number of levels a nodes can be nested (default 0). 0 means no limit. It can override the `data-max-depth` in `ui-tree`.
262272
**Note**
263-
If you write your own [$callbacks.accept](#accept) method, you have to check `data-nodrop` and `data-max-depth` by yourself.
273+
If you write your own [$callbacks.accept](#accept) method, you have to check `data-nodrop-enabled` and `data-max-depth` by yourself.
264274

265275
Example: turn off drop.
266276
```html
267-
<ol ui-tree-nodes ng-model="nodes" data-nodrop>
277+
<ol ui-tree-nodes ng-model="nodes" data-nodrop-enabled="true">
268278
<li ng-repeat="node in nodes" ui-tree-node>{{node.title}}</li>
269279
</ol>
270280
```
@@ -295,8 +305,8 @@ The property `$nodeScope of` `nodes 1.1` is `node 1.1`. The property `$nodes` of
295305
##### maxDepth
296306
Number of levels a node can be nested. It bases on the attribute [data-max-depth](#nodes_attrs_maxDepth).
297307

298-
##### nodrop
299-
Turn off drop on nodes. It bases on the attribute [data-nodrag](#nodes_attrs_nodrop).
308+
##### nodropEnabled
309+
Turn off drop on nodes. It bases on the attribute [data-nodrop-enabled](#nodes_attrs_nodrop).
300310

301311
#### Methods of scope
302312
##### depth()

demo/clone-node-trees.html

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8">
5+
<title>AngularJS Tree demo</title>
6+
7+
<!-- Stylesheets -->
8+
<link rel="stylesheet" type="text/css" href="bower_components/bootstrap/dist/css/bootstrap.min.css">
9+
<link rel="stylesheet" href="dist/angular-ui-tree.min.css">
10+
<link rel="stylesheet" href="css/tree.css">
11+
</head>
12+
<body ng-app="cloneNodesApp">
13+
14+
<!-- Nested node template -->
15+
<script type="text/ng-template" id="nodes_renderer1.html">
16+
<div ui-tree-handle class="tree-node">
17+
<div class="tree-node-content">
18+
<a class="btn btn-success btn-xs" data-nodrag ng-click="toggle(this)"><span class="glyphicon" ng-class="{'glyphicon-chevron-right': collapsed, 'glyphicon-chevron-down': !collapsed}"></span></a>
19+
{{node.title}}
20+
<a class="pull-right btn btn-danger btn-xs" data-nodrag ng-click="remove(this)"><span class="glyphicon glyphicon-remove"></span></a>
21+
<a class="pull-right btn btn-primary btn-xs" data-nodrag ng-click="newSubItem(this)" style="margin-right: 8px;"><span class="glyphicon glyphicon-plus"></span></a>
22+
</div>
23+
</div>
24+
<ol ui-tree-nodes="" ng-model="node.nodes" ng-class="{hidden: collapsed}">
25+
<li ng-repeat="node in node.nodes" ui-tree-node ng-include="'nodes_renderer1.html'">
26+
</li>
27+
</ol>
28+
</script>
29+
<script type="text/ng-template" id="nodes_renderer2.html">
30+
<div class="tree-node">
31+
<div class="pull-left tree-handle" ui-tree-handle>
32+
<span class="glyphicon glyphicon-list"></span>
33+
</div>
34+
<div class="tree-node-content">
35+
<a class="btn btn-success btn-xs" data-nodrag ng-click="toggle(this)"><span class="glyphicon" ng-class="{'glyphicon-chevron-right': collapsed, 'glyphicon-chevron-down': !collapsed}"></span></a>
36+
{{node.title}}
37+
<a class="pull-right btn btn-danger btn-xs" data-nodrag ng-click="remove(this)"><span class="glyphicon glyphicon-remove"></span></a>
38+
<a class="pull-right btn btn-primary btn-xs" data-nodrag ng-click="newSubItem(this)" style="margin-right: 8px;"><span class="glyphicon glyphicon-plus"></span></a>
39+
</div>
40+
</div>
41+
<ol ui-tree-nodes="" ng-model="node.nodes" ng-class="{hidden: collapsed}">
42+
<li ng-repeat="node in node.nodes" ui-tree-node ng-include="'nodes_renderer2.html'">
43+
</li>
44+
</ol>
45+
</script>
46+
<div class="container" ng-controller="cloneNodesCtrl">
47+
<h1 class="page-header">Clone Nodes - Connected lists</h1>
48+
<a href="index.html"><i class="glyphicon glyphicon-chevron-left"></i> Back to overview page</a>
49+
50+
<h3>Connected lists with clone the right tree nodes when dragging to the tree. The right also has No Drop enabled since it is the base for cloning.</h3>
51+
<sup>Depending on your tree model you may get a <i>[ngRepeat:dupes]</i> error. If you do you can use the <a href="https://docs.angularjs.org/error/ngRepeat/dupes" target="_blank">track by $index</a> in your ngRepeat expression</sup>
52+
<div class="row">
53+
<div class="col-sm-6">
54+
<h3>Tree 1 (Clone Tree 2 items here)</h3>
55+
<div ui-tree id="tree1-root">
56+
<ol ui-tree-nodes="" ng-model="tree1">
57+
<li ng-repeat="node in tree1 track by $index" ui-tree-node ng-include="'nodes_renderer1.html'"></li>
58+
</ol>
59+
</div>
60+
</div>
61+
62+
<div class="col-sm-6">
63+
<h3>Origin Tree 2 (No Drop)</h3>
64+
<div ui-tree id="tree2-root" data-nodrop-enabled="true" data-clone-enabled="true">
65+
<ol ui-tree-nodes="" ng-model="tree2">
66+
<li ng-repeat="node in tree2" ui-tree-node ng-include="'nodes_renderer2.html'"></li>
67+
</ol>
68+
</div>
69+
</div>
70+
</div>
71+
72+
<h3>Data binding</h3>
73+
<div class="row">
74+
<div class="col-sm-6">
75+
<pre class="code">{{ tree1 | json }}</pre>
76+
</div>
77+
78+
<div class="col-sm-6">
79+
<pre class="code">{{ tree2 | json }}</pre>
80+
</div>
81+
</div>
82+
83+
</div>
84+
85+
<!--[if IE 8]>
86+
<script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
87+
<script src="http://cdnjs.cloudflare.com/ajax/libs/es5-shim/3.4.0/es5-shim.min.js"></script>
88+
<![endif]-->
89+
<script src="bower_components/angular/angular.min.js"></script>
90+
<script type="text/javascript" src="dist/angular-ui-tree.js"></script>
91+
<script type="text/javascript" src="js/clone-nodes.js"></script>
92+
</body>
93+
</html>

demo/dist/angular-ui-tree.js

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,17 @@
7777
* @return {Bool} check if the node can be dragged.
7878
*/
7979
nodrag: function (targetElm) {
80-
return (typeof targetElm.attr('data-nodrag')) != "undefined";
80+
if (typeof targetElm.attr('data-nodrag') != "undefined") {
81+
if (targetElm.attr('data-nodrag') === 'false') {
82+
return false;
83+
}
84+
return true;
85+
}
86+
return false;
8187
},
8288

8389
/**
84-
* get the event object for touchs
90+
* get the event object for touches
8591
* @param {[type]} e [description]
8692
* @return {[type]} [description]
8793
*/
@@ -157,9 +163,21 @@
157163
},
158164

159165
apply: function() {
160-
var nodeData = this.source.$modelValue;
161-
this.source.remove();
162-
this.parent.insertNode(this.index, nodeData);
166+
//no drop so no changes
167+
if (this.parent.$treeScope.nodropEnabled !== true) {
168+
var nodeData = this.source.$modelValue;
169+
170+
//cloneEnabled so do not remove from source
171+
if (this.source.$treeScope.cloneEnabled !== true) {
172+
this.source.remove();
173+
}
174+
175+
//if the tree is set to cloneEnabled and source === dest do not insert node or it will cause a duplicate in the repeater
176+
if ((this.source.$treeScope.cloneEnabled === true) && (this.source.$treeScope === this.parent.$treeScope)) {
177+
return false;
178+
}
179+
this.parent.insertNode(this.index, nodeData);
180+
}
163181
}
164182
};
165183
},
@@ -312,6 +330,8 @@
312330
$scope.emptyPlaceHolderEnabled = true;
313331
$scope.maxDepth = 0;
314332
$scope.dragDelay = 0;
333+
$scope.cloneEnabled = false;
334+
$scope.nodropEnabled = false;
315335

316336
// Check if it's a empty tree
317337
$scope.isEmpty = function() {
@@ -373,8 +393,9 @@
373393
$scope.$type = 'uiTreeNodes';
374394
$scope.$nodesMap = {};
375395

376-
$scope.nodrop = false;
396+
$scope.nodropEnabled = false;
377397
$scope.maxDepth = 0;
398+
$scope.cloneEnabled = false;
378399

379400
$scope.initSubNode = function(subNode) {
380401
if(!subNode.$modelValue) {
@@ -667,6 +688,18 @@
667688
}
668689
});
669690

691+
scope.$watch(attrs.nodropEnabled, function(val) {
692+
if((typeof val) == "boolean") {
693+
scope.nodropEnabled = val;
694+
}
695+
});
696+
697+
scope.$watch(attrs.cloneEnabled, function(val) {
698+
if((typeof val) == "boolean") {
699+
scope.cloneEnabled = val;
700+
}
701+
});
702+
670703
scope.$watch(attrs.maxDepth, function(val) {
671704
if((typeof val) == "number") {
672705
scope.maxDepth = val;
@@ -680,11 +713,11 @@
680713
});
681714

682715
// check if the dest node can accept the dragging node
683-
// by default, we check the 'data-nodrop' attribute in `ui-tree-nodes`
716+
// by default, we check the 'data-nodrop-enabled' attribute in `ui-tree-nodes`
684717
// and the 'max-depth' attribute in `ui-tree` or `ui-tree-nodes`.
685718
// the method can be overrided
686719
callbacks.accept = function(sourceNodeScope, destNodesScope, destIndex) {
687-
if (destNodesScope.nodrop || destNodesScope.outOfDepth(sourceNodeScope)) {
720+
if (destNodesScope.nodropEnabled || destNodesScope.outOfDepth(sourceNodeScope)) {
688721
return false;
689722
}
690723
return true;
@@ -785,10 +818,10 @@
785818
});
786819

787820
scope.$watch(function () {
788-
return attrs.nodrop;
821+
return attrs.nodropEnabled;
789822
}, function (newVal) {
790823
if((typeof newVal) != "undefined") {
791-
scope.nodrop = true;
824+
scope.nodropEnabled = true;
792825
}
793826
}, true);
794827

@@ -918,7 +951,6 @@
918951
}
919952
pos = $uiTreeHelper.positionStarted(eventObj, scope.$element);
920953
placeElm.css('height', $uiTreeHelper.height(scope.$element) + 'px');
921-
placeElm.css('width', $uiTreeHelper.width(scope.$element) + 'px');
922954
dragElm = angular.element($window.document.createElement(scope.$parentNodesScope.$element.prop('tagName')))
923955
.addClass(scope.$parentNodesScope.$element.attr('class')).addClass(config.dragClass);
924956
dragElm.css('width', $uiTreeHelper.width(scope.$element) + 'px');
@@ -1157,8 +1189,8 @@
11571189
dragElm.remove();
11581190
dragElm = null;
11591191
if (scope.$$apply) {
1160-
dragInfo.apply();
11611192
scope.$treeScope.$apply(function() {
1193+
dragInfo.apply();
11621194
scope.$callbacks.dropped(dragInfo.eventArgs(elements, pos));
11631195
});
11641196
} else {

demo/dist/angular-ui-tree.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

demo/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ <h2>Examples</h2>
4242
<li><a href="trees.html">Connected trees</a></li>
4343
<li><a href="groups.html">Groups &amp; Categories</a></li>
4444
<li><a href="filter.html">Filter</a></li>
45+
<li><a href="clone-node-trees.html">Clone nodes</a></li>
4546
</ol>
4647
</div>
4748
</div>

demo/js/clone-nodes.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
(function() {
2+
'use strict';
3+
4+
angular.module('cloneNodesApp', ['ui.tree'])
5+
.controller('cloneNodesCtrl', function($scope) {
6+
7+
$scope.remove = function(scope) {
8+
scope.remove();
9+
};
10+
11+
$scope.toggle = function(scope) {
12+
scope.toggle();
13+
};
14+
15+
$scope.newSubItem = function(scope) {
16+
var nodeData = scope.$modelValue;
17+
nodeData.nodes.push({
18+
id: nodeData.id * 10 + nodeData.nodes.length,
19+
title: nodeData.title + '.' + (nodeData.nodes.length + 1),
20+
nodes: []
21+
});
22+
};
23+
24+
25+
$scope.tree1 = [{
26+
"id": 1,
27+
"title": "tree1 - item1",
28+
"nodes": []
29+
}, {
30+
"id": 2,
31+
"title": "tree1 - item2",
32+
"nodes": []
33+
}, {
34+
"id": 3,
35+
"title": "tree1 - item3",
36+
"nodes": []
37+
}, {
38+
"id": 4,
39+
"title": "tree1 - item4",
40+
"nodes": []
41+
}];
42+
$scope.tree2 = [{
43+
"id": 1,
44+
"title": "tree2 - item1",
45+
"nodes": []
46+
}, {
47+
"id": 2,
48+
"title": "tree2 - item2",
49+
"nodes": []
50+
}, {
51+
"id": 3,
52+
"title": "tree2 - item3",
53+
"nodes": []
54+
}, {
55+
"id": 4,
56+
"title": "tree2 - item4",
57+
"nodes": []
58+
}];
59+
});
60+
61+
})();

0 commit comments

Comments
 (0)