blob: a22befc49d7ca64000e40f0781e1fd135b56b540 [file] [log] [blame]
/*
Copyright (c) 2004-2006, The Dojo Foundation
All Rights Reserved.
Licensed under the Academic Free License version 2.1 or above OR the
modified BSD license. For more information on Dojo licensing, see:
http://dojotoolkit.org/community/licensing.shtml
*/
dojo.provide("dojo.widget.TreeTimeoutIterator");
dojo.require("dojo.event.*");
dojo.require("dojo.json")
dojo.require("dojo.io.*");
dojo.require("dojo.widget.TreeCommon");
/**
* Iterates the tree processNext
* filterFunc/filterObj called to determine if I need to pass the node
*
* callFunc/callObj called to process the node
* callObj.callFunc(elem, iterator) should call iterator.forward() to go on
* callFunc may change elem to another object (e.g create widget from it),
* keeping its parent and parent position are untouched *
*
* finishFunc/finishObj called at the end
*
* TODO: it should work only sync-way to solve CPU-hungry tasks
*/
dojo.declare(
"dojo.widget.TreeTimeoutIterator",
null,
function(elem, callFunc, callObj) {
var _this = this;
this.currentParent = elem;
this.callFunc = callFunc;
this.callObj = callObj ? callObj: this;
this.stack = [];
},
{
// public
maxStackDepth: Number.POSITIVE_INFINITY,
stack: null,
currentParent: null,
currentIndex: 0,
filterFunc: function() { return true },
finishFunc: function() { return true },
setFilter: function(func, obj) {
this.filterFunc = func;
this.filterObj = obj;
},
setMaxLevel: function(level) {
this.maxStackDepth = level-2;
},
forward: function(timeout) {
var _this = this;
if (this.timeout) { // if timeout required between forwards
// tid will be assigned at the end of outer func execution
var tid = setTimeout(function() {_this.processNext(); clearTimeout(tid); }, _this.timeout);
} else {
return this.processNext();
}
},
start: function(processFirst) {
if (processFirst) {
return this.callFunc.call(this.callObj, this.currentParent, this);
}
return this.processNext();
},
/**
* @private
* find next node, move current parent to it if possible & process
*/
processNext: function() {
//dojo.debug("processNext with currentParent "+this.currentParent+" index "+this.currentIndex);
var handler;
var _this = this;
var found;
var next;
if (this.maxStackDepth == -2) {
return; // process only first cause level=0, do not process children
}
while (true) {
var children = this.currentParent.children;
if (children && children.length) {
// look for a node that can be the next target
do {
next = children[this.currentIndex];
//dojo.debug("check "+next);
} while (this.currentIndex++ < children.length && !(found = this.filterFunc.call(this.filterObj,next)));
if (found) {
//dojo.debug("found "+next);
// move to next node as new parent if depth is fine
// I can't check current children to decide whether to move it or not,
// because expand may populate children
if (next.isFolder && this.stack.length <= this.maxStackDepth) {
this.moveParent(next,0);
}
//dojo.debug("Run callFunc on "+next);
return this.callFunc.call(this.callObj, next, this);
}
}
if (this.stack.length) {
this.popParent();
continue;
}
break;
}
/**
* couldn't find next node to process, finish here
*/
return this.finishFunc.call(this.finishObj);
},
setFinish: function(func, obj) {
this.finishFunc = func;
this.finishObj = obj;
},
popParent: function() {
var p = this.stack.pop();
//dojo.debug("Pop "+p[0]+":"+p[1]);
this.currentParent = p[0];
this.currentIndex = p[1];
},
moveParent: function(nextParent, nextIndex) {
//dojo.debug("Move from "+this.currentParent+":"+this.currentIndex+" to "+nextParent+":"+nextIndex);
this.stack.push([this.currentParent, this.currentIndex]);
this.currentParent = nextParent;
this.currentIndex = nextIndex;
}
});