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