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