/* 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; } });