Stateful.html
14.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>The source code</title>
<link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
<script type="text/javascript" src="../resources/prettify/prettify.js"></script>
<style type="text/css">
.highlight { display: block; background-color: #ddd; }
</style>
<script type="text/javascript">
function highlight() {
document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
}
</script>
</head>
<body onload="prettyPrint(); highlight();">
<pre class="prettyprint lang-js"><span id='Ext-state-Stateful'>/**
</span> * @class Ext.state.Stateful
* A mixin for being able to save the state of an object to an underlying
* {@link Ext.state.Provider}.
*/
Ext.define('Ext.state.Stateful', {
/* Begin Definitions */
mixins: {
observable: 'Ext.util.Observable'
},
requires: ['Ext.state.Manager'],
/* End Definitions */
<span id='Ext-state-Stateful-cfg-stateful'> /**
</span> * @cfg {Boolean} stateful
* A flag which causes the object to attempt to restore the state of
* internal properties from a saved state on startup. The object must have
* a {@link #stateId} for state to be managed.
*
* Auto-generated ids are not guaranteed to be stable across page loads and
* cannot be relied upon to save and restore the same state for a object.<p>
*
* For state saving to work, the state manager's provider must have been
* set to an implementation of {@link Ext.state.Provider} which overrides the
* {@link Ext.state.Provider#set set} and {@link Ext.state.Provider#get get}
* methods to save and recall name/value pairs. A built-in implementation,
* {@link Ext.state.CookieProvider} is available.
*
* To set the state provider for the current page:
*
* Ext.state.Manager.setProvider(new Ext.state.CookieProvider({
* expires: new Date(new Date().getTime()+(1000*60*60*24*7)), //7 days from now
* }));
*
* A stateful object attempts to save state when one of the events
* listed in the {@link #stateEvents} configuration fires.
*
* To save state, a stateful object first serializes its state by
* calling *{@link #getState}*.
*
* The Component base class implements {@link #getState} to save its width and height within the state
* only if they were initially configured, and have changed from the configured value.
*
* The Panel class saves its collapsed state in addition to that.
*
* The Grid class saves its column state in addition to its superclass state.
*
* If there is more application state to be save, the developer must provide an implementation which
* first calls the superclass method to inherit the above behaviour, and then injects new properties
* into the returned object.
*
* The value yielded by getState is passed to {@link Ext.state.Manager#set}
* which uses the configured {@link Ext.state.Provider} to save the object
* keyed by the {@link #stateId}.
*
* During construction, a stateful object attempts to *restore* its state by calling
* {@link Ext.state.Manager#get} passing the {@link #stateId}
*
* The resulting object is passed to {@link #applyState}*. The default implementation of
* {@link #applyState} simply copies properties into the object, but a developer may
* override this to support restoration of more complex application state.
*
* You can perform extra processing on state save and restore by attaching
* handlers to the {@link #beforestaterestore}, {@link #staterestore},
* {@link #beforestatesave} and {@link #statesave} events.
*/
stateful: false,
<span id='Ext-state-Stateful-cfg-stateId'> /**
</span> * @cfg {String} stateId
* The unique id for this object to use for state management purposes.
* <p>See {@link #stateful} for an explanation of saving and restoring state.</p>
*/
<span id='Ext-state-Stateful-cfg-stateEvents'> /**
</span> * @cfg {String[]} stateEvents
* <p>An array of events that, when fired, should trigger this object to
* save its state. Defaults to none. <code>stateEvents</code> may be any type
* of event supported by this object, including browser or custom events
* (e.g., <tt>['click', 'customerchange']</tt>).</p>
* <p>See <code>{@link #stateful}</code> for an explanation of saving and
* restoring object state.</p>
*/
<span id='Ext-state-Stateful-cfg-saveDelay'> /**
</span> * @cfg {Number} saveDelay
* A buffer to be applied if many state events are fired within a short period.
*/
saveDelay: 100,
constructor: function(config) {
var me = this;
config = config || {};
if (config.stateful !== undefined) {
me.stateful = config.stateful;
}
if (config.saveDelay !== undefined) {
me.saveDelay = config.saveDelay;
}
me.stateId = me.stateId || config.stateId;
if (!me.stateEvents) {
me.stateEvents = [];
}
if (config.stateEvents) {
me.stateEvents.concat(config.stateEvents);
}
this.addEvents(
<span id='Ext-state-Stateful-event-beforestaterestore'> /**
</span> * @event beforestaterestore
* Fires before the state of the object is restored. Return false from an event handler to stop the restore.
* @param {Ext.state.Stateful} this
* @param {Object} state The hash of state values returned from the StateProvider. If this
* event is not vetoed, then the state object is passed to <b><tt>applyState</tt></b>. By default,
* that simply copies property values into this object. The method maybe overriden to
* provide custom state restoration.
*/
'beforestaterestore',
<span id='Ext-state-Stateful-event-staterestore'> /**
</span> * @event staterestore
* Fires after the state of the object is restored.
* @param {Ext.state.Stateful} this
* @param {Object} state The hash of state values returned from the StateProvider. This is passed
* to <b><tt>applyState</tt></b>. By default, that simply copies property values into this
* object. The method maybe overriden to provide custom state restoration.
*/
'staterestore',
<span id='Ext-state-Stateful-event-beforestatesave'> /**
</span> * @event beforestatesave
* Fires before the state of the object is saved to the configured state provider. Return false to stop the save.
* @param {Ext.state.Stateful} this
* @param {Object} state The hash of state values. This is determined by calling
* <b><tt>getState()</tt></b> on the object. This method must be provided by the
* developer to return whetever representation of state is required, by default, Ext.state.Stateful
* has a null implementation.
*/
'beforestatesave',
<span id='Ext-state-Stateful-event-statesave'> /**
</span> * @event statesave
* Fires after the state of the object is saved to the configured state provider.
* @param {Ext.state.Stateful} this
* @param {Object} state The hash of state values. This is determined by calling
* <b><tt>getState()</tt></b> on the object. This method must be provided by the
* developer to return whetever representation of state is required, by default, Ext.state.Stateful
* has a null implementation.
*/
'statesave'
);
me.mixins.observable.constructor.call(me);
if (me.stateful !== false) {
me.addStateEvents(me.stateEvents);
me.initState();
}
},
<span id='Ext-state-Stateful-method-addStateEvents'> /**
</span> * Add events that will trigger the state to be saved. If the first argument is an
* array, each element of that array is the name of a state event. Otherwise, each
* argument passed to this method is the name of a state event.
*
* @param {String/String[]} events The event name or an array of event names.
*/
addStateEvents: function (events) {
var me = this,
i, event, stateEventsByName;
if (me.stateful && me.getStateId()) {
if (typeof events == 'string') {
events = Array.prototype.slice.call(arguments, 0);
}
stateEventsByName = me.stateEventsByName || (me.stateEventsByName = {});
for (i = events.length; i--; ) {
event = events[i];
if (!stateEventsByName[event]) {
stateEventsByName[event] = 1;
me.on(event, me.onStateChange, me);
}
}
}
},
<span id='Ext-state-Stateful-method-onStateChange'> /**
</span> * This method is called when any of the {@link #stateEvents} are fired.
* @private
*/
onStateChange: function(){
var me = this,
delay = me.saveDelay,
statics, runner;
if (!me.stateful) {
return;
}
if (delay) {
if (!me.stateTask) {
statics = Ext.state.Stateful;
runner = statics.runner || (statics.runner = new Ext.util.TaskRunner());
me.stateTask = runner.newTask({
run: me.saveState,
scope: me,
interval: delay,
repeat: 1
});
}
me.stateTask.start();
} else {
me.saveState();
}
},
<span id='Ext-state-Stateful-method-saveState'> /**
</span> * Saves the state of the object to the persistence store.
*/
saveState: function() {
var me = this,
id = me.stateful && me.getStateId(),
hasListeners = me.hasListeners,
state;
if (id) {
state = me.getState() || {}; //pass along for custom interactions
if (!hasListeners.beforestatesave || me.fireEvent('beforestatesave', me, state) !== false) {
Ext.state.Manager.set(id, state);
if (hasListeners.statesave) {
me.fireEvent('statesave', me, state);
}
}
}
},
<span id='Ext-state-Stateful-method-getState'> /**
</span> * Gets the current state of the object. By default this function returns null,
* it should be overridden in subclasses to implement methods for getting the state.
* @return {Object} The current state
*/
getState: function(){
return null;
},
<span id='Ext-state-Stateful-method-applyState'> /**
</span> * Applies the state to the object. This should be overridden in subclasses to do
* more complex state operations. By default it applies the state properties onto
* the current object.
* @param {Object} state The state
*/
applyState: function(state) {
if (state) {
Ext.apply(this, state);
}
},
<span id='Ext-state-Stateful-method-getStateId'> /**
</span> * Gets the state id for this object.
* @return {String} The 'stateId' or the implicit 'id' specified by component configuration.
* @private
*/
getStateId: function() {
var me = this;
return me.stateId || (me.autoGenId ? null : me.id);
},
<span id='Ext-state-Stateful-method-initState'> /**
</span> * Initializes the state of the object upon construction.
* @private
*/
initState: function(){
var me = this,
id = me.stateful && me.getStateId(),
hasListeners = me.hasListeners,
state;
if (id) {
state = Ext.state.Manager.get(id);
if (state) {
state = Ext.apply({}, state);
if (!hasListeners.beforestaterestore || me.fireEvent('beforestaterestore', me, state) !== false) {
me.applyState(state);
if (hasListeners.staterestore) {
me.fireEvent('staterestore', me, state);
}
}
}
}
},
<span id='Ext-state-Stateful-method-savePropToState'> /**
</span> * Conditionally saves a single property from this object to the given state object.
* The idea is to only save state which has changed from the initial state so that
* current software settings do not override future software settings. Only those
* values that are user-changed state should be saved.
*
* @param {String} propName The name of the property to save.
* @param {Object} state The state object in to which to save the property.
* @param {String} stateName (optional) The name to use for the property in state.
* @return {Boolean} True if the property was saved, false if not.
*/
savePropToState: function (propName, state, stateName) {
var me = this,
value = me[propName],
config = me.initialConfig;
if (me.hasOwnProperty(propName)) {
if (!config || config[propName] !== value) {
if (state) {
state[stateName || propName] = value;
}
return true;
}
}
return false;
},
<span id='Ext-state-Stateful-method-savePropsToState'> /**
</span> * Gathers additional named properties of the instance and adds their current values
* to the passed state object.
* @param {String/String[]} propNames The name (or array of names) of the property to save.
* @param {Object} state The state object in to which to save the property values.
* @return {Object} state
*/
savePropsToState: function (propNames, state) {
var me = this,
i, n;
if (typeof propNames == 'string') {
me.savePropToState(propNames, state);
} else {
for (i = 0, n = propNames.length; i < n; ++i) {
me.savePropToState(propNames[i], state);
}
}
return state;
},
<span id='Ext-state-Stateful-method-destroy'> /**
</span> * Destroys this stateful object.
*/
destroy: function(){
var me = this,
task = me.stateTask;
if (task) {
task.destroy();
me.stateTask = null;
}
me.clearListeners();
}
});
</pre>
</body>
</html>