3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
16 * @class Ext.state.Stateful
17 * A mixin for being able to save the state of an object to an underlying
18 * {@link Ext.state.Provider}.
20 Ext.define('Ext.state.Stateful', {
22 /* Begin Definitions */
25 observable: 'Ext.util.Observable'
28 requires: ['Ext.state.Manager'],
33 * @cfg {Boolean} stateful
34 * <p>A flag which causes the object to attempt to restore the state of
35 * internal properties from a saved state on startup. The object must have
36 * a <code>{@link #stateId}</code> for state to be managed.
37 * Auto-generated ids are not guaranteed to be stable across page loads and
38 * cannot be relied upon to save and restore the same state for a object.<p>
39 * <p>For state saving to work, the state manager's provider must have been
40 * set to an implementation of {@link Ext.state.Provider} which overrides the
41 * {@link Ext.state.Provider#set set} and {@link Ext.state.Provider#get get}
42 * methods to save and recall name/value pairs. A built-in implementation,
43 * {@link Ext.state.CookieProvider} is available.</p>
44 * <p>To set the state provider for the current page:</p>
46 Ext.state.Manager.setProvider(new Ext.state.CookieProvider({
47 expires: new Date(new Date().getTime()+(1000*60*60*24*7)), //7 days from now
50 * <p>A stateful object attempts to save state when one of the events
51 * listed in the <code>{@link #stateEvents}</code> configuration fires.</p>
52 * <p>To save state, a stateful object first serializes its state by
53 * calling <b><code>{@link #getState}</code></b>. By default, this function does
54 * nothing. The developer must provide an implementation which returns an
55 * object hash which represents the restorable state of the object.</p>
56 * <p>The value yielded by getState is passed to {@link Ext.state.Manager#set}
57 * which uses the configured {@link Ext.state.Provider} to save the object
58 * keyed by the <code>{@link #stateId}</code>.</p>
59 * <p>During construction, a stateful object attempts to <i>restore</i>
60 * its state by calling {@link Ext.state.Manager#get} passing the
61 * <code>{@link #stateId}</code></p>
62 * <p>The resulting object is passed to <b><code>{@link #applyState}</code></b>.
63 * The default implementation of <code>{@link #applyState}</code> simply copies
64 * properties into the object, but a developer may override this to support
66 * <p>You can perform extra processing on state save and restore by attaching
67 * handlers to the {@link #beforestaterestore}, {@link #staterestore},
68 * {@link #beforestatesave} and {@link #statesave} events.</p>
73 * @cfg {String} stateId
74 * The unique id for this object to use for state management purposes.
75 * <p>See {@link #stateful} for an explanation of saving and restoring state.</p>
79 * @cfg {String[]} stateEvents
80 * <p>An array of events that, when fired, should trigger this object to
81 * save its state. Defaults to none. <code>stateEvents</code> may be any type
82 * of event supported by this object, including browser or custom events
83 * (e.g., <tt>['click', 'customerchange']</tt>).</p>
84 * <p>See <code>{@link #stateful}</code> for an explanation of saving and
85 * restoring object state.</p>
89 * @cfg {Number} saveDelay
90 * A buffer to be applied if many state events are fired within a short period.
94 autoGenIdRe: /^((\w+-)|(ext-comp-))\d{4,}$/i,
96 constructor: function(config) {
99 config = config || {};
100 if (Ext.isDefined(config.stateful)) {
101 me.stateful = config.stateful;
103 if (Ext.isDefined(config.saveDelay)) {
104 me.saveDelay = config.saveDelay;
106 me.stateId = me.stateId || config.stateId;
108 if (!me.stateEvents) {
111 if (config.stateEvents) {
112 me.stateEvents.concat(config.stateEvents);
116 * @event beforestaterestore
117 * Fires before the state of the object is restored. Return false from an event handler to stop the restore.
118 * @param {Ext.state.Stateful} this
119 * @param {Object} state The hash of state values returned from the StateProvider. If this
120 * event is not vetoed, then the state object is passed to <b><tt>applyState</tt></b>. By default,
121 * that simply copies property values into this object. The method maybe overriden to
122 * provide custom state restoration.
124 'beforestaterestore',
127 * @event staterestore
128 * Fires after the state of the object is restored.
129 * @param {Ext.state.Stateful} this
130 * @param {Object} state The hash of state values returned from the StateProvider. This is passed
131 * to <b><tt>applyState</tt></b>. By default, that simply copies property values into this
132 * object. The method maybe overriden to provide custom state restoration.
137 * @event beforestatesave
138 * Fires before the state of the object is saved to the configured state provider. Return false to stop the save.
139 * @param {Ext.state.Stateful} this
140 * @param {Object} state The hash of state values. This is determined by calling
141 * <b><tt>getState()</tt></b> on the object. This method must be provided by the
142 * developer to return whetever representation of state is required, by default, Ext.state.Stateful
143 * has a null implementation.
149 * Fires after the state of the object is saved to the configured state provider.
150 * @param {Ext.state.Stateful} this
151 * @param {Object} state The hash of state values. This is determined by calling
152 * <b><tt>getState()</tt></b> on the object. This method must be provided by the
153 * developer to return whetever representation of state is required, by default, Ext.state.Stateful
154 * has a null implementation.
158 me.mixins.observable.constructor.call(me);
159 if (me.stateful !== false) {
160 me.initStateEvents();
166 * Initializes any state events for this object.
169 initStateEvents: function() {
170 this.addStateEvents(this.stateEvents);
174 * Add events that will trigger the state to be saved.
175 * @param {String/String[]} events The event name or an array of event names.
177 addStateEvents: function(events){
178 if (!Ext.isArray(events)) {
186 for (; i < len; ++i) {
187 me.on(events[i], me.onStateChange, me);
192 * This method is called when any of the {@link #stateEvents} are fired.
195 onStateChange: function(){
197 delay = me.saveDelay;
201 me.stateTask = Ext.create('Ext.util.DelayedTask', me.saveState, me);
203 me.stateTask.delay(me.saveDelay);
210 * Saves the state of the object to the persistence store.
213 saveState: function() {
218 if (me.stateful !== false) {
219 id = me.getStateId();
221 state = me.getState();
222 if (me.fireEvent('beforestatesave', me, state) !== false) {
223 Ext.state.Manager.set(id, state);
224 me.fireEvent('statesave', me, state);
231 * Gets the current state of the object. By default this function returns null,
232 * it should be overridden in subclasses to implement methods for getting the state.
233 * @return {Object} The current state
235 getState: function(){
240 * Applies the state to the object. This should be overridden in subclasses to do
241 * more complex state operations. By default it applies the state properties onto
242 * the current object.
243 * @param {Object} state The state
245 applyState: function(state) {
247 Ext.apply(this, state);
252 * Gets the state id for this object.
253 * @return {String} The state id, null if not found.
255 getStateId: function() {
260 id = me.autoGenIdRe.test(String(me.id)) ? null : me.id;
266 * Initializes the state of the object upon construction.
269 initState: function(){
271 id = me.getStateId(),
274 if (me.stateful !== false) {
276 state = Ext.state.Manager.get(id);
278 state = Ext.apply({}, state);
279 if (me.fireEvent('beforestaterestore', me, state) !== false) {
280 me.applyState(state);
281 me.fireEvent('staterestore', me, state);
289 * Conditionally saves a single property from this object to the given state object.
290 * The idea is to only save state which has changed from the initial state so that
291 * current software settings do not override future software settings. Only those
292 * values that are user-changed state should be saved.
294 * @param {String} propName The name of the property to save.
295 * @param {Object} state The state object in to which to save the property.
296 * @param {String} stateName (optional) The name to use for the property in state.
297 * @return {Boolean} True if the property was saved, false if not.
299 savePropToState: function (propName, state, stateName) {
301 value = me[propName],
302 config = me.initialConfig;
304 if (me.hasOwnProperty(propName)) {
305 if (!config || config[propName] !== value) {
307 state[stateName || propName] = value;
315 savePropsToState: function (propNames, state) {
317 Ext.each(propNames, function (propName) {
318 me.savePropToState(propName, state);
324 * Destroys this stateful object.
327 var task = this.stateTask;
331 this.clearListeners();