/** * @private */Ext.define('Ext.Evented', { alternateClassName: 'Ext.EventedBase', mixins: [ 'Ext.mixin.Observable' ], /** * @cfg {Object} eventedConfig * Config options defined within `eventedConfig` will auto-generate the setter / * getter methods (see {@link #cfg-config config} for more information on * auto-generated getter / setter methods). Additionally, when an * `eventedConfig` is set it will also fire a before{cfg}change and {cfg}change * event when the value of the eventedConfig is changed from its originally * defined value. * * **Note:** When creating a custom class you'll need to extend Ext.Evented * * Example custom class: * * Ext.define('MyApp.util.Test', { * extend: 'Ext.Evented', * * eventedConfig: { * foo: null * } * }); * * In this example, the `foo` config will initially be null. Changing it via * `setFoo` will fire the `beforefoochange` event. The call to the setter can be * halted by returning `false` from a listener on the **before** event. * * var test = Ext.create('MyApp.util.Test', { * listeners: { * beforefoochange: function (instance, newValue, oldValue) { * return newValue !== 'bar'; * }, * foochange: function (instance, newValue, oldValue) { * console.log('foo changed to:', newValue); * } * } * }); * * test.setFoo('bar'); * * The `before` event handler can be used to validate changes to `foo`. * Returning `false` will prevent the setter from changing the value of the * config. In the previous example the `beforefoochange` handler returns false * so `foo` will not be updated and `foochange` will not be fired. * * test.setFoo('baz'); * * Setting `foo` to 'baz' will not be prevented by the `before` handler. Foo * will be set to the value: 'baz' and the `foochange` event will be fired. */ statics: { generateSetter: function (cfg) { var names = cfg.names, name = cfg.name, prefixedName = names.internal, applyName = names.apply, changeEventName = names.changeEvent, doSetName = names.doSet; return function(value) { var me = this, internalName = me.$configPrefixed ? prefixedName : name, initialized = me.initialized, oldValue, applier = me[applyName]; if (applier) { value = applier.call(me, value, me[internalName]); if (value === undefined) { return me; } } // The old value might have been changed at this point // (after the apply call chain) so it should be read here oldValue = me[internalName]; if (value !== oldValue) { if (initialized) { me.fireAction(changeEventName, [me, value, oldValue], me.doSet, me, { nameMap: names }); } else { me[internalName] = value; if (me[doSetName]) { me[doSetName](value, oldValue); } } } return this; }; } }, initialized: false, constructor: function(config) { this.mixins.observable.constructor.call(this, config); this.initialized = true; }, doSet: function(me, value, oldValue, options) { var nameMap = options.nameMap; me[nameMap.internal] = value; if (me[nameMap.doSet]) { me[nameMap.doSet].call(this, value, oldValue); } }, onClassExtended: function(cls, data) { if (!data.hasOwnProperty('eventedConfig')) { return; } var config = data.config, eventedConfig = data.eventedConfig, cacheName = 'eventedSetter', name, cfg; if (config) { Ext.applyIf(config, eventedConfig); } else { cls.addConfig(eventedConfig); } /* * These are generated setters for eventedConfig * * If the component is initialized, it invokes fireAction to fire the event as well, * which indicate something has changed. Otherwise, it just executes the action * (happens during initialization) * * This is helpful when we only want the event to be fired for subsequent changes. * Also it's a major performance improvement for instantiation when fired events * are mostly useless since there's no listeners */ for (name in eventedConfig) { if (eventedConfig.hasOwnProperty(name)) { cfg = Ext.Config.get(name); data[cfg.names.set] = cfg[cacheName] || (cfg[cacheName] = this.generateSetter(cfg)); } } }});