Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions angular-tree-control.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
'use strict';

angular.module( 'treeControl', [] )
.directive( 'treecontrol', ['$compile', function( $compile ) {
.directive( 'treecontrol', ['$compile', '$timeout', function( $compile, $timeout) {
/**
* @param cssClass - the css class
* @param addClassProperty - should we wrap the class name with class=""
Expand Down Expand Up @@ -90,6 +90,9 @@
ensureDefault($scope.options.injectClasses, "labelSelected", "");
ensureDefault($scope.options, "equality", defaultEquality);
ensureDefault($scope.options, "isLeaf", defaultIsLeaf);
ensureDefault($scope.options, "enableIntervalToggle", false);
ensureDefault($scope.options, "childrenLimitInterval", 10);
ensureDefault($scope.options, "childrenTimeInterval", 10);

$scope.selectedNodes = $scope.selectedNodes || [];
$scope.expandedNodes = $scope.expandedNodes || [];
Expand Down Expand Up @@ -202,11 +205,25 @@
return isThisNodeSelected?"tree-selected" + injectSelectionClass:"";
};

$scope.enableIntervalToggleOnScope = function(scope){
var limitInterval = $scope.options.childrenLimitInterval*1;
var timeInterval = $scope.options.childrenTimeInterval*1;

scope.childrenLimit = limitInterval;
$timeout(function addChildren(){
if(scope.childrenLimit < (scope.node.children || []).length){
scope.childrenLimit = scope.childrenLimit + limitInterval;
$timeout(addChildren, timeInterval);
}
}, timeInterval);
};

//tree template
var orderBy = $scope.orderBy ? ' | orderBy:orderBy:reverseOrder' : '';
var limitTo = $scope.options.enableIntervalToggle ? ' | limitTo:childrenLimit' : '';
var template =
'<ul '+classIfDefined($scope.options.injectClasses.ul, true)+'>' +
'<li ng-repeat="node in node.' + $scope.options.nodeChildren + ' | filter:filterExpression:filterComparator ' + orderBy + '" ng-class="headClass(node)" '+classIfDefined($scope.options.injectClasses.li, true)+'>' +
'<li ng-repeat="node in node.' + $scope.options.nodeChildren + ' | filter:filterExpression:filterComparator ' + orderBy + limitTo + '" ng-class="headClass(node)" '+classIfDefined($scope.options.injectClasses.li, true)+'>' +
'<i class="tree-branch-head" ng-class="iBranchClass()" ng-click="selectNodeHead(node)"></i>' +
'<i class="tree-leaf-head '+classIfDefined($scope.options.injectClasses.iLeaf, false)+'"></i>' +
'<div class="tree-label '+classIfDefined($scope.options.injectClasses.label, false)+'" ng-class="selectedClass()" ng-click="selectNodeLabel(node)" tree-transclude></div>' +
Expand Down Expand Up @@ -270,6 +287,7 @@
//Rendering template for a root node
treemodelCntr.template( scope, function(clone) {
element.html('').append( clone );
if(scope.options.enableIntervalToggle) scope.enableIntervalToggleOnScope(scope);
});
// save the transclude function from compile (which is not bound to a scope as apposed to the one from link)
// we can fix this to work with the link transclude function with angular 1.2.6. as for angular 1.2.0 we need
Expand All @@ -285,8 +303,9 @@
require: "^treecontrol",
link: function( scope, element, attrs, treemodelCntr) {
// Rendering template for the current node
treemodelCntr.template(scope, function(clone) {
treemodelCntr.template(scope, function(clone) {
element.html('').append(clone);
if(scope.options.enableIntervalToggle) scope.enableIntervalToggleOnScope(scope);
});
}
}
Expand Down
6 changes: 3 additions & 3 deletions bower.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "angular-tree-control",
"version": "0.2.9",
"name": "angular-tree-control-smooth-expand",
"version": "0.3.0",
"main": [
"./angular-tree-control.js",
"./css/tree-control.css"
Expand All @@ -12,7 +12,7 @@
"karma.conf.js"
],
"dependencies": {
"angular": "~1.2.7"
"angular": "~1.3.15"
},
"devDependencies": {
"angular-mocks": "~1.2.7",
Expand Down
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
{
"name": "angular-tree-control",
"version": "0.2.0",
"name": "angular-tree-control-smooth-expand",
"version": "0.3.0",
"description": "Angular Tree Control",
"main": "angular-tree-control.js",
"scripts": {
"test": "grunt test"
},
"repository": {
"type": "git",
"url": "git://github.com/wix/angular-tree-control.git"
"url": "git://github.com/ssteffl/angular-tree-control.git"
},
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/wix/angular-tree-control/issues"
"url": "https://github.com/ssteffl/angular-tree-control-smooth-expand/issues"
},
"homepage": "https://github.com/wix/angular-tree-control",
"homepage": "https://github.com/ssteffl/angular-tree-control-smooth-expand",
"devDependencies": {
"grunt": "~0.4.2",
"grunt-release": "~0.6.0",
Expand Down
119 changes: 119 additions & 0 deletions test/angular-tree-control-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ describe('treeControl', function() {
inject(function ($injector) {
$compile = $injector.get('$compile');
$rootScope = $injector.get('$rootScope');
$timeout = $injector.get('$timeout');
});
num = 1;
});
Expand Down Expand Up @@ -639,4 +640,122 @@ describe('treeControl', function() {

});

describe('gradual children expanding', function(){
it('should add 20 children per 25 ms', function(){
var TIME_INTERVAL = 25,
LIMIT_INTERVAL = 20,
MAX_NODES = 100;
$rootScope.treedata = createSubTree(1, MAX_NODES);
$rootScope.treeOptions = {
enableIntervalToggle: true,
childrenLimitInterval: LIMIT_INTERVAL,
childrenTimeInterval: TIME_INTERVAL
};
element = $compile('<treecontrol tree-model="treedata" options="treeOptions">{{node.label}}</treecontrol>')($rootScope);
$rootScope.$digest();

var expectedChildCount = LIMIT_INTERVAL, flag = false;
runs(function(){
setTimeout(function checkChildCount(){
if(expectedChildCount<=MAX_NODES){
expect(element.find('li').length).toBe(expectedChildCount);
expectedChildCount += LIMIT_INTERVAL;
$timeout.flush();
setTimeout(checkChildCount, TIME_INTERVAL);
}
else flag = true;
}, TIME_INTERVAL/2);
});
waitsFor(function(){ return flag;}, 'Timeouts finished', TIME_INTERVAL*(MAX_NODES/LIMIT_INTERVAL*2));
});
it('should default childrenTimeInterval to 10 ms', function(){
var TIME_INTERVAL = 10,
LIMIT_INTERVAL = 20,
MAX_NODES = 100;
$rootScope.treedata = createSubTree(1, MAX_NODES);
$rootScope.treeOptions = {
enableIntervalToggle: true,
childrenLimitInterval: LIMIT_INTERVAL,
};
element = $compile('<treecontrol tree-model="treedata" options="treeOptions">{{node.label}}</treecontrol>')($rootScope);
$rootScope.$digest();
var expectedChildCount = LIMIT_INTERVAL, flag = false;
runs(function(){
setTimeout(function checkChildCount(){
if(expectedChildCount<=MAX_NODES){
expect(element.find('li').length).toBe(expectedChildCount);
expectedChildCount += LIMIT_INTERVAL;
$timeout.flush();
setTimeout(checkChildCount, TIME_INTERVAL);
}
else flag = true;
}, TIME_INTERVAL/2);
});
waitsFor(function(){ return flag;}, 'Timeouts finished', TIME_INTERVAL*(MAX_NODES/LIMIT_INTERVAL*2));
});
it('should default childrenLimitInterval to 10', function(){
var TIME_INTERVAL = 20,
LIMIT_INTERVAL = 10,
MAX_NODES = 50;
$rootScope.treedata = createSubTree(1, MAX_NODES);
$rootScope.treeOptions = {
enableIntervalToggle: true,
childrenTimeInterval: TIME_INTERVAL
};
element = $compile('<treecontrol tree-model="treedata" options="treeOptions">{{node.label}}</treecontrol>')($rootScope);
$rootScope.$digest();
var expectedChildCount = LIMIT_INTERVAL, flag = false;
runs(function(){
setTimeout(function checkChildCount(){
if(expectedChildCount<=MAX_NODES){
expect(element.find('li').length).toBe(expectedChildCount);
expectedChildCount += LIMIT_INTERVAL;
$timeout.flush();
setTimeout(checkChildCount, TIME_INTERVAL);
}
else flag = true;
}, TIME_INTERVAL/2);
});
waitsFor(function(){ return flag;}, 'Timeouts finished', TIME_INTERVAL*(MAX_NODES/LIMIT_INTERVAL*2));
});
it('should handle nested expansion properly', function(){
var TIME_INTERVAL = 10,
LIMIT_INTERVAL = 10,
MAX_NODES = 50;
$rootScope.treedata = createSubTree(2, MAX_NODES);
$rootScope.treeOptions = {
enableIntervalToggle: true
};
element = $compile('<treecontrol tree-model="treedata" options="treeOptions">{{node.label}}</treecontrol>')($rootScope);
$rootScope.$digest();
var expectedChildCount = LIMIT_INTERVAL, subTreeExpectedChildCount = LIMIT_INTERVAL, flag = false;
runs(function(){
setTimeout(function checkChildCount(){
if(expectedChildCount<=MAX_NODES){
expect(element.find('li').length).toBe(expectedChildCount);
expectedChildCount += LIMIT_INTERVAL;
$timeout.flush();
setTimeout(checkChildCount, TIME_INTERVAL);
}
else {
element.find('li:eq(0) .tree-branch-head').click()
testSubTree();
}
}, TIME_INTERVAL/2);

function testSubTree(){
setTimeout(function checkChildCount(){
if(subTreeExpectedChildCount<=MAX_NODES){
expect(element.find('li:eq(0) li').length).toBe(subTreeExpectedChildCount);
subTreeExpectedChildCount += LIMIT_INTERVAL;
$timeout.flush();
setTimeout(checkChildCount, TIME_INTERVAL);
}
else flag = true;
}, TIME_INTERVAL/2);
}
});
waitsFor(function(){ return flag;}, 'Timeouts finished', 2*TIME_INTERVAL*(MAX_NODES/LIMIT_INTERVAL*2));
});
});
});