var arrayPrototype = Array.prototype,
slice = arrayPrototype.slice,
+ supportsSplice = function () {
+ var array = [],
+ lengthBefore,
+ j = 20;
+
+ if (!array.splice) {
+ return false;
+ }
+
+ // This detects a bug in IE8 splice method:
+ // see http://social.msdn.microsoft.com/Forums/en-US/iewebdevelopment/thread/6e946d03-e09f-4b22-a4dd-cd5e276bf05a/
+
+ while (j--) {
+ array.push("A");
+ }
+
+ array.splice(15, 0, "F", "F", "F", "F", "F","F","F","F","F","F","F","F","F","F","F","F","F","F","F","F","F");
+
+ lengthBefore = array.length; //41
+ array.splice(13, 0, "XXX"); // add one element
+
+ if (lengthBefore+1 != array.length) {
+ return false;
+ }
+ // end IE8 bug
+
+ return true;
+ }(),
supportsForEach = 'forEach' in arrayPrototype,
supportsMap = 'map' in arrayPrototype,
supportsIndexOf = 'indexOf' in arrayPrototype,
}(),
supportsSliceOnNodeList = true,
ExtArray;
+
try {
// IE 6 - 8 will throw an error when using Array.prototype.slice on NodeList
if (typeof document !== 'undefined') {
supportsSliceOnNodeList = false;
}
- ExtArray = Ext.Array = {
-<span id='Ext-Array-method-each'> /**
-</span> * Iterates an array or an iterable value and invoke the given callback function for each item.
+ function fixArrayIndex (array, index) {
+ return (index < 0) ? Math.max(0, array.length + index)
+ : Math.min(array.length, index);
+ }
- var countries = ['Vietnam', 'Singapore', 'United States', 'Russia'];
+ /*
+ Does the same work as splice, but with a slightly more convenient signature. The splice
+ method has bugs in IE8, so this is the implementation we use on that platform.
+
+ The rippling of items in the array can be tricky. Consider two use cases:
+
+ index=2
+ removeCount=2
+ /=====\
+ +---+---+---+---+---+---+---+---+
+ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
+ +---+---+---+---+---+---+---+---+
+ / \/ \/ \/ \
+ / /\ /\ /\ \
+ / / \/ \/ \ +--------------------------+
+ / / /\ /\ +--------------------------+ \
+ / / / \/ +--------------------------+ \ \
+ / / / /+--------------------------+ \ \ \
+ / / / / \ \ \ \
+ v v v v v v v v
+ +---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+---+
+ | 0 | 1 | 4 | 5 | 6 | 7 | | 0 | 1 | a | b | c | 4 | 5 | 6 | 7 |
+ +---+---+---+---+---+---+ +---+---+---+---+---+---+---+---+---+
+ A B \=========/
+ insert=[a,b,c]
+
+ In case A, it is obvious that copying of [4,5,6,7] must be left-to-right so
+ that we don't end up with [0,1,6,7,6,7]. In case B, we have the opposite; we
+ must go right-to-left or else we would end up with [0,1,a,b,c,4,4,4,4].
+ */
+ function replaceSim (array, index, removeCount, insert) {
+ var add = insert ? insert.length : 0,
+ length = array.length,
+ pos = fixArrayIndex(array, index);
+
+ // we try to use Array.push when we can for efficiency...
+ if (pos === length) {
+ if (add) {
+ array.push.apply(array, insert);
+ }
+ } else {
+ var remove = Math.min(removeCount, length - pos),
+ tailOldPos = pos + remove,
+ tailNewPos = tailOldPos + add - remove,
+ tailCount = length - tailOldPos,
+ lengthAfterRemove = length - remove,
+ i;
- Ext.Array.each(countries, function(name, index, countriesItSelf) {
- console.log(name);
- });
+ if (tailNewPos < tailOldPos) { // case A
+ for (i = 0; i < tailCount; ++i) {
+ array[tailNewPos+i] = array[tailOldPos+i];
+ }
+ } else if (tailNewPos > tailOldPos) { // case B
+ for (i = tailCount; i--; ) {
+ array[tailNewPos+i] = array[tailOldPos+i];
+ }
+ } // else, add == remove (nothing to do)
+
+ if (add && pos === lengthAfterRemove) {
+ array.length = lengthAfterRemove; // truncate array
+ array.push.apply(array, insert);
+ } else {
+ array.length = lengthAfterRemove + add; // reserves space
+ for (i = 0; i < add; ++i) {
+ array[pos+i] = insert[i];
+ }
+ }
+ }
- var sum = function() {
- var sum = 0;
+ return array;
+ }
- Ext.Array.each(arguments, function(value) {
- sum += value;
- });
+ function replaceNative (array, index, removeCount, insert) {
+ if (insert && insert.length) {
+ if (index < array.length) {
+ array.splice.apply(array, [index, removeCount].concat(insert));
+ } else {
+ array.push.apply(array, insert);
+ }
+ } else {
+ array.splice(index, removeCount);
+ }
+ return array;
+ }
- return sum;
- };
+ function eraseSim (array, index, removeCount) {
+ return replaceSim(array, index, removeCount);
+ }
- sum(1, 2, 3); // returns 6
+ function eraseNative (array, index, removeCount) {
+ array.splice(index, removeCount);
+ return array;
+ }
- * The iteration can be stopped by returning false in the function callback.
+ function spliceSim (array, index, removeCount) {
+ var pos = fixArrayIndex(array, index),
+ removed = array.slice(index, fixArrayIndex(array, pos+removeCount));
- Ext.Array.each(countries, function(name, index, countriesItSelf) {
- if (name === 'Singapore') {
- return false; // break here
+ if (arguments.length < 4) {
+ replaceSim(array, pos, removeCount);
+ } else {
+ replaceSim(array, pos, removeCount, slice.call(arguments, 3));
}
- });
+ return removed;
+ }
+
+ function spliceNative (array) {
+ return array.splice.apply(array, slice.call(arguments, 1));
+ }
+
+ var erase = supportsSplice ? eraseNative : eraseSim,
+ replace = supportsSplice ? replaceNative : replaceSim,
+ splice = supportsSplice ? spliceNative : spliceSim;
+
+ // NOTE: from here on, use erase, replace or splice (not native methods)...
+
+ ExtArray = Ext.Array = {
+<span id='Ext-Array-method-each'> /**
+</span> * Iterates an array or an iterable value and invoke the given callback function for each item.
+ *
+ * var countries = ['Vietnam', 'Singapore', 'United States', 'Russia'];
+ *
+ * Ext.Array.each(countries, function(name, index, countriesItSelf) {
+ * console.log(name);
+ * });
+ *
+ * var sum = function() {
+ * var sum = 0;
+ *
+ * Ext.Array.each(arguments, function(value) {
+ * sum += value;
+ * });
+ *
+ * return sum;
+ * };
+ *
+ * sum(1, 2, 3); // returns 6
+ *
+ * The iteration can be stopped by returning false in the function callback.
+ *
+ * Ext.Array.each(countries, function(name, index, countriesItSelf) {
+ * if (name === 'Singapore') {
+ * return false; // break here
+ * }
+ * });
+ *
+ * {@link Ext#each Ext.each} is alias for {@link Ext.Array#each Ext.Array.each}
+ *
* @param {Array/NodeList/Mixed} iterable The value to be iterated. If this
* argument is not iterable, the callback function is called once.
* @param {Function} fn The callback function. If it returns false, the iteration stops and this method returns
* the current `index`. Arguments passed to this callback function are:
-
-- `item`: {Mixed} The item at the current `index` in the passed `array`
-- `index`: {Number} The current `index` within the `array`
-- `allItems`: {Array/NodeList/Mixed} The `array` passed as the first argument to `Ext.Array.each`
-
+ *
+ * - `item` : Mixed - The item at the current `index` in the passed `array`
+ * - `index` : Number - The current `index` within the `array`
+ * - `allItems` : Array/NodeList/Mixed - The `array` passed as the first argument to `Ext.Array.each`
+ *
* @param {Object} scope (Optional) The scope (`this` reference) in which the specified function is executed.
* @param {Boolean} reverse (Optional) Reverse the iteration order (loop from the end to the beginning)
* Defaults false
* @return {Boolean} See description for the `fn` parameter.
- * @markdown
*/
each: function(array, fn, scope, reverse) {
array = ExtArray.from(array);
* @param {Array} array The array to iterate
* @param {Function} fn The function callback, to be invoked these arguments:
*
-- `item`: {Mixed} The item at the current `index` in the passed `array`
-- `index`: {Number} The current `index` within the `array`
-- `allItems`: {Array} The `array` itself which was passed as the first argument
-
+ * - `item` : Mixed - The item at the current `index` in the passed `array`
+ * - `index` : Number - The current `index` within the `array`
+ * - `allItems` : Array - The `array` itself which was passed as the first argument
+ *
* @param {Object} scope (Optional) The execution scope (`this`) in which the specified function is executed.
- * @markdown
*/
forEach: function(array, fn, scope) {
if (supportsForEach) {
* @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)
- * @markdown
*/
indexOf: function(array, item, from) {
if (supportsIndexOf) {
* @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
- * @markdown
*/
contains: function(array, item) {
if (supportsIndexOf) {
<span id='Ext-Array-method-toArray'> /**
</span> * Converts any iterable (numeric indices and a length property) into a true array.
-
-function test() {
- var args = Ext.Array.toArray(arguments),
- fromSecondToLastArgs = Ext.Array.toArray(arguments, 1);
-
- alert(args.join(' '));
- alert(fromSecondToLastArgs.join(' '));
-}
-
-test('just', 'testing', 'here'); // alerts 'just testing here';
- // alerts 'testing here';
-
-Ext.Array.toArray(document.getElementsByTagName('div')); // will convert the NodeList into an array
-Ext.Array.toArray('splitted'); // returns ['s', 'p', 'l', 'i', 't', 't', 'e', 'd']
-Ext.Array.toArray('splitted', 0, 3); // returns ['s', 'p', 'l', 'i']
-
+ *
+ * function test() {
+ * var args = Ext.Array.toArray(arguments),
+ * fromSecondToLastArgs = Ext.Array.toArray(arguments, 1);
+ *
+ * alert(args.join(' '));
+ * alert(fromSecondToLastArgs.join(' '));
+ * }
+ *
+ * test('just', 'testing', 'here'); // alerts 'just testing here';
+ * // alerts 'testing here';
+ *
+ * Ext.Array.toArray(document.getElementsByTagName('div')); // will convert the NodeList into an array
+ * Ext.Array.toArray('splitted'); // returns ['s', 'p', 'l', 'i', 't', 't', 'e', 'd']
+ * Ext.Array.toArray('splitted', 0, 3); // returns ['s', 'p', 'l', 'i']
+ *
+ * {@link Ext#toArray Ext.toArray} is alias for {@link Ext.Array#toArray Ext.Array.toArray}
+ *
* @param {Mixed} iterable the iterable object to be turned into a true Array.
* @param {Number} start (Optional) a zero-based index that specifies the start of extraction. Defaults to 0
* @param {Number} end (Optional) a zero-based index that specifies the end of extraction. Defaults to the last
* index of the iterable value
* @return {Array} array
- * @markdown
*/
toArray: function(iterable, start, end){
if (!iterable || !iterable.length) {
<span id='Ext-Array-method-pluck'> /**
</span> * Plucks the value of a property from each item in the Array. Example:
*
- Ext.Array.pluck(Ext.query("p"), "className"); // [el1.className, el2.className, ..., elN.className]
-
+ * Ext.Array.pluck(Ext.query("p"), "className"); // [el1.className, el2.className, ..., elN.className]
+ *
* @param {Array|NodeList} array The Array of items to pluck the value from.
* @param {String} propertyName The property name to pluck from each element.
* @return {Array} The value from each item in the Array.
<span id='Ext-Array-method-map'> /**
</span> * 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
<span id='Ext-Array-method-clean'> /**
</span> * Filter through an array and remove empty item as defined in {@link Ext#isEmpty Ext.isEmpty}
*
- * @see Ext.Array.filter
+ * See {@link Ext.Array#filter}
+ *
* @param {Array} array
* @return {Array} results
*/
<span id='Ext-Array-method-filter'> /**
</span> * 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
* @param {Boolean} (Optional) newReference True to clone the given array and return a new reference if necessary,
* defaults to false
* @return {Array} array
- * @markdown
*/
from: function(value, newReference) {
if (value === undefined || value === null) {
var index = ExtArray.indexOf(array, item);
if (index !== -1) {
- array.splice(index, 1);
+ erase(array, index, 1);
}
return array;
*
* @param {Array} array The array
* @param {Mixed} item The item to include
- * @return {Array} The passed array itself
*/
include: function(array, item) {
if (!ExtArray.contains(array, item)) {
},
<span id='Ext-Array-method-merge'> /**
-</span> * Merge multiple arrays into one with unique items. Alias to {@link Ext.Array#union}.
+</span> * Merge multiple arrays into one with unique items.
+ *
+ * {@link Ext.Array#union} is alias for {@link Ext.Array#merge}
*
- * @param {Array} array,...
+ * @param {Array} array1
+ * @param {Array} array2
+ * @param {Array} etc
* @return {Array} merged
*/
merge: function() {
<span id='Ext-Array-method-intersect'> /**
</span> * Merge multiple arrays into one with unique items that exist in all of the arrays.
*
- * @param {Array} array,...
+ * @param {Array} array1
+ * @param {Array} array2
+ * @param {Array} etc
* @return {Array} intersect
*/
intersect: function() {
}
}
- minArray = Ext.Array.unique(minArray);
- arrays.splice(x, 1);
+ minArray = ExtArray.unique(minArray);
+ erase(arrays, x, 1);
// Use the smallest unique'd array as the anchor loop. If the other array(s) do contain
// an item in the small array, we're likely to find it before reaching the end
<span id='Ext-Array-method-difference'> /**
</span> * Perform a set difference A-B by subtracting all items in array B from array A.
*
- * @param {Array} array A
- * @param {Array} array B
+ * @param {Array} arrayA
+ * @param {Array} arrayB
* @return {Array} difference
*/
difference: function(arrayA, arrayB) {
for (i = 0,lnB = arrayB.length; i < lnB; i++) {
for (j = 0; j < ln; j++) {
if (clone[j] === arrayB[i]) {
- clone.splice(j, 1);
+ erase(clone, j, 1);
j--;
ln--;
}
return clone;
},
+<span id='Ext-Array-method-slice'> /**
+</span> * Returns a shallow copy of a part of an array. This is equivalent to the native
+ * call "Array.prototype.slice.call(array, begin, end)". This is often used when "array"
+ * is "arguments" since the arguments object does not supply a slice method but can
+ * be the context object to Array.prototype.slice.
+ *
+ * @param {Array} array The array (or arguments object).
+ * @param {Number} begin The index at which to begin. Negative values are offsets from
+ * the end of the array.
+ * @param {Number} end The index at which to end. The copied items do not include
+ * end. Negative values are offsets from the end of the array. If end is omitted,
+ * all items up to the end of the array are copied.
+ * @return {Array} The copied piece of the array.
+ */
+ slice: function(array, begin, end) {
+ return slice.call(array, begin, end);
+ },
+
<span id='Ext-Array-method-sort'> /**
</span> * Sorts the elements of an Array.
* By default, this method sorts the elements alphabetically and ascending.
<span id='Ext-Array-method-flatten'> /**
</span> * Recursively flattens into 1-d Array. Injects Arrays inline.
- * @param {Array} array The array to flatten
- * @return {Array} The new, flattened array.
+ *
*/
flatten: function(array) {
var worker = [];
<span id='Ext-Array-method-min'> /**
</span> * Returns the minimum value in the Array.
+ *
* @param {Array|NodeList} array The Array from which to select the minimum value.
* @param {Function} comparisonFn (optional) a function to perform the comparision which determines minimization.
- * If omitted the "<" operator will be used. Note: gt = 1; eq = 0; lt = -1
+ * If omitted the "<" operator will be used. Note: gt = 1; eq = 0; lt = -1
* @return {Mixed} minValue The minimum value
*/
min: function(array, comparisonFn) {
},
<span id='Ext-Array-method-max'> /**
-</span> * Returns the maximum value in the Array
+</span> * Returns the maximum value in the Array.
+ *
* @param {Array|NodeList} array The Array from which to select the maximum value.
* @param {Function} comparisonFn (optional) a function to perform the comparision which determines maximization.
- * If omitted the ">" operator will be used. Note: gt = 1; eq = 0; lt = -1
+ * If omitted the ">" operator will be used. Note: gt = 1; eq = 0; lt = -1
* @return {Mixed} maxValue The maximum value
*/
max: function(array, comparisonFn) {
},
<span id='Ext-Array-method-mean'> /**
-</span> * Calculates the mean of all items in the array
+</span> * Calculates the mean of all items in the array.
+ *
* @param {Array} array The Array to calculate the mean value of.
* @return {Number} The mean.
*/
},
<span id='Ext-Array-method-sum'> /**
-</span> * Calculates the sum of all items in the given array
+</span> * Calculates the sum of all items in the given array.
+ *
* @param {Array} array The Array to calculate the sum value of.
* @return {Number} The sum.
*/
}
return sum;
- }
+ },
+ //<debug>
+ _replaceSim: replaceSim, // for unit testing
+ _spliceSim: spliceSim,
+ //</debug>
+
+<span id='Ext-Array-method-erase'> /**
+</span> * Removes items from an array. This is functionally equivalent to the splice method
+ * of Array, but works around bugs in IE8's splice method and does not copy the
+ * removed elements in order to return them (because very often they are ignored).
+ *
+ * @param {Array} array The Array on which to replace.
+ * @param {Number} index The index in the array at which to operate.
+ * @param {Number} removeCount The number of items to remove at index.
+ * @return {Array} The array passed.
+ * @method
+ */
+ erase: erase,
+
+<span id='Ext-Array-method-insert'> /**
+</span> * Inserts items in to an array.
+ *
+ * @param {Array} array The Array on which to replace.
+ * @param {Number} index The index in the array at which to operate.
+ * @param {Array} items The array of items to insert at index.
+ * @return {Array} The array passed.
+ */
+ insert: function (array, index, items) {
+ return replace(array, index, 0, items);
+ },
+
+<span id='Ext-Array-method-replace'> /**
+</span> * Replaces items in an array. This is functionally equivalent to the splice method
+ * of Array, but works around bugs in IE8's splice method and is often more convenient
+ * to call because it accepts an array of items to insert rather than use a variadic
+ * argument list.
+ *
+ * @param {Array} array The Array on which to replace.
+ * @param {Number} index The index in the array at which to operate.
+ * @param {Number} removeCount The number of items to remove at index (can be 0).
+ * @param {Array} insert An optional array of items to insert at index.
+ * @return {Array} The array passed.
+ * @method
+ */
+ replace: replace,
+
+<span id='Ext-Array-method-splice'> /**
+</span> * Replaces items in an array. This is equivalent to the splice method of Array, but
+ * works around bugs in IE8's splice method. The signature is exactly the same as the
+ * splice method except that the array is the first argument. All arguments following
+ * removeCount are inserted in the array at index.
+ *
+ * @param {Array} array The Array on which to replace.
+ * @param {Number} index The index in the array at which to operate.
+ * @param {Number} removeCount The number of items to remove at index (can be 0).
+ * @return {Array} An array containing the removed items.
+ * @method
+ */
+ splice: splice
};
<span id='Ext-method-each'> /**
-</span> * Convenient alias to {@link Ext.Array#each}
+</span> * @method
* @member Ext
- * @method each
+ * @alias Ext.Array#each
*/
- Ext.each = Ext.Array.each;
+ Ext.each = ExtArray.each;
<span id='Ext-Array-method-union'> /**
-</span> * Alias to {@link Ext.Array#merge}.
+</span> * @method
* @member Ext.Array
- * @method union
+ * @alias Ext.Array#merge
*/
- Ext.Array.union = Ext.Array.merge;
+ ExtArray.union = ExtArray.merge;
<span id='Ext-method-min'> /**
</span> * Old alias to {@link Ext.Array#min}
* @deprecated 4.0.0 Use {@link Ext.Array#min} instead
+ * @method
* @member Ext
- * @method min
+ * @alias Ext.Array#min
*/
- Ext.min = Ext.Array.min;
+ Ext.min = ExtArray.min;
<span id='Ext-method-max'> /**
</span> * Old alias to {@link Ext.Array#max}
* @deprecated 4.0.0 Use {@link Ext.Array#max} instead
+ * @method
* @member Ext
- * @method max
+ * @alias Ext.Array#max
*/
- Ext.max = Ext.Array.max;
+ Ext.max = ExtArray.max;
<span id='Ext-method-sum'> /**
</span> * Old alias to {@link Ext.Array#sum}
* @deprecated 4.0.0 Use {@link Ext.Array#sum} instead
+ * @method
* @member Ext
- * @method sum
+ * @alias Ext.Array#sum
*/
- Ext.sum = Ext.Array.sum;
+ Ext.sum = ExtArray.sum;
<span id='Ext-method-mean'> /**
</span> * Old alias to {@link Ext.Array#mean}
* @deprecated 4.0.0 Use {@link Ext.Array#mean} instead
+ * @method
* @member Ext
- * @method mean
+ * @alias Ext.Array#mean
*/
- Ext.mean = Ext.Array.mean;
+ Ext.mean = ExtArray.mean;
<span id='Ext-method-flatten'> /**
</span> * Old alias to {@link Ext.Array#flatten}
* @deprecated 4.0.0 Use {@link Ext.Array#flatten} instead
+ * @method
* @member Ext
- * @method flatten
+ * @alias Ext.Array#flatten
*/
- Ext.flatten = Ext.Array.flatten;
+ Ext.flatten = ExtArray.flatten;
<span id='Ext-method-clean'> /**
-</span> * Old alias to {@link Ext.Array#clean Ext.Array.clean}
- * @deprecated 4.0.0 Use {@link Ext.Array.clean} instead
+</span> * Old alias to {@link Ext.Array#clean}
+ * @deprecated 4.0.0 Use {@link Ext.Array#clean} instead
+ * @method
* @member Ext
- * @method clean
+ * @alias Ext.Array#clean
*/
- Ext.clean = Ext.Array.clean;
+ Ext.clean = ExtArray.clean;
<span id='Ext-method-unique'> /**
-</span> * Old alias to {@link Ext.Array#unique Ext.Array.unique}
- * @deprecated 4.0.0 Use {@link Ext.Array.unique} instead
+</span> * Old alias to {@link Ext.Array#unique}
+ * @deprecated 4.0.0 Use {@link Ext.Array#unique} instead
+ * @method
* @member Ext
- * @method unique
+ * @alias Ext.Array#unique
*/
- Ext.unique = Ext.Array.unique;
+ Ext.unique = ExtArray.unique;
<span id='Ext-method-pluck'> /**
</span> * Old alias to {@link Ext.Array#pluck Ext.Array.pluck}
* @deprecated 4.0.0 Use {@link Ext.Array#pluck Ext.Array.pluck} instead
+ * @method
* @member Ext
- * @method pluck
+ * @alias Ext.Array#pluck
*/
- Ext.pluck = Ext.Array.pluck;
+ Ext.pluck = ExtArray.pluck;
<span id='Ext-method-toArray'> /**
-</span> * Convenient alias to {@link Ext.Array#toArray Ext.Array.toArray}
- * @param {Iterable} the iterable object to be turned into a true Array.
+</span> * @method
* @member Ext
- * @method toArray
- * @return {Array} array
+ * @alias Ext.Array#toArray
*/
Ext.toArray = function() {
return ExtArray.toArray.apply(ExtArray, arguments);
- }
+ };
})();
</pre>
</body>