/* Copyright (c) 2009, Yahoo! Inc. All rights reserved. Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt version: 2.8.0r4 */ /** * The Storage module manages client-side data storage. * @module Storage */ (function() { // internal shorthand var Y = YAHOO, YU = Y.util, YL = Y.lang, _logOverwriteError; if (! YU.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 location {String} Required. The storage location. * @parm name {String} Required. The engine name. * @param conf {Object} Required. A configuration object. */ YU.Storage = function(location, name, conf) { var that = this; Y.env._id_counter += 1; // protected variables that._cfg = YL.isObject(conf) ? conf : {}; that._location = location; that._name = name; that.isReady = false; // public variables that.createEvent(that.CE_READY, {scope: that}); that.createEvent(that.CE_CHANGE, {scope: that}); that.subscribe(that.CE_READY, function() { that.isReady = true; }); }; YU.Storage.prototype = { /** * The event name for when the storage item is ready. * @property CE_READY * @type {String} * @public */ CE_READY: 'YUIStorageReady', /** * The event name for when the storage item has changed. * @property CE_CHANGE * @type {String} * @public */ CE_CHANGE: 'YUIStorageChange', /** * The delimiter uesed between the data type and the data. * @property DELIMITER * @type {String} * @public */ DELIMITER: '__', /** * 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 key {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(key) { Y.log("Fetching item at " + key); var item = this._getItem(key); return YL.isValue(item) ? this._getValue(item) : 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 key {String} Required. The key to search for. * @return {Boolean} True when key has been set. * @public */ hasKey: function(key) { return YL.isString(key) && this._hasKey(key); }, /** * Retrieve the key stored at the provided index; should be overwritten by storage engine. * @method key * @param index {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(index) { Y.log("Fetching key at " + index); if (YL.isNumber(index) && -1 < index && this.length > index) { var value = this._key(index); if (value) {return value;} } // this is thrown according to the HTML5 spec throw('INDEX_SIZE_ERR - Storage.setItem - The provided index (' + index + ') is not available'); }, /** * Remove an item from the data storage. * @method setItem * @param key {String} Required. The key to remove (DOMString in HTML 5 spec). * @public */ removeItem: function(key) { Y.log("removing " + key); if (this.hasKey(key)) { var oldValue = this._getItem(key); if (! oldValue) {oldValue = null;} this._removeItem(key); this.fireEvent(this.CE_CHANGE, new YU.StorageEvent(this, key, oldValue, null, YU.StorageEvent.TYPE_REMOVE_ITEM)); } else { // HTML 5 spec says to do nothing } }, /** * Adds an item to the data storage. * @method setItem * @param key {String} Required. The key used to reference this value (DOMString in HTML 5 spec). * @param data {Object} Required. The data to store at key (DOMString in HTML 5 spec). * @public * @throws QUOTA_EXCEEDED_ERROR */ setItem: function(key, data) { Y.log("SETTING " + data + " to " + key); if (YL.isString(key)) { var eventType = this.hasKey(key) ? YU.StorageEvent.TYPE_UPDATE_ITEM : YU.StorageEvent.TYPE_ADD_ITEM, oldValue = this._getItem(key); if (! oldValue) {oldValue = null;} if (this._setItem(key, this._createValue(data))) { this.fireEvent(this.CE_CHANGE, new YU.StorageEvent(this, key, oldValue, data, eventType)); } else { // this is thrown according to the HTML5 spec throw('QUOTA_EXCEEDED_ERROR - Storage.setItem - The choosen storage method (' + this.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 s {Object} Required. An object to store. * @protected */ _createValue: function(s) { var type = (YL.isNull(s) || YL.isUndefined(s)) ? ('' + s) : typeof s; return 'string' === type ? s : type + this.DELIMITER + s; }, /** * Implementation of the getItem login; should be overwritten by storage engine. * @method _getItem * @param key {String} Required. The key used to reference this value. * @return {String|NULL} The value stored at the provided key. * @protected */ _getItem: function(key) { _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 a = s ? s.split(this.DELIMITER) : []; if (1 == a.length) {return s;} switch (a[0]) { case 'boolean': return 'true' === a[1]; case 'number': return parseFloat(a[1]); case 'null': return null; default: return a[1]; } }, /** * Implementation of the key logic; should be overwritten by storage engine. * @method _key * @param index {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(index) { _logOverwriteError('_key'); return ''; }, /* * Implementation to fetch evaluate the existence of a key. * @see YAHOO.util.Storage._hasKey */ _hasKey: function(key) { return null !== this._getItem(key); }, /** * Implementation of the removeItem login; should be overwritten by storage engine. * @method _removeItem * @param key {String} Required. The key to remove. * @protected */ _removeItem: function(key) { _logOverwriteError('_removeItem'); return ''; }, /** * Implementation of the setItem login; should be overwritten by storage engine. * @method _setItem * @param key {String} Required. The key used to reference this value. * @param data {Object} Required. The data to storage at key. * @return {Boolean} True when successful, false when size QUOTA exceeded. * @protected */ _setItem: function(key, data) { _logOverwriteError('_setItem'); return ''; } }; YL.augmentProto(YU.Storage, YU.EventProvider); } }()); /** * The StorageManager class is a singleton that registers DataStorage objects and returns instances of those objects. * @class StorageManager * @namespace YAHOO.util * @static */ (function() { // internal shorthand var Y = YAHOO.util, YL = YAHOO.lang, // private variables _locationEngineMap = {}, // cached engines _registeredEngineSet = [], // set of available engines _registeredEngineMap = {}, // map of available engines /** * Fetches a storage constructor if it is available, otherwise returns NULL. * @method _getClass * @param klass {Function} Required. The storage constructor to test. * @return {Function} An available storage constructor or NULL. * @private */ _getClass = function(klass) { return (klass && klass.isAvailable()) ? klass : null; }, /** * Fetches the storage engine from the cache, or creates and caches it. * @method _getStorageEngine * @param location {String} Required. The location to store. * @param klass {Function} Required. A pointer to the engineType Class. * @param conf {Object} Optional. Additional configuration for the data source engine. * @private */ _getStorageEngine = function(location, klass, conf) { var engine = _locationEngineMap[location + klass.ENGINE_NAME]; if (! engine) { engine = new klass(location, conf); _locationEngineMap[location + klass.ENGINE_NAME] = engine; } return engine; }, /** * Ensures that the location is valid before returning it or a default value. * @method _getValidLocation * @param location {String} Required. The location to evaluate. * @private */ _getValidLocation = function(location) { switch (location) { case Y.StorageManager.LOCATION_LOCAL: case Y.StorageManager.LOCATION_SESSION: return location; default: return Y.StorageManager.LOCATION_SESSION; } }; // public namespace Y.StorageManager = { /** * The storage location - session; data cleared at the end of a user's session. * @property LOCATION_SESSION * @type {String} * @static */ LOCATION_SESSION: 'sessionStorage', /** * The storage location - local; data cleared on demand. * @property LOCATION_LOCAL * @type {String} * @static */ LOCATION_LOCAL: 'localStorage', /** * Fetches the desired engine type or first available engine type. * @method get * @param engineType {String} Optional. The engine type, see engines. * @param location {String} Optional. The storage location - LOCATION_SESSION & LOCATION_LOCAL; default is LOCAL. * @param conf {Object} Optional. Additional configuration for the getting the storage engine. * { * engine: {Object} configuration parameters for the desired engine * order: {Array} an array of storage engine names; the desired order to try engines} * } * @static */ get: function(engineType, location, conf) { var _cfg = YL.isObject(conf) ? conf : {}, klass = _getClass(_registeredEngineMap[engineType]); if (! klass && ! _cfg.force) { var i, j; if (_cfg.order) { j = _cfg.order.length; for (i = 0; i < j && ! klass; i += 1) { klass = _getClass(_cfg.order[i]); } } if (! klass) { j = _registeredEngineSet.length; for (i = 0; i < j && ! klass; i += 1) { klass = _getClass(_registeredEngineSet[i]); } } } if (klass) { return _getStorageEngine(_getValidLocation(location), klass, _cfg.engine); } throw('YAHOO.util.StorageManager.get - No engine available, please include an engine before calling this function.'); }, /* * Estimates the size of the string using 1 byte for each alpha-numeric character and 3 for each non-alpha-numeric character. * @method getByteSize * @param s {String} Required. The string to evaulate. * @return {Number} The estimated string size. * @private */ getByteSize: function(s) { return encodeURIComponent('' + s).length; }, /** * Registers a engineType Class with the StorageManager singleton; first in is the first out. * @method register * @param engineConstructor {Function} Required. The engine constructor function, see engines. * @return {Boolean} When successfully registered. * @static */ register: function(engineConstructor) { if (YL.isFunction(engineConstructor) && YL.isFunction(engineConstructor.isAvailable) && YL.isString(engineConstructor.ENGINE_NAME)) { _registeredEngineMap[engineConstructor.ENGINE_NAME] = engineConstructor; _registeredEngineSet.push(engineConstructor); return true; } return false; } }; YAHOO.register("StorageManager", Y.SWFStore, {version: "2.8.0r4", build: "2449"}); }()); (function() { /** * The StorageEvent class manages the storage events by emulating the HTML 5 implementation. * @namespace YAHOO.util * @class StorageEvent * @constructor * @param storageArea {Object} Required. The Storage object that was affected. * @param key {String} Required. The key being changed; DOMString in HTML 5 spec. * @param oldValue {String} Required. The old value of the key being changed; DOMString in HTML 5 spec. * @param newValue {String} Required. The new value of the key being changed; DOMString in HTML 5 spec. * @param type {String} Required. The storage event type. */ YAHOO.util.StorageEvent = function(storageArea, key, oldValue, newValue, type) { this.key = key; this.oldValue = oldValue; this.newValue = newValue; this.url = window.location.href; this.window = window; // todo: think about the CAJA and innocent code this.storageArea = storageArea; this.type = type; }; YAHOO.lang.augmentObject(YAHOO.util.StorageEvent, { TYPE_ADD_ITEM: 'addItem', TYPE_REMOVE_ITEM: 'removeItem', TYPE_UPDATE_ITEM: 'updateItem' }); YAHOO.util.StorageEvent.prototype = { /** * The 'key' attribute represents the key being changed. * @property key * @type {String} * @static * @readonly */ key: null, /** * The 'newValue' attribute represents the new value of the key being changed. * @property newValue * @type {String} * @static * @readonly */ newValue: null, /** * The 'oldValue' attribute represents the old value of the key being changed. * @property oldValue * @type {String} * @static * @readonly */ oldValue: null, /** * The 'source' attribute represents the WindowProxy object of the browsing context of the document whose key changed. * @property source * @type {Object} * @static * @readonly */ source: null, /** * The 'storageArea' attribute represents the Storage object that was affected. * @property storageArea * @type {Object} * @static * @readonly */ storageArea: null, /** * The 'type' attribute represents the Storage event type. * @property type * @type {Object} * @static * @readonly */ type: null, /** * The 'url' attribute represents the address of the document whose key changed. * @property url * @type {String} * @static * @readonly */ url: null }; }()); (function() { var Y = YAHOO.util, YL = YAHOO.lang; /** * The StorageEngineKeyed class implements the interface necessary for managing keys. * @namespace YAHOO.util * @class StorageEngineKeyed * @constructor * @extend YAHOO.util.Storage */ Y.StorageEngineKeyed = function() { Y.StorageEngineKeyed.superclass.constructor.apply(this, arguments); this._keys = []; this._keyMap = {}; }; YL.extend(Y.StorageEngineKeyed, Y.Storage, { /** * A collection of keys applicable to the current location. This should never be edited by the developer. * @property _keys * @type {Array} * @protected */ _keys: null, /** * A map of keys to their applicable position in keys array. This should never be edited by the developer. * @property _keyMap * @type {Object} * @protected */ _keyMap: null, /** * Adds the key to the set. * @method _addKey * @param key {String} Required. The key to evaluate. * @protected */ _addKey: function(key) { this._keyMap[key] = this.length; this._keys.push(key); this.length = this._keys.length; }, /** * Evaluates if a key exists in the keys array; indexOf does not work in all flavors of IE. * @method _indexOfKey * @param key {String} Required. The key to evaluate. * @protected */ _indexOfKey: function(key) { var i = this._keyMap[key]; return undefined === i ? -1 : i; }, /** * Removes a key from the keys array. * @method _removeKey * @param key {String} Required. The key to remove. * @protected */ _removeKey: function(key) { var j = this._indexOfKey(key), rest = this._keys.slice(j + 1); delete this._keyMap[key]; for (var k in this._keyMap) { if (j < this._keyMap[k]) { this._keyMap[k] -= 1; } } this._keys.length = j; this._keys = this._keys.concat(rest); this.length = this._keys.length; } }); }()); /* * HTML limitations: * - 5MB in FF and Safari, 10MB in IE 8 * - only FF 3.5 recovers session storage after a browser crash * * Thoughts: * - how can we not use cookies to handle session */ (function() { // internal shorthand var Y = YAHOO.util, YL = YAHOO.lang, /* * Required for IE 8 to make synchronous. */ _beginTransaction = function(engine) { if (engine.begin) {engine.begin();} }, /* * Required for IE 8 to make synchronous. */ _commitTransaction = function(engine) { if (engine.commit) {engine.commit();} }; /** * The StorageEngineHTML5 class implements the HTML5 storage engine. * @namespace YAHOO.util * @class StorageEngineHTML5 * @constructor * @extend YAHOO.util.Storage * @param location {String} Required. The storage location. * @param conf {Object} Required. A configuration object. */ Y.StorageEngineHTML5 = function(location, conf) { var _this = this; Y.StorageEngineHTML5.superclass.constructor.call(_this, location, Y.StorageEngineHTML5.ENGINE_NAME, conf);// not set, are cookies available _this._engine = window[location]; _this.length = _this._engine.length; YL.later(250, _this, function() { // temporary solution so that CE_READY can be subscribed to after this object is created _this.fireEvent(_this.CE_READY); }); }; YAHOO.lang.extend(Y.StorageEngineHTML5, Y.Storage, { _engine: null, /* * Implementation to clear the values from the storage engine. * @see YAHOO.util.Storage._clear */ _clear: function() { var _this = this; if (_this._engine.clear) { _this._engine.clear(); } // for FF 3, fixed in FF 3.5 else { for (var i = _this.length, key; 0 <= i; i -= 1) { key = _this._key(i); _this._removeItem(key); } } }, /* * Implementation to fetch an item from the storage engine. * @see YAHOO.util.Storage._getItem */ _getItem: function(key) { var o = this._engine.getItem(key); return YL.isObject(o) ? o.value : o; // for FF 3, fixed in FF 3.5 }, /* * Implementation to fetch a key from the storage engine. * @see YAHOO.util.Storage._key */ _key: function(index) {return this._engine.key(index);}, /* * Implementation to remove an item from the storage engine. * @see YAHOO.util.Storage._removeItem */ _removeItem: function(key) { var _this = this; _beginTransaction(_this._engine); _this._engine.removeItem(key); _commitTransaction(_this._engine); _this.length = _this._engine.length; }, /* * Implementation to remove an item from the storage engine. * @see YAHOO.util.Storage._setItem */ _setItem: function(key, value) { var _this = this; try { _beginTransaction(_this._engine); _this._engine.setItem(key, value); _commitTransaction(_this._engine); _this.length = _this._engine.length; return true; } catch (e) { return false; } } }, true); Y.StorageEngineHTML5.ENGINE_NAME = 'html5'; Y.StorageEngineHTML5.isAvailable = function() { return window.localStorage; }; Y.StorageManager.register(Y.StorageEngineHTML5); }()); /* * Gears limitation: * - SQLite limitations - http://www.sqlite.org/limits.html * - DB Best Practices - http://code.google.com/apis/gears/gears_faq.html#bestPracticeDB * - the user must approve before gears can be used * - each SQL query has a limited number of characters (9948 bytes), data will need to be spread across rows * - no query should insert or update more than 9948 bytes of data in a single statement or GEARs will throw: * [Exception... "'Error: SQL statement is too long.' when calling method: [nsIDOMEventListener::handleEvent]" nsresult: "0x8057001c (NS_ERROR_XPC_JS_THREW_JS_OBJECT)" location: "" data: no] * * Thoughts: * - we may want to implement additional functions for the gears only implementation * - how can we not use cookies to handle session location */ (function() { // internal shorthand var Y = YAHOO.util, YL = YAHOO.lang, _SQL_STMT_LIMIT = 9948, _TABLE_NAME = 'YUIStorageEngine', // local variables _engine = null, eURI = encodeURIComponent, dURI = decodeURIComponent; /** * The StorageEngineGears class implements the Google Gears storage engine. * @namespace YAHOO.util * @class StorageEngineGears * @constructor * @extend YAHOO.util.Storage * @param location {String} Required. The storage location. * @param conf {Object} Required. A configuration object. */ Y.StorageEngineGears = function(location, conf) { var _this = this; Y.StorageEngineGears.superclass.constructor.call(_this, location, Y.StorageEngineGears.ENGINE_NAME, conf); if (! _engine) { // create the database _engine = google.gears.factory.create(Y.StorageEngineGears.GEARS); _engine.open(window.location.host + '-' + Y.StorageEngineGears.DATABASE); _engine.execute('CREATE TABLE IF NOT EXISTS ' + _TABLE_NAME + ' (key TEXT, location TEXT, value TEXT)'); } var isSessionStorage = Y.StorageManager.LOCATION_SESSION === _this._location, sessionKey = Y.Cookie.get('sessionKey' + Y.StorageEngineGears.ENGINE_NAME); if (! sessionKey) { _engine.execute('BEGIN'); _engine.execute('DELETE FROM ' + _TABLE_NAME + ' WHERE location="' + eURI(Y.StorageManager.LOCATION_SESSION) + '"'); _engine.execute('COMMIT'); } var rs = _engine.execute('SELECT key FROM ' + _TABLE_NAME + ' WHERE location="' + eURI(_this._location) + '"'), keyMap = {}; try { // iterate on the rows and map the keys while (rs.isValidRow()) { var fld = dURI(rs.field(0)); if (! keyMap[fld]) { keyMap[fld] = true; _this._addKey(fld); } rs.next(); } } finally { rs.close(); } // this is session storage, ensure that the session key is set if (isSessionStorage) { Y.Cookie.set('sessionKey' + Y.StorageEngineGears.ENGINE_NAME, true); } _this.length = _this._keys.length; YL.later(250, _this, function() { // temporary solution so that CE_READY can be subscribed to after this object is created _this.fireEvent(_this.CE_READY); }); }; YL.extend(Y.StorageEngineGears, Y.StorageEngineKeyed, { /* * Implementation to clear the values from the storage engine. * @see YAHOO.util.Storage._clear */ _clear: function() { _engine.execute('BEGIN'); _engine.execute('DELETE FROM ' + _TABLE_NAME + ' WHERE location="' + eURI(this._location) + '"'); _engine.execute('COMMIT'); this._keys = []; this.length = 0; }, /* * Implementation to fetch an item from the storage engine. * @see YAHOO.util.Storage._getItem */ _getItem: function(key) { var rs = _engine.execute('SELECT value FROM ' + _TABLE_NAME + ' WHERE key="' + eURI(key) + '" AND location="' + eURI(this._location) + '"'), value = ''; try { while (rs.isValidRow()) { var temp = rs.field(0); value += rs.field(0); rs.next(); } } finally { rs.close(); } return value ? dURI(value) : null; }, /* * Implementation to fetch a key from the storage engine. * @see YAHOO.util.Storage.key */ _key: function(index) {return this._keys[index];}, /* * Implementation to remove an item from the storage engine. * @see YAHOO.util.Storage._removeItem */ _removeItem: function(key) { _engine.execute('BEGIN'); _engine.execute('DELETE FROM ' + _TABLE_NAME + ' WHERE key="' + eURI(key) + '" AND location="' + eURI(this._location) + '"'); _engine.execute('COMMIT'); this._removeKey(key); }, /* * Implementation to remove an item from the storage engine. * @see YAHOO.util.Storage._setItem */ _setItem: function(key, data) { if (! this.hasKey(key)) { this._addKey(key); } var _key = eURI(key), _location = eURI(this._location), _value = eURI(data), _values = [], _len = _SQL_STMT_LIMIT - (_key + _location).length; // the length of the value exceeds the available space if (_len < _value.length) { for (var i = 0, j = _value.length; i < j; i += _len) { _values.push(_value.substr(i, _len)); } } else { _values.push(_value); } // Google recommends using INSERT instead of update, because it is faster _engine.execute('BEGIN'); _engine.execute('DELETE FROM ' + _TABLE_NAME + ' WHERE key="' + eURI(key) + '" AND location="' + eURI(this._location) + '"'); for (var m = 0, n = _values.length; m < n; m += 1) { _engine.execute('INSERT INTO ' + _TABLE_NAME + ' VALUES ("' + _key + '", "' + _location + '", "' + _values[m] + '")'); } _engine.execute('COMMIT'); return true; } }); // releases the engine when the page unloads Y.Event.on('unload', function() { if (_engine) {_engine.close();} }); Y.StorageEngineGears.ENGINE_NAME = 'gears'; Y.StorageEngineGears.GEARS = 'beta.database'; Y.StorageEngineGears.DATABASE = 'yui.database'; Y.StorageEngineGears.isAvailable = function() { if (window.google && window.google.gears) { try { // this will throw an exception if the user denies gears google.gears.factory.create(Y.StorageEngineGears.GEARS); return true; } catch (e) { // no need to do anything } } return false; }; Y.StorageManager.register(Y.StorageEngineGears); }()); /* * SWF limitation: * - only 100,000 bytes of data may be stored this way * - data is publicly available on user machine * * Thoughts: * - data can be shared across browsers * - how can we not use cookies to handle session location */ (function() { // internal shorthand var Y = YAHOO.util, YL = YAHOO.lang, YD = Y.Dom, /* * The minimum width required to be able to display the settings panel within the SWF. */ MINIMUM_WIDTH = 215, /* * The minimum height required to be able to display the settings panel within the SWF. */ MINIMUM_HEIGHT = 138, // local variables _engine = null, /* * Creates a location bound key. */ _getKey = function(that, key) { return that._location + that.DELIMITER + key; }, /* * Initializes the engine, if it isn't already initialized. */ _initEngine = function(cfg) { if (! _engine) { if (! YL.isString(cfg.swfURL)) {cfg.swfURL = Y.StorageEngineSWF.SWFURL;} if (! cfg.containerID) { var bd = document.getElementsByTagName('body')[0], container = bd.appendChild(document.createElement('div')); cfg.containerID = YD.generateId(container); } if (! cfg.attributes) {cfg.attributes = {};} if (! cfg.attributes.flashVars) {cfg.attributes.flashVars = {};} cfg.attributes.flashVars.useCompression = 'true'; cfg.attributes.version = 9.115; _engine = new YAHOO.widget.SWF(cfg.containerID, cfg.swfURL, cfg.attributes); } }; /** * The StorageEngineSWF class implements the SWF storage engine. * @namespace YAHOO.util * @class StorageEngineSWF * @uses YAHOO.widget.SWF * @constructor * @extend YAHOO.util.Storage * @param location {String} Required. The storage location. * @param conf {Object} Required. A configuration object. */ Y.StorageEngineSWF = function(location, conf) { var _this = this; Y.StorageEngineSWF.superclass.constructor.call(_this, location, Y.StorageEngineSWF.ENGINE_NAME, conf); _initEngine(_this._cfg); // evaluates when the SWF is loaded _engine.unsubscribe('contentReady'); // prevents local and session content ready callbacks from firing, when switching between context _engine.addListener("contentReady", function() { _this._swf = _engine._swf; _engine.initialized = true; var isSessionStorage = Y.StorageManager.LOCATION_SESSION === _this._location, sessionKey = Y.Cookie.get('sessionKey' + Y.StorageEngineSWF.ENGINE_NAME); for (var i = _engine.callSWF("getLength", []) - 1; 0 <= i; i -= 1) { var key = _engine.callSWF("getNameAt", [i]), isKeySessionStorage = -1 < key.indexOf(Y.StorageManager.LOCATION_SESSION + _this.DELIMITER); // this is session storage, but the session key is not set, so remove item if (isSessionStorage && ! sessionKey) { _engine.callSWF("removeItem", [key]); } // the key matches the storage type, add to key collection else if (isSessionStorage === isKeySessionStorage) { _this._addKey(key); } } // this is session storage, ensure that the session key is set if (isSessionStorage) { Y.Cookie.set('sessionKey' + Y.StorageEngineSWF.ENGINE_NAME, true); } _this.length = _this._keys.length; _this.fireEvent(_this.CE_READY); }); // required for pages with both a session and local storage if (_engine.initialized) {_engine.fireEvent('contentReady');} }; YL.extend(Y.StorageEngineSWF, Y.StorageEngineKeyed, { /** * The underlying SWF of the engine, exposed so developers can modify the adapter behavior. * @property _swf * @type {Object} * @protected */ _swf: null, /* * Implementation to clear the values from the storage engine. * @see YAHOO.util.Storage._clear */ _clear: function() { for (var i = this._keys.length - 1; 0 <= i; i -= 1) { var key = this._keys[i]; _engine.callSWF("removeItem", [key]); } this._keys = []; this.length = 0; }, /* * Implementation to fetch an item from the storage engine. * @see YAHOO.util.Storage._getItem */ _getItem: function(key) { var _key = _getKey(this, key); return _engine.callSWF("getValueOf", [_key]); }, /* * Implementation to fetch a key from the storage engine. * @see YAHOO.util.Storage.key */ _key: function(index) { return (this._keys[index] || '').replace(/^.*?__/, ''); }, /* * Implementation to remove an item from the storage engine. * @see YAHOO.util.Storage._removeItem */ _removeItem: function(key) { var _key = _getKey(this, key); _engine.callSWF("removeItem", [_key]); this._removeKey(_key); }, /* * Implementation to remove an item from the storage engine. * @see YAHOO.util.Storage._setItem */ _setItem: function(key, data) { var _key = _getKey(this, key), swfNode; // setting the value returns false if the value didn't change, // so I changed this to clear the key if it exists so that the // fork below works. if (_engine.callSWF("getValueOf", [_key])) { this._removeItem(key); } this._addKey(_key); if (_engine.callSWF("setItem", [_key, data])) { return true; } else { // @TODO we should not assume that a false return means that // the quota has been exceeded. this dialog should only be // displayed if the quotaExceededError event fired. swfNode = YD.get(_engine._id); if (MINIMUM_WIDTH > YD.getStyle(swfNode, 'width').replace(/\D+/g, '')) { YD.setStyle(swfNode, 'width', MINIMUM_WIDTH + 'px'); } if (MINIMUM_HEIGHT > YD.getStyle(swfNode, 'height').replace(/\D+/g, '')) { YD.setStyle(swfNode, 'height', MINIMUM_HEIGHT + 'px'); } return _engine.callSWF("displaySettings", []); } } }); Y.StorageEngineSWF.SWFURL = "swfstore.swf"; Y.StorageEngineSWF.ENGINE_NAME = 'swf'; Y.StorageEngineSWF.isAvailable = function() { return (6 <= YAHOO.env.ua.flash && YAHOO.widget.SWF); }; Y.StorageManager.register(Y.StorageEngineSWF); }()); YAHOO.register("storage", YAHOO.util.Storage, {version: "2.8.0r4", build: "2449"});