storage-debug.js 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186
  1. /*
  2. Copyright (c) 2009, Yahoo! Inc. All rights reserved.
  3. Code licensed under the BSD License:
  4. http://developer.yahoo.net/yui/license.txt
  5. version: 2.8.0r4
  6. */
  7. /**
  8. * The Storage module manages client-side data storage.
  9. * @module Storage
  10. */
  11. (function() {
  12. // internal shorthand
  13. var Y = YAHOO,
  14. YU = Y.util,
  15. YL = Y.lang,
  16. _logOverwriteError;
  17. if (! YU.Storage) {
  18. _logOverwriteError = function(fxName) {
  19. Y.log('Exception in YAHOO.util.Storage.?? - must be extended by a storage engine'.replace('??', fxName).replace('??', this.getName ? this.getName() : 'Unknown'), 'error');
  20. };
  21. /**
  22. * The Storage class is an HTML 5 storage API clone, used to wrap individual storage implementations with a common API.
  23. * @class Storage
  24. * @namespace YAHOO.util
  25. * @constructor
  26. * @param location {String} Required. The storage location.
  27. * @parm name {String} Required. The engine name.
  28. * @param conf {Object} Required. A configuration object.
  29. */
  30. YU.Storage = function(location, name, conf) {
  31. var that = this;
  32. Y.env._id_counter += 1;
  33. // protected variables
  34. that._cfg = YL.isObject(conf) ? conf : {};
  35. that._location = location;
  36. that._name = name;
  37. that.isReady = false;
  38. // public variables
  39. that.createEvent(that.CE_READY, {scope: that});
  40. that.createEvent(that.CE_CHANGE, {scope: that});
  41. that.subscribe(that.CE_READY, function() {
  42. that.isReady = true;
  43. });
  44. };
  45. YU.Storage.prototype = {
  46. /**
  47. * The event name for when the storage item is ready.
  48. * @property CE_READY
  49. * @type {String}
  50. * @public
  51. */
  52. CE_READY: 'YUIStorageReady',
  53. /**
  54. * The event name for when the storage item has changed.
  55. * @property CE_CHANGE
  56. * @type {String}
  57. * @public
  58. */
  59. CE_CHANGE: 'YUIStorageChange',
  60. /**
  61. * The delimiter uesed between the data type and the data.
  62. * @property DELIMITER
  63. * @type {String}
  64. * @public
  65. */
  66. DELIMITER: '__',
  67. /**
  68. * The configuration of the engine.
  69. * @property _cfg
  70. * @type {Object}
  71. * @protected
  72. */
  73. _cfg: '',
  74. /**
  75. * The name of this engine.
  76. * @property _name
  77. * @type {String}
  78. * @protected
  79. */
  80. _name: '',
  81. /**
  82. * The location for this instance.
  83. * @property _location
  84. * @type {String}
  85. * @protected
  86. */
  87. _location: '',
  88. /**
  89. * The current length of the keys.
  90. * @property length
  91. * @type {Number}
  92. * @public
  93. */
  94. length: 0,
  95. /**
  96. * This engine singleton has been initialized already.
  97. * @property isReady
  98. * @type {String}
  99. * @protected
  100. */
  101. isReady: false,
  102. /**
  103. * Clears any existing key/value pairs.
  104. * @method clear
  105. * @public
  106. */
  107. clear: function() {
  108. this._clear();
  109. this.length = 0;
  110. },
  111. /**
  112. * Fetches the data stored and the provided key.
  113. * @method getItem
  114. * @param key {String} Required. The key used to reference this value (DOMString in HTML 5 spec).
  115. * @return {String|NULL} The value stored at the provided key (DOMString in HTML 5 spec).
  116. * @public
  117. */
  118. getItem: function(key) {
  119. Y.log("Fetching item at " + key);
  120. var item = this._getItem(key);
  121. return YL.isValue(item) ? this._getValue(item) : null; // required by HTML 5 spec
  122. },
  123. /**
  124. * Fetches the storage object's name; should be overwritten by storage engine.
  125. * @method getName
  126. * @return {String} The name of the data storage object.
  127. * @public
  128. */
  129. getName: function() {return this._name;},
  130. /**
  131. * Tests if the key has been set (not in HTML 5 spec); should be overwritten by storage engine.
  132. * @method hasKey
  133. * @param key {String} Required. The key to search for.
  134. * @return {Boolean} True when key has been set.
  135. * @public
  136. */
  137. hasKey: function(key) {
  138. return YL.isString(key) && this._hasKey(key);
  139. },
  140. /**
  141. * Retrieve the key stored at the provided index; should be overwritten by storage engine.
  142. * @method key
  143. * @param index {Number} Required. The index to retrieve (unsigned long in HTML 5 spec).
  144. * @return {String} Required. The key at the provided index (DOMString in HTML 5 spec).
  145. * @public
  146. */
  147. key: function(index) {
  148. Y.log("Fetching key at " + index);
  149. if (YL.isNumber(index) && -1 < index && this.length > index) {
  150. var value = this._key(index);
  151. if (value) {return value;}
  152. }
  153. // this is thrown according to the HTML5 spec
  154. throw('INDEX_SIZE_ERR - Storage.setItem - The provided index (' + index + ') is not available');
  155. },
  156. /**
  157. * Remove an item from the data storage.
  158. * @method setItem
  159. * @param key {String} Required. The key to remove (DOMString in HTML 5 spec).
  160. * @public
  161. */
  162. removeItem: function(key) {
  163. Y.log("removing " + key);
  164. if (this.hasKey(key)) {
  165. var oldValue = this._getItem(key);
  166. if (! oldValue) {oldValue = null;}
  167. this._removeItem(key);
  168. this.fireEvent(this.CE_CHANGE, new YU.StorageEvent(this, key, oldValue, null, YU.StorageEvent.TYPE_REMOVE_ITEM));
  169. }
  170. else {
  171. // HTML 5 spec says to do nothing
  172. }
  173. },
  174. /**
  175. * Adds an item to the data storage.
  176. * @method setItem
  177. * @param key {String} Required. The key used to reference this value (DOMString in HTML 5 spec).
  178. * @param data {Object} Required. The data to store at key (DOMString in HTML 5 spec).
  179. * @public
  180. * @throws QUOTA_EXCEEDED_ERROR
  181. */
  182. setItem: function(key, data) {
  183. Y.log("SETTING " + data + " to " + key);
  184. if (YL.isString(key)) {
  185. var eventType = this.hasKey(key) ? YU.StorageEvent.TYPE_UPDATE_ITEM : YU.StorageEvent.TYPE_ADD_ITEM,
  186. oldValue = this._getItem(key);
  187. if (! oldValue) {oldValue = null;}
  188. if (this._setItem(key, this._createValue(data))) {
  189. this.fireEvent(this.CE_CHANGE, new YU.StorageEvent(this, key, oldValue, data, eventType));
  190. }
  191. else {
  192. // this is thrown according to the HTML5 spec
  193. throw('QUOTA_EXCEEDED_ERROR - Storage.setItem - The choosen storage method (' +
  194. this.getName() + ') has exceeded capacity');
  195. }
  196. }
  197. else {
  198. // HTML 5 spec says to do nothing
  199. }
  200. },
  201. /**
  202. * Implementation of the clear login; should be overwritten by storage engine.
  203. * @method _clear
  204. * @protected
  205. */
  206. _clear: function() {
  207. _logOverwriteError('_clear');
  208. return '';
  209. },
  210. /**
  211. * Converts the object into a string, with meta data (type), so it can be restored later.
  212. * @method _createValue
  213. * @param s {Object} Required. An object to store.
  214. * @protected
  215. */
  216. _createValue: function(s) {
  217. var type = (YL.isNull(s) || YL.isUndefined(s)) ? ('' + s) : typeof s;
  218. return 'string' === type ? s : type + this.DELIMITER + s;
  219. },
  220. /**
  221. * Implementation of the getItem login; should be overwritten by storage engine.
  222. * @method _getItem
  223. * @param key {String} Required. The key used to reference this value.
  224. * @return {String|NULL} The value stored at the provided key.
  225. * @protected
  226. */
  227. _getItem: function(key) {
  228. _logOverwriteError('_getItem');
  229. return '';
  230. },
  231. /**
  232. * Converts the stored value into its appropriate type.
  233. * @method _getValue
  234. * @param s {String} Required. The stored value.
  235. * @protected
  236. */
  237. _getValue: function(s) {
  238. var a = s ? s.split(this.DELIMITER) : [];
  239. if (1 == a.length) {return s;}
  240. switch (a[0]) {
  241. case 'boolean': return 'true' === a[1];
  242. case 'number': return parseFloat(a[1]);
  243. case 'null': return null;
  244. default: return a[1];
  245. }
  246. },
  247. /**
  248. * Implementation of the key logic; should be overwritten by storage engine.
  249. * @method _key
  250. * @param index {Number} Required. The index to retrieve (unsigned long in HTML 5 spec).
  251. * @return {String|NULL} Required. The key at the provided index (DOMString in HTML 5 spec).
  252. * @protected
  253. */
  254. _key: function(index) {
  255. _logOverwriteError('_key');
  256. return '';
  257. },
  258. /*
  259. * Implementation to fetch evaluate the existence of a key.
  260. * @see YAHOO.util.Storage._hasKey
  261. */
  262. _hasKey: function(key) {
  263. return null !== this._getItem(key);
  264. },
  265. /**
  266. * Implementation of the removeItem login; should be overwritten by storage engine.
  267. * @method _removeItem
  268. * @param key {String} Required. The key to remove.
  269. * @protected
  270. */
  271. _removeItem: function(key) {
  272. _logOverwriteError('_removeItem');
  273. return '';
  274. },
  275. /**
  276. * Implementation of the setItem login; should be overwritten by storage engine.
  277. * @method _setItem
  278. * @param key {String} Required. The key used to reference this value.
  279. * @param data {Object} Required. The data to storage at key.
  280. * @return {Boolean} True when successful, false when size QUOTA exceeded.
  281. * @protected
  282. */
  283. _setItem: function(key, data) {
  284. _logOverwriteError('_setItem');
  285. return '';
  286. }
  287. };
  288. YL.augmentProto(YU.Storage, YU.EventProvider);
  289. }
  290. }());
  291. /**
  292. * The StorageManager class is a singleton that registers DataStorage objects and returns instances of those objects.
  293. * @class StorageManager
  294. * @namespace YAHOO.util
  295. * @static
  296. */
  297. (function() {
  298. // internal shorthand
  299. var Y = YAHOO.util,
  300. YL = YAHOO.lang,
  301. // private variables
  302. _locationEngineMap = {}, // cached engines
  303. _registeredEngineSet = [], // set of available engines
  304. _registeredEngineMap = {}, // map of available engines
  305. /**
  306. * Fetches a storage constructor if it is available, otherwise returns NULL.
  307. * @method _getClass
  308. * @param klass {Function} Required. The storage constructor to test.
  309. * @return {Function} An available storage constructor or NULL.
  310. * @private
  311. */
  312. _getClass = function(klass) {
  313. return (klass && klass.isAvailable()) ? klass : null;
  314. },
  315. /**
  316. * Fetches the storage engine from the cache, or creates and caches it.
  317. * @method _getStorageEngine
  318. * @param location {String} Required. The location to store.
  319. * @param klass {Function} Required. A pointer to the engineType Class.
  320. * @param conf {Object} Optional. Additional configuration for the data source engine.
  321. * @private
  322. */
  323. _getStorageEngine = function(location, klass, conf) {
  324. var engine = _locationEngineMap[location + klass.ENGINE_NAME];
  325. if (! engine) {
  326. engine = new klass(location, conf);
  327. _locationEngineMap[location + klass.ENGINE_NAME] = engine;
  328. }
  329. return engine;
  330. },
  331. /**
  332. * Ensures that the location is valid before returning it or a default value.
  333. * @method _getValidLocation
  334. * @param location {String} Required. The location to evaluate.
  335. * @private
  336. */
  337. _getValidLocation = function(location) {
  338. switch (location) {
  339. case Y.StorageManager.LOCATION_LOCAL:
  340. case Y.StorageManager.LOCATION_SESSION:
  341. return location;
  342. default: return Y.StorageManager.LOCATION_SESSION;
  343. }
  344. };
  345. // public namespace
  346. Y.StorageManager = {
  347. /**
  348. * The storage location - session; data cleared at the end of a user's session.
  349. * @property LOCATION_SESSION
  350. * @type {String}
  351. * @static
  352. */
  353. LOCATION_SESSION: 'sessionStorage',
  354. /**
  355. * The storage location - local; data cleared on demand.
  356. * @property LOCATION_LOCAL
  357. * @type {String}
  358. * @static
  359. */
  360. LOCATION_LOCAL: 'localStorage',
  361. /**
  362. * Fetches the desired engine type or first available engine type.
  363. * @method get
  364. * @param engineType {String} Optional. The engine type, see engines.
  365. * @param location {String} Optional. The storage location - LOCATION_SESSION & LOCATION_LOCAL; default is LOCAL.
  366. * @param conf {Object} Optional. Additional configuration for the getting the storage engine.
  367. * {
  368. * engine: {Object} configuration parameters for the desired engine
  369. * order: {Array} an array of storage engine names; the desired order to try engines}
  370. * }
  371. * @static
  372. */
  373. get: function(engineType, location, conf) {
  374. var _cfg = YL.isObject(conf) ? conf : {},
  375. klass = _getClass(_registeredEngineMap[engineType]);
  376. if (! klass && ! _cfg.force) {
  377. var i, j;
  378. if (_cfg.order) {
  379. j = _cfg.order.length;
  380. for (i = 0; i < j && ! klass; i += 1) {
  381. klass = _getClass(_cfg.order[i]);
  382. }
  383. }
  384. if (! klass) {
  385. j = _registeredEngineSet.length;
  386. for (i = 0; i < j && ! klass; i += 1) {
  387. klass = _getClass(_registeredEngineSet[i]);
  388. }
  389. }
  390. }
  391. if (klass) {
  392. return _getStorageEngine(_getValidLocation(location), klass, _cfg.engine);
  393. }
  394. throw('YAHOO.util.StorageManager.get - No engine available, please include an engine before calling this function.');
  395. },
  396. /*
  397. * Estimates the size of the string using 1 byte for each alpha-numeric character and 3 for each non-alpha-numeric character.
  398. * @method getByteSize
  399. * @param s {String} Required. The string to evaulate.
  400. * @return {Number} The estimated string size.
  401. * @private
  402. */
  403. getByteSize: function(s) {
  404. return encodeURIComponent('' + s).length;
  405. },
  406. /**
  407. * Registers a engineType Class with the StorageManager singleton; first in is the first out.
  408. * @method register
  409. * @param engineConstructor {Function} Required. The engine constructor function, see engines.
  410. * @return {Boolean} When successfully registered.
  411. * @static
  412. */
  413. register: function(engineConstructor) {
  414. if (YL.isFunction(engineConstructor) && YL.isFunction(engineConstructor.isAvailable) && YL.isString(engineConstructor.ENGINE_NAME)) {
  415. _registeredEngineMap[engineConstructor.ENGINE_NAME] = engineConstructor;
  416. _registeredEngineSet.push(engineConstructor);
  417. return true;
  418. }
  419. return false;
  420. }
  421. };
  422. YAHOO.register("StorageManager", Y.SWFStore, {version: "2.8.0r4", build: "2449"});
  423. }());
  424. (function() {
  425. /**
  426. * The StorageEvent class manages the storage events by emulating the HTML 5 implementation.
  427. * @namespace YAHOO.util
  428. * @class StorageEvent
  429. * @constructor
  430. * @param storageArea {Object} Required. The Storage object that was affected.
  431. * @param key {String} Required. The key being changed; DOMString in HTML 5 spec.
  432. * @param oldValue {String} Required. The old value of the key being changed; DOMString in HTML 5 spec.
  433. * @param newValue {String} Required. The new value of the key being changed; DOMString in HTML 5 spec.
  434. * @param type {String} Required. The storage event type.
  435. */
  436. YAHOO.util.StorageEvent = function(storageArea, key, oldValue, newValue, type) {
  437. this.key = key;
  438. this.oldValue = oldValue;
  439. this.newValue = newValue;
  440. this.url = window.location.href;
  441. this.window = window; // todo: think about the CAJA and innocent code
  442. this.storageArea = storageArea;
  443. this.type = type;
  444. };
  445. YAHOO.lang.augmentObject(YAHOO.util.StorageEvent, {
  446. TYPE_ADD_ITEM: 'addItem',
  447. TYPE_REMOVE_ITEM: 'removeItem',
  448. TYPE_UPDATE_ITEM: 'updateItem'
  449. });
  450. YAHOO.util.StorageEvent.prototype = {
  451. /**
  452. * The 'key' attribute represents the key being changed.
  453. * @property key
  454. * @type {String}
  455. * @static
  456. * @readonly
  457. */
  458. key: null,
  459. /**
  460. * The 'newValue' attribute represents the new value of the key being changed.
  461. * @property newValue
  462. * @type {String}
  463. * @static
  464. * @readonly
  465. */
  466. newValue: null,
  467. /**
  468. * The 'oldValue' attribute represents the old value of the key being changed.
  469. * @property oldValue
  470. * @type {String}
  471. * @static
  472. * @readonly
  473. */
  474. oldValue: null,
  475. /**
  476. * The 'source' attribute represents the WindowProxy object of the browsing context of the document whose key changed.
  477. * @property source
  478. * @type {Object}
  479. * @static
  480. * @readonly
  481. */
  482. source: null,
  483. /**
  484. * The 'storageArea' attribute represents the Storage object that was affected.
  485. * @property storageArea
  486. * @type {Object}
  487. * @static
  488. * @readonly
  489. */
  490. storageArea: null,
  491. /**
  492. * The 'type' attribute represents the Storage event type.
  493. * @property type
  494. * @type {Object}
  495. * @static
  496. * @readonly
  497. */
  498. type: null,
  499. /**
  500. * The 'url' attribute represents the address of the document whose key changed.
  501. * @property url
  502. * @type {String}
  503. * @static
  504. * @readonly
  505. */
  506. url: null
  507. };
  508. }());
  509. (function() {
  510. var Y = YAHOO.util,
  511. YL = YAHOO.lang;
  512. /**
  513. * The StorageEngineKeyed class implements the interface necessary for managing keys.
  514. * @namespace YAHOO.util
  515. * @class StorageEngineKeyed
  516. * @constructor
  517. * @extend YAHOO.util.Storage
  518. */
  519. Y.StorageEngineKeyed = function() {
  520. Y.StorageEngineKeyed.superclass.constructor.apply(this, arguments);
  521. this._keys = [];
  522. this._keyMap = {};
  523. };
  524. YL.extend(Y.StorageEngineKeyed, Y.Storage, {
  525. /**
  526. * A collection of keys applicable to the current location. This should never be edited by the developer.
  527. * @property _keys
  528. * @type {Array}
  529. * @protected
  530. */
  531. _keys: null,
  532. /**
  533. * A map of keys to their applicable position in keys array. This should never be edited by the developer.
  534. * @property _keyMap
  535. * @type {Object}
  536. * @protected
  537. */
  538. _keyMap: null,
  539. /**
  540. * Adds the key to the set.
  541. * @method _addKey
  542. * @param key {String} Required. The key to evaluate.
  543. * @protected
  544. */
  545. _addKey: function(key) {
  546. this._keyMap[key] = this.length;
  547. this._keys.push(key);
  548. this.length = this._keys.length;
  549. },
  550. /**
  551. * Evaluates if a key exists in the keys array; indexOf does not work in all flavors of IE.
  552. * @method _indexOfKey
  553. * @param key {String} Required. The key to evaluate.
  554. * @protected
  555. */
  556. _indexOfKey: function(key) {
  557. var i = this._keyMap[key];
  558. return undefined === i ? -1 : i;
  559. },
  560. /**
  561. * Removes a key from the keys array.
  562. * @method _removeKey
  563. * @param key {String} Required. The key to remove.
  564. * @protected
  565. */
  566. _removeKey: function(key) {
  567. var j = this._indexOfKey(key),
  568. rest = this._keys.slice(j + 1);
  569. delete this._keyMap[key];
  570. for (var k in this._keyMap) {
  571. if (j < this._keyMap[k]) {
  572. this._keyMap[k] -= 1;
  573. }
  574. }
  575. this._keys.length = j;
  576. this._keys = this._keys.concat(rest);
  577. this.length = this._keys.length;
  578. }
  579. });
  580. }());
  581. /*
  582. * HTML limitations:
  583. * - 5MB in FF and Safari, 10MB in IE 8
  584. * - only FF 3.5 recovers session storage after a browser crash
  585. *
  586. * Thoughts:
  587. * - how can we not use cookies to handle session
  588. */
  589. (function() {
  590. // internal shorthand
  591. var Y = YAHOO.util,
  592. YL = YAHOO.lang,
  593. /*
  594. * Required for IE 8 to make synchronous.
  595. */
  596. _beginTransaction = function(engine) {
  597. if (engine.begin) {engine.begin();}
  598. },
  599. /*
  600. * Required for IE 8 to make synchronous.
  601. */
  602. _commitTransaction = function(engine) {
  603. if (engine.commit) {engine.commit();}
  604. };
  605. /**
  606. * The StorageEngineHTML5 class implements the HTML5 storage engine.
  607. * @namespace YAHOO.util
  608. * @class StorageEngineHTML5
  609. * @constructor
  610. * @extend YAHOO.util.Storage
  611. * @param location {String} Required. The storage location.
  612. * @param conf {Object} Required. A configuration object.
  613. */
  614. Y.StorageEngineHTML5 = function(location, conf) {
  615. var _this = this;
  616. Y.StorageEngineHTML5.superclass.constructor.call(_this, location, Y.StorageEngineHTML5.ENGINE_NAME, conf);// not set, are cookies available
  617. _this._engine = window[location];
  618. _this.length = _this._engine.length;
  619. YL.later(250, _this, function() { // temporary solution so that CE_READY can be subscribed to after this object is created
  620. _this.fireEvent(_this.CE_READY);
  621. });
  622. };
  623. YAHOO.lang.extend(Y.StorageEngineHTML5, Y.Storage, {
  624. _engine: null,
  625. /*
  626. * Implementation to clear the values from the storage engine.
  627. * @see YAHOO.util.Storage._clear
  628. */
  629. _clear: function() {
  630. var _this = this;
  631. if (_this._engine.clear) {
  632. _this._engine.clear();
  633. }
  634. // for FF 3, fixed in FF 3.5
  635. else {
  636. for (var i = _this.length, key; 0 <= i; i -= 1) {
  637. key = _this._key(i);
  638. _this._removeItem(key);
  639. }
  640. }
  641. },
  642. /*
  643. * Implementation to fetch an item from the storage engine.
  644. * @see YAHOO.util.Storage._getItem
  645. */
  646. _getItem: function(key) {
  647. var o = this._engine.getItem(key);
  648. return YL.isObject(o) ? o.value : o; // for FF 3, fixed in FF 3.5
  649. },
  650. /*
  651. * Implementation to fetch a key from the storage engine.
  652. * @see YAHOO.util.Storage._key
  653. */
  654. _key: function(index) {return this._engine.key(index);},
  655. /*
  656. * Implementation to remove an item from the storage engine.
  657. * @see YAHOO.util.Storage._removeItem
  658. */
  659. _removeItem: function(key) {
  660. var _this = this;
  661. _beginTransaction(_this._engine);
  662. _this._engine.removeItem(key);
  663. _commitTransaction(_this._engine);
  664. _this.length = _this._engine.length;
  665. },
  666. /*
  667. * Implementation to remove an item from the storage engine.
  668. * @see YAHOO.util.Storage._setItem
  669. */
  670. _setItem: function(key, value) {
  671. var _this = this;
  672. try {
  673. _beginTransaction(_this._engine);
  674. _this._engine.setItem(key, value);
  675. _commitTransaction(_this._engine);
  676. _this.length = _this._engine.length;
  677. return true;
  678. }
  679. catch (e) {
  680. return false;
  681. }
  682. }
  683. }, true);
  684. Y.StorageEngineHTML5.ENGINE_NAME = 'html5';
  685. Y.StorageEngineHTML5.isAvailable = function() {
  686. return window.localStorage;
  687. };
  688. Y.StorageManager.register(Y.StorageEngineHTML5);
  689. }());
  690. /*
  691. * Gears limitation:
  692. * - SQLite limitations - http://www.sqlite.org/limits.html
  693. * - DB Best Practices - http://code.google.com/apis/gears/gears_faq.html#bestPracticeDB
  694. * - the user must approve before gears can be used
  695. * - each SQL query has a limited number of characters (9948 bytes), data will need to be spread across rows
  696. * - no query should insert or update more than 9948 bytes of data in a single statement or GEARs will throw:
  697. * [Exception... "'Error: SQL statement is too long.' when calling method: [nsIDOMEventListener::handleEvent]" nsresult: "0x8057001c (NS_ERROR_XPC_JS_THREW_JS_OBJECT)" location: "<unknown>" data: no]
  698. *
  699. * Thoughts:
  700. * - we may want to implement additional functions for the gears only implementation
  701. * - how can we not use cookies to handle session location
  702. */
  703. (function() {
  704. // internal shorthand
  705. var Y = YAHOO.util,
  706. YL = YAHOO.lang,
  707. _SQL_STMT_LIMIT = 9948,
  708. _TABLE_NAME = 'YUIStorageEngine',
  709. // local variables
  710. _engine = null,
  711. eURI = encodeURIComponent,
  712. dURI = decodeURIComponent;
  713. /**
  714. * The StorageEngineGears class implements the Google Gears storage engine.
  715. * @namespace YAHOO.util
  716. * @class StorageEngineGears
  717. * @constructor
  718. * @extend YAHOO.util.Storage
  719. * @param location {String} Required. The storage location.
  720. * @param conf {Object} Required. A configuration object.
  721. */
  722. Y.StorageEngineGears = function(location, conf) {
  723. var _this = this;
  724. Y.StorageEngineGears.superclass.constructor.call(_this, location, Y.StorageEngineGears.ENGINE_NAME, conf);
  725. if (! _engine) {
  726. // create the database
  727. _engine = google.gears.factory.create(Y.StorageEngineGears.GEARS);
  728. _engine.open(window.location.host + '-' + Y.StorageEngineGears.DATABASE);
  729. _engine.execute('CREATE TABLE IF NOT EXISTS ' + _TABLE_NAME + ' (key TEXT, location TEXT, value TEXT)');
  730. }
  731. var isSessionStorage = Y.StorageManager.LOCATION_SESSION === _this._location,
  732. sessionKey = Y.Cookie.get('sessionKey' + Y.StorageEngineGears.ENGINE_NAME);
  733. if (! sessionKey) {
  734. _engine.execute('BEGIN');
  735. _engine.execute('DELETE FROM ' + _TABLE_NAME + ' WHERE location="' + eURI(Y.StorageManager.LOCATION_SESSION) + '"');
  736. _engine.execute('COMMIT');
  737. }
  738. var rs = _engine.execute('SELECT key FROM ' + _TABLE_NAME + ' WHERE location="' + eURI(_this._location) + '"'),
  739. keyMap = {};
  740. try {
  741. // iterate on the rows and map the keys
  742. while (rs.isValidRow()) {
  743. var fld = dURI(rs.field(0));
  744. if (! keyMap[fld]) {
  745. keyMap[fld] = true;
  746. _this._addKey(fld);
  747. }
  748. rs.next();
  749. }
  750. }
  751. finally {
  752. rs.close();
  753. }
  754. // this is session storage, ensure that the session key is set
  755. if (isSessionStorage) {
  756. Y.Cookie.set('sessionKey' + Y.StorageEngineGears.ENGINE_NAME, true);
  757. }
  758. _this.length = _this._keys.length;
  759. YL.later(250, _this, function() { // temporary solution so that CE_READY can be subscribed to after this object is created
  760. _this.fireEvent(_this.CE_READY);
  761. });
  762. };
  763. YL.extend(Y.StorageEngineGears, Y.StorageEngineKeyed, {
  764. /*
  765. * Implementation to clear the values from the storage engine.
  766. * @see YAHOO.util.Storage._clear
  767. */
  768. _clear: function() {
  769. _engine.execute('BEGIN');
  770. _engine.execute('DELETE FROM ' + _TABLE_NAME + ' WHERE location="' + eURI(this._location) + '"');
  771. _engine.execute('COMMIT');
  772. this._keys = [];
  773. this.length = 0;
  774. },
  775. /*
  776. * Implementation to fetch an item from the storage engine.
  777. * @see YAHOO.util.Storage._getItem
  778. */
  779. _getItem: function(key) {
  780. var rs = _engine.execute('SELECT value FROM ' + _TABLE_NAME + ' WHERE key="' + eURI(key) + '" AND location="' + eURI(this._location) + '"'),
  781. value = '';
  782. try {
  783. while (rs.isValidRow()) {
  784. var temp = rs.field(0);
  785. value += rs.field(0);
  786. rs.next();
  787. }
  788. }
  789. finally {
  790. rs.close();
  791. }
  792. return value ? dURI(value) : null;
  793. },
  794. /*
  795. * Implementation to fetch a key from the storage engine.
  796. * @see YAHOO.util.Storage.key
  797. */
  798. _key: function(index) {return this._keys[index];},
  799. /*
  800. * Implementation to remove an item from the storage engine.
  801. * @see YAHOO.util.Storage._removeItem
  802. */
  803. _removeItem: function(key) {
  804. YAHOO.log("removing " + key);
  805. _engine.execute('BEGIN');
  806. _engine.execute('DELETE FROM ' + _TABLE_NAME + ' WHERE key="' + eURI(key) + '" AND location="' + eURI(this._location) + '"');
  807. _engine.execute('COMMIT');
  808. this._removeKey(key);
  809. },
  810. /*
  811. * Implementation to remove an item from the storage engine.
  812. * @see YAHOO.util.Storage._setItem
  813. */
  814. _setItem: function(key, data) {
  815. YAHOO.log("SETTING " + data + " to " + key);
  816. if (! this.hasKey(key)) {
  817. this._addKey(key);
  818. }
  819. var _key = eURI(key),
  820. _location = eURI(this._location),
  821. _value = eURI(data),
  822. _values = [],
  823. _len = _SQL_STMT_LIMIT - (_key + _location).length;
  824. // the length of the value exceeds the available space
  825. if (_len < _value.length) {
  826. for (var i = 0, j = _value.length; i < j; i += _len) {
  827. _values.push(_value.substr(i, _len));
  828. }
  829. }
  830. else {
  831. _values.push(_value);
  832. }
  833. // Google recommends using INSERT instead of update, because it is faster
  834. _engine.execute('BEGIN');
  835. _engine.execute('DELETE FROM ' + _TABLE_NAME + ' WHERE key="' + eURI(key) + '" AND location="' + eURI(this._location) + '"');
  836. for (var m = 0, n = _values.length; m < n; m += 1) {
  837. _engine.execute('INSERT INTO ' + _TABLE_NAME + ' VALUES ("' + _key + '", "' + _location + '", "' + _values[m] + '")');
  838. }
  839. _engine.execute('COMMIT');
  840. return true;
  841. }
  842. });
  843. // releases the engine when the page unloads
  844. Y.Event.on('unload', function() {
  845. if (_engine) {_engine.close();}
  846. });
  847. Y.StorageEngineGears.ENGINE_NAME = 'gears';
  848. Y.StorageEngineGears.GEARS = 'beta.database';
  849. Y.StorageEngineGears.DATABASE = 'yui.database';
  850. Y.StorageEngineGears.isAvailable = function() {
  851. if (window.google && window.google.gears) {
  852. try {
  853. // this will throw an exception if the user denies gears
  854. google.gears.factory.create(Y.StorageEngineGears.GEARS);
  855. return true;
  856. }
  857. catch (e) {
  858. // no need to do anything
  859. }
  860. }
  861. return false;
  862. };
  863. Y.StorageManager.register(Y.StorageEngineGears);
  864. }());
  865. /*
  866. * SWF limitation:
  867. * - only 100,000 bytes of data may be stored this way
  868. * - data is publicly available on user machine
  869. *
  870. * Thoughts:
  871. * - data can be shared across browsers
  872. * - how can we not use cookies to handle session location
  873. */
  874. (function() {
  875. // internal shorthand
  876. var Y = YAHOO.util,
  877. YL = YAHOO.lang,
  878. YD = Y.Dom,
  879. /*
  880. * The minimum width required to be able to display the settings panel within the SWF.
  881. */
  882. MINIMUM_WIDTH = 215,
  883. /*
  884. * The minimum height required to be able to display the settings panel within the SWF.
  885. */
  886. MINIMUM_HEIGHT = 138,
  887. // local variables
  888. _engine = null,
  889. /*
  890. * Creates a location bound key.
  891. */
  892. _getKey = function(that, key) {
  893. return that._location + that.DELIMITER + key;
  894. },
  895. /*
  896. * Initializes the engine, if it isn't already initialized.
  897. */
  898. _initEngine = function(cfg) {
  899. if (! _engine) {
  900. if (! YL.isString(cfg.swfURL)) {cfg.swfURL = Y.StorageEngineSWF.SWFURL;}
  901. if (! cfg.containerID) {
  902. var bd = document.getElementsByTagName('body')[0],
  903. container = bd.appendChild(document.createElement('div'));
  904. cfg.containerID = YD.generateId(container);
  905. }
  906. if (! cfg.attributes) {cfg.attributes = {};}
  907. if (! cfg.attributes.flashVars) {cfg.attributes.flashVars = {};}
  908. cfg.attributes.flashVars.useCompression = 'true';
  909. cfg.attributes.version = 9.115;
  910. _engine = new YAHOO.widget.SWF(cfg.containerID, cfg.swfURL, cfg.attributes);
  911. }
  912. };
  913. /**
  914. * The StorageEngineSWF class implements the SWF storage engine.
  915. * @namespace YAHOO.util
  916. * @class StorageEngineSWF
  917. * @uses YAHOO.widget.SWF
  918. * @constructor
  919. * @extend YAHOO.util.Storage
  920. * @param location {String} Required. The storage location.
  921. * @param conf {Object} Required. A configuration object.
  922. */
  923. Y.StorageEngineSWF = function(location, conf) {
  924. var _this = this;
  925. Y.StorageEngineSWF.superclass.constructor.call(_this, location, Y.StorageEngineSWF.ENGINE_NAME, conf);
  926. _initEngine(_this._cfg);
  927. // evaluates when the SWF is loaded
  928. _engine.unsubscribe('contentReady'); // prevents local and session content ready callbacks from firing, when switching between context
  929. _engine.addListener("contentReady", function() {
  930. _this._swf = _engine._swf;
  931. _engine.initialized = true;
  932. var isSessionStorage = Y.StorageManager.LOCATION_SESSION === _this._location,
  933. sessionKey = Y.Cookie.get('sessionKey' + Y.StorageEngineSWF.ENGINE_NAME);
  934. for (var i = _engine.callSWF("getLength", []) - 1; 0 <= i; i -= 1) {
  935. var key = _engine.callSWF("getNameAt", [i]),
  936. isKeySessionStorage = -1 < key.indexOf(Y.StorageManager.LOCATION_SESSION + _this.DELIMITER);
  937. // this is session storage, but the session key is not set, so remove item
  938. if (isSessionStorage && ! sessionKey) {
  939. _engine.callSWF("removeItem", [key]);
  940. }
  941. // the key matches the storage type, add to key collection
  942. else if (isSessionStorage === isKeySessionStorage) {
  943. _this._addKey(key);
  944. }
  945. }
  946. // this is session storage, ensure that the session key is set
  947. if (isSessionStorage) {
  948. Y.Cookie.set('sessionKey' + Y.StorageEngineSWF.ENGINE_NAME, true);
  949. }
  950. _this.length = _this._keys.length;
  951. _this.fireEvent(_this.CE_READY);
  952. });
  953. // required for pages with both a session and local storage
  954. if (_engine.initialized) {_engine.fireEvent('contentReady');}
  955. };
  956. YL.extend(Y.StorageEngineSWF, Y.StorageEngineKeyed, {
  957. /**
  958. * The underlying SWF of the engine, exposed so developers can modify the adapter behavior.
  959. * @property _swf
  960. * @type {Object}
  961. * @protected
  962. */
  963. _swf: null,
  964. /*
  965. * Implementation to clear the values from the storage engine.
  966. * @see YAHOO.util.Storage._clear
  967. */
  968. _clear: function() {
  969. for (var i = this._keys.length - 1; 0 <= i; i -= 1) {
  970. var key = this._keys[i];
  971. _engine.callSWF("removeItem", [key]);
  972. }
  973. this._keys = [];
  974. this.length = 0;
  975. },
  976. /*
  977. * Implementation to fetch an item from the storage engine.
  978. * @see YAHOO.util.Storage._getItem
  979. */
  980. _getItem: function(key) {
  981. var _key = _getKey(this, key);
  982. return _engine.callSWF("getValueOf", [_key]);
  983. },
  984. /*
  985. * Implementation to fetch a key from the storage engine.
  986. * @see YAHOO.util.Storage.key
  987. */
  988. _key: function(index) {
  989. return (this._keys[index] || '').replace(/^.*?__/, '');
  990. },
  991. /*
  992. * Implementation to remove an item from the storage engine.
  993. * @see YAHOO.util.Storage._removeItem
  994. */
  995. _removeItem: function(key) {
  996. var _key = _getKey(this, key);
  997. _engine.callSWF("removeItem", [_key]);
  998. this._removeKey(_key);
  999. },
  1000. /*
  1001. * Implementation to remove an item from the storage engine.
  1002. * @see YAHOO.util.Storage._setItem
  1003. */
  1004. _setItem: function(key, data) {
  1005. var _key = _getKey(this, key), swfNode;
  1006. // setting the value returns false if the value didn't change,
  1007. // so I changed this to clear the key if it exists so that the
  1008. // fork below works.
  1009. if (_engine.callSWF("getValueOf", [_key])) {
  1010. this._removeItem(key);
  1011. }
  1012. this._addKey(_key);
  1013. if (_engine.callSWF("setItem", [_key, data])) {
  1014. return true;
  1015. } else {
  1016. // @TODO we should not assume that a false return means that
  1017. // the quota has been exceeded. this dialog should only be
  1018. // displayed if the quotaExceededError event fired.
  1019. swfNode = YD.get(_engine._id);
  1020. if (MINIMUM_WIDTH > YD.getStyle(swfNode, 'width').replace(/\D+/g, '')) {
  1021. YD.setStyle(swfNode, 'width', MINIMUM_WIDTH + 'px');
  1022. }
  1023. if (MINIMUM_HEIGHT > YD.getStyle(swfNode, 'height').replace(/\D+/g, '')) {
  1024. YD.setStyle(swfNode, 'height', MINIMUM_HEIGHT + 'px');
  1025. }
  1026. return _engine.callSWF("displaySettings", []);
  1027. }
  1028. }
  1029. });
  1030. Y.StorageEngineSWF.SWFURL = "swfstore.swf";
  1031. Y.StorageEngineSWF.ENGINE_NAME = 'swf';
  1032. Y.StorageEngineSWF.isAvailable = function() {
  1033. return (6 <= YAHOO.env.ua.flash && YAHOO.widget.SWF);
  1034. };
  1035. Y.StorageManager.register(Y.StorageEngineSWF);
  1036. }());
  1037. YAHOO.register("storage", YAHOO.util.Storage, {version: "2.8.0r4", build: "2449"});