NOBUG: Fixed file access permissions
[moodle.git] / lib / yuilib / 3.13.0 / model-sync-local / model-sync-local-debug.js
blob35638425d2e15b1e165852a2db763f727926c4a5
1 /*
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/
6 */
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.
15 @module app
16 @submodule model-sync-local
17 @since 3.13.0
18 **/
20 /**
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], {
29         root: 'user'
30     });
32     var Users = Y.Base.create('users', Y.ModelList, [Y.ModelSync.Local], {
33         model: User,
34     });
36 @class ModelSync.Local
37 @extensionfor Model
38 @extensionfor ModelList
39 @since 3.13.0
40 **/
41 function LocalSync() {}
43 /**
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
48 @type Array
49 @default ['root']
50 @static
51 @protected
52 @since 3.13.0
53 **/
54 LocalSync._NON_ATTRS_CFG = ['root'];
56 /**
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
62 @type Boolean
63 @private
64 **/
65 LocalSync._hasLocalStorage = (function () {
66     var LS   = Y.config.win.localStorage,
67         test = Y.guid();
69     try {
70         LS.setItem(test, test);
71         LS.removeItem(test);
72         return true;
73     } catch (e) {
74         return false;
75     }
76 })(),
78 /**
79 Object of key/value pairs to fall back on when localStorage is not available.
81 @property _data
82 @type Object
83 @private
84 **/
85 LocalSync._data = {};
87 /**
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`.
91 @property _idMap
92 @type Object
93 @private
94 **/
96 LocalSync._idMap = {};
98 LocalSync.prototype = {
100     // -- Public Methods -------------------------------------------------------
101     
102     /**
103     Root used as the key inside of localStorage and/or the in-memory store.
104     
105     @property root
106     @type String
107     @default ""
108     @since 3.13.0
109     **/
110     root: '',
112     /**
113     Shortcut for access to localStorage.
114     
115     @property storage
116     @type Storage
117     @default null
118     @since 3.13.0
119     **/
120     storage: null,
122     // -- Lifecycle Methods -----------------------------------------------------
123     initializer: function (config) {
124         var store, data;
126         config || (config = {});
128         if ('root' in config) {
129             this.root = config.root || '';
130         }
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;
137         }
139         if (LocalSync._hasLocalStorage) {
140             this.storage = Y.config.win.localStorage;
141             store = this.storage.getItem(this.root);
142         } else {
143             Y.log("Could not access localStorage.", "warn");
144         }
146         // Pull in existing data from localStorage, if possible.
147         // Otherwise, see if there's existing data on the local cache.
148         if (store) {
149             try {
150                 LocalSync._data[this.root] = Y.JSON.parse(store);
151             } catch (e) {
152                 LocalSync._data[this.root] = [];
153             }
154         } else {
155             LocalSync._data[this.root] || (LocalSync._data[this.root] = []);
156         }
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) {
162             var id = item.id;
163             if (id) {
164                 LocalSync._idMap[this.root][id] = item;
165             }
166         }, this);
167     },
168     
169     // -- Public Methods -----------------------------------------------------------
170     
171     /**
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().
177     @method sync
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
189         falsey.
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.
193     **/
194     sync: function (action, options, callback) {
195         options || (options = {});
196         var response, errorInfo;
198         try {
199             switch (action) {
200                 case 'read':
201                     if (this._isYUIModelList) {
202                         response = this._index(options);
203                     } else {
204                         response = this._show(options);
205                     }
206                     break;
207                 case 'create':
208                     response = this._create(options);
209                     break;
210                 case 'update':
211                     response = this._update(options);
212                     break;
213                 case 'delete':
214                     response = this._destroy(options);
215                     break;
216             }
217         } catch (error) {
218             errorInfo = error.message;
219         }
221         if (response) {
222             callback(null, response);
223         } else if (errorInfo) {
224             callback(errorInfo);
225         } else {
226             callback("Data not found in LocalStorage");
227         }
228     },
230     /**
231     Generate a random GUID for our Models. This can be overriden if you have
232     another method of generating different IDs.
233     
234     @method generateID
235     @protected
236     @param {String} pre Optional GUID prefix
237     **/
238     generateID: function (pre) {
239         return Y.guid(pre + '_');
240     },
242     // -- Protected Methods ----------------------------------------------------
244     /**
245     Sync method correlating to the "read" operation, for a Model List
246     
247     @method _index
248     @return {Object[]} Array of objects found for that root key
249     @protected
250     @since 3.13.0
251     **/
252     _index: function () {
253         return LocalSync._data[this.root];
254     },
256     /**
257     Sync method correlating to the "read" operation, for a Model
258     
259     @method _show
260     @return {Object} Object found for that root key and model ID
261     @protected
262     @since 3.13.0
263     **/
264     _show: function () {
265         return LocalSync._idMap[this.root][this.get('id')] || null;
266     },
267     
268     /**
269     Sync method correlating to the "create" operation
270     
271     @method _show
272     @return {Object} The new object created.
273     @protected
274     @since 3.13.0
275     **/
276     _create: function () {
277         var hash  = this.toJSON(),
278             data  = LocalSync._data[this.root],
279             idMap = LocalSync._idMap[this.root];
280         
281         hash.id = this.generateID(this.root);
282         data.push(hash);
283         idMap[hash.id] = hash;
285         this._save();
286         return hash;
287     },
289     /**
290     Sync method correlating to the "update" operation
292     @method _update
293     @return {Object} The updated object.
294     @protected
295     @since 3.13.0
296     **/
297     _update: function () {
298         var hash = Y.merge(this.toJSON());
299         LocalSync._idMap[this.get('id')] = hash;
300         
301         this._save();
302         return hash;
303     },
305     /**
306     Sync method correlating to the "delete" operation.  Deletes the data
307     from the in-memory object, and saves into localStorage if available.
308     
309     @method _destroy
310     @return {Object} The deleted object.
311     @protected
312     @since 3.13.0
313     **/
314     _destroy: function () {
315         delete LocalSync._idMap[this.get('id')];
316         this._save();
317         return this.toJSON();
318     },
319     
320     /**
321     Saves the current in-memory store into a localStorage key/value pair
322     if localStorage is available; otherwise, does nothing.
323     
324     @method _save
325     @protected
326     @since 3.13.0
327     **/
328     _save: function () {
329         if (LocalSync._hasLocalStorage) {
330             this.storage && this.storage.setItem(
331                 this.root,
332                 Y.JSON.stringify(LocalSync._data[this.root])
333             );
334         }
335     }
338 // -- Namespace ---------------------------------------------------------------
340 Y.namespace('ModelSync').Local = LocalSync;
343 }, '3.13.0', {"requires": ["model", "json-stringify"]});