API Docs for: 1.0.1

File: js\grape\collections\array.js

define(['../class'], function (Class) {
    var returnsNewArray = ['slice', 'filter', 'map'], //must return a new instance of the class instead of the native array
        slice = Array.prototype.slice,
        splice = Array.prototype.splice,
        methods, methodNames, i, orig;


    /**
     * An array class created with Grape.Class mixing all of the Array.prototype methods and some new utility.
     * Some functions are modified (like slice) to return a new instance of the current class instead of a plain array.
     * If you extend this class, these methods will return an instance of your class.
     * In the future, we should create implementations of default methods for old browsers.
     * Note that adding elements with indexing does not change the length property unlike the native Array.
     *
     * @constructor
     * @class Grape.Array
     */
    methods = {
        /**
         * Calls a method of each item. The subsequent parameters are passed to the method.
         *
         * @method call
         * @param which {String} The method name to call
         * @return {Grape.Array} this
         */
        call: function (which/*,params*/) {
            var params = Array.prototype.slice.call(arguments, 1),
                i = 0, max = this.length;
            for (; i < max; ++i) {
                this[i][which].apply(this[i], params);
            }
            return this;
        },
        /**
         * Calls a method of each item, but the parameters are passed as an array like in Function.prototype.apply
         *
         * @method apply
         * @param which {String} The method name to call
         * @param params {Array} The method parameters
         * @return {Grape.Array} this
         */
        apply: function (which, params) {
            var i = 0, max = this.length;
            for (; i < max; ++i) {
                this[i][which].apply(this[i], params);
            }
            return this;
        },

        /**
         * Returns true if the length of the array is 0.
         *
         * @method isEmpty
         * @return {boolean} true, if length is 0
         */
        isEmpty: function () {
            return this.length === 0;
        },

        /**
         * Creates a native Array by copying the items
         *
         * @method toArray
         * @return {Array} The native Array
         */
        toArray: function () {
            return slice.call(this, 0);
        },

        /**
         * Sets an attribute on each item.
         *
         * @method attr
         * @param name {String} The attribute name
         * @param newVal {*} The new value of the attribute
         * @return {Grape.Array} this
         */
        attr: function (name, newVal) { //todov2 use as attr({x:10, y:20})
            var i = 0, max = this.length;
            for (; i < max; ++i) {
                this[i][name] = newVal;
            }
            return this;
        },

        /**
         * Creates a new instance of the current class, containing the item at the index i if exists, or an empty array
         *
         * @method eq
         * @param i {number} The index
         * @return {Grape.Array} The array containing 0 or 1 item
         */
        eq: function (i) {
            var result = new (this.getClass())();
            if (this.length > i) {
                result.push(this[i]);
            }
            return result;
        },

        /**
         * Returns an item at the given position. Equivalent to arr[i].
         *
         * @method get
         * @param i {number} The index of the item to return
         * @return {*} The item at the given position
         */
        get: function (i) {
            return this[i];
        },

        /**
         * Returns one (the first) item from the array.
         *
         * @method one
         * @return {*} The first item
         */
        one: function () {
            return this[0];
        },

        /**
         * Returns a new instance of the current class containing random items from the original array.
         *
         * @method random
         * @param num {number|undefined} The number of random items. If not set returns one item.
         * @return {Grape.Array} The random items
         */
        random: function (num) {
            var result;
            if (num === undefined) {
                return this[Math.random() * this.length >> 0];
            }

            result = this.clone(); //todov2 performance
            while (result.length > num) {
                result.splice(Math.random() * result.length >> 0, 1);
            }
            return result;
        },

        /**
         * Clones the array (shallow copy) by creating a new instance of the current class.
         *
         * @method clone
         * @return {*} The cloned array
         */
        clone: function () {
            return this.slice(0);
        },

        /**
         * Returns the length of the array.
         *
         * @method size
         * @return {number} The size of the array
         */
        size: function () {
            return this.length;
        }
        //TODOv2 union, intersect, complement, etc.);

    };

    //TODOv2 implement methods if not available
    if (Object.getOwnPropertyNames) {
        methodNames = Object.getOwnPropertyNames(Array.prototype);
    } else {
        methodNames = ['concat', 'constructor', 'indexOf', 'join', 'pop', 'push', 'reverse', 'shift', 'slice', 'splice', 'sort', 'toString', 'unshift', 'valueOf']; //IE8
    }

    for (i = methodNames.length - 1; i >= 0; i--) {
        //if (methodNames[i] !== 'length') {
            methods[methodNames[i]] = Array.prototype[methodNames[i]];
        //}
    }

    function createProxy(orig) {
        return function () {
            var result = new (this.getClass())();
            var origResult = orig.apply(this, arguments);
            origResult.splice(0, 0, 0, 0); //push 0 twitce at the beginning
            splice.apply(result, origResult); //result.splice(0,0,r1,r2,r3..): push all items to the result array
            return result;
        };
    }

    for (i = returnsNewArray.length - 1; i >= 0; i--) {
        orig = methods[returnsNewArray[i]];
        methods[returnsNewArray[i]] = createProxy(orig);
    }


    return Class('Array', methods);
});