Skip to content

Commit 12f35e3

Browse files
committed
Merge pull request #221 from wix/destromas1-master
Destromas1 master
2 parents 59288ea + 962d66e commit 12f35e3

File tree

4 files changed

+108
-74
lines changed

4 files changed

+108
-74
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ bower_components
44
coverage
55
treecontrol.iml
66
.DS_Store
7+
Chromium 49.0.2623 (Ubuntu)

Gruntfile.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ module.exports = function(grunt) {
3030
background: true,
3131
options: {
3232
files: [
33-
'bower_components/jquery/jquery.js',
33+
'bower_components/jquery/dist/jquery.js',
3434
'demo/angular.1.3.12.js',
3535
'demo/angular-mocks.1.3.12.js',
3636
'angular-tree-control.js',

angular-tree-control.js

Lines changed: 84 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,67 @@ if (typeof module !== "undefined" && typeof exports !== "undefined" && module.ex
1919
return _path;
2020
}
2121
}
22+
23+
function ensureDefault(obj, prop, value) {
24+
if (!obj.hasOwnProperty(prop))
25+
obj[prop] = value;
26+
}
27+
28+
function defaultIsLeaf(node, $scope) {
29+
return !node[$scope.options.nodeChildren] || node[$scope.options.nodeChildren].length === 0;
30+
}
31+
32+
function shallowCopy(src, dst) {
33+
if (angular.isArray(src)) {
34+
dst = dst || [];
35+
36+
for (var i = 0; i < src.length; i++) {
37+
dst[i] = src[i];
38+
}
39+
} else if (angular.isObject(src)) {
40+
dst = dst || {};
41+
42+
for (var key in src) {
43+
if (hasOwnProperty.call(src, key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
44+
dst[key] = src[key];
45+
}
46+
}
47+
}
48+
49+
return dst || src;
50+
}
51+
function defaultEquality(a, b,$scope) {
52+
if (!a || !b)
53+
return false;
54+
a = shallowCopy(a);
55+
a[$scope.options.nodeChildren] = [];
56+
b = shallowCopy(b);
57+
b[$scope.options.nodeChildren] = [];
58+
return angular.equals(a, b);
59+
}
60+
61+
function defaultIsSelectable() {
62+
return true;
63+
}
64+
65+
function ensureAllDefaultOptions($scope) {
66+
ensureDefault($scope.options, "multiSelection", false);
67+
ensureDefault($scope.options, "nodeChildren", "children");
68+
ensureDefault($scope.options, "dirSelectable", "true");
69+
ensureDefault($scope.options, "injectClasses", {});
70+
ensureDefault($scope.options.injectClasses, "ul", "");
71+
ensureDefault($scope.options.injectClasses, "li", "");
72+
ensureDefault($scope.options.injectClasses, "liSelected", "");
73+
ensureDefault($scope.options.injectClasses, "iExpanded", "");
74+
ensureDefault($scope.options.injectClasses, "iCollapsed", "");
75+
ensureDefault($scope.options.injectClasses, "iLeaf", "");
76+
ensureDefault($scope.options.injectClasses, "label", "");
77+
ensureDefault($scope.options.injectClasses, "labelSelected", "");
78+
ensureDefault($scope.options, "equality", defaultEquality);
79+
ensureDefault($scope.options, "isLeaf", defaultIsLeaf);
80+
ensureDefault($scope.options, "allowDeselect", true);
81+
ensureDefault($scope.options, "isSelectable", defaultIsSelectable);
82+
}
2283

2384
angular.module( 'treeControl', [] )
2485
.constant('treeConfig', {
@@ -40,10 +101,7 @@ if (typeof module !== "undefined" && typeof exports !== "undefined" && module.ex
40101
return "";
41102
}
42103

43-
function ensureDefault(obj, prop, value) {
44-
if (!obj.hasOwnProperty(prop))
45-
obj[prop] = value;
46-
}
104+
47105

48106
return {
49107
restrict: 'EA',
@@ -62,62 +120,11 @@ if (typeof module !== "undefined" && typeof exports !== "undefined" && module.ex
62120
filterExpression: "=?",
63121
filterComparator: "=?"
64122
},
65-
controller: ['$scope', '$templateCache', '$interpolate', 'treeConfig', function( $scope, $templateCache, $interpolate, treeConfig ) {
66-
67-
function defaultIsLeaf(node) {
68-
return !node[$scope.options.nodeChildren] || node[$scope.options.nodeChildren].length === 0;
69-
}
70-
71-
function shallowCopy(src, dst) {
72-
if (angular.isArray(src)) {
73-
dst = dst || [];
74-
75-
for ( var i = 0; i < src.length; i++) {
76-
dst[i] = src[i];
77-
}
78-
} else if (angular.isObject(src)) {
79-
dst = dst || {};
80-
81-
for (var key in src) {
82-
if (hasOwnProperty.call(src, key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
83-
dst[key] = src[key];
84-
}
85-
}
86-
}
87-
88-
return dst || src;
89-
}
90-
function defaultEquality(a, b) {
91-
if (!a || !b )
92-
return false;
93-
a = shallowCopy(a);
94-
a[$scope.options.nodeChildren] = [];
95-
b = shallowCopy(b);
96-
b[$scope.options.nodeChildren] = [];
97-
return angular.equals(a, b);
98-
}
99-
100-
function defaultIsSelectable() {
101-
return true;
102-
}
103-
123+
controller: ['$scope', '$templateCache', '$interpolate', 'treeConfig', function ($scope, $templateCache, $interpolate, treeConfig) {
124+
104125
$scope.options = $scope.options || {};
105-
ensureDefault($scope.options, "multiSelection", false);
106-
ensureDefault($scope.options, "nodeChildren", "children");
107-
ensureDefault($scope.options, "dirSelectable", "true");
108-
ensureDefault($scope.options, "injectClasses", {});
109-
ensureDefault($scope.options.injectClasses, "ul", "");
110-
ensureDefault($scope.options.injectClasses, "li", "");
111-
ensureDefault($scope.options.injectClasses, "liSelected", "");
112-
ensureDefault($scope.options.injectClasses, "iExpanded", "");
113-
ensureDefault($scope.options.injectClasses, "iCollapsed", "");
114-
ensureDefault($scope.options.injectClasses, "iLeaf", "");
115-
ensureDefault($scope.options.injectClasses, "label", "");
116-
ensureDefault($scope.options.injectClasses, "labelSelected", "");
117-
ensureDefault($scope.options, "equality", defaultEquality);
118-
ensureDefault($scope.options, "isLeaf", defaultIsLeaf);
119-
ensureDefault($scope.options, "allowDeselect", true);
120-
ensureDefault($scope.options, "isSelectable", defaultIsSelectable);
126+
127+
ensureAllDefaultOptions($scope);
121128

122129
$scope.selectedNodes = $scope.selectedNodes || [];
123130
$scope.expandedNodes = $scope.expandedNodes || [];
@@ -129,11 +136,11 @@ if (typeof module !== "undefined" && typeof exports !== "undefined" && module.ex
129136

130137

131138
function isSelectedNode(node) {
132-
if (!$scope.options.multiSelection && ($scope.options.equality(node, $scope.selectedNode)))
139+
if (!$scope.options.multiSelection && ($scope.options.equality(node, $scope.selectedNode , $scope)))
133140
return true;
134141
else if ($scope.options.multiSelection && $scope.selectedNodes) {
135142
for (var i = 0; (i < $scope.selectedNodes.length); i++) {
136-
if ($scope.options.equality(node, $scope.selectedNodes[i])) {
143+
if ($scope.options.equality(node, $scope.selectedNodes[i] , $scope)) {
137144
return true;
138145
}
139146
}
@@ -146,7 +153,7 @@ if (typeof module !== "undefined" && typeof exports !== "undefined" && module.ex
146153
var injectSelectionClass = "";
147154
if (liSelectionClass && isSelectedNode(node))
148155
injectSelectionClass = " " + liSelectionClass;
149-
if ($scope.options.isLeaf(node))
156+
if ($scope.options.isLeaf(node, $scope))
150157
return "tree-leaf" + injectSelectionClass;
151158
if ($scope.expandedNodesMap[this.$id])
152159
return "tree-expanded" + injectSelectionClass;
@@ -175,7 +182,7 @@ if (typeof module !== "undefined" && typeof exports !== "undefined" && module.ex
175182
else {
176183
var index;
177184
for (var i=0; (i < $scope.expandedNodes.length) && !index; i++) {
178-
if ($scope.options.equality($scope.expandedNodes[i], transcludedScope.node)) {
185+
if ($scope.options.equality($scope.expandedNodes[i], transcludedScope.node , $scope)) {
179186
index = i;
180187
}
181188
}
@@ -194,11 +201,11 @@ if (typeof module !== "undefined" && typeof exports !== "undefined" && module.ex
194201

195202
$scope.selectNodeLabel = function( selectedNode){
196203
var transcludedScope = this;
197-
if(!$scope.options.isLeaf(selectedNode) && (!$scope.options.dirSelectable || !$scope.options.isSelectable(selectedNode))) {
204+
if(!$scope.options.isLeaf(selectedNode, $scope) && (!$scope.options.dirSelectable || !$scope.options.isSelectable(selectedNode))) {
198205
// Branch node is not selectable, expand
199206
this.selectNodeHead();
200207
}
201-
else if($scope.options.isLeaf(selectedNode) && (!$scope.options.isSelectable(selectedNode))) {
208+
else if($scope.options.isLeaf(selectedNode, $scope) && (!$scope.options.isSelectable(selectedNode))) {
202209
// Leaf node is not selectable
203210
return;
204211
}
@@ -207,7 +214,7 @@ if (typeof module !== "undefined" && typeof exports !== "undefined" && module.ex
207214
if ($scope.options.multiSelection) {
208215
var pos = -1;
209216
for (var i=0; i < $scope.selectedNodes.length; i++) {
210-
if($scope.options.equality(selectedNode, $scope.selectedNodes[i])) {
217+
if($scope.options.equality(selectedNode, $scope.selectedNodes[i] , $scope)) {
211218
pos = i;
212219
break;
213220
}
@@ -219,7 +226,7 @@ if (typeof module !== "undefined" && typeof exports !== "undefined" && module.ex
219226
$scope.selectedNodes.splice(pos, 1);
220227
}
221228
} else {
222-
if (!$scope.options.equality(selectedNode, $scope.selectedNode)) {
229+
if (!$scope.options.equality(selectedNode, $scope.selectedNode , $scope)) {
223230
$scope.selectedNode = selectedNode;
224231
selected = true;
225232
}
@@ -338,7 +345,7 @@ if (typeof module !== "undefined" && typeof exports !== "undefined" && module.ex
338345
var found = false;
339346
for (var i=0; (i < existingScopes.length) && !found; i++) {
340347
var existingScope = existingScopes[i];
341-
if (scope.options.equality(newExNode, existingScope.node)) {
348+
if (scope.options.equality(newExNode, existingScope.node , scope)) {
342349
newExpandedNodesMap[existingScope.$id] = existingScope.node;
343350
found = true;
344351
}
@@ -386,23 +393,27 @@ if (typeof module !== "undefined" && typeof exports !== "undefined" && module.ex
386393
}
387394
};
388395
})
389-
.directive("treeTransclude", function() {
396+
.directive("treeTransclude", function () {
390397
return {
398+
controller: function ($scope) {
399+
ensureAllDefaultOptions($scope);
400+
},
401+
391402
link: function(scope, element, attrs, controller) {
392-
if (!scope.options.isLeaf(scope.node)) {
403+
if (!scope.options.isLeaf(scope.node, scope)) {
393404
angular.forEach(scope.expandedNodesMap, function (node, id) {
394-
if (scope.options.equality(node, scope.node)) {
405+
if (scope.options.equality(node, scope.node , scope)) {
395406
scope.expandedNodesMap[scope.$id] = scope.node;
396407
scope.expandedNodesMap[id] = undefined;
397408
}
398409
});
399410
}
400-
if (!scope.options.multiSelection && scope.options.equality(scope.node, scope.selectedNode)) {
411+
if (!scope.options.multiSelection && scope.options.equality(scope.node, scope.selectedNode , scope)) {
401412
scope.selectedNode = scope.node;
402413
} else if (scope.options.multiSelection) {
403414
var newSelectedNodes = [];
404415
for (var i = 0; (i < scope.selectedNodes.length); i++) {
405-
if (scope.options.equality(scope.node, scope.selectedNodes[i])) {
416+
if (scope.options.equality(scope.node, scope.selectedNodes[i] , scope)) {
406417
newSelectedNodes.push(scope.node);
407418
}
408419
}

test/angular-tree-control-test.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,28 @@ describe('treeControl', function() {
9898
expect(element.find('li.tree-leaf').length).toBe(3);
9999
});
100100

101+
it('should display first level parents as leafs, based on condition', function () {
102+
$rootScope.treedata = createSubTree(2, 2);
103+
// reverse which is leaf and which is branch - now we have 2 leafs that are not expanded
104+
$rootScope.treeOptions = {isLeaf: function(node) {return node.children.length > 0;}};
105+
element = $compile('<treecontrol tree-model="treedata" options="treeOptions">{{node.label}}</treecontrol>')($rootScope);
106+
$rootScope.$digest();
107+
expect(element.find('li.tree-collapsed').length).toBe(0);
108+
expect(element.find('li.tree-leaf').length).toBe(2);
109+
});
110+
111+
it('should display second level as branches, based on condition', function () {
112+
$rootScope.treedata = createSubTree(2, 2);
113+
// reverse which is leaf and which is branch - now we have 2 leafs that are not expanded
114+
$rootScope.treeOptions = {isLeaf: function(node) {return node.children.length > 0;}};
115+
element = $compile('<treecontrol tree-model="treedata" options="treeOptions">{{node.label}}</treecontrol>')($rootScope);
116+
$rootScope.$digest();
117+
element.find('li:eq(1) .tree-branch-head').click();
118+
element.find('li:eq(0) .tree-branch-head').click();
119+
// now the first level "leafs" are expanded, and we have 4 second level "branches"
120+
expect(element.find('li.tree-collapsed').length).toBe(4);
121+
expect(element.find('li.tree-leaf').length).toBe(2);
122+
});
101123
});
102124

103125
describe('rendering using external scope data', function () {

0 commit comments

Comments
 (0)