2 YUI 3.13.0 (build 508226d)
3 Copyright 2013 Yahoo! Inc. All rights reserved.
4 Licensed under the BSD License.
5 http://yuilibrary.com/license/
8 YUI.add('model-sync-local', function (Y, NAME) {
11 An extension which provides a sync implementation through locally stored
12 key value pairs, either through the HTML localStorage API or falling back
13 onto an in-memory cache, that can be mixed into a Model or ModelList subclass.
16 @submodule model-sync-local
21 An extension which provides a sync implementation through locally stored
22 key value pairs, either through the HTML localStorage API or falling back
23 onto an in-memory cache, that can be mixed into a Model or ModelList subclass.
25 A group of Models/ModelLists is serialized in localStorage by either its
26 class name, or a specified 'root' that is provided.
28 var User = Y.Base.create('user', Y.Model, [Y.ModelSync.Local], {
32 var Users = Y.Base.create('users', Y.ModelList, [Y.ModelSync.Local], {
36 @class ModelSync.Local
38 @extensionfor ModelList
41 function LocalSync() {}
44 Properties that shouldn't be turned into ad-hoc attributes when passed to a
45 Model or ModelList constructor.
47 @property _NON_ATTRS_CFG
54 LocalSync._NON_ATTRS_CFG = ['root'];
57 Feature testing for `localStorage` availability.
58 Will return falsey for browsers with `localStorage`, but that don't
59 actually work, such as iOS Safari in private browsing mode.
61 @property _hasLocalStorage
65 LocalSync._hasLocalStorage = (function () {
66 var LS = Y.config.win.localStorage,
70 LS.setItem(test, test);
79 Object of key/value pairs to fall back on when localStorage is not available.
88 Cache to quickly access a specific object with a given ID.
89 This maps a model's ID to its reference inside of `LocalSync._data`.
96 LocalSync._idMap = {};
98 LocalSync.prototype = {
100 // -- Public Methods -------------------------------------------------------
103 Root used as the key inside of localStorage and/or the in-memory store.
113 Shortcut for access to localStorage.
122 // -- Lifecycle Methods -----------------------------------------------------
123 initializer: function (config) {
126 config || (config = {});
128 if ('root' in config) {
129 this.root = config.root || '';
132 // This is checking to see if the sync layer is being applied to
133 // a ModelList, and if so, is looking for a `root` property on its
134 // Model's prototype instead.
135 if (!this.root && this.model && this.model.prototype.root) {
136 this.root = this.model.prototype.root;
139 if (LocalSync._hasLocalStorage) {
140 this.storage = Y.config.win.localStorage;
141 store = this.storage.getItem(this.root);
143 Y.log("Could not access localStorage.", "warn");
146 // Pull in existing data from localStorage, if possible.
147 // Otherwise, see if there's existing data on the local cache.
150 LocalSync._data[this.root] = Y.JSON.parse(store);
152 LocalSync._data[this.root] = [];
155 LocalSync._data[this.root] || (LocalSync._data[this.root] = []);
158 // Map each model's ID to its reference inside of data, if there
159 // are already existing models inside of `localStorage`.
160 LocalSync._idMap[this.root] || (LocalSync._idMap[this.root] = {});
161 Y.Array.each(LocalSync._data[this.root], function (item) {
164 LocalSync._idMap[this.root][id] = item;
169 // -- Public Methods -----------------------------------------------------------
172 Creates a synchronization layer with the localStorage API, if available.
173 Otherwise, falls back to a in-memory data store.
175 This method is called internally by load(), save(), and destroy().
178 @param {String} action Sync action to perform. May be one of the following:
180 * **create**: Store a newly-created model for the first time.
181 * **read** : Load an existing model.
182 * **update**: Update an existing model.
183 * **delete**: Delete an existing model.
185 @param {Object} [options] Sync options
186 @param {callback} [callback] Called when the sync operation finishes.
187 @param {Error|null} callback.err If an error occurred, this parameter will
188 contain the error. If the sync operation succeeded, _err_ will be
190 @param {Any} [callback.response] The response from our sync. This value will
191 be passed to the parse() method, which is expected to parse it and
192 return an attribute hash.
194 sync: function (action, options, callback) {
195 options || (options = {});
196 var response, errorInfo;
201 if (this._isYUIModelList) {
202 response = this._index(options);
204 response = this._show(options);
208 response = this._create(options);
211 response = this._update(options);
214 response = this._destroy(options);
218 errorInfo = error.message;
222 callback(null, response);
223 } else if (errorInfo) {
226 callback("Data not found in LocalStorage");
231 Generate a random GUID for our Models. This can be overriden if you have
232 another method of generating different IDs.
236 @param {String} pre Optional GUID prefix
238 generateID: function (pre) {
239 return Y.guid(pre + '_');
242 // -- Protected Methods ----------------------------------------------------
245 Sync method correlating to the "read" operation, for a Model List
248 @return {Object[]} Array of objects found for that root key
252 _index: function () {
253 return LocalSync._data[this.root];
257 Sync method correlating to the "read" operation, for a Model
260 @return {Object} Object found for that root key and model ID
265 return LocalSync._idMap[this.root][this.get('id')] || null;
269 Sync method correlating to the "create" operation
272 @return {Object} The new object created.
276 _create: function () {
277 var hash = this.toJSON(),
278 data = LocalSync._data[this.root],
279 idMap = LocalSync._idMap[this.root];
281 hash.id = this.generateID(this.root);
283 idMap[hash.id] = hash;
290 Sync method correlating to the "update" operation
293 @return {Object} The updated object.
297 _update: function () {
298 var hash = Y.merge(this.toJSON());
299 LocalSync._idMap[this.get('id')] = hash;
306 Sync method correlating to the "delete" operation. Deletes the data
307 from the in-memory object, and saves into localStorage if available.
310 @return {Object} The deleted object.
314 _destroy: function () {
315 delete LocalSync._idMap[this.get('id')];
317 return this.toJSON();
321 Saves the current in-memory store into a localStorage key/value pair
322 if localStorage is available; otherwise, does nothing.
329 if (LocalSync._hasLocalStorage) {
330 this.storage && this.storage.setItem(
332 Y.JSON.stringify(LocalSync._data[this.root])
338 // -- Namespace ---------------------------------------------------------------
340 Y.namespace('ModelSync').Local = LocalSync;
343 }, '3.13.0', {"requires": ["model", "json-stringify"]});