Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
YUI.add('model-sync-local', function (Y, NAME) {
2
 
3
/*
4
An extension which provides a sync implementation through locally stored
5
key value pairs, either through the HTML localStorage API or falling back
6
onto an in-memory cache, that can be mixed into a Model or ModelList subclass.
7
 
8
@module app
9
@submodule model-sync-local
10
@since 3.13.0
11
**/
12
 
13
/**
14
An extension which provides a sync implementation through locally stored
15
key value pairs, either through the HTML localStorage API or falling back
16
onto an in-memory cache, that can be mixed into a Model or ModelList subclass.
17
 
18
A group of Models/ModelLists is serialized in localStorage by either its
19
class name, or a specified 'root' that is provided.
20
 
21
    var User = Y.Base.create('user', Y.Model, [Y.ModelSync.Local], {
22
        root: 'user'
23
    });
24
 
25
    var Users = Y.Base.create('users', Y.ModelList, [Y.ModelSync.Local], {
26
        model: User,
27
    });
28
 
29
@class ModelSync.Local
30
@extensionfor Model
31
@extensionfor ModelList
32
@since 3.13.0
33
**/
34
function LocalSync() {}
35
 
36
/**
37
Properties that shouldn't be turned into ad-hoc attributes when passed to a
38
Model or ModelList constructor.
39
 
40
@property _NON_ATTRS_CFG
41
@type Array
42
@default ['root']
43
@static
44
@protected
45
@since 3.13.0
46
**/
47
LocalSync._NON_ATTRS_CFG = ['root'];
48
 
49
/**
50
Feature testing for `localStorage` availability.
51
Will return falsey for browsers with `localStorage`, but that don't
52
actually work, such as iOS Safari in private browsing mode.
53
 
54
@property _hasLocalStorage
55
@type Boolean
56
@private
57
**/
58
LocalSync._hasLocalStorage = (function () {
59
    var LS   = Y.config.win.localStorage,
60
        test = Y.guid();
61
 
62
    try {
63
        LS.setItem(test, test);
64
        LS.removeItem(test);
65
        return true;
66
    } catch (e) {
67
        return false;
68
    }
69
})(),
70
 
71
/**
72
Object of key/value pairs to fall back on when localStorage is not available.
73
 
74
@property _data
75
@type Object
76
@private
77
**/
78
 
79
LocalSync._data = LocalSync._data || {};
80
 
81
/**
82
Cache to quickly access a specific object with a given ID.
83
 
84
@property _store
85
@type Array
86
@private
87
**/
88
 
89
LocalSync._store = LocalSync._store || {};
90
 
91
LocalSync.prototype = {
92
 
93
    // -- Public Methods -------------------------------------------------------
94
 
95
    /**
96
    Root used as the key inside of localStorage and/or the in-memory store.
97
 
98
    @property root
99
    @type String
100
    @default ""
101
    @since 3.13.0
102
    **/
103
    root: '',
104
 
105
    /**
106
    Shortcut for access to localStorage.
107
 
108
    @property storage
109
    @type Storage
110
    @default null
111
    @since 3.13.0
112
    **/
113
    storage: null,
114
 
115
    // -- Lifecycle Methods -----------------------------------------------------
116
    initializer: function (config) {
117
        var store, data;
118
 
119
        config || (config = {});
120
 
121
        if ('root' in config) {
122
            this.root = config.root || '';
123
        }
124
 
125
        // This is checking to see if the sync layer is being applied to
126
        // a ModelList, and if so, is looking for a `root` property on its
127
        // Model's prototype instead.
128
        if (!this.root && this.model && this.model.prototype.root) {
129
            this.root = this.model.prototype.root;
130
        }
131
 
132
        if (LocalSync._hasLocalStorage) {
133
            this.storage = Y.config.win.localStorage;
134
            store = this.storage.getItem(this.root);
135
        } else {
136
        }
137
 
138
        // Pull in existing data from localStorage, if possible.
139
        // Otherwise, see if there's existing data on the local cache.
140
        if (store) {
141
            LocalSync._store[this.root] = store.split('|') || [];
142
 
143
            Y.Array.each(LocalSync._store[this.root], function (id) {
144
                LocalSync._data[id] = Y.JSON.parse(this.storage.getItem(id));
145
            }, this);
146
        } else {
147
            LocalSync._store[this.root] || (LocalSync._store[this.root] = []);
148
        }
149
    },
150
 
151
    // -- Public Methods -----------------------------------------------------------
152
 
153
    /**
154
    Creates a synchronization layer with the localStorage API, if available.
155
    Otherwise, falls back to a in-memory data store.
156
 
157
    This method is called internally by load(), save(), and destroy().
158
 
159
    @method sync
160
    @param {String} action Sync action to perform. May be one of the following:
161
 
162
      * **create**: Store a newly-created model for the first time.
163
      * **read**  : Load an existing model.
164
      * **update**: Update an existing model.
165
      * **delete**: Delete an existing model.
166
 
167
    @param {Object} [options] Sync options
168
    @param {Function} [callback] Called when the sync operation finishes.
169
      @param {Error|null} callback.err If an error occurred, this parameter will
170
        contain the error. If the sync operation succeeded, _err_ will be
171
        falsey.
172
      @param {Any} [callback.response] The response from our sync. This value will
173
        be passed to the parse() method, which is expected to parse it and
174
        return an attribute hash.
175
    **/
176
    sync: function (action, options, callback) {
177
        options || (options = {});
178
        var response, errorInfo;
179
 
180
        try {
181
            switch (action) {
182
                case 'read':
183
                    if (this._isYUIModelList) {
184
                        response = this._index(options);
185
                    } else {
186
                        response = this._show(options);
187
                    }
188
                    break;
189
                case 'create':
190
                    response = this._create(options);
191
                    break;
192
                case 'update':
193
                    response = this._update(options);
194
                    break;
195
                case 'delete':
196
                    response = this._destroy(options);
197
                    break;
198
            }
199
        } catch (error) {
200
            errorInfo = error.message;
201
        }
202
 
203
        if (response) {
204
            callback(null, response);
205
        } else if (errorInfo) {
206
            callback(errorInfo);
207
        } else {
208
            callback("Data not found in LocalStorage");
209
        }
210
    },
211
 
212
    /**
213
    Generate a random GUID for our Models. This can be overriden if you have
214
    another method of generating different IDs.
215
 
216
    @method generateID
217
    @protected
218
    @param {String} pre Optional GUID prefix
219
    **/
220
    generateID: function (pre) {
221
        return Y.guid(pre + '_');
222
    },
223
 
224
    // -- Protected Methods ----------------------------------------------------
225
 
226
    /**
227
    Sync method correlating to the "read" operation, for a Model List
228
 
229
    @method _index
230
    @return {Object[]} Array of objects found for that root key
231
    @protected
232
    @since 3.13.0
233
    **/
234
    _index: function () {
235
        var store = LocalSync._store[this.root],
236
            data  = Y.Array.map(store, function (id) {
237
                return LocalSync._data[id];
238
            });
239
 
240
        return data;
241
    },
242
 
243
    /**
244
    Sync method correlating to the "read" operation, for a Model
245
 
246
    @method _show
247
    @return {Object} Object found for that root key and model ID
248
    @protected
249
    @since 3.13.0
250
    **/
251
    _show: function () {
252
        return LocalSync._data[this.get('id')] || null;
253
    },
254
 
255
    /**
256
    Sync method correlating to the "create" operation
257
 
258
    @method _show
259
    @return {Object} The new object created.
260
    @protected
261
    @since 3.13.0
262
    **/
263
    _create: function () {
264
        var hash  = this.toJSON();
265
 
266
        hash.id = this.generateID(this.root);
267
 
268
        LocalSync._data[hash.id] = hash;
269
        if (this.storage) {
270
            this.storage.setItem(hash.id, Y.JSON.stringify(hash));
271
        }
272
 
273
        LocalSync._store[this.root].push(hash.id);
274
 
275
        this._save();
276
        return hash;
277
    },
278
 
279
    /**
280
    Sync method correlating to the "update" operation
281
 
282
    @method _update
283
    @return {Object} The updated object.
284
    @protected
285
    @since 3.13.0
286
    **/
287
    _update: function () {
288
        var hash = this.toJSON(),
289
            id = this.get('id');
290
 
291
        LocalSync._data[id] = hash;
292
 
293
        if (this.storage) {
294
            this.storage.setItem(id, hash);
295
        }
296
 
297
        if (Y.Array.indexOf(LocalSync._store[this.root], id) === -1) {
298
            LocalSync._store[this.root].push(id);
299
        }
300
 
301
        this._save();
302
 
303
        return hash;
304
    },
305
 
306
    /**
307
    Sync method correlating to the "delete" operation.  Deletes the data
308
    from the in-memory object, and saves into localStorage if available.
309
 
310
    @method _destroy
311
    @protected
312
    @since 3.13.0
313
    **/
314
    _destroy: function () {
315
        var id = this.get('id'),
316
            storage = this.storage;
317
 
318
        if (!LocalSync._data[id]) {
319
            return;
320
        }
321
 
322
        delete LocalSync._data[id];
323
 
324
        if (storage) {
325
            storage.removeItem(id);
326
        }
327
 
328
        LocalSync._store[this.root] = Y.Array.filter(LocalSync._store[this.root], function (item) {
329
            return item.id != id;
330
        });
331
 
332
        this._save();
333
        return this.toJSON();
334
    },
335
 
336
    /**
337
    Saves the current in-memory store into a localStorage key/value pair
338
    if localStorage is available; otherwise, does nothing.
339
 
340
    @method _save
341
    @protected
342
    @since 3.13.0
343
    **/
344
    _save: function () {
345
        if (LocalSync._hasLocalStorage && this.storage) {
346
            this.storage.setItem(
347
                this.root,
348
                LocalSync._store[this.root].join('|')
349
            );
350
        }
351
    }
352
};
353
 
354
// -- Namespace ---------------------------------------------------------------
355
 
356
Y.namespace('ModelSync').Local = LocalSync;
357
 
358
 
359
}, '3.18.1', {"requires": ["model", "json-stringify"]});