/** * This mixin provides a `dirty` config that tracks the modified state of an object. If * the class using this mixin is {@link Ext.mixin.Observable observable}, changes to the * `dirty` config will fire the `dirtychange` event. * @protected * @since 6.2.0 */Ext.define('Ext.mixin.Dirty', { mixinId: 'dirty', /** * @event dirtychange * Fires when a change in the object's {@link #cfg-dirty} state is detected. * * **Note:** In order for this event to fire, the class that mixes in this mixin * must be `{@link Ext.mixin.Observable Observable}`. * * @param {Ext.Base} this * @param {Boolean} dirty Whether or not the object is now dirty. */ config: { /** * @cfg {Boolean} dirty * This config property describes the modified state of this object. In most * cases this config's value is maintained by the object and should be considered * readonly. The class implementor should be the only one to call the setter. */ dirty: { $value: false, lazy: true } }, dirty: false, // on the prototype as false (not undefined) /** * @property {Number} _dirtyRecordCount * The number of newly created, modified or dropped records. * @private * @readonly */ _dirtyRecordCount: 0, /** * @cfg {Boolean} ignoreDirty * This config property indicates that the `dirty` state of this object should be * ignored. Because this capability is mixed in at a class level, this config can * be helpful when some instances do not participate in dirty state tracking. * * This option should be set at construction time. When set to `true`, the object * will always have `dirty` value of `false`. */ ignoreDirty: false, /** * @cfg {Boolean} recordStateIsDirtyState * Set this config at construction time (or on the class body) to automatically set * the `dirty` state based on the records passed to `trackRecordState`. * * This config defaults to `true` but only has an effect when the record tracking * methods are called (`trackRecordState`, `untrackRecordState` and `clearRecordStates`). * @protected */ recordStateIsDirtyState: true, /** * Returns `true` if this object is `dirty`. */ isDirty: function () { // This alias matches the Ext.form.field.* family. return this.getDirty(); }, applyDirty: function (dirty) { return this.ignoreDirty ? false : dirty; }, updateDirty: function (dirty) { var me = this; // Store the property directly in case we are used in an "_dirty" world. me.dirty = dirty; if (me.fireEvent && !me.isDirtyInitializing) { me.fireDirtyChange(); } }, /** * Clears all record state tracking. This state is maintained by `trackRecordState` * and `untrackRecordState`. * @protected */ clearRecordStates: function () { var me = this, counters = me._crudCounters; if (counters) { counters.C = counters.U = counters.D = 0; } me._dirtyRecordCount = 0; if (me.recordStateIsDirtyState) { me.setDirty(false); } }, fireDirtyChange: function() { var me = this; if (!me.ignoreDirty && me.hasListeners.dirtychange) { me.fireEvent('dirtychange', me, me.dirty); } }, /** * This method is called to track a given record in the total number of dirty records * (modified, created or dropped). See `untrackRecordState` and `clearRecordStates`. * * @param {Ext.data.Model} record The record to track. * @param {Boolean} initial Pass `true` the first time a record is introduced. * @return {Boolean} Returns `true` if the state of dirty records has changed. * @protected */ trackRecordState: function (record, initial) { var me = this, counters = me._crudCounters || (me._crudCounters = { C:0, R:0, U:0, D:0 }), dirtyRecordCountWas = me._dirtyRecordCount, state = record.crudState, stateWas = record.crudStateWas, changed, dirtyRecordCount; if (initial || state !== stateWas) { if (!initial && stateWas) { --counters[stateWas]; } if (!(record.phantom && state === 'D')) { ++counters[state]; } //<debug> me.checkCounters(); //</debug> me._dirtyRecordCount = dirtyRecordCount = counters.C + counters.U + counters.D; changed = !dirtyRecordCount !== !dirtyRecordCountWas; if (changed && me.recordStateIsDirtyState) { me.setDirty(dirtyRecordCount > 0); } } return changed; }, /** * This method is called to remove the tracking of a given record from the total number * of dirty records (modified, created or dropped). The record passed to this method * must have been previously passed to `trackRecordState`. * * @param {Ext.data.Model} record The record to stop tracking. * @return {Boolean} Returns `true` if the state of dirty records has changed. * @protected */ untrackRecordState: function (record) { var me = this, counters = me._crudCounters, dirtyRecordCountWas = me._dirtyRecordCount, state = record.crudState, changed, dirtyRecordCount; // If it's erased and dropped, it will have already been tracked if (counters && state !== 'D' && !record.erased) { --counters[state]; //<debug> me.checkCounters(); //</debug> me._dirtyRecordCount = dirtyRecordCount = counters.C + counters.U + counters.D; changed = !dirtyRecordCount !== !dirtyRecordCountWas; if (changed && me.recordStateIsDirtyState) { me.setDirty(dirtyRecordCount > 0); } } return changed; } //<debug> ,checkCounters: function() { var counters = this._crudCounters, key; for (key in counters) { if (counters[key] < 0) { Ext.raise('Invalid state for ' + key); } } } //</debug> });