# Yahoo! UI Library

### Storage 2.9.0

Yahoo! UI Library > Storage > Storage.js (source view)
Search:
Filters Show Private Show Protected Show Deprecated

    /**
     * The Storage module manages client-side data storage.
     * @module Storage
     */

    (function() {

    	// internal shorthand
    var Y = YAHOO,
    	Util = Y.util,
    	Lang = Y.lang,
    	_logOverwriteError,
        Storage,

    	RX_TYPE = /^type=(\w+)/i,
    	RX_VALUE = /&value=(.*)/i;

    if (! Util.Storage) {
    	_logOverwriteError = function(fxName) {
    		Y.log('Exception in YAHOO.util.Storage.?? - must be extended by a storage engine'.replace('??', fxName).replace('??', this.getName ? this.getName() : 'Unknown'), 'error');
    	};

    	/**
    	 * The Storage class is an HTML 5 storage API clone, used to wrap individual storage implementations with a common API.
    	 * @class Storage
    	 * @namespace YAHOO.util
    	 * @constructor
    	 * @param sLocation {String} Required. The storage location.
    	 * @parm sName {String} Required. The engine name.
    	 * @param oConf {Object} Required. A configuration object.
    	 */
    	Storage = function(sLocation, sName, oConf) {
    		var that = this;
    		Y.env._id_counter += 1;

    		// protected variables
    		that._cfg = Lang.isObject(oConf) ? oConf : {};
    		that._location = sLocation;
    		that._name = sName;
    		that.isReady = false;

    		// public variables
    		that.createEvent(Storage.CE_READY, {scope: that, fireOnce: true});
    		that.createEvent(Storage.CE_CHANGE, {scope: that});

    		that.subscribe(Storage.CE_READY, function() {
    			that.isReady = true;
    		});
    	};

        Storage.CE_READY = 'YUIStorageReady';
        Storage.CE_CHANGE = 'YUIStorageChange';

    	Storage.prototype = {

    		/**
    		 * The event name for when the storage item is ready.
    		 * @property CE_READY
    		 * @type {String}
    		 * @public
    		 */
    		CE_READY: Storage.CE_READY,

    		/**
    		 * The event name for when the storage item has changed.
    		 * @property CE_CHANGE
    		 * @type {String}
    		 * @public
    		 */
    		CE_CHANGE: Storage.CE_CHANGE,

    		/**
    		 * The configuration of the engine.
    		 * @property _cfg
    		 * @type {Object}
    		 * @protected
    		 */
    		_cfg: '',

    		/**
    		 * The name of this engine.
    		 * @property _name
    		 * @type {String}
    		 * @protected
    		 */
    		_name: '',

    		/**
    		 * The location for this instance.
    		 * @property _location
    		 * @type {String}
    		 * @protected
    		 */
    		_location: '',

    		/**
    		 * The current length of the keys.
    		 * @property length
    		 * @type {Number}
    		 * @public
    		 */
    		length: 0,

    		/**
    		 * This engine singleton has been initialized already.
    		 * @property isReady
    		 * @type {String}
    		 * @protected
    		 */
    		isReady: false,

    		/**
    		 * Clears any existing key/value pairs.
    		 * @method clear
    		 * @public
    		 */
    		clear: function() {
    			this._clear();
    			this.length = 0;
    		},

    		/**
    		 * Fetches the data stored and the provided key.
    		 * @method getItem
    		 * @param sKey {String} Required. The key used to reference this value (DOMString in HTML 5 spec).
    		 * @return {String|NULL} The value stored at the provided key (DOMString in HTML 5 spec).
    		 * @public
    		 */
    		getItem: function(sKey) {
    			Y.log("Fetching item at  " + sKey);
    			var oItem = this._getItem(sKey);
    			return Lang.isValue(oItem) ? this._getValue(oItem) : null; // required by HTML 5 spec
    		},

    		/**
    		 * Fetches the storage object's name; should be overwritten by storage engine.
    		 * @method getName
    		 * @return {String} The name of the data storage object.
    		 * @public
    		 */
    		getName: function() {return this._name;},

    		/**
    		 * Tests if the key has been set (not in HTML 5 spec); should be overwritten by storage engine.
    		 * @method hasKey
    		 * @param sKey {String} Required. The key to search for.
    		 * @return {Boolean} True when key has been set.
    		 * @public
    		 */
    		hasKey: function(sKey) {
    			return Lang.isString(sKey) && this._hasKey(sKey);
    		},

    		/**
    		 * Retrieve the key stored at the provided index; should be overwritten by storage engine.
    		 * @method key
    		 * @param nIndex {Number} Required. The index to retrieve (unsigned long in HTML 5 spec).
    		 * @return {String} Required. The key at the provided index (DOMString in HTML 5 spec).
    		 * @public
    		 */
    		key: function(nIndex) {
    			Y.log("Fetching key at " + nIndex);

    			if (Lang.isNumber(nIndex) && -1 < nIndex && this.length > nIndex) {
    				var value = this._key(nIndex);
    				if (value) {return value;}
    			}

    			// this is thrown according to the HTML5 spec
    			throw('INDEX_SIZE_ERR - Storage.setItem - The provided index (' + nIndex + ') is not available');
    		},

    		/**
    		 * Remove an item from the data storage.
    		 * @method removeItem
    		 * @param sKey {String} Required. The key to remove (DOMString in HTML 5 spec).
    		 * @public
    		 */
    		removeItem: function(sKey) {
    			Y.log("removing " + sKey);
                var that = this,
                    oOldValue;

    			if (that.hasKey(sKey)) {
                    oOldValue = that._getItem(sKey);
                    if (! oOldValue) {oOldValue = null;}
                    that._removeItem(sKey);
    				that.fireEvent(Storage.CE_CHANGE, new Util.StorageEvent(that, sKey, oOldValue, null, Util.StorageEvent.TYPE_REMOVE_ITEM));
    			}
    			else {
    				// HTML 5 spec says to do nothing
    			}
    		},

    		/**
    		 * Adds an item to the data storage.
    		 * @method setItem
    		 * @param sKey {String} Required. The key used to reference this value (DOMString in HTML 5 spec).
    		 * @param oData {Object} Required. The data to store at key (DOMString in HTML 5 spec).
    		 * @public
    		 * @throws QUOTA_EXCEEDED_ERROR
    		 */
    		setItem: function(sKey, oData) {
    			Y.log("SETTING " + oData + " to " + sKey);

    			if (Lang.isString(sKey)) {
    				var that = this,
                        oOldValue = that._getItem(sKey);

    				if (! oOldValue) {oOldValue = null;}

    				if (that._setItem(sKey, that._createValue(oData))) {
    					that.fireEvent(Storage.CE_CHANGE, new Util.StorageEvent(that, sKey, oOldValue, oData,
                                that.hasKey(sKey) ? Util.StorageEvent.TYPE_UPDATE_ITEM : Util.StorageEvent.TYPE_ADD_ITEM));
    				}
    				else {
    					// that is thrown according to the HTML5 spec
    					throw('QUOTA_EXCEEDED_ERROR - Storage.setItem - The choosen storage method (' +
    						  that.getName() + ') has exceeded capacity');
    				}
    			}
    			else {
    				// HTML 5 spec says to do nothing
    			}
    		},

    		/**
    		 * Implementation of the clear login; should be overwritten by storage engine.
    		 * @method _clear
    		 * @protected
    		 */
    		_clear: function() {
    			_logOverwriteError('_clear');
    			return '';
    		},

    		/**
    		 * Converts the object into a string, with meta data (type), so it can be restored later.
    		 * @method _createValue
    		 * @param o {Object} Required. An object to store.
    		 * @protected
    		 */
    		_createValue: function(o) {
    			var sType = (Lang.isNull(o) || Lang.isUndefined(o)) ? ('' + o) : typeof o;
    			return 'type=' + sType + '&value=' + encodeURIComponent('' + o);
    		},

    		/**
    		 * Implementation of the getItem login; should be overwritten by storage engine.
    		 * @method _getItem
    		 * @param sKey {String} Required. The key used to reference this value.
    		 * @return {String|NULL} The value stored at the provided key.
    		 * @protected
    		 */
    		_getItem: function(sKey) {
    			_logOverwriteError('_getItem');
    			return '';
    		},

    		/**
    		 * Converts the stored value into its appropriate type.
    		 * @method _getValue
    		 * @param s {String} Required. The stored value.
    		 * @protected
    		 */
    		_getValue: function(s) {
    			var sType = s.match(RX_TYPE)[1],
    				sValue = s.match(RX_VALUE)[1];

    			switch (sType) {
    				case 'boolean': return 'true' == sValue;
    				case 'number': return parseFloat(sValue);
    				case 'null': return null;
    				default: return decodeURIComponent(sValue);
    			}
    		},

    		/**
    		 * Implementation of the key logic; should be overwritten by storage engine.
    		 * @method _key
    		 * @param nIndex {Number} Required. The index to retrieve (unsigned long in HTML 5 spec).
    		 * @return {String|NULL} Required. The key at the provided index (DOMString in HTML 5 spec).
    		 * @protected
    		 */
    		_key: function(nIndex) {
    			_logOverwriteError('_key');
    			return '';
    		},

    		/*
    		 * Implementation to fetch evaluate the existence of a key.
    		 */
    		_hasKey: function(sKey) {
    			return null !== this._getItem(sKey);
    		},

    		/**
    		 * Implementation of the removeItem login; should be overwritten by storage engine.
    		 * @method _removeItem
    		 * @param sKey {String} Required. The key to remove.
    		 * @protected
    		 */
    		_removeItem: function(sKey) {
    			_logOverwriteError('_removeItem');
    			return '';
    		},

    		/**
    		 * Implementation of the setItem login; should be overwritten by storage engine.
    		 * @method _setItem
    		 * @param sKey {String} Required. The key used to reference this value.
    		 * @param oData {Object} Required. The data to storage at key.
    		 * @return {Boolean} True when successful, false when size QUOTA exceeded.
    		 * @protected
    		 */
    		_setItem: function(sKey, oData) {
    			_logOverwriteError('_setItem');
    			return '';
    		}
    	};

    	Lang.augmentProto(Storage, Util.EventProvider);

        Util.Storage = Storage;
    }

    }());

Copyright © 2011 Yahoo! Inc. All rights reserved.