/** * @class Ext.util.Stateful * Represents any object whose data can be saved by a {@link Ext.data.Proxy Proxy}. Ext.Model * and Ext.View both inherit from this class as both can save state (Models save field state, * Views save configuration) */ Ext.define('Ext.util.Stateful', { mixins: { observable: 'Ext.util.Observable' },
/** * Internal flag used to track whether or not the model instance is currently being edited. Read-only * @property editing * @type Boolean */ editing : false,
/** * Readonly flag - true if this Record has been modified. * @type Boolean */ dirty : false,
/** * @cfg {String} persistanceProperty The property on this Persistable object that its data is saved to. * Defaults to 'data' (e.g. all persistable data resides in this.data.) */ persistanceProperty: 'data', constructor: function(config) { Ext.applyIf(this, { data: {} });
/** * Key: value pairs of all fields whose values have changed * @property modified * @type Object */ this.modified = {}; this[this.persistanceProperty] = {}; this.mixins.observable.constructor.call(this); },
/** * Returns the value of the given field * @param {String} fieldName The field to fetch the value for * @return {Mixed} The value */ get: function(field) { return this[this.persistanceProperty][field]; },
/** * Sets the given field to the given value, marks the instance as dirty * @param {String|Object} fieldName The field to set, or an object containing key/value pairs * @param {Mixed} value The value to set */ set: function(fieldName, value) { var fields = this.fields, convertFields = [], field, key, i; /* * If we're passed an object, iterate over that object. NOTE: we pull out fields with a convert function and * set those last so that all other possible data is set before the convert function is called */ if (arguments.length == 1 && Ext.isObject(fieldName)) { for (key in fieldName) { if (!fieldName.hasOwnProperty(key)) { continue; } //here we check for the custom convert function. Note that if a field doesn't have a convert function, //we default it to its type's convert function, so we have to check that here. This feels rather dirty. field = fields.get(key); if (field && field.convert !== field.type.convert) { convertFields.push(key); continue; } this.set(key, fieldName[key]); } for (i = 0; i < convertFields.length; i++) { field = convertFields[i]; this.set(field, fieldName[field]); } } else { if (fields) { field = fields.get(fieldName); if (field && field.convert) { value = field.convert(value, this); } } this[this.persistanceProperty][fieldName] = value; this.dirty = true; if (!this.editing) { this.afterEdit(); } } },
/** * Gets a hash of only the fields that have been modified since this Model was created or commited. * @return Object */ getChanges : function(){ var modified = this.modified, changes = {}, field; for (field in modified) { if (modified.hasOwnProperty(field)){ changes[field] = this[this.persistanceProperty][field]; } } return changes; },
/** * Returns true if the passed field name has been {@link #modified} * since the load or last commit. * @param {String} fieldName {@link Ext.data.Field#name} * @return {Boolean} */ isModified : function(fieldName) { return !!(this.modified && this.modified.hasOwnProperty(fieldName)); },
/** *

Marks this Record as {@link #dirty}. This method * is used interally when adding {@link #phantom} records to a * {@link Ext.data.Store#writer writer enabled store}.

*

Marking a record {@link #dirty} causes the phantom to * be returned by {@link Ext.data.Store#getModifiedRecords} where it will * have a create action composed for it during {@link Ext.data.Store#save store save} * operations.

*/ setDirty : function() { this.dirty = true; if (!this.modified) { this.modified = {}; } this.fields.each(function(field) { this.modified[field.name] = this[this.persistanceProperty][field.name]; }, this); }, // markDirty : function() { throw new Error("Stateful: markDirty has been deprecated. Please use setDirty."); }, //
/** * Usually called by the {@link Ext.data.Store} to which this model instance has been {@link #join joined}. * Rejects all changes made to the model instance since either creation, or the last commit operation. * Modified fields are reverted to their original values. *

Developers should subscribe to the {@link Ext.data.Store#update} event * to have their code notified of reject operations.

* @param {Boolean} silent (optional) True to skip notification of the owning * store of the change (defaults to false) */ reject : function(silent) { var modified = this.modified, field; for (field in modified) { if (!modified.hasOwnProperty(field)) { continue; } if (typeof modified[field] != "function") { this[this.persistanceProperty][field] = modified[field]; } } this.dirty = false; this.editing = false; delete this.modified; if (silent !== true) { this.afterReject(); } },
/** * Usually called by the {@link Ext.data.Store} which owns the model instance. * Commits all changes made to the instance since either creation or the last commit operation. *

Developers should subscribe to the {@link Ext.data.Store#update} event * to have their code notified of commit operations.

* @param {Boolean} silent (optional) True to skip notification of the owning * store of the change (defaults to false) */ commit : function(silent) { this.dirty = false; this.editing = false; delete this.modified; if (silent !== true) { this.afterCommit(); } },
/** * Creates a copy (clone) of this Model instance. * @param {String} id (optional) A new id, defaults to the id * of the instance being copied. See {@link #id}. * To generate a phantom instance with a new id use:

var rec = record.copy(); // clone the record
Ext.data.Model.id(rec); // automatically generate a unique sequential id
     * 
* @return {Record} */ copy : function(newId) { return new this.self(Ext.apply({}, this[this.persistanceProperty]), newId || this.internalId); } });