#

API Docs for: 3.10.3
Show: Inherited Protected Private Deprecated

# File: collection/js/arraylist.js

    /**
     * Collection utilities beyond what is provided in the YUI core
     * @module collection
     * @submodule arraylist
     */

    var YArray      = Y.Array,
        YArray_each = YArray.each,
        ArrayListProto;

    /**
     * Generic ArrayList class for managing lists of items and iterating operations
     * over them.  The targeted use for this class is for augmentation onto a
     * class that is responsible for managing multiple instances of another class
     * (e.g. NodeList for Nodes).  The recommended use is to augment your class with
     * ArrayList, then use ArrayList.addMethod to mirror the API of the constituent
     * items on the list's API.
     *
     * The default implementation creates immutable lists, but mutability can be
     * provided via the arraylist-add submodule or by implementing mutation methods
     * directly on the augmented class's prototype.
     *
     * @class ArrayList
     * @constructor
     * @param items { Array } array of items this list will be responsible for
     */
    function ArrayList( items ) {
        if ( items !== undefined ) {
            this._items = Y.Lang.isArray( items ) ? items : YArray( items );
        } else {
            // ||= to support lazy initialization from augment
            this._items = this._items || [];
        }
    }

    ArrayListProto = {
        /**
         * Get an item by index from the list.  Override this method if managing a
         * list of objects that have a different public representation (e.g. Node
         * instances vs DOM nodes).  The iteration methods that accept a user
         * function will use this method for access list items for operation.
         *
         * @method item
         * @param i { Integer } index to fetch
         * @return { mixed } the item at the requested index
         */
        item: function ( i ) {
            return this._items[i];
        },

        /**
         * <p>Execute a function on each item of the list, optionally providing a
         * custom execution context.  Default context is the item.</p>
         *
         * <p>The callback signature is <code>callback( item, index )</code>.</p>
         *
         * @method each
         * @param fn { Function } the function to execute
         * @param context { mixed } optional override 'this' in the function
         * @return { ArrayList } this instance
         * @chainable
         */
        each: function ( fn, context ) {
            YArray_each( this._items, function ( item, i ) {
                item = this.item( i );

                fn.call( context || item, item, i, this );
            }, this);

            return this;
        },

        /**
         * <p>Execute a function on each item of the list, optionally providing a
         * custom execution context.  Default context is the item.</p>
         *
         * <p>The callback signature is <code>callback( item, index )</code>.</p>
         *
         * <p>Unlike <code>each</code>, if the callback returns true, the
         * iteratation will stop.</p>
         *
         * @method some
         * @param fn { Function } the function to execute
         * @param context { mixed } optional override 'this' in the function
         * @return { Boolean } True if the function returned true on an item
         */
        some: function ( fn, context ) {
            return YArray.some( this._items, function ( item, i ) {
                item = this.item( i );

                return fn.call( context || item, item, i, this );
            }, this);
        },

        /**
         * Finds the first index of the needle in the managed array of items.
         *
         * @method indexOf
         * @param needle { mixed } The item to search for
         * @return { Integer } Array index if found.  Otherwise -1
         */
        indexOf: function ( needle ) {
            return YArray.indexOf( this._items, needle );
        },

        /**
         * How many items are in this list?
         *
         * @method size
         * @return { Integer } Number of items in the list
         */
        size: function () {
            return this._items.length;
        },

        /**
         * Is this instance managing any items?
         *
         * @method isEmpty
         * @return { Boolean } true if 1 or more items are being managed
         */
        isEmpty: function () {
            return !this.size();
        },

        /**
         * Provides an array-like representation for JSON.stringify.
         *
         * @method toJSON
         * @return { Array } an array representation of the ArrayList
         */
        toJSON: function () {
            return this._items;
        }
    };
    // Default implementation does not distinguish between public and private
    // item getter
    /**
     * Protected method for optimizations that may be appropriate for API
     * mirroring. Similar in functionality to <code>item</code>, but is used by
     * methods added with <code>ArrayList.addMethod()</code>.
     *
     * @method _item
     * @protected
     * @param i { Integer } Index of item to fetch
     * @return { mixed } The item appropriate for pass through API methods
     */
    ArrayListProto._item = ArrayListProto.item;

    // Mixed onto existing proto to preserve constructor NOT being an own property.
    // This has bitten me when composing classes by enumerating, copying prototypes.
    Y.mix(ArrayList.prototype, ArrayListProto);

    Y.mix( ArrayList, {

        /**
         * <p>Adds a pass through method to dest (typically the prototype of a list
         * class) that calls the named method on each item in the list with
         * whatever parameters are passed in.  Allows for API indirection via list
         * instances.</p>
         *
         * <p>Accepts a single string name or an array of string names.</p>
         *
         * <pre><code>list.each( function ( item ) {
         *     item.methodName( 1, 2, 3 );
         * } );
         * // becomes
         * list.methodName( 1, 2, 3 );</code></pre>
         *
         * <p>Additionally, the pass through methods use the item retrieved by the
         * <code>_item</code> method in case there is any special behavior that is
         * appropriate for API mirroring.</p>
         *
         * <p>If the iterated method returns a value, the return value from the
         * added method will be an array of values with each value being at the
         * corresponding index for that item.  If the iterated method does not
         * return a value, the added method will be chainable.
         *
         * @method addMethod
         * @static
         * @param dest {Object} Object or prototype to receive the iterator method
         * @param name {String|String[]} Name of method of methods to create
         */
        addMethod: function ( dest, names ) {

            names = YArray( names );

            YArray_each( names, function ( name ) {
                dest[ name ] = function () {
                    var args = YArray( arguments, 0, true ),
                        ret  = [];

                    YArray_each( this._items, function ( item, i ) {
                        item = this._item( i );

                        var result = item[ name ].apply( item, args );

                        if ( result !== undefined && result !== item ) {
                            ret[i] = result;
                        }
                    }, this);

                    return ret.length ? ret : this;
                };
            } );
        }
    } );

    Y.ArrayList = ArrayList;