/* * Ext iterators * Version: 6 * * Copyright (c) 2009, All rights reserved * Davis Davis * Michael Smyers * * License: BSD */ Ext.namespace('Ext.iterators'); Ext.apply(Ext, { /** * Inspect the type of data, and return the correct iterator. * This is an iterator factory. * * @param data * @param fn * @param scope * @returns an appropriate iterator */ iter : function(data, fn, scope, args) { if (!data) return null; args = Ext.value(args, {}); if (Ext.isArray(data) || args.type == 'array'){ return new Ext.iterators.ArrayIterator(data, fn, scope); }else if (data.getCount && data.getAt || args.type == 'store') { return new Ext.iterators.StoreIterator(data, fn, scope); }else if (args.type == 'property'){ return new Ext.iterators.PropertyIterator(data, fn, scope); }else{ return new Ext.iterators.SingleIterator(data, fn, scope); } } }); /** * Allows you to traverse down a list of *THINGS*, where *THINGS* are defined by the class you use. */ Ext.iterators.Iterator = Ext.extend(Object, { data : null, fn : null, scope : null, constructor : function( data, fn, scope ) { this.scope = scope||this; this.fn = fn || Ext.emptyFn; this.data = data; }, /** * Operate a function on each item in this iterator. Always from FIRST to LAST. Does not affect the index pointer. * * @param {function} fn Optional parameter, defaults to the fn passed in originally. * @param {Object} scope Optional parameter, defaults to the scope passed in originally. */ each : function( fn, scope ) { var iter = new Ext.iter(this.data, fn||this.fn, scope||this.scope); while(iter.hasNext()){ iter.next(); } iter.destroy(); return null; }, /** * Retrieve the next item. Moves the index pointer. Returns null if there is nothing next (will not execute your fn if nothing is next). * If your fn returns something, this fn will return it too. * * @param {function} fn Optional parameter, defaults to the fn passed in originally. * @param {Object} scope Optional parameter, defaults to the scope passed in originally. */ next : function( fn, scope ) { if (this.hasNext()){ var item = this.getAndTransition(); // alert someone that we moved next var result = this.onNext(item, fn, scope); if (result){ return result; }else{ return item; } } return null; }, /** * @returns true if you are at the end of the list. The subclass will implement this. */ hasNext : Ext.emptyFn, // private getAndTransition : Ext.emptyFn, //private. allow a subclass to change the alert method. (maybe an event?) onNext : function(item, fn, scope) { fn = fn || this.fn; scope = scope || this.scope; return fn.call(scope, item, this.index, this.data); }, /** * Delete the pointers to your data. Only really useful for IE6 which uses ref counting. */ destroy : function() { // tell the base class this.onDestroy(); // kill it delete this.data; delete this.fn; delete this.scope; }, onDestroy : Ext.emptyFn }); /** * Returns a single item. hasNext returns true until you receive the item. */ Ext.iterators.SingleIterator = Ext.extend(Ext.iterators.Iterator, { getAndTransition : function() { this.shown = true; return this.data; }, hasNext : function() { return this.shown; } }); /** * Iterates an array. */ Ext.iterators.ArrayIterator = Ext.extend(Ext.iterators.Iterator, { index : 0, hasNext : function() { return this.index < this.getLength(); }, getAndTransition : function() { var item = this.get(); this.transition(); return item; }, // private. allows subclass to override get portion get : function() { return this.data[this.index]; }, // private. allows subclass to override transition portion transition : function() { this.index++; }, // private. allows subclass to override max portion getLength : function() { return this.data.length; } }); Ext.iterators.PropertyIterator = Ext.extend(Ext.iterators.ArrayIterator, { _data : null, /** * Allows for "lazy initialization" of the property list. Will only "spread out" the properties of the object * if you need it. */ initialize : function() { this._data = []; for(var prop in this.data){ if (this.data.hasOwnProperty(prop)){ this._data.push(prop); } } }, getLength : function() { if (!this._data) this.initialize(); return this._data.length; }, get : function() { if (!this._data) this.initialize(); return this._data[this.index]; } }); /** * Iterates through an Ext.data.Store */ Ext.iterators.StoreIterator = Ext.extend(Ext.iterators.ArrayIterator, { getLength : function() { return this.data.getCount(); }, get : function() { return this.data.getAt(this.index); } }); Ext.iterators.MixedCollectionIterator = Ext.extend(Ext.iterators.StoreIterator, { get : function() { return this.data.itemAt(this.index); } });