/** * @class Ext.Array * * A set of useful static methods to deal with arrays; provide missing methods for older browsers * @singleton */ (function() { var arrayPrototype = Array.prototype, supportsForEach = 'forEach' in arrayPrototype, supportsMap = 'map' in arrayPrototype, supportsIndexOf = 'indexOf' in arrayPrototype, supportsEvery = 'every' in arrayPrototype, supportsSome = 'some' in arrayPrototype, supportsFilter = 'filter' in arrayPrototype; Ext.Array = {
/** * Iterates an array calling the supplied function. * @param {Array/NodeList/Mixed} array The array to be iterated. If this * argument is not really an array, the supplied function is called once. * @param {Function} fn The function to be called with each item. If the * supplied function returns false, iteration stops and this method returns * the current index. This function is called with * the following arguments: * * @param {Object} scope The scope (this reference) in which the specified function is executed. * Defaults to the item at the current index * within the passed array. * @return {Boolean} See description for the fn parameter. */ each: function(array, fn, scope) { if (Ext.isEmpty(array, true)) { return 0; } if (!Ext.isIterable(array) || Ext.isPrimitive(array)) { array = [array]; } for (var i = 0, len = array.length; i < len; i++) { if (fn.call(scope || array[i], array[i], i, array) === false) { return i; } } return true; },
/** * Executes the provided function (callback) once for each element present in the array. * Note that this will delegate to the native forEach method in Array.prototype if the current * browser supports it. It doesn't support breaking out of the iteration by returning false * in the callback function like {@link Ext.Array.each}. Use this method when you don't need * that feature for a huge performance boost on modern browsers * * @param {Array} array The array to loop through * @param {Function} fn The function callback, to be invoked with three arguments: the value of the element, * the index of the element, and the Array object being traversed. * @param {Object} scope The scope (this reference) in which the specified function is executed. */ forEach: function(array, fn, scope) { if (supportsForEach) { return array.forEach(fn, scope); } return Ext.Array.each(array, fn, scope); },
/** * Get the index of the provided item in the given array, a supplement for the * missing Array.prototype.indexOf in Internet Explorer. * * @param {Array} array The array to check * @param {Mixed} item The item to look for * @param {Number} from (Optional) The index at which to begin the search * @return {Number} The index of item in the array (or -1 if it is not found) */ indexOf: function(array, item, from) { if (supportsIndexOf) { return array.indexOf(item, from); } var i, length = array.length; for (i = (from < 0) ? Math.max(0, length + from) : from || 0; i < length; i++) { if (array[i] === item) { return i; } } return -1; },
/** * Checks whether or not the given array contains the specified item * * @param {Array} array The array to check * @param {Mixed} item The item to look for * @return {Boolean} True if the array contains the item, false otherwise */ contains: function(array, item) { return (Ext.Array.indexOf(array, item) !== -1); },
/** * Converts any iterable (numeric indices and a length property) into a true array * Don't use this on strings. IE doesn't support "abc"[0] which this implementation depends on. * For strings, use this instead: "abc".match(/./g) => [a,b,c]; * * @param {Iterable} array the iterable object to be turned into a true Array. * @param {Number} start a number that specifies where to start the selection. * @param {Number} end a number that specifies where to end the selection. * @return {Array} array */ toArray: function(array, start, end) { return Array.prototype.slice.call(array, start || 0, end || array.length); },
/** * Plucks the value of a property from each item in the Array * Example: *

		 * Ext.pluck(Ext.query("p"), "className"); // [el1.className, el2.className, ..., elN.className]
		 * 
* * @param {Array|NodeList} arr The Array of items to pluck the value from. * @param {String} prop The property name to pluck from each element. * @return {Array} The value from each item in the Array. */ pluck: function(arr, prop) { var ret = []; Ext.each(arr, function(v) { ret.push(v[prop]); }); return ret; },
/** * Creates a new array with the results of calling a provided function on every element in this array. * @param {Array} array * @param {Function} fn Callback function for each item * @param {Object} scope Callback function scope * @return {Array} results */ map: function(array, fn, scope) { if (!fn) { throw new Error("[Ext.Array.map] fn must be a valid callback function"); } if (supportsMap) { return array.map(fn, scope); } var results = [], i = 0, len = array.length; for (; i < len; i++) { if (i in array) { results[i] = fn.call(scope, array[i], i, array); } } return results; },
/** * Executes the specified function for each array element until the function returns a falsy value. * If such an item is found, the function will return false immediately. * Otherwise, it will return true. * @param {Array} array * @param {Function} fn Callback function for each item * @param {Object} scope Callback function scope * @return {Boolean} True if no false value is returned by the callback function. */ every: function(array, fn, scope) { if (supportsEvery) { return array.every(fn, scope); } var i = 0, len = array.length; for (; i < len; ++i) { if (i in array && !fn.call(scope, array[i], i, array)) { return false; } } return true; },
/** * Executes the specified function for each array element until the function returns a truthy value. * If such an item is found, the function will return true immediately. Otherwise, it will return false. * @param {Array} array * @param {Function} fn Callback function for each item * @param {Object} scope Callback function scope * @return {Boolean} True if the callback function returns a truthy value. */ some: function(array, fn, scope) { if (supportsSome) { return array.some(fn, scope); } var i = 0, len = array.length; for (; i < len; ++i) { if (i in array && fn.call(scope, array[i], i, array)) { return true; } } return false; },
/** * Filter through an array and remove empty item as defined in {@link Ext.isEmpty} * @see Ext.Array.filter * @param {Array} array * @return {Array} results */ clean: function(array) { var results = [], i, ln, item; for (i = 0, ln = array.length; i < ln; i++) { item = array[i]; if (!Ext.isEmpty(item)) { results.push(item); } } return results; },
/** * Returns a new array with unique items * @param {Array} array * @return {Array} results */ unique: function(array) { var clone = [], me = Ext.Array; me.forEach(array, function(item) { if (!me.contains(clone, item)) { clone.push(item); } }); return clone; },
/** * Creates a new array with all of the elements of this array for which * the provided filtering function returns true. * @param {Array} array * @param {Function} fn Callback function for each item * @param {Object} scope Callback function scope * @return {Array} results */ filter: function(array, fn, scope) { if (!fn) { throw new Error("[Ext.Array.filter] fn must be a valid callback function"); } if (supportsFilter) { return array.filter(fn, scope); } var results = [], i = 0, len = array.length; for (; i < len; i++) { if ((i in array) && fn.call(scope, array[i], i, array)) { results.push(array[i]); } } return results; },
/** * Converts a value to an array if it's not already an array * * @param {Array/Mixed} value The value to convert to an array if it is defined and not already an array. * @return {Array} array */ from: function(value) { if (Ext.isIterable(value)) { return Ext.Array.toArray(value); } if (Ext.isDefined(value) && value !== null) { return [value]; } return []; },
/** * Removes the specified item from the array if it exists * * @param {Array} array The array * @param {Mixed} item The item to remove * @return {Array} The passed array itself */ remove: function(array, item) { var index = Ext.Array.indexOf(array, item); if (index !== -1) { array.splice(index, 1); } return array; },
/** * Push an item into the array only if the array doesn't contain it yet * * @param {Array} array The array * @param {Mixed} item The item to include * @return {Array} The passed array itself */ include: function(array, item) { if (!Ext.Array.contains(array, item)) { array.push(item); } },
/** * Clone a flat array without referencing the previous one. Note that this is different * from Ext.clone since it doesn't handle recursive cloning. Simply a convenient, easy-to-remember method * for Array.prototype.slice.call(array) * * @param {Array} array The array * @return {Array} The clone array */ clone: function(array) { return arrayPrototype.slice.call(array); },
/** * Merge multiple arrays into one with unique items * * @param {Array} array,... * @return {Array} merged */ merge: function() { var source = arguments[0], toMerge = arrayPrototype.slice.call(arguments, 1), i, j, ln, subLn, array; for (i = 0, ln = toMerge.length; i < ln; i++) { array = toMerge[i]; for (j = 0, subLn = array.length; j < subLn; j++) { Ext.Array.include(source, array[j]); } } return source; } }; Ext.deprecate('core', '4.0dev', function() {
/** * This method is deprecated, use {@link Ext.Array.toArray} instead * @member Ext * @method toArray * @deprecated */ Ext.toArray = function() { console.warn("[DEPRECATED][Ext.toArray] please use Ext.Array.toArray instead"); return Ext.Array.toArray.apply(Ext.Array, arguments); };
/** * This method is deprecated, Use {@link Ext.Array.pluck} instead * @member Ext * @method pluck * @deprecated */ Ext.pluck = function(arr, prop) { console.warn("[DEPRECATED][Ext.pluck] please use Ext.Array.pluck instead"); return Ext.Array.pluck.apply(Ext.Array, arguments); }; }); })();