[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/2in3/2.9.0/build/yui2-storage/ -> yui2-storage.js (source)

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


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1