/* Copyright (c) 2008, Yahoo! Inc. All rights reserved. Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt version: 2.6.0 */ /** * Mechanism to execute a series of callbacks in a non-blocking queue. Each callback is executed via setTimout unless configured with a negative timeout, in which case it is run in blocking mode in the same execution thread as the previous callback. Callbacks can be function references or object literals with the following keys: * * * @namespace YAHOO.util * @class Chain * @constructor * @param callback* {Function|Object} Any number of callbacks to initialize the queue */ YAHOO.util.Chain = function () { /** * The callback queue * @property q * @type {Array} * @private */ this.q = [].slice.call(arguments); /** * Event fired when the callback queue is emptied via execution (not via * a call to chain.stop(). * @event end */ this.createEvent('end'); }; YAHOO.util.Chain.prototype = { /** * Timeout id used to pause or stop execution and indicate the execution state of the Chain. 0 indicates paused or stopped, -1 indicates blocking execution, and any positive number indicates non-blocking execution. * @property id * @type {number} * @private */ id : 0, /** * Begin executing the chain, or resume execution from the last paused position. * @method run * @return {Chain} the Chain instance */ run : function () { // Grab the first callback in the queue var c = this.q[0], fn; // If there is no callback in the queue or the Chain is currently // in an execution mode, return if (!c) { this.fireEvent('end'); return this; } else if (this.id) { return this; } fn = c.method || c; if (typeof fn === 'function') { var o = c.scope || {}, args = c.argument || [], ms = c.timeout || 0, me = this; if (!(args instanceof Array)) { args = [args]; } // Execute immediately if the callback timeout is negative. if (ms < 0) { this.id = ms; if (c.until) { for (;!c.until();) { // Execute the callback from scope, with argument fn.apply(o,args); } } else if (c.iterations) { for (;c.iterations-- > 0;) { fn.apply(o,args); } } else { fn.apply(o,args); } this.q.shift(); this.id = 0; return this.run(); } else { // If the until condition is set, check if we're done if (c.until) { if (c.until()) { // Shift this callback from the queue and execute the next // callback this.q.shift(); return this.run(); } // Otherwise if either iterations is not set or we're // executing the last iteration, shift callback from the queue } else if (!c.iterations || !--c.iterations) { this.q.shift(); } // Otherwise set to execute after the configured timeout this.id = setTimeout(function () { // Execute the callback from scope, with argument fn.apply(o,args); // Check if the Chain was not paused from inside the callback if (me.id) { // Indicate ready to run state me.id = 0; // Start the fun all over again me.run(); } },ms); } } return this; }, /** * Add a callback to the end of the queue * @method add * @param c {Function|Object} the callback function ref or object literal * @return {Chain} the Chain instance */ add : function (c) { this.q.push(c); return this; }, /** * Pause the execution of the Chain after the current execution of the * current callback completes. If called interstitially, clears the * timeout for the pending callback. Paused Chains can be restarted with * chain.run() * @method pause * @return {Chain} the Chain instance */ pause: function () { clearTimeout(this.id); this.id = 0; return this; }, /** * Stop and clear the Chain's queue after the current execution of the * current callback completes. * @method stop * @return {Chain} the Chain instance */ stop : function () { this.pause(); this.q = []; return this; } }; YAHOO.lang.augmentProto(YAHOO.util.Chain,YAHOO.util.EventProvider); /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ /** * The ColumnSet class defines and manages a DataTable's Columns, * including nested hierarchies and access to individual Column instances. * * @namespace YAHOO.widget * @class ColumnSet * @uses YAHOO.util.EventProvider * @constructor * @param aDefinitions {Object[]} Array of object literals that define cells in * the THEAD. */ YAHOO.widget.ColumnSet = function(aDefinitions) { this._sId = "yui-cs" + YAHOO.widget.ColumnSet._nCount; // First clone the defs aDefinitions = YAHOO.widget.DataTable._cloneObject(aDefinitions); this._init(aDefinitions); YAHOO.widget.ColumnSet._nCount++; YAHOO.log("ColumnSet initialized", "info", this.toString()); }; ///////////////////////////////////////////////////////////////////////////// // // Private member variables // ///////////////////////////////////////////////////////////////////////////// /** * Internal class variable to index multiple ColumnSet instances. * * @property ColumnSet._nCount * @type Number * @private * @static */ YAHOO.widget.ColumnSet._nCount = 0; YAHOO.widget.ColumnSet.prototype = { /** * Unique instance name. * * @property _sId * @type String * @private */ _sId : null, /** * Array of object literal Column definitions passed to the constructor. * * @property _aDefinitions * @type Object[] * @private */ _aDefinitions : null, ///////////////////////////////////////////////////////////////////////////// // // Public member variables // ///////////////////////////////////////////////////////////////////////////// /** * Top-down tree representation of Column hierarchy. * * @property tree * @type YAHOO.widget.Column[] */ tree : null, /** * Flattened representation of all Columns. * * @property flat * @type YAHOO.widget.Column[] * @default [] */ flat : null, /** * Array of Columns that map one-to-one to a table column. * * @property keys * @type YAHOO.widget.Column[] * @default [] */ keys : null, /** * ID index of nested parent hierarchies for HEADERS accessibility attribute. * * @property headers * @type String[] * @default [] */ headers : null, ///////////////////////////////////////////////////////////////////////////// // // Private methods // ///////////////////////////////////////////////////////////////////////////// /** * Initializes ColumnSet instance with data from Column definitions. * * @method _init * @param aDefinitions {Object[]} Array of object literals that define cells in * the THEAD . * @private */ _init : function(aDefinitions) { // DOM tree representation of all Columns var tree = []; // Flat representation of all Columns var flat = []; // Flat representation of only Columns that are meant to display data var keys = []; // Array of HEADERS attribute values for all keys in the "keys" array var headers = []; // Tracks current node list depth being tracked var nodeDepth = -1; // Internal recursive function to define Column instances var parseColumns = function(nodeList, parent) { // One level down nodeDepth++; // Create corresponding tree node if not already there for this depth if(!tree[nodeDepth]) { tree[nodeDepth] = []; } // Parse each node at this depth for attributes and any children for(var j=0; j maxRowDepth) { maxRowDepth = tmpRowDepth; } } } }; // Count max row depth for each row for(var m=0; m-1; i--) { if(allColumns[i]._sId === column) { return allColumns[i]; } } } return null; }, /** * Returns Column instance with given key or ColumnSet key index. * * @method getColumn * @param column {String | Number} Column key or ColumnSet key index. * @return {YAHOO.widget.Column} Column instance. */ getColumn : function(column) { if(YAHOO.lang.isNumber(column) && this.keys[column]) { return this.keys[column]; } else if(YAHOO.lang.isString(column)) { var allColumns = this.flat; var aColumns = []; for(var i=0; i 1) { return aColumns; } } return null; }, /** * Public accessor returns array of given Column's desendants (if any), including itself. * * @method getDescendants * @parem {YAHOO.widget.Column} Column instance. * @return {Array} Array including the Column itself and all descendants (if any). */ getDescendants : function(oColumn) { var oSelf = this; var allDescendants = []; var i; // Recursive function to loop thru all children var parse = function(oParent) { allDescendants.push(oParent); // This Column has children if(oParent.children) { for(i=0; i