76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav GlassYUI.add('model-list', function(Y) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass/**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav GlassProvides an API for managing an ordered list of Model instances.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
f50179c7ad363c27b2d90fbb8aa37b714bc9a51eEric Ferraiuolo@module app
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove@submodule model-list
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove@since 3.4.0
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove**/
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove/**
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan GroveProvides an API for managing an ordered list of Model instances.
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan GroveIn addition to providing convenient `add`, `create`, `reset`, and `remove`
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glassmethods for managing the models in the list, ModelLists are also bubble targets
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glassfor events on the model instances they contain. This means, for example, that
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glassyou can add several models to a list, and then subscribe to the `*:change` event
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glasson the list to be notified whenever any model in the list changes.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav GlassModelLists also maintain sort order efficiently as models are added and removed,
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glassbased on a custom `comparator` function you may define (if no comparator is
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glassdefined, models are sorted in insertion order).
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass@class ModelList
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove@extends Base
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass@uses ArrayList
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove@constructor
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove@since 3.4.0
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass**/
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grovevar AttrProto = Y.Attribute.prototype,
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove Lang = Y.Lang,
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove YArray = Y.Array,
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Fired when a model is added to the list.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Listen to the `on` phase of this event to be notified before a model is
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass added to the list. Calling `e.preventDefault()` during the `on` phase will
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass prevent the model from being added.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Listen to the `after` phase of this event to be notified after a model has
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass been added to the list.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @event add
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {Model} model The model being added.
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove @param {Number} index The index at which the model will be added.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @preventable _defAddFn
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass **/
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass EVT_ADD = 'add',
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove /**
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove Fired when a model is created or updated via the `create()` method, but
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove before the model is actually saved or added to the list. The `add` event
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove will be fired after the model has been saved and added to the list.
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove @event create
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove @param {Model} model The model being created/updated.
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove @since 3.5.0
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove **/
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove EVT_CREATE = 'create',
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove /**
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove Fired when an error occurs, such as when an attempt is made to add a
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove duplicate model to the list, or when a sync layer response can't be parsed.
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove @event error
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove @param {Any} error Error message, object, or exception generated by the
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove error. Calling `toString()` on this should result in a meaningful error
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove message.
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove @param {String} src Source of the error. May be one of the following (or any
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove custom error source defined by a ModelList subclass):
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove * `add`: Error while adding a model (probably because it's already in the
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove list and can't be added again). The model in question will be provided
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove as the `model` property on the event facade.
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove * `parse`: An error parsing a JSON response. The response in question will
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove be provided as the `response` property on the event facade.
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove * `remove`: Error while removing a model (probably because it isn't in the
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove list and can't be removed). The model in question will be provided as
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove the `model` property on the event facade.
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove **/
d561b35ed5a1899db0e91d791e606b951a3c1180Ryan Grove EVT_ERROR = 'error',
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove Fired after models are loaded from a sync layer.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove @event load
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove @param {Object} parsed The parsed version of the sync layer's response to
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove the load request.
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove @param {Mixed} response The sync layer's raw, unparsed response to the load
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove request.
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove @since 3.5.0
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass **/
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove EVT_LOAD = 'load',
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Fired when a model is removed from the list.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Listen to the `on` phase of this event to be notified before a model is
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass removed from the list. Calling `e.preventDefault()` during the `on` phase
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass will prevent the model from being removed.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Listen to the `after` phase of this event to be notified after a model has
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass been removed from the list.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @event remove
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {Model} model The model being removed.
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove @param {Number} index The index of the model being removed.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @preventable _defRemoveFn
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass **/
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove EVT_REMOVE = 'remove',
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove /**
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove Fired when the list is completely reset via the `reset()` method or sorted
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove via the `sort()` method.
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove Listen to the `on` phase of this event to be notified before the list is
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove reset. Calling `e.preventDefault()` during the `on` phase will prevent
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove the list from being reset.
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove Listen to the `after` phase of this event to be notified after the list has
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove been reset.
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove @event reset
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove @param {Model[]} models Array of the list's new models after the reset.
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove @param {String} src Source of the event. May be either `'reset'` or
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove `'sort'`.
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove @preventable _defResetFn
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove **/
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove EVT_RESET = 'reset';
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glassfunction ModelList() {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass ModelList.superclass.constructor.apply(this, arguments);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass}
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav GlassY.ModelList = Y.extend(ModelList, Y.Base, {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // -- Public Properties ----------------------------------------------------
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass The `Model` class or subclass of the models in this list.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
db664634abff07e378add55f2ef12fcd2f37f62dRyan Grove The class specified here will be used to create model instances
db664634abff07e378add55f2ef12fcd2f37f62dRyan Grove automatically based on attribute hashes passed to the `add()`, `create()`,
db664634abff07e378add55f2ef12fcd2f37f62dRyan Grove and `reset()` methods.
db664634abff07e378add55f2ef12fcd2f37f62dRyan Grove
db664634abff07e378add55f2ef12fcd2f37f62dRyan Grove You may specify the class as an actual class reference or as a string that
db664634abff07e378add55f2ef12fcd2f37f62dRyan Grove resolves to a class reference at runtime (the latter can be useful if the
db664634abff07e378add55f2ef12fcd2f37f62dRyan Grove specified class will be loaded lazily).
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @property model
db664634abff07e378add55f2ef12fcd2f37f62dRyan Grove @type Model|String
db664634abff07e378add55f2ef12fcd2f37f62dRyan Grove @default Y.Model
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass **/
db664634abff07e378add55f2ef12fcd2f37f62dRyan Grove model: Y.Model,
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove // -- Protected Properties -------------------------------------------------
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove /**
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove Total hack to allow us to identify ModelList instances without using
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove `instanceof`, which won't work when the instance was created in another
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove window or YUI sandbox.
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove @property _isYUIModelList
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove @type Boolean
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove @default true
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove @protected
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove @since 3.5.0
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove **/
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove _isYUIModelList: true,
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // -- Lifecycle Methods ----------------------------------------------------
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass initializer: function (config) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass config || (config = {});
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass var model = this.model = config.model || this.model;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
db664634abff07e378add55f2ef12fcd2f37f62dRyan Grove if (typeof model === 'string') {
db664634abff07e378add55f2ef12fcd2f37f62dRyan Grove // Look for a namespaced Model class on `Y`.
db664634abff07e378add55f2ef12fcd2f37f62dRyan Grove this.model = Y.Object.getValue(Y, model.split('.'));
db664634abff07e378add55f2ef12fcd2f37f62dRyan Grove
db664634abff07e378add55f2ef12fcd2f37f62dRyan Grove if (!this.model) {
db664634abff07e378add55f2ef12fcd2f37f62dRyan Grove Y.error('ModelList: Model class not found: ' + model);
db664634abff07e378add55f2ef12fcd2f37f62dRyan Grove }
db664634abff07e378add55f2ef12fcd2f37f62dRyan Grove }
db664634abff07e378add55f2ef12fcd2f37f62dRyan Grove
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove this.publish(EVT_ADD, {defaultFn: this._defAddFn});
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove this.publish(EVT_RESET, {defaultFn: this._defResetFn});
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove this.publish(EVT_REMOVE, {defaultFn: this._defRemoveFn});
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
db664634abff07e378add55f2ef12fcd2f37f62dRyan Grove this.after('*:idChange', this._afterIdChange);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this._clear();
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass },
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass destructor: function () {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass YArray.each(this._items, this._detachList, this);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass },
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // -- Public Methods -------------------------------------------------------
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove Adds the specified model or array of models to this list. You may also pass
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove another ModelList instance, in which case all the models in that list will
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove be added to this one as well.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @example
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // Add a single model instance.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass list.add(new Model({foo: 'bar'}));
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // Add a single model, creating a new instance automatically.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass list.add({foo: 'bar'});
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // Add multiple models, creating new instances automatically.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass list.add([
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass {foo: 'bar'},
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass {baz: 'quux'}
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass ]);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove // Add all the models in another ModelList instance.
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove list.add(otherList);
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @method add
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove @param {Model|Model[]|ModelList|Object|Object[]} models Model or array of
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove models to add. May be existing model instances or hashes of model
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove attributes, in which case new model instances will be created from the
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove hashes. You may also pass a ModelList instance to add all the models it
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove contains.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {Object} [options] Data to be mixed into the event facade of the
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass `add` event(s) for the added models.
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove @param {Boolean} [options.silent=false] If `true`, no `add` event(s)
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove will be fired.
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @return {Model|Model[]} Added model or array of added models.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass **/
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass add: function (models, options) {
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove var isList = models._isYUIModelList;
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove if (isList || Lang.isArray(models)) {
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove return YArray.map(isList ? models.toArray() : models, function (model) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return this._add(model, options);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }, this);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass } else {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return this._add(models, options);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass },
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Define this method to provide a function that takes a model as a parameter
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass and returns a value by which that model should be sorted relative to other
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass models in this list.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass By default, no comparator is defined, meaning that models will not be sorted
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass (they'll be stored in the order they're added).
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @example
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass var list = new Y.ModelList({model: Y.Model});
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass list.comparator = function (model) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return model.get('id'); // Sort models by id.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass };
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @method comparator
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {Model} model Model being sorted.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @return {Number|String} Value by which the model should be sorted relative
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass to other models in this list.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass **/
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // comparator is not defined by default
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Creates or updates the specified model on the server, then adds it to this
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass list if the server indicates success.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @method create
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {Model|Object} model Model to create. May be an existing model
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass instance or a hash of model attributes, in which case a new model instance
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass will be created from the hash.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {Object} [options] Options to be passed to the model's `sync()` and
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove `set()` methods and mixed into the `create` and `add` event facades.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {Boolean} [options.silent=false] If `true`, no `add` event(s) will
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass be fired.
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove @param {Function} [callback] Called when the sync operation finishes.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {Error} callback.err If an error occurred, this parameter will
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass contain the error. If the sync operation succeeded, _err_ will be
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass falsy.
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove @param {Any} callback.response The server's response.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @return {Model} Created model.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass **/
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass create: function (model, options, callback) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass var self = this;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // Allow callback as second arg.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (typeof options === 'function') {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass callback = options;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass options = {};
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove options || (options = {});
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove if (!model._isYUIModel) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass model = new this.model(model);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove self.fire(EVT_CREATE, Y.merge(options, {
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove model: model
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove }));
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return model.save(options, function (err) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (!err) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass self.add(model, options);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass callback && callback.apply(null, arguments);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass });
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass },
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove /**
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove Executes the supplied function on each model in this list. Returns an array
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove containing the models for which the supplied function returned a truthy
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove value.
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove The callback function's `this` object will refer to this ModelList. Use
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove `Y.bind()` to bind the `this` object to another object if desired.
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove @example
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove // Get an array containing only the models whose "enabled" attribute is
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove // truthy.
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove var filtered = list.filter(function (model) {
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove return model.get('enabled');
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove });
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove // Get a new ModelList containing only the models whose "enabled"
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove // attribute is truthy.
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove var filteredList = list.filter({asList: true}, function (model) {
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove return model.get('enabled');
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove });
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove @method filter
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove @param {Object} [options] Filter options.
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove @param {Boolean} [options.asList=false] If truthy, results will be
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove returned as a new ModelList instance rather than as an array.
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove @param {Function} callback Function to execute on each model.
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove @param {Model} callback.model Model instance.
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove @param {Number} callback.index Index of the current model.
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove @param {ModelList} callback.list The ModelList being filtered.
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove @return {Array|ModelList} Array of models for which the callback function
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove returned a truthy value (empty if it never returned a truthy value). If
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove the `options.asList` option is truthy, a new ModelList instance will be
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove returned instead of an array.
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove @since 3.5.0
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove */
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove filter: function (options, callback) {
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove var filtered = [],
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove items = this._items,
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove i, item, len, list;
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove // Allow options as first arg.
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove if (typeof options === 'function') {
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove callback = options;
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove options = {};
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove }
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove for (i = 0, len = items.length; i < len; ++i) {
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove item = items[i];
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove if (callback.call(this, item, i, this)) {
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove filtered.push(item);
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove }
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove }
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove if (options.asList) {
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove list = new Y.ModelList({model: this.model});
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove filtered.length && list.add(filtered, {silent: true});
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove return list;
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove } else {
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove return filtered;
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove }
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove },
b98c93424e77aff8fc01021ac42db126270c918eRyan Grove
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove /**
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove If _name_ refers to an attribute on this ModelList instance, returns the
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove value of that attribute. Otherwise, returns an array containing the values
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove of the specified attribute from each model in this list.
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove @method get
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove @param {String} name Attribute name or object property path.
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove @return {Any|Array} Attribute value or array of attribute values.
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove @see Model.get()
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove **/
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove get: function (name) {
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove if (this.attrAdded(name)) {
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove return AttrProto.get.apply(this, arguments);
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove }
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove return this.invoke('get', name);
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove },
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove /**
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove If _name_ refers to an attribute on this ModelList instance, returns the
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove HTML-escaped value of that attribute. Otherwise, returns an array containing
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove the HTML-escaped values of the specified attribute from each model in this
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove list.
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove The values are escaped using `Escape.html()`.
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove @method getAsHTML
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove @param {String} name Attribute name or object property path.
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove @return {String|String[]} HTML-escaped value or array of HTML-escaped
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove values.
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove @see Model.getAsHTML()
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove **/
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove getAsHTML: function (name) {
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove if (this.attrAdded(name)) {
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove return Y.Escape.html(AttrProto.get.apply(this, arguments));
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove }
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove return this.invoke('getAsHTML', name);
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove },
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove /**
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove If _name_ refers to an attribute on this ModelList instance, returns the
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove URL-encoded value of that attribute. Otherwise, returns an array containing
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove the URL-encoded values of the specified attribute from each model in this
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove list.
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove The values are encoded using the native `encodeURIComponent()` function.
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove @method getAsURL
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove @param {String} name Attribute name or object property path.
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove @return {String|String[]} URL-encoded value or array of URL-encoded values.
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove @see Model.getAsURL()
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove **/
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove getAsURL: function (name) {
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove if (this.attrAdded(name)) {
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove return encodeURIComponent(AttrProto.get.apply(this, arguments));
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove }
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove return this.invoke('getAsURL', name);
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove },
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Returns the model with the specified _clientId_, or `null` if not found.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @method getByClientId
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {String} clientId Client id.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @return {Model} Model, or `null` if not found.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass **/
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass getByClientId: function (clientId) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return this._clientIdMap[clientId] || null;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass },
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Returns the model with the specified _id_, or `null` if not found.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Note that models aren't expected to have an id until they're saved, so if
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass you're working with unsaved models, it may be safer to call
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass `getByClientId()`.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @method getById
d561b35ed5a1899db0e91d791e606b951a3c1180Ryan Grove @param {String|Number} id Model id.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @return {Model} Model, or `null` if not found.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass **/
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass getById: function (id) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return this._idMap[id] || null;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass },
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Calls the named method on every model in the list. Any arguments provided
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass after _name_ will be passed on to the invoked method.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @method invoke
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {String} name Name of the method to call on each model.
a7bf61fe73568ec8f3615c238acbe69d5986e21dRyan Grove @param {Any} [args*] Zero or more arguments to pass to the invoked method.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @return {Array} Array of return values, indexed according to the index of
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass the model on which the method was called.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass **/
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove invoke: function (name /*, args* */) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass var args = [this._items, name].concat(YArray(arguments, 1, true));
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return YArray.invoke.apply(YArray, args);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass },
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Returns the model at the specified _index_.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @method item
d561b35ed5a1899db0e91d791e606b951a3c1180Ryan Grove @param {Number} index Index of the model to fetch.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @return {Model} The model at the specified index, or `undefined` if there
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass isn't a model there.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass **/
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // item() is inherited from ArrayList.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Loads this list of models from the server.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass This method delegates to the `sync()` method to perform the actual load
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass operation, which is an asynchronous action. Specify a _callback_ function to
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass be notified of success or failure.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove If the load operation succeeds, a `reset` event will be fired.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @method load
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {Object} [options] Options to be passed to `sync()` and to
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove `reset()` when adding the loaded models. It's up to the custom sync
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass implementation to determine what options it supports or requires, if any.
d561b35ed5a1899db0e91d791e606b951a3c1180Ryan Grove @param {Function} [callback] Called when the sync operation finishes.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {Error} callback.err If an error occurred, this parameter will
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass contain the error. If the sync operation succeeded, _err_ will be
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass falsy.
d561b35ed5a1899db0e91d791e606b951a3c1180Ryan Grove @param {Any} callback.response The server's response. This value will
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass be passed to the `parse()` method, which is expected to parse it and
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return an array of model attribute hashes.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @chainable
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass **/
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass load: function (options, callback) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass var self = this;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // Allow callback as only arg.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (typeof options === 'function') {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass callback = options;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass options = {};
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove options || (options = {});
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this.sync('read', options, function (err, response) {
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove var facade = {
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove options : options,
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove response: response
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove },
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove parsed;
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove if (err) {
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove facade.error = err;
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove facade.src = 'load';
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove self.fire(EVT_ERROR, facade);
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove } else {
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove // Lazy publish.
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove if (!self._loadEvent) {
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove self._loadEvent = self.publish(EVT_LOAD, {
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove preventable: false
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove });
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove }
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove parsed = facade.parsed = self.parse(response);
8d1b319266cfadd16e94cc674d9fd785dd3c9a06Ryan Grove
8d1b319266cfadd16e94cc674d9fd785dd3c9a06Ryan Grove self.reset(parsed, options);
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove self.fire(EVT_LOAD, facade);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass callback && callback.apply(null, arguments);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass });
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return this;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass },
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Executes the specified function on each model in this list and returns an
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass array of the function's collected return values.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @method map
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {Function} fn Function to execute on each model.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {Model} fn.model Current model being iterated.
d561b35ed5a1899db0e91d791e606b951a3c1180Ryan Grove @param {Number} fn.index Index of the current model in the list.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {Model[]} fn.models Array of models being iterated.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {Object} [thisObj] `this` object to use when calling _fn_.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @return {Array} Array of return values from _fn_.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass **/
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass map: function (fn, thisObj) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return YArray.map(this._items, fn, thisObj);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass },
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Called to parse the _response_ when the list is loaded from the server.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass This method receives a server _response_ and is expected to return an array
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass of model attribute hashes.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass The default implementation assumes that _response_ is either an array of
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass attribute hashes or a JSON string that can be parsed into an array of
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass attribute hashes. If _response_ is a JSON string and either `Y.JSON` or the
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass native `JSON` object are available, it will be parsed automatically. If a
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass parse error occurs, an `error` event will be fired and the model will not be
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass updated.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass You may override this method to implement custom parsing logic if necessary.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @method parse
d561b35ed5a1899db0e91d791e606b951a3c1180Ryan Grove @param {Any} response Server response.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @return {Object[]} Array of model attribute hashes.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass **/
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass parse: function (response) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (typeof response === 'string') {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass try {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return Y.JSON.parse(response) || [];
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass } catch (ex) {
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove this.fire(EVT_ERROR, {
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove error : ex,
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove response: response,
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove src : 'parse'
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove });
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return null;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return response || [];
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass },
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove /**
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove Removes the specified model or array of models from this list. You may also
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove pass another ModelList instance to remove all the models that are in both
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove that instance and this instance.
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove @method remove
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove @param {Model|Model[]|ModelList} models Models to remove.
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove @param {Object} [options] Data to be mixed into the event facade of the
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove `remove` event(s) for the removed models.
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove @param {Boolean} [options.silent=false] If `true`, no `remove` event(s)
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove will be fired.
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove @return {Model|Model[]} Removed model or array of removed models.
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove **/
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove remove: function (models, options) {
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove var isList = models._isYUIModelList;
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove if (isList || Lang.isArray(models)) {
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove return YArray.map(isList ? models.toArray() : models, function (model) {
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove return this._remove(model, options);
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove }, this);
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove } else {
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove return this._remove(models, options);
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove }
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove },
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Completely replaces all models in the list with those specified, and fires a
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove single `reset` event.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove Use `reset` when you want to add or remove a large number of items at once
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove with less overhead, and without firing `add` or `remove` events for each
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove one.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove @method reset
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove @param {Model[]|ModelList|Object[]} [models] Models to add. May be existing
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove model instances or hashes of model attributes, in which case new model
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove instances will be created from the hashes. If a ModelList is passed, all
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove the models in that list will be added to this list. Calling `reset()`
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove without passing in any models will clear the list.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {Object} [options] Data to be mixed into the event facade of the
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove `reset` event.
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove @param {Boolean} [options.silent=false] If `true`, no `reset` event will
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove be fired.
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @chainable
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass **/
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove reset: function (models, options) {
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove models || (models = []);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass options || (options = {});
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
2d4284c750133bd4bb777a8de566e6477db1de17Ryan Grove var facade = Y.merge({src: 'reset'}, options);
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove if (models._isYUIModelList) {
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove models = models.toArray();
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove } else {
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove models = YArray.map(models, function (model) {
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove return model._isYUIModel ? model : new this.model(model);
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove }, this);
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove facade.models = models;
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove if (options.silent) {
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove this._defResetFn(facade);
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove } else {
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove // Sort the models before firing the reset event.
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove if (this.comparator) {
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove models.sort(Y.bind(this._sort, this));
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove }
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove this.fire(EVT_RESET, facade);
45f4b3ceef57583b65c64e2e544b7c16b3ef7817Ryan Grove }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return this;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass },
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Forcibly re-sorts the list.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Usually it shouldn't be necessary to call this method since the list
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass maintains its sort order when items are added and removed, but if you change
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass the `comparator` function after items are already in the list, you'll need
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass to re-sort.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @method sort
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {Object} [options] Data to be mixed into the event facade of the
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove `reset` event.
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove @param {Boolean} [options.silent=false] If `true`, no `reset` event will
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass be fired.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @chainable
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass **/
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass sort: function (options) {
05077064e34396660f0e2b4e2ce06098b0edf077Ryan Grove if (!this.comparator) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return this;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
d2d5766755177225f179a7b9df7e0d66fda034f1Ryan Grove var models = this._items.concat(),
d2d5766755177225f179a7b9df7e0d66fda034f1Ryan Grove facade;
d2d5766755177225f179a7b9df7e0d66fda034f1Ryan Grove
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass options || (options = {});
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
05077064e34396660f0e2b4e2ce06098b0edf077Ryan Grove models.sort(Y.bind(this._sort, this));
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass facade = Y.merge(options, {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass models: models,
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass src : 'sort'
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass });
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove options.silent ? this._defResetFn(facade) :
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove this.fire(EVT_RESET, facade);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return this;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass },
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Override this method to provide a custom persistence implementation for this
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass list. The default method just calls the callback without actually doing
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass anything.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass This method is called internally by `load()`.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @method sync
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {String} action Sync action to perform. May be one of the following:
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * `create`: Store a list of newly-created models for the first time.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * `delete`: Delete a list of existing models.
fbb8b3b8c5a0aad2d7eb5f62e4507a20696adb43Ryan Grove * `read` : Load a list of existing models.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass * `update`: Update a list of existing models.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Currently, model lists only make use of the `read` action, but other
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass actions may be used in future versions.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {Object} [options] Sync options. It's up to the custom sync
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass implementation to determine what options it supports or requires, if any.
d561b35ed5a1899db0e91d791e606b951a3c1180Ryan Grove @param {Function} [callback] Called when the sync operation finishes.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {Error} callback.err If an error occurred, this parameter will
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass contain the error. If the sync operation succeeded, _err_ will be
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass falsy.
d561b35ed5a1899db0e91d791e606b951a3c1180Ryan Grove @param {Any} [callback.response] The server's response. This value will
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass be passed to the `parse()` method, which is expected to parse it and
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return an array of model attribute hashes.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass **/
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass sync: function (/* action, options, callback */) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass var callback = YArray(arguments, 0, true).pop();
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (typeof callback === 'function') {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass callback();
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass },
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Returns an array containing the models in this list.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @method toArray
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @return {Array} Array containing the models in this list.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass **/
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass toArray: function () {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return this._items.concat();
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass },
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Returns an array containing attribute hashes for each model in this list,
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass suitable for being passed to `Y.JSON.stringify()`.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Under the hood, this method calls `toJSON()` on each model in the list and
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass pushes the results into an array.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @method toJSON
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @return {Object[]} Array of model attribute hashes.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @see Model.toJSON()
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass **/
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass toJSON: function () {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return this.map(function (model) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return model.toJSON();
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass });
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass },
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // -- Protected Methods ----------------------------------------------------
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Adds the specified _model_ if it isn't already in this list.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove If the model's `clientId` or `id` matches that of a model that's already in
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove the list, an `error` event will be fired and the model will not be added.
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @method _add
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {Model|Object} model Model or object to add.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {Object} [options] Data to be mixed into the event facade of the
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass `add` event for the added model.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {Boolean} [options.silent=false] If `true`, no `add` event will be
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass fired.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @return {Model} The added model.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @protected
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass **/
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass _add: function (model, options) {
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove var facade, id;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass options || (options = {});
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
db6ab26807536dd9f592542d92e39dc79cb855ccRyan Grove if (!model._isYUIModel) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass model = new this.model(model);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove id = model.get('id');
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove if (this._clientIdMap[model.get('clientId')]
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove || (Lang.isValue(id) && this._idMap[id])) {
9b71de7bf983c179eec345f10cbf2087063ec60bRyan Grove
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove this.fire(EVT_ERROR, {
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove error: 'Model is already in the list.',
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove model: model,
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove src : 'add'
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove });
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass facade = Y.merge(options, {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass index: this._findIndex(model),
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass model: model
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass });
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass options.silent ? this._defAddFn(facade) : this.fire(EVT_ADD, facade);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return model;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass },
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Adds this list as a bubble target for the specified model's events.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @method _attachList
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {Model} model Model to attach to this list.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @protected
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass **/
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass _attachList: function (model) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // Attach this list and make it a bubble target for the model.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass model.lists.push(this);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass model.addTarget(this);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass },
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Clears all internal state and the internal list of models, returning this
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass list to an empty state. Automatically detaches all models in the list.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @method _clear
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @protected
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass **/
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass _clear: function () {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass YArray.each(this._items, this._detachList, this);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this._clientIdMap = {};
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this._idMap = {};
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this._items = [];
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass },
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
d2d5766755177225f179a7b9df7e0d66fda034f1Ryan Grove /**
d2d5766755177225f179a7b9df7e0d66fda034f1Ryan Grove Compares the value _a_ to the value _b_ for sorting purposes. Values are
d2d5766755177225f179a7b9df7e0d66fda034f1Ryan Grove assumed to be the result of calling a model's `comparator()` method. You can
d2d5766755177225f179a7b9df7e0d66fda034f1Ryan Grove override this method to implement custom sorting logic, such as a descending
d2d5766755177225f179a7b9df7e0d66fda034f1Ryan Grove sort or multi-field sorting.
d2d5766755177225f179a7b9df7e0d66fda034f1Ryan Grove
d2d5766755177225f179a7b9df7e0d66fda034f1Ryan Grove @method _compare
d2d5766755177225f179a7b9df7e0d66fda034f1Ryan Grove @param {Mixed} a First value to compare.
d2d5766755177225f179a7b9df7e0d66fda034f1Ryan Grove @param {Mixed} b Second value to compare.
d2d5766755177225f179a7b9df7e0d66fda034f1Ryan Grove @return {Number} `-1` if _a_ should come before _b_, `0` if they're
d2d5766755177225f179a7b9df7e0d66fda034f1Ryan Grove equivalent, `1` if _a_ should come after _b_.
d2d5766755177225f179a7b9df7e0d66fda034f1Ryan Grove @protected
d2d5766755177225f179a7b9df7e0d66fda034f1Ryan Grove @since 3.5.0
d2d5766755177225f179a7b9df7e0d66fda034f1Ryan Grove **/
d2d5766755177225f179a7b9df7e0d66fda034f1Ryan Grove _compare: function (a, b) {
d2d5766755177225f179a7b9df7e0d66fda034f1Ryan Grove return a < b ? -1 : (a > b ? 1 : 0);
d2d5766755177225f179a7b9df7e0d66fda034f1Ryan Grove },
d2d5766755177225f179a7b9df7e0d66fda034f1Ryan Grove
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Removes this list as a bubble target for the specified model's events.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @method _detachList
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {Model} model Model to detach.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @protected
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass **/
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass _detachList: function (model) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass var index = YArray.indexOf(model.lists, this);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (index > -1) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass model.lists.splice(index, 1);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass model.removeTarget(this);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass },
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Returns the index at which the given _model_ should be inserted to maintain
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass the sort order of the list.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @method _findIndex
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {Model} model The model being inserted.
d561b35ed5a1899db0e91d791e606b951a3c1180Ryan Grove @return {Number} Index at which the model should be inserted.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @protected
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass **/
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass _findIndex: function (model) {
d2d5766755177225f179a7b9df7e0d66fda034f1Ryan Grove var items = this._items,
d2d5766755177225f179a7b9df7e0d66fda034f1Ryan Grove max = items.length,
d2d5766755177225f179a7b9df7e0d66fda034f1Ryan Grove min = 0,
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass item, middle, needle;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
d2d5766755177225f179a7b9df7e0d66fda034f1Ryan Grove if (!this.comparator || !max) {
d2d5766755177225f179a7b9df7e0d66fda034f1Ryan Grove return max;
d2d5766755177225f179a7b9df7e0d66fda034f1Ryan Grove }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
d2d5766755177225f179a7b9df7e0d66fda034f1Ryan Grove needle = this.comparator(model);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // Perform an iterative binary search to determine the correct position
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // based on the return value of the `comparator` function.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass while (min < max) {
05077064e34396660f0e2b4e2ce06098b0edf077Ryan Grove middle = (min + max) >> 1; // Divide by two and discard remainder.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass item = items[middle];
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
d2d5766755177225f179a7b9df7e0d66fda034f1Ryan Grove if (this._compare(this.comparator(item), needle) < 0) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass min = middle + 1;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass } else {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass max = middle;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return min;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass },
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Removes the specified _model_ if it's in this list.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @method _remove
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {Model} model Model to remove.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {Object} [options] Data to be mixed into the event facade of the
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass `remove` event for the removed model.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {Boolean} [options.silent=false] If `true`, no `remove` event will
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass be fired.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @return {Model} Removed model.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @protected
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass **/
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass _remove: function (model, options) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass var index = this.indexOf(model),
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass facade;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass options || (options = {});
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass if (index === -1) {
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove this.fire(EVT_ERROR, {
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove error: 'Model is not in the list.',
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove model: model,
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove src : 'remove'
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove });
d3e7704f3fd45efa522b537b83189cd8a511e67fRyan Grove
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
307532b5488ffbd7d839996ef17afbc70dc268d3Ryan Grove
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass facade = Y.merge(options, {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass index: index,
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass model: model
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass });
307532b5488ffbd7d839996ef17afbc70dc268d3Ryan Grove
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass options.silent ? this._defRemoveFn(facade) :
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this.fire(EVT_REMOVE, facade);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass return model;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass },
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
05077064e34396660f0e2b4e2ce06098b0edf077Ryan Grove /**
05077064e34396660f0e2b4e2ce06098b0edf077Ryan Grove Array sort function used by `sort()` to re-sort the models in the list.
05077064e34396660f0e2b4e2ce06098b0edf077Ryan Grove
05077064e34396660f0e2b4e2ce06098b0edf077Ryan Grove @method _sort
05077064e34396660f0e2b4e2ce06098b0edf077Ryan Grove @param {Model} a First model to compare.
05077064e34396660f0e2b4e2ce06098b0edf077Ryan Grove @param {Model} b Second model to compare.
05077064e34396660f0e2b4e2ce06098b0edf077Ryan Grove @return {Number} `-1` if _a_ is less than _b_, `0` if equal, `1` if greater.
05077064e34396660f0e2b4e2ce06098b0edf077Ryan Grove @protected
05077064e34396660f0e2b4e2ce06098b0edf077Ryan Grove **/
05077064e34396660f0e2b4e2ce06098b0edf077Ryan Grove _sort: function (a, b) {
d2d5766755177225f179a7b9df7e0d66fda034f1Ryan Grove return this._compare(this.comparator(a), this.comparator(b));
05077064e34396660f0e2b4e2ce06098b0edf077Ryan Grove },
05077064e34396660f0e2b4e2ce06098b0edf077Ryan Grove
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // -- Event Handlers -------------------------------------------------------
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Updates the model maps when a model's `id` attribute changes.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @method _afterIdChange
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {EventFacade} e
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @protected
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass **/
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass _afterIdChange: function (e) {
d561b35ed5a1899db0e91d791e606b951a3c1180Ryan Grove Lang.isValue(e.prevVal) && delete this._idMap[e.prevVal];
d561b35ed5a1899db0e91d791e606b951a3c1180Ryan Grove Lang.isValue(e.newVal) && (this._idMap[e.newVal] = e.target);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass },
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass // -- Default Event Handlers -----------------------------------------------
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Default event handler for `add` events.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @method _defAddFn
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {EventFacade} e
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @protected
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass **/
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass _defAddFn: function (e) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass var model = e.model,
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass id = model.get('id');
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this._clientIdMap[model.get('clientId')] = model;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
d561b35ed5a1899db0e91d791e606b951a3c1180Ryan Grove if (Lang.isValue(id)) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this._idMap[id] = model;
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this._attachList(model);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this._items.splice(e.index, 0, model);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass },
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass /**
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass Default event handler for `remove` events.
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @method _defRemoveFn
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @param {EventFacade} e
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass @protected
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass **/
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass _defRemoveFn: function (e) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass var model = e.model,
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass id = model.get('id');
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this._detachList(model);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass delete this._clientIdMap[model.get('clientId')];
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
d561b35ed5a1899db0e91d791e606b951a3c1180Ryan Grove if (Lang.isValue(id)) {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass delete this._idMap[id];
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass this._items.splice(e.index, 1);
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove },
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove /**
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove Default event handler for `reset` events.
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove @method _defResetFn
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove @param {EventFacade} e
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove @protected
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove **/
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove _defResetFn: function (e) {
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove // When fired from the `sort` method, we don't need to clear the list or
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove // add any models, since the existing models are sorted in place.
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove if (e.src === 'sort') {
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove this._items = e.models.concat();
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove return;
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove }
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove this._clear();
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove if (e.models.length) {
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove this.add(e.models, {silent: true});
213abf076aeae2f3b6b834155b0a5b7dbae72d7cRyan Grove }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass }
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass}, {
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass NAME: 'modelList'
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass});
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav GlassY.augment(ModelList, Y.ArrayList);
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
76ca635d61eb3f9fb7c9d788a44fa8b1690aa138Dav Glass
abe38d7e07e114761db3feb3c22ef22fce3ecccaRyan Grove}, '@VERSION@' ,{requires:['array-extras', 'array-invoke', 'arraylist', 'base-build', 'escape', 'json-parse', 'model']});