model.js revision 87b4846e2d395d3f76f87f727e1d9dc280a0935d
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsyncYUI.add('model', function(Y) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync/**
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsyncAttribute-based data model with APIs for getting, setting, validating, and
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsyncsyncing attribute values, as well as events for being notified of model changes.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync@submodule model
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync@since 3.4.0
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync**/
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync/**
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsyncAttribute-based data model with APIs for getting, setting, validating, and
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsyncsyncing attribute values, as well as events for being notified of model changes.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsyncIn most cases, you'll want to create your own subclass of `Y.Model` and
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsynccustomize it to meet your needs. In particular, the `sync()` and `validate()`
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsyncmethods are meant to be overridden by custom implementations. You may also want
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsyncto override the `parse()` method to parse non-generic server responses.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync@class Model
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync@constructor
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync@extends Base
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync@since 3.4.0
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync**/
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsyncvar GlobalEnv = YUI.namespace('Env.Model'),
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync Lang = Y.Lang,
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync YArray = Y.Array,
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync YObject = Y.Object,
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync /**
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync Fired when one or more attributes on this model are changed.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @event change
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Object} changed Hash of change information for each attribute that
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync changed. Each item in the hash has the following properties:
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Any} changed.newVal New value of the attribute.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Any} changed.prevVal Previous value of the attribute.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {String|null} changed.src Source of the change event, if any.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync **/
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync EVT_CHANGE = 'change',
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync /**
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync Fired when an error occurs, such as when the model doesn't validate or when
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync a sync layer response can't be parsed.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @event error
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Any} error Error message, object, or exception generated by the
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync error. Calling `toString()` on this should result in a meaningful error
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync message.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {String} src Source of the error. May be one of the following (or any
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync custom error source defined by a Model subclass):
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync * `load`: An error loading the model from a sync layer. The sync layer's
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync response (if any) will be provided as the `response` property on the
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync event facade.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync * `parse`: An error parsing a JSON response. The response in question will
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync be provided as the `response` property on the event facade.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync * `save`: An error saving the model to a sync layer. The sync layer's
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync response (if any) will be provided as the `response` property on the
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync event facade.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync * `validate`: The model failed to validate. The attributes being validated
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync will be provided as the `attributes` property on the event facade.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync **/
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync EVT_ERROR = 'error',
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync /**
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync Fired after model attributes are loaded from a sync layer.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @event load
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Object} parsed The parsed version of the sync layer's response to
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync the load request.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {any} response The sync layer's raw, unparsed response to the load
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync request.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @since 3.5.0
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync **/
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync EVT_LOAD = 'load',
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync /**
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync Fired after model attributes are saved to a sync layer.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @event save
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Object} [parsed] The parsed version of the sync layer's response to
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync the save request, if there was a response.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {any} [response] The sync layer's raw, unparsed response to the save
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync request, if there was one.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @since 3.5.0
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync **/
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync EVT_SAVE = 'save';
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsyncfunction Model() {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync Model.superclass.constructor.apply(this, arguments);
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync}
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsyncY.Model = Y.extend(Model, Y.Base, {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync // -- Public Properties ----------------------------------------------------
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync /**
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync Hash of attributes that have changed since the last time this model was
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync saved.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @property changed
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @type Object
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @default {}
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync **/
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync /**
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync Name of the attribute to use as the unique id (or primary key) for this
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync model.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync The default is `id`, but if your persistence layer uses a different name for
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync the primary key (such as `_id` or `uid`), you can specify that here.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync The built-in `id` attribute will always be an alias for whatever attribute
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync name you specify here, so getting and setting `id` will always behave the
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync same as getting and setting your custom id attribute.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @property idAttribute
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @type String
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @default `'id'`
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync **/
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync idAttribute: 'id',
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync /**
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync Hash of attributes that were changed in the last `change` event. Each item
b025d5f11836934ade517ff53604078b5aff12e5vboxsync in this hash is an object with the following properties:
b025d5f11836934ade517ff53604078b5aff12e5vboxsync
b025d5f11836934ade517ff53604078b5aff12e5vboxsync * `newVal`: The new value of the attribute after it changed.
b025d5f11836934ade517ff53604078b5aff12e5vboxsync * `prevVal`: The old value of the attribute before it changed.
b025d5f11836934ade517ff53604078b5aff12e5vboxsync * `src`: The source of the change, or `null` if no source was specified.
b025d5f11836934ade517ff53604078b5aff12e5vboxsync
b025d5f11836934ade517ff53604078b5aff12e5vboxsync @property lastChange
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @type Object
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @default {}
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync **/
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync /**
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync Array of `ModelList` instances that contain this model.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync When a model is in one or more lists, the model's events will bubble up to
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync those lists. You can subscribe to a model event on a list to be notified
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync when any model in the list fires that event.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync This property is updated automatically when this model is added to or
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync removed from a `ModelList` instance. You shouldn't alter it manually. When
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync working with models in a list, you should always add and remove models using
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync the list's `add()` and `remove()` methods.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @example Subscribing to model events on a list:
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync // Assuming `list` is an existing Y.ModelList instance.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync list.on('*:change', function (e) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync // This function will be called whenever any model in the list
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync // fires a `change` event.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync //
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync // `e.target` will refer to the model instance that fired the
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync // event.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync });
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @property lists
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @type ModelList[]
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @default `[]`
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync **/
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync // -- Protected Properties -------------------------------------------------
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync /**
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync This tells `Y.Base` that it should create ad-hoc attributes for config
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync properties passed to Model's constructor. This makes it possible to
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync instantiate a model and set a bunch of attributes without having to subclass
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync `Y.Model` and declare all those attributes first.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @property _allowAdHocAttrs
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @type Boolean
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @default true
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @protected
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @since 3.5.0
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync **/
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync _allowAdHocAttrs: true,
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync /**
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync Total hack to allow us to identify Model instances without using
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync `instanceof`, which won't work when the instance was created in another
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync window or YUI sandbox.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @property _isYUIModel
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @type Boolean
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @default true
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @protected
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @since 3.5.0
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync **/
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync _isYUIModel: true,
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync // -- Lifecycle Methods ----------------------------------------------------
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync initializer: function (config) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync this.changed = {};
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync this.lastChange = {};
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync this.lists = [];
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync },
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync // -- Public Methods -------------------------------------------------------
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync /**
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync Destroys this model instance and removes it from its containing lists, if
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync any.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync The _callback_, if one is provided, will be called after the model is
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync destroyed.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync If `options.remove` is `true`, then this method delegates to the `sync()`
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync method to delete the model from the persistence layer, which is an
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync asynchronous action. In this case, the _callback_ (if provided) will be
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync called after the sync layer indicates success or failure of the delete
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync operation.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @method destroy
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Object} [options] Sync options. It's up to the custom sync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync implementation to determine what options it supports or requires, if
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync any.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Boolean} [options.remove=false] If `true`, the model will be
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync deleted via the sync layer in addition to the instance being destroyed.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {callback} [callback] Called after the model has been destroyed (and
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync deleted via the sync layer if `options.remove` is `true`).
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Error|null} callback.err If an error occurred, this parameter will
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync contain the error. Otherwise _err_ will be `null`.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @chainable
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync **/
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync destroy: function (options, callback) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync var self = this;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync // Allow callback as only arg.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if (typeof options === 'function') {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync callback = options;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync options = null;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync self.onceAfter('destroy', function () {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync function finish(err) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if (!err) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync YArray.each(self.lists.concat(), function (list) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync list.remove(self, options);
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync });
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync callback && callback.apply(null, arguments);
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
3268c8aab4681e1f7aff21e300dd0fdef1bb6f7fvboxsync
3268c8aab4681e1f7aff21e300dd0fdef1bb6f7fvboxsync if (options && (options.remove || options['delete'])) {
3268c8aab4681e1f7aff21e300dd0fdef1bb6f7fvboxsync self.sync('delete', options, finish);
3268c8aab4681e1f7aff21e300dd0fdef1bb6f7fvboxsync } else {
3268c8aab4681e1f7aff21e300dd0fdef1bb6f7fvboxsync finish();
3268c8aab4681e1f7aff21e300dd0fdef1bb6f7fvboxsync }
3268c8aab4681e1f7aff21e300dd0fdef1bb6f7fvboxsync });
3268c8aab4681e1f7aff21e300dd0fdef1bb6f7fvboxsync
3a17531e9a12c3582ebe7a0e76f562b70d4875c1vboxsync return Model.superclass.destroy.call(self);
3a17531e9a12c3582ebe7a0e76f562b70d4875c1vboxsync },
3a17531e9a12c3582ebe7a0e76f562b70d4875c1vboxsync
3a17531e9a12c3582ebe7a0e76f562b70d4875c1vboxsync /**
3a17531e9a12c3582ebe7a0e76f562b70d4875c1vboxsync Returns a clientId string that's unique among all models on the current page
3a17531e9a12c3582ebe7a0e76f562b70d4875c1vboxsync (even models in other YUI instances). Uniqueness across pageviews is
3a17531e9a12c3582ebe7a0e76f562b70d4875c1vboxsync unlikely.
3a17531e9a12c3582ebe7a0e76f562b70d4875c1vboxsync
3a17531e9a12c3582ebe7a0e76f562b70d4875c1vboxsync @method generateClientId
3a17531e9a12c3582ebe7a0e76f562b70d4875c1vboxsync @return {String} Unique clientId.
3a17531e9a12c3582ebe7a0e76f562b70d4875c1vboxsync **/
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync generateClientId: function () {
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync GlobalEnv.lastId || (GlobalEnv.lastId = 0);
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync return this.constructor.NAME + '_' + (GlobalEnv.lastId += 1);
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync },
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync /**
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync Returns the value of the specified attribute.
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync If the attribute's value is an object, _name_ may use dot notation to
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync specify the path to a specific property within the object, and the value of
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync that property will be returned.
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync @example
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync // Set the 'foo' attribute to an object.
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync myModel.set('foo', {
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync bar: {
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync baz: 'quux'
57f59a6f0c871da46b4c8f2e71a0f6a1d0bf772evboxsync }
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync });
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync // Get the value of 'foo'.
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync myModel.get('foo');
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync // => {bar: {baz: 'quux'}}
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync // Get the value of 'foo.bar.baz'.
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync myModel.get('foo.bar.baz');
57f59a6f0c871da46b4c8f2e71a0f6a1d0bf772evboxsync // => 'quux'
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync @method get
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync @param {String} name Attribute name or object property path.
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync @return {Any} Attribute value, or `undefined` if the attribute doesn't
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync exist.
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync **/
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync // get() is defined by Y.Attribute.
57f59a6f0c871da46b4c8f2e71a0f6a1d0bf772evboxsync
57f59a6f0c871da46b4c8f2e71a0f6a1d0bf772evboxsync /**
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync Returns an HTML-escaped version of the value of the specified string
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync attribute. The value is escaped using `Y.Escape.html()`.
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync @method getAsHTML
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync @param {String} name Attribute name or object property path.
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync @return {String} HTML-escaped attribute value.
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync **/
57f59a6f0c871da46b4c8f2e71a0f6a1d0bf772evboxsync getAsHTML: function (name) {
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync var value = this.get(name);
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync return Y.Escape.html(Lang.isValue(value) ? String(value) : '');
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync },
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync /**
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync Returns a URL-encoded version of the value of the specified string
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync attribute. The value is encoded using the native `encodeURIComponent()`
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync function.
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync
57f59a6f0c871da46b4c8f2e71a0f6a1d0bf772evboxsync @method getAsURL
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync @param {String} name Attribute name or object property path.
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync @return {String} URL-encoded attribute value.
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync **/
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync getAsURL: function (name) {
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync var value = this.get(name);
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync return encodeURIComponent(Lang.isValue(value) ? String(value) : '');
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync },
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync
57f59a6f0c871da46b4c8f2e71a0f6a1d0bf772evboxsync /**
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync Returns `true` if any attribute of this model has been changed since the
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync model was last saved.
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync New models (models for which `isNew()` returns `true`) are implicitly
cb1b4ee184d6bc409437422b8dbeaf4f0ba5f398vboxsync considered to be "modified" until the first time they're saved.
3a17531e9a12c3582ebe7a0e76f562b70d4875c1vboxsync
4084fd2e85cf5edb77bfc0b444c30c3e3a13be03vboxsync @method isModified
4084fd2e85cf5edb77bfc0b444c30c3e3a13be03vboxsync @return {Boolean} `true` if this model has changed since it was last saved,
57f59a6f0c871da46b4c8f2e71a0f6a1d0bf772evboxsync `false` otherwise.
4084fd2e85cf5edb77bfc0b444c30c3e3a13be03vboxsync **/
4084fd2e85cf5edb77bfc0b444c30c3e3a13be03vboxsync isModified: function () {
4084fd2e85cf5edb77bfc0b444c30c3e3a13be03vboxsync return this.isNew() || !YObject.isEmpty(this.changed);
4084fd2e85cf5edb77bfc0b444c30c3e3a13be03vboxsync },
4084fd2e85cf5edb77bfc0b444c30c3e3a13be03vboxsync
4084fd2e85cf5edb77bfc0b444c30c3e3a13be03vboxsync /**
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync Returns `true` if this model is "new", meaning it hasn't been saved since it
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync was created.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync Newness is determined by checking whether the model's `id` attribute has
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync been set. An empty id is assumed to indicate a new model, whereas a
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync non-empty id indicates a model that was either loaded or has been saved
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync since it was created.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @method isNew
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @return {Boolean} `true` if this model is new, `false` otherwise.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync **/
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync isNew: function () {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync return !Lang.isValue(this.get('id'));
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync },
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync /**
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync Loads this model from the server.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync This method delegates to the `sync()` method to perform the actual load
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync operation, which is an asynchronous action. Specify a _callback_ function to
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync be notified of success or failure.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync A successful load operation will fire a `load` event, while an unsuccessful
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync load operation will fire an `error` event with the `src` value "load".
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync If the load operation succeeds and one or more of the loaded attributes
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync differ from this model's current attributes, a `change` event will be fired.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @method load
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Object} [options] Options to be passed to `sync()` and to `set()`
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync when setting the loaded attributes. It's up to the custom sync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync implementation to determine what options it supports or requires, if any.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {callback} [callback] Called when the sync operation finishes.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Error|null} callback.err If an error occurred, this parameter will
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync contain the error. If the sync operation succeeded, _err_ will be
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync `null`.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Any} callback.response The server's response. This value will
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync be passed to the `parse()` method, which is expected to parse it and
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync return an attribute hash.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @chainable
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync **/
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync load: function (options, callback) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync var self = this;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync // Allow callback as only arg.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if (typeof options === 'function') {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync callback = options;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync options = {};
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync options || (options = {});
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync self.sync('read', options, function (err, response) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync var facade = {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync options : options,
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync response: response
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync },
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync parsed;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if (err) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync facade.error = err;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync facade.src = 'load';
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync self.fire(EVT_ERROR, facade);
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync } else {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync // Lazy publish.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if (!self._loadEvent) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync self._loadEvent = self.publish(EVT_LOAD, {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync preventable: false
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync });
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync parsed = facade.parsed = self.parse(response);
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync self.setAttrs(parsed, options);
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync self.changed = {};
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync self.fire(EVT_LOAD, facade);
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync callback && callback.apply(null, arguments);
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync });
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync return self;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync },
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync /**
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync Called to parse the _response_ when the model is loaded from the server.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync This method receives a server _response_ and is expected to return an
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync attribute hash.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync The default implementation assumes that _response_ is either an attribute
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync hash or a JSON string that can be parsed into an attribute hash. If
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync _response_ is a JSON string and either `Y.JSON` or the native `JSON` object
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync are available, it will be parsed automatically. If a parse error occurs, an
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync `error` event will be fired and the model will not be updated.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync You may override this method to implement custom parsing logic if necessary.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @method parse
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Any} response Server response.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @return {Object} Attribute hash.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync **/
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync parse: function (response) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if (typeof response === 'string') {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync try {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync return Y.JSON.parse(response);
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync } catch (ex) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync this.fire(EVT_ERROR, {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync error : ex,
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync response: response,
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync src : 'parse'
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync });
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync return null;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync return response;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync },
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync /**
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync Saves this model to the server.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync This method delegates to the `sync()` method to perform the actual save
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync operation, which is an asynchronous action. Specify a _callback_ function to
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync be notified of success or failure.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync A successful save operation will fire a `save` event, while an unsuccessful
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync save operation will fire an `error` event with the `src` value "save".
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync If the save operation succeeds and one or more of the attributes returned in
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync the server's response differ from this model's current attributes, a
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync `change` event will be fired.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @method save
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Object} [options] Options to be passed to `sync()` and to `set()`
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync when setting synced attributes. It's up to the custom sync implementation
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync to determine what options it supports or requires, if any.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Function} [callback] Called when the sync operation finishes.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Error|null} callback.err If an error occurred or validation
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync failed, this parameter will contain the error. If the sync operation
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync succeeded, _err_ will be `null`.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Any} callback.response The server's response. This value will
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync be passed to the `parse()` method, which is expected to parse it and
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync return an attribute hash.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @chainable
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync **/
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync save: function (options, callback) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync var self = this;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync // Allow callback as only arg.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if (typeof options === 'function') {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync callback = options;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync options = {};
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync options || (options = {});
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync self._validate(self.toJSON(), function (err) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if (err) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync callback && callback.call(null, err);
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync return;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync self.sync(self.isNew() ? 'create' : 'update', options, function (err, response) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync var facade = {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync options : options,
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync response: response
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync },
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync parsed;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if (err) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync facade.error = err;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync facade.src = 'save';
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync self.fire(EVT_ERROR, facade);
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync } else {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync // Lazy publish.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if (!self._saveEvent) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync self._saveEvent = self.publish(EVT_SAVE, {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync preventable: false
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync });
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if (response) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync parsed = facade.parsed = self.parse(response);
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync self.setAttrs(parsed, options);
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync self.changed = {};
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync self.fire(EVT_SAVE, facade);
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync callback && callback.apply(null, arguments);
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync });
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync });
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync return self;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync },
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync /**
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync Sets the value of a single attribute. If model validation fails, the
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync attribute will not be set and an `error` event will be fired.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync Use `setAttrs()` to set multiple attributes at once.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @example
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync model.set('foo', 'bar');
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @method set
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {String} name Attribute name or object property path.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {any} value Value to set.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Object} [options] Data to be mixed into the event facade of the
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync `change` event(s) for these attributes.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Boolean} [options.silent=false] If `true`, no `change` event will
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync be fired.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @chainable
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync **/
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync set: function (name, value, options) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync var attributes = {};
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync attributes[name] = value;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync return this.setAttrs(attributes, options);
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync },
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync /**
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync Sets the values of multiple attributes at once. If model validation fails,
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync the attributes will not be set and an `error` event will be fired.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @example
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync model.setAttrs({
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync foo: 'bar',
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync baz: 'quux'
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync });
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @method setAttrs
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Object} attributes Hash of attribute names and values to set.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Object} [options] Data to be mixed into the event facade of the
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync `change` event(s) for these attributes.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Boolean} [options.silent=false] If `true`, no `change` event will
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync be fired.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @chainable
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync **/
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync setAttrs: function (attributes, options) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync var idAttribute = this.idAttribute,
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync changed, e, key, lastChange, transaction;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync options || (options = {});
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync transaction = options._transaction = {};
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync // When a custom id attribute is in use, always keep the default `id`
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync // attribute in sync.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if (idAttribute !== 'id') {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync // So we don't modify someone else's object.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync attributes = Y.merge(attributes);
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if (YObject.owns(attributes, idAttribute)) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync attributes.id = attributes[idAttribute];
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync } else if (YObject.owns(attributes, 'id')) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync attributes[idAttribute] = attributes.id;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync for (key in attributes) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if (YObject.owns(attributes, key)) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync this._setAttr(key, attributes[key], options);
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if (!YObject.isEmpty(transaction)) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync changed = this.changed;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync lastChange = this.lastChange = {};
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync for (key in transaction) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if (YObject.owns(transaction, key)) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync e = transaction[key];
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync changed[key] = e.newVal;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync lastChange[key] = {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync newVal : e.newVal,
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync prevVal: e.prevVal,
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync src : e.src || null
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync };
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if (!options.silent) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync // Lazy publish for the change event.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if (!this._changeEvent) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync this._changeEvent = this.publish(EVT_CHANGE, {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync preventable: false
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync });
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync this.fire(EVT_CHANGE, Y.merge(options, {changed: lastChange}));
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync return this;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync },
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync /**
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync Override this method to provide a custom persistence implementation for this
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync model. The default just calls the callback without actually doing anything.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync This method is called internally by `load()`, `save()`, and `destroy()`.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @method sync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {String} action Sync action to perform. May be one of the following:
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync * `create`: Store a newly-created model for the first time.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync * `delete`: Delete an existing model.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync * `read` : Load an existing model.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync * `update`: Update an existing model.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Object} [options] Sync options. It's up to the custom sync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync implementation to determine what options it supports or requires, if any.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Function} [callback] Called when the sync operation finishes.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Error|null} callback.err If an error occurred, this parameter will
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync contain the error. If the sync operation succeeded, _err_ will be
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync falsy.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Any} [callback.response] The server's response.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync **/
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync sync: function (/* action, options, callback */) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync var callback = YArray(arguments, 0, true).pop();
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if (typeof callback === 'function') {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync callback();
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync },
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync /**
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync Returns a copy of this model's attributes that can be passed to
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync `Y.JSON.stringify()` or used for other nefarious purposes.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync The `clientId` attribute is not included in the returned object.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync If you've specified a custom attribute name in the `idAttribute` property,
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync the default `id` attribute will not be included in the returned object.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync Note: This method is named `toJSON()`, but it returns an object, not a JSON
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync string. We know that. It's not because we're idiots who are incapable of
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync naming things. It's because the method name "toJSON" and the object return
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync type are specified in the ECMAScript 5 standard. Adhering to this standard
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync allows you to stringify a model by doing `JSON.stringify(model)` if you want
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync to. Please don't file a bug telling us we're idiots. We'll just sigh, cry a
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync little, and mark the bug invalid.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync See <http://es5.github.com/#x15.12.3>.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @method toJSON
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @return {Object} Copy of this model's attributes.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync **/
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync toJSON: function () {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync var attrs = this.getAttrs();
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync delete attrs.clientId;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync delete attrs.destroyed;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync delete attrs.initialized;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if (this.idAttribute !== 'id') {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync delete attrs.id;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync return attrs;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync },
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync /**
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync Reverts the last change to the model.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync If an _attrNames_ array is provided, then only the named attributes will be
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync reverted (and only if they were modified in the previous change). If no
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync _attrNames_ array is provided, then all changed attributes will be reverted
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync to their previous values.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync Note that only one level of undo is available: from the current state to the
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync previous state. If `undo()` is called when no previous state is available,
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync it will simply do nothing.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @method undo
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Array} [attrNames] Array of specific attribute names to revert. If
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync not specified, all attributes modified in the last change will be
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync reverted.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Object} [options] Data to be mixed into the event facade of the
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync change event(s) for these attributes.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Boolean} [options.silent=false] If `true`, no `change` event will
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync be fired.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @chainable
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync **/
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync undo: function (attrNames, options) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync var lastChange = this.lastChange,
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync idAttribute = this.idAttribute,
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync toUndo = {},
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync needUndo;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync attrNames || (attrNames = YObject.keys(lastChange));
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync YArray.each(attrNames, function (name) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if (YObject.owns(lastChange, name)) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync // Don't generate a double change for custom id attributes.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync name = name === idAttribute ? 'id' : name;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync needUndo = true;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync toUndo[name] = lastChange[name].prevVal;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync });
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync return needUndo ? this.setAttrs(toUndo, options) : this;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync },
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync /**
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync Override this method to provide custom validation logic for this model.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync While attribute-specific validators can be used to validate individual
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync attributes, this method gives you a hook to validate a hash of all
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync attributes before the model is saved. This method is called automatically
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync before `save()` takes any action. If validation fails, the `save()` call
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync will be aborted.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync In your validation method, call the provided `callback` function with no
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync arguments to indicate success. To indicate failure, pass a single argument,
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync which may contain an error message, an array of error messages, or any other
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync value. This value will be passed along to the `error` event.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @example
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync model.validate = function (attrs, callback) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if (attrs.pie !== true) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync // No pie?! Invalid!
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync callback('Must provide pie.');
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync return;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync // Success!
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync callback();
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync };
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @method validate
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Object} attrs Attribute hash containing all model attributes to
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync be validated.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Function} callback Validation callback. Call this function when your
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync validation logic finishes. To trigger a validation failure, pass any
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync value as the first argument to the callback (ideally a meaningful
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync validation error of some kind).
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Any} [callback.err] Validation error. Don't provide this
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync argument if validation succeeds. If validation fails, set this to an
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync error message or some other meaningful value. It will be passed
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync along to the resulting `error` event.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync **/
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync validate: function (attrs, callback) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync callback && callback();
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync },
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync // -- Protected Methods ----------------------------------------------------
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync /**
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync Duckpunches the `addAttr` method provided by `Y.Attribute` to keep the
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync `id` attribute’s value and a custom id attribute’s (if provided) value
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync in sync when adding the attributes to the model instance object.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync Marked as protected to hide it from Model's public API docs, even though
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync this is a public method in Attribute.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @method addAttr
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {String} name The name of the attribute.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Object} config An object with attribute configuration property/value
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync pairs, specifying the configuration for the attribute.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Boolean} lazy (optional) Whether or not to add this attribute lazily
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync (on the first call to get/set).
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @return {Object} A reference to the host object.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @chainable
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @protected
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync **/
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync addAttr: function (name, config, lazy) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync var idAttribute = this.idAttribute,
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync idAttrCfg, id;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if (idAttribute && name === idAttribute) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync idAttrCfg = this._isLazyAttr('id') || this._getAttrCfg('id');
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync id = config.value === config.defaultValue ? null : config.value;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if (!Lang.isValue(id)) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync // Hunt for the id value.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync id = idAttrCfg.value === idAttrCfg.defaultValue ? null : idAttrCfg.value;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if (!Lang.isValue(id)) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync // No id value provided on construction, check defaults.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync id = Lang.isValue(config.defaultValue) ?
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync config.defaultValue :
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync idAttrCfg.defaultValue;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync config.value = id;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync // Make sure `id` is in sync.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if (idAttrCfg.value !== id) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync idAttrCfg.value = id;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if (this._isLazyAttr('id')) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync this._state.add('id', 'lazy', idAttrCfg);
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync } else {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync this._state.add('id', 'value', id);
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync return Model.superclass.addAttr.apply(this, arguments);
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync },
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync /**
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync Calls the public, overridable `validate()` method and fires an `error` event
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if validation fails.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @method _validate
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Object} attributes Attribute hash.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Function} callback Validation callback.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {Any} [callback.err] Value on failure, non-value on success.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @protected
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync **/
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync _validate: function (attributes, callback) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync var self = this;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync function handler(err) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if (Lang.isValue(err)) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync // Validation failed. Fire an error.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync self.fire(EVT_ERROR, {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync attributes: attributes,
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync error : err,
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync src : 'validate'
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync });
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync callback(err);
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync return;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync callback();
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if (self.validate.length === 1) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync // Backcompat for 3.4.x-style synchronous validate() functions that
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync // don't take a callback argument.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync handler(self.validate(attributes, handler));
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync } else {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync self.validate(attributes, handler);
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync },
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync // -- Protected Event Handlers ---------------------------------------------
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync /**
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync Duckpunches the `_defAttrChangeFn()` provided by `Y.Attribute` so we can
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync have a single global notification when a change event occurs.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @method _defAttrChangeFn
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @param {EventFacade} e
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @protected
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync **/
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync _defAttrChangeFn: function (e) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync var attrName = e.attrName;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if (!this._setAttrVal(attrName, e.subAttrName, e.prevVal, e.newVal)) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync // Prevent "after" listeners from being invoked since nothing changed.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync e.stopImmediatePropagation();
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync } else {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync e.newVal = this.get(attrName);
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync if (e._transaction) {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync e._transaction[attrName] = e;
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync}, {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync NAME: 'model',
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync ATTRS: {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync /**
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync A client-only identifier for this model.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync Like the `id` attribute, `clientId` may be used to retrieve model
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync instances from lists. Unlike the `id` attribute, `clientId` is
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync automatically generated, and is only intended to be used on the client
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync during the current pageview.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @attribute clientId
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @type String
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @readOnly
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync **/
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync clientId: {
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync valueFn : 'generateClientId',
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync readOnly: true
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync },
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync /**
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync A unique identifier for this model. Among other things, this id may be
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync used to retrieve model instances from lists, so it should be unique.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync If the id is empty, this model instance is assumed to represent a new
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync item that hasn't yet been saved.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync If you would prefer to use a custom attribute as this model's id instead
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync of using the `id` attribute (for example, maybe you'd rather use `_id`
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync or `uid` as the primary id), you may set the `idAttribute` property to
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync the name of your custom id attribute. The `id` attribute will then
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync act as an alias for your custom attribute.
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @attribute id
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @type String|Number|null
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync @default `null`
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync **/
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync id: {value: null}
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync }
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync});
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync}, '@VERSION@' ,{requires:['base-build', 'escape', 'json-parse']});
febf3f1de573e25fb134b8453a22b0732b4c52e2vboxsync