4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5 <title>The source code</title>
6 <link href="../prettify/prettify.css" type="text/css" rel="stylesheet" />
7 <script type="text/javascript" src="../prettify/prettify.js"></script>
8 <style type="text/css">
9 .highlight { display: block; background-color: #ddd; }
11 <script type="text/javascript">
12 function highlight() {
13 document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
17 <body onload="prettyPrint(); highlight();">
18 <pre class="prettyprint lang-js"><span id='Ext-data-proxy-WebStorage-method-constructor'><span id='Ext-data-proxy-WebStorage'>/**
19 </span></span> * @author Ed Spencer
20 * @class Ext.data.proxy.WebStorage
21 * @extends Ext.data.proxy.Client
23 * <p>WebStorageProxy is simply a superclass for the {@link Ext.data.proxy.LocalStorage localStorage} and
24 * {@link Ext.data.proxy.SessionStorage sessionStorage} proxies. It uses the new HTML5 key/value client-side storage
25 * objects to save {@link Ext.data.Model model instances} for offline use.</p>
28 * Creates the proxy, throws an error if local storage is not supported in the current browser
29 * @param {Object} config Optional config object
31 Ext.define('Ext.data.proxy.WebStorage', {
32 extend: 'Ext.data.proxy.Client',
33 alternateClassName: 'Ext.data.WebStorageProxy',
35 <span id='Ext-data-proxy-WebStorage-cfg-id'> /**
36 </span> * @cfg {String} id The unique ID used as the key in which all record data are stored in the local storage object
40 <span id='Ext-data-proxy-WebStorage-method-constructor'> /**
43 constructor: function(config) {
44 this.callParent(arguments);
46 <span id='Ext-data-proxy-WebStorage-property-cache'> /**
47 </span> * Cached map of records already retrieved by this Proxy - ensures that the same instance is always retrieved
54 if (this.getStorageObject() === undefined) {
55 Ext.Error.raise("Local Storage is not supported in this browser, please use another type of data proxy");
59 //if an id is not given, try to use the store's id instead
60 this.id = this.id || (this.store ? this.store.storeId : undefined);
63 if (this.id === undefined) {
64 Ext.Error.raise("No unique id was provided to the local storage proxy. See Ext.data.proxy.LocalStorage documentation for details");
72 create: function(operation, callback, scope) {
73 var records = operation.records,
74 length = records.length,
78 operation.setStarted();
80 for (i = 0; i < length; i++) {
84 record.phantom = false;
85 id = this.getNextId();
90 this.setRecord(record, id);
96 operation.setCompleted();
97 operation.setSuccessful();
99 if (typeof callback == 'function') {
100 callback.call(scope || this, operation);
105 read: function(operation, callback, scope) {
106 //TODO: respect sorters, filters, start and limit options on the Operation
111 i, recordData, record;
113 //read a single record
115 record = this.getRecord(operation.id);
118 records.push(record);
119 operation.setSuccessful();
122 for (i = 0; i < length; i++) {
123 records.push(this.getRecord(ids[i]));
125 operation.setSuccessful();
128 operation.setCompleted();
130 operation.resultSet = Ext.create('Ext.data.ResultSet', {
132 total : records.length,
136 if (typeof callback == 'function') {
137 callback.call(scope || this, operation);
142 update: function(operation, callback, scope) {
143 var records = operation.records,
144 length = records.length,
148 operation.setStarted();
150 for (i = 0; i < length; i++) {
152 this.setRecord(record);
154 //we need to update the set of ids here because it's possible that a non-phantom record was added
155 //to this proxy - in which case the record's id would never have been added via the normal 'create' call
157 if (id !== undefined && Ext.Array.indexOf(ids, id) == -1) {
163 operation.setCompleted();
164 operation.setSuccessful();
166 if (typeof callback == 'function') {
167 callback.call(scope || this, operation);
172 destroy: function(operation, callback, scope) {
173 var records = operation.records,
174 length = records.length,
177 //newIds is a copy of ids, from which we remove the destroyed records
178 newIds = [].concat(ids),
181 for (i = 0; i < length; i++) {
182 Ext.Array.remove(newIds, records[i].getId());
183 this.removeRecord(records[i], false);
188 operation.setCompleted();
189 operation.setSuccessful();
191 if (typeof callback == 'function') {
192 callback.call(scope || this, operation);
196 <span id='Ext-data-proxy-WebStorage-method-getRecord'> /**
198 * Fetches a model instance from the Proxy by ID. Runs each field's decode function (if present) to decode the data
199 * @param {String} id The record's unique ID
200 * @return {Ext.data.Model} The model instance
202 getRecord: function(id) {
203 if (this.cache[id] === undefined) {
204 var rawData = Ext.decode(this.getStorageObject().getItem(this.getRecordKey(id))),
207 fields = Model.prototype.fields.items,
208 length = fields.length,
209 i, field, name, record;
211 for (i = 0; i < length; i++) {
215 if (typeof field.decode == 'function') {
216 data[name] = field.decode(rawData[name]);
218 data[name] = rawData[name];
222 record = new Model(data, id);
223 record.phantom = false;
225 this.cache[id] = record;
228 return this.cache[id];
231 <span id='Ext-data-proxy-WebStorage-method-setRecord'> /**
232 </span> * Saves the given record in the Proxy. Runs each field's encode function (if present) to encode the data
233 * @param {Ext.data.Model} record The model instance
234 * @param {String} id The id to save the record under (defaults to the value of the record's getId() function)
236 setRecord: function(record, id) {
244 rawData = record.data,
247 fields = model.prototype.fields.items,
248 length = fields.length,
250 field, name, obj, key;
252 for (; i < length; i++) {
256 if (typeof field.encode == 'function') {
257 data[name] = field.encode(rawData[name], record);
259 data[name] = rawData[name];
263 obj = me.getStorageObject();
264 key = me.getRecordKey(id);
266 //keep the cache up to date
267 me.cache[id] = record;
269 //iPad bug requires that we remove the item before setting it
271 obj.setItem(key, Ext.encode(data));
274 <span id='Ext-data-proxy-WebStorage-method-removeRecord'> /**
276 * Physically removes a given record from the local storage. Used internally by {@link #destroy}, which you should
277 * use instead because it updates the list of currently-stored record ids
278 * @param {String|Number|Ext.data.Model} id The id of the record to remove, or an Ext.data.Model instance
280 removeRecord: function(id, updateIds) {
288 if (updateIds !== false) {
290 Ext.Array.remove(ids, id);
294 me.getStorageObject().removeItem(me.getRecordKey(id));
297 <span id='Ext-data-proxy-WebStorage-method-getRecordKey'> /**
299 * Given the id of a record, returns a unique string based on that id and the id of this proxy. This is used when
300 * storing data in the local storage object and should prevent naming collisions.
301 * @param {String|Number|Ext.data.Model} id The record id, or a Model instance
302 * @return {String} The unique key for this record
304 getRecordKey: function(id) {
309 return Ext.String.format("{0}-{1}", this.id, id);
312 <span id='Ext-data-proxy-WebStorage-method-getRecordCounterKey'> /**
314 * Returns the unique key used to store the current record counter for this proxy. This is used internally when
315 * realizing models (creating them when they used to be phantoms), in order to give each model instance a unique id.
316 * @return {String} The counter key
318 getRecordCounterKey: function() {
319 return Ext.String.format("{0}-counter", this.id);
322 <span id='Ext-data-proxy-WebStorage-method-getIds'> /**
324 * Returns the array of record IDs stored in this Proxy
325 * @return {Array} The record IDs. Each is cast as a Number
328 var ids = (this.getStorageObject().getItem(this.id) || "").split(","),
332 if (length == 1 && ids[0] === "") {
335 for (i = 0; i < length; i++) {
336 ids[i] = parseInt(ids[i], 10);
343 <span id='Ext-data-proxy-WebStorage-method-setIds'> /**
345 * Saves the array of ids representing the set of all records in the Proxy
346 * @param {Array} ids The ids to set
348 setIds: function(ids) {
349 var obj = this.getStorageObject(),
350 str = ids.join(",");
352 obj.removeItem(this.id);
354 if (!Ext.isEmpty(str)) {
355 obj.setItem(this.id, str);
359 <span id='Ext-data-proxy-WebStorage-method-getNextId'> /**
361 * Returns the next numerical ID that can be used when realizing a model instance (see getRecordCounterKey). Increments
363 * @return {Number} The id
365 getNextId: function() {
366 var obj = this.getStorageObject(),
367 key = this.getRecordCounterKey(),
368 last = obj.getItem(key),
373 last = ids[ids.length - 1] || 0;
376 id = parseInt(last, 10) + 1;
377 obj.setItem(key, id);
382 <span id='Ext-data-proxy-WebStorage-method-initialize'> /**
384 * Sets up the Proxy by claiming the key in the storage object that corresponds to the unique id of this Proxy. Called
385 * automatically by the constructor, this should not need to be called again unless {@link #clear} has been called.
387 initialize: function() {
388 var storageObject = this.getStorageObject();
389 storageObject.setItem(this.id, storageObject.getItem(this.id) || "");
392 <span id='Ext-data-proxy-WebStorage-method-clear'> /**
393 </span> * Destroys all records stored in the proxy and removes all keys and values used to support the proxy from the storage object
396 var obj = this.getStorageObject(),
401 //remove all the records
402 for (i = 0; i < len; i++) {
403 this.removeRecord(ids[i]);
406 //remove the supporting objects
407 obj.removeItem(this.getRecordCounterKey());
408 obj.removeItem(this.id);
411 <span id='Ext-data-proxy-WebStorage-method-getStorageObject'> /**
413 * Abstract function which should return the storage object that data will be saved to. This must be implemented
415 * @return {Object} The storage object
417 getStorageObject: function() {
419 Ext.Error.raise("The getStorageObject function has not been defined in your Ext.data.proxy.WebStorage subclass");