Version 3.18.1
Show:

File: cache/js/cache-offline.js

            /**
             * Provides a Cache subclass which uses HTML5 `localStorage` for persistence.
             *
             * @module cache
             * @submodule cache-offline
             */
            
            /**
             * Extends Cache utility with offline functionality.
             * @class CacheOffline
             * @extends Cache
             * @constructor
             */
            function CacheOffline() {
                CacheOffline.superclass.constructor.apply(this, arguments);
            }
            
            var localStorage = null,
                JSON = Y.JSON;
            
            // Bug 2529572
            try {
                localStorage = Y.config.win.localStorage;
            }
            catch(e) {
                Y.log("Could not access localStorage.", "warn", "cache");
            }
            
            /////////////////////////////////////////////////////////////////////////////
            //
            // CacheOffline events
            //
            /////////////////////////////////////////////////////////////////////////////
            
            /**
            * @event error
            * @description Fired when an entry could not be added, most likely due to
            * exceeded browser quota.
            * <dl>
            * <dt>error (Object)</dt> <dd>The error object.</dd>
            * </dl>
            */
            
            /////////////////////////////////////////////////////////////////////////////
            //
            // CacheOffline static
            //
            /////////////////////////////////////////////////////////////////////////////
            Y.mix(CacheOffline, {
                /**
                 * Class name.
                 *
                 * @property NAME
                 * @type String
                 * @static
                 * @final
                 * @value "cacheOffline"
                 */
                NAME: "cacheOffline",
            
                ATTRS: {
                    /////////////////////////////////////////////////////////////////////////////
                    //
                    // CacheOffline Attributes
                    //
                    /////////////////////////////////////////////////////////////////////////////
            
                    /**
                    * @attribute sandbox
                    * @description A string that must be passed in via the constructor.
                    * This identifier is used to sandbox one cache instance's entries
                    * from another. Calling the cache instance's flush and length methods
                    * or get("entries") will apply to only these sandboxed entries.
                    * @type String
                    * @default "default"
                    * @initOnly
                    */
                    sandbox: {
                        value: "default",
                        writeOnce: "initOnly"
                    },
            
                    /**
                    * @attribute expires
                    * @description Absolute Date when data expires or
                    * relative number of milliseconds. Zero disables expiration.
                    * @type Date | Number
                    * @default 86400000 (one day)
                    */
                    expires: {
                        value: 86400000
                    },
            
                    /**
                    * @attribute max
                    * @description Disabled.
                    * @readOnly
                    * @default null
                    */
                    max: {
                        value: null,
                        readOnly: true
                    },
            
                    /**
                    * @attribute uniqueKeys
                    * @description Always true for CacheOffline.
                    * @readOnly
                    * @default true
                    */
                    uniqueKeys: {
                        value: true,
                        readOnly: true,
                        setter: function() {
                            return true;
                        }
                    }
                },
            
                /**
                 * Removes all items from all sandboxes. Useful if localStorage has
                 * exceeded quota. Only supported on browsers that implement HTML 5
                 * localStorage.
                 *
                 * @method flushAll
                 * @static
                 */
                flushAll: function() {
                    var store = localStorage, key;
                    if(store) {
                        if(store.clear) {
                            store.clear();
                        }
                        // FF2.x and FF3.0.x
                        else {
                            for (key in store) {
                                if (store.hasOwnProperty(key)) {
                                    store.removeItem(key);
                                    delete store[key];
                                }
                            }
                        }
                        Y.log("All sandboxes of OfflineCache flushed", "info", "cache");
                    }
                    else {
                        Y.log("Could not flush all OfflineCache sandboxes.", "warn", "cache");
                    }
                }
            });
            
            Y.extend(CacheOffline, Y.Cache, localStorage ? {
            /////////////////////////////////////////////////////////////////////////////
            //
            // Offline is supported
            //
            /////////////////////////////////////////////////////////////////////////////
            
                /////////////////////////////////////////////////////////////////////////////
                //
                // CacheOffline protected methods
                //
                /////////////////////////////////////////////////////////////////////////////
                /**
                 * Always return null.
                 *
                 * @method _setMax
                 * @protected
                 */
                _setMax: function(value) {
                    return null;
                },
            
                /**
                 * Gets size.
                 *
                 * @method _getSize
                 * @protected
                 */
                _getSize: function() {
                    var count = 0,
                        i=0,
                        l=localStorage.length;
                    for(; i<l; ++i) {
                        // Match sandbox id
                        if(localStorage.key(i).indexOf(this.get("sandbox")) === 0) {
                            count++;
                        }
                    }
                    return count;
                },
            
                /**
                 * Gets all entries.
                 *
                 * @method _getEntries
                 * @protected
                 */
                _getEntries: function() {
                    var entries = [],
                        i=0,
                        l=localStorage.length,
                        sandbox = this.get("sandbox");
                    for(; i<l; ++i) {
                        // Match sandbox id
                        if(localStorage.key(i).indexOf(sandbox) === 0) {
                            entries[i] = JSON.parse(localStorage.key(i).substring(sandbox.length));
                        }
                    }
                    return entries;
                },
            
                /**
                 * Adds entry to cache.
                 *
                 * @method _defAddFn
                 * @param e {EventFacade} Event Facade with the following properties:
                 * <dl>
                 * <dt>entry (Object)</dt> <dd>The cached entry.</dd>
                 * </dl>
                 * @protected
                 */
                _defAddFn: function(e) {
                    var entry = e.entry,
                        request = entry.request,
                        cached = entry.cached,
                        expires = entry.expires;
            
                    // Convert Dates to msecs on the way into localStorage
                    entry.cached = cached.getTime();
                    entry.expires = expires ? expires.getTime() : expires;
            
                    try {
                        localStorage.setItem(this.get("sandbox")+JSON.stringify({"request":request}), JSON.stringify(entry));
                        Y.log("Cached offline entry: " + Y.dump(entry), "info", "cache");
                    }
                    catch(error) {
                        this.fire("error", {error:error});
                        Y.log("Could not cache offline entry: " + Y.dump(entry) +
                        " due to error: " + Y.dump(error), "warn", "cache");
                    }
                },
            
                /**
                 * Flushes cache.
                 *
                 * @method _defFlushFn
                 * @param e {EventFacade} Event Facade object.
                 * @protected
                 */
                _defFlushFn: function(e) {
                    var key,
                        i=localStorage.length-1;
                    for(; i>-1; --i) {
                        // Match sandbox id
                        key = localStorage.key(i);
                        if(key.indexOf(this.get("sandbox")) === 0) {
                            localStorage.removeItem(key);
                        }
                    }
                },
            
                /////////////////////////////////////////////////////////////////////////////
                //
                // CacheOffline public methods
                //
                /////////////////////////////////////////////////////////////////////////////
                /**
                 * Adds a new entry to the cache of the format
                 * {request:request, response:response, cached:cached, expires: expires}.
                 *
                 * @method add
                 * @param request {Object} Request value must be a String or JSON.
                 * @param response {Object} Response value must be a String or JSON.
                 */
            
                /**
                 * Retrieves cached object for given request, if available.
                 * Returns null if there is no cache match.
                 *
                 * @method retrieve
                 * @param request {Object} Request object.
                 * @return {Object} Cached object with the properties request, response,
                 * and expires, or null.
                 */
                retrieve: function(request) {
                    this.fire("request", {request: request});
            
                    var entry, expires, sandboxedrequest;
            
                    try {
                        sandboxedrequest = this.get("sandbox")+JSON.stringify({"request":request});
                        try {
                            entry = JSON.parse(localStorage.getItem(sandboxedrequest));
                        }
                        catch(e) {
                        }
                    }
                    catch(e2) {
                    }
            
                    if(entry) {
                        // Convert msecs to Dates on the way out of localStorage
                        entry.cached = new Date(entry.cached);
                        expires = entry.expires;
                        expires = !expires ? null : new Date(expires);
                        entry.expires = expires;
            
                        if(this._isMatch(request, entry)) {
                            this.fire("retrieve", {entry: entry});
                            Y.log("Retrieved offlinecached response: " + Y.dump(entry) +
                                    " for request: " + Y.dump(request), "info", "cache");
                            return entry;
                        }
                    }
                    return null;
                }
            } :
            /////////////////////////////////////////////////////////////////////////////
            //
            // Offline is not supported
            //
            /////////////////////////////////////////////////////////////////////////////
            {
                /**
                 * Always return null.
                 *
                 * @method _setMax
                 * @protected
                 */
                _setMax: function(value) {
                    return null;
                }
            });
            
            
            Y.CacheOffline = CacheOffline;