Upgrade to ExtJS 4.0.2 - Released 06/09/2011
[extjs.git] / src / core / src / lang / Array.js
index 6b52ac9..50519c8 100644 (file)
@@ -1,3 +1,17 @@
+/*
+
+This file is part of Ext JS 4
+
+Copyright (c) 2011 Sencha Inc
+
+Contact:  http://www.sencha.com/contact
+
+GNU General Public License Usage
+This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+
+If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
+
+*/
 /**
  * @author Jacky Nguyen <jacky@sencha.com>
  * @docauthor Jacky Nguyen <jacky@sencha.com>
 
     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,
@@ -24,6 +66,7 @@
         }(),
         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 = {
-        /**
-         * 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 = {
+        /**
+         * 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) {
 
         /**
          * 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) {
@@ -236,8 +400,8 @@ Ext.Array.toArray('splitted', 0, 3); // returns ['s', 'p', 'l', 'i']
         /**
          * 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.
@@ -257,6 +421,7 @@ Ext.Array.toArray('splitted', 0, 3); // returns ['s', 'p', 'l', 'i']
 
         /**
          * 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
@@ -344,7 +509,8 @@ Ext.Array.toArray('splitted', 0, 3); // returns ['s', 'p', 'l', 'i']
         /**
          * 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
          */
@@ -391,6 +557,7 @@ Ext.Array.toArray('splitted', 0, 3); // returns ['s', 'p', 'l', 'i']
         /**
          * 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
@@ -426,7 +593,6 @@ Ext.Array.toArray('splitted', 0, 3); // returns ['s', 'p', 'l', 'i']
          * @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) {
@@ -455,7 +621,7 @@ Ext.Array.toArray('splitted', 0, 3); // returns ['s', 'p', 'l', 'i']
             var index = ExtArray.indexOf(array, item);
 
             if (index !== -1) {
-                array.splice(index, 1);
+                erase(array, index, 1);
             }
 
             return array;
@@ -466,7 +632,6 @@ Ext.Array.toArray('splitted', 0, 3); // returns ['s', 'p', 'l', 'i']
          *
          * @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)) {
@@ -487,9 +652,13 @@ Ext.Array.toArray('splitted', 0, 3); // returns ['s', 'p', 'l', 'i']
         },
 
         /**
-         * Merge multiple arrays into one with unique items. Alias to {@link Ext.Array#union}.
+         * Merge multiple arrays into one with unique items.
          *
-         * @param {Array} array,...
+         * {@link Ext.Array#union} is alias for {@link Ext.Array#merge}
+         *
+         * @param {Array} array1
+         * @param {Array} array2
+         * @param {Array} etc
          * @return {Array} merged
          */
         merge: function() {
@@ -507,7 +676,9 @@ Ext.Array.toArray('splitted', 0, 3); // returns ['s', 'p', 'l', 'i']
         /**
          * 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() {
@@ -527,8 +698,8 @@ Ext.Array.toArray('splitted', 0, 3); // returns ['s', 'p', 'l', 'i']
                 }
             }
 
-            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
@@ -556,8 +727,8 @@ Ext.Array.toArray('splitted', 0, 3); // returns ['s', 'p', 'l', 'i']
         /**
          * 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) {
@@ -568,7 +739,7 @@ Ext.Array.toArray('splitted', 0, 3); // returns ['s', 'p', 'l', 'i']
             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--;
                     }
@@ -578,6 +749,24 @@ Ext.Array.toArray('splitted', 0, 3); // returns ['s', 'p', 'l', 'i']
             return clone;
         },
 
+        /**
+         * 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);
+        },
+
         /**
          * Sorts the elements of an Array.
          * By default, this method sorts the elements alphabetically and ascending.
@@ -624,8 +813,7 @@ Ext.Array.toArray('splitted', 0, 3); // returns ['s', 'p', 'l', 'i']
 
         /**
          * 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 = [];
@@ -651,9 +839,10 @@ Ext.Array.toArray('splitted', 0, 3); // returns ['s', 'p', 'l', 'i']
 
         /**
          * 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) {
@@ -679,10 +868,11 @@ Ext.Array.toArray('splitted', 0, 3); // returns ['s', 'p', 'l', 'i']
         },
 
         /**
-         * Returns the maximum value in the Array
+         * 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) {
@@ -708,7 +898,8 @@ Ext.Array.toArray('splitted', 0, 3); // returns ['s', 'p', 'l', 'i']
         },
 
         /**
-         * Calculates the mean of all items in the array
+         * Calculates the mean of all items in the array.
+         *
          * @param {Array} array The Array to calculate the mean value of.
          * @return {Number} The mean.
          */
@@ -717,7 +908,8 @@ Ext.Array.toArray('splitted', 0, 3); // returns ['s', 'p', 'l', 'i']
         },
 
         /**
-         * Calculates the sum of all items in the given array
+         * 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.
          */
@@ -732,96 +924,161 @@ Ext.Array.toArray('splitted', 0, 3); // returns ['s', 'p', 'l', 'i']
             }
 
             return sum;
-        }
+        },
+
+        //<debug>
+        _replaceSim: replaceSim, // for unit testing
+        _spliceSim: spliceSim,
+        //</debug>
+
+        /**
+         * 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,
+
+        /**
+         * 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);
+        },
+
+        /**
+         * 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,
 
+        /**
+         * 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
     };
 
     /**
-     * Convenient alias to {@link Ext.Array#each}
+     * @method
      * @member Ext
-     * @method each
+     * @alias Ext.Array#each
      */
-    Ext.each = Ext.Array.each;
+    Ext.each = ExtArray.each;
 
     /**
-     * Alias to {@link Ext.Array#merge}.
+     * @method
      * @member Ext.Array
-     * @method union
+     * @alias Ext.Array#merge
      */
-    Ext.Array.union = Ext.Array.merge;
+    ExtArray.union = ExtArray.merge;
 
     /**
      * 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;
 
     /**
      * 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;
 
     /**
      * 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;
 
     /**
      * 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;
 
     /**
      * 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;
 
     /**
-     * Old alias to {@link Ext.Array#clean Ext.Array.clean}
-     * @deprecated 4.0.0 Use {@link Ext.Array.clean} instead
+     * 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;
 
     /**
-     * Old alias to {@link Ext.Array#unique Ext.Array.unique}
-     * @deprecated 4.0.0 Use {@link Ext.Array.unique} instead
+     * 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;
 
     /**
      * 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;
 
     /**
-     * Convenient alias to {@link Ext.Array#toArray Ext.Array.toArray}
-     * @param {Iterable} the iterable object to be turned into a true Array.
+     * @method
      * @member Ext
-     * @method toArray
-     * @return {Array} array
+     * @alias Ext.Array#toArray
      */
     Ext.toArray = function() {
         return ExtArray.toArray.apply(ExtArray, arguments);
-    }
+    };
 })();
+