| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 | 
							- // Copyright 2011 The Closure Library Authors. All Rights Reserved.
 
- //
 
- // Licensed under the Apache License, Version 2.0 (the "License");
 
- // you may not use this file except in compliance with the License.
 
- // You may obtain a copy of the License at
 
- //
 
- //      http://www.apache.org/licenses/LICENSE-2.0
 
- //
 
- // Unless required by applicable law or agreed to in writing, software
 
- // distributed under the License is distributed on an "AS-IS" BASIS,
 
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
- // See the License for the specific language governing permissions and
 
- // limitations under the License.
 
- /**
 
-  * @fileoverview Provides data persistence using IE userData mechanism.
 
-  * UserData uses proprietary Element.addBehavior(), Element.load(),
 
-  * Element.save(), and Element.XMLDocument() methods, see:
 
-  * http://msdn.microsoft.com/en-us/library/ms531424(v=vs.85).aspx.
 
-  *
 
-  */
 
- goog.provide('goog.storage.mechanism.IEUserData');
 
- goog.require('goog.asserts');
 
- goog.require('goog.iter.Iterator');
 
- goog.require('goog.iter.StopIteration');
 
- goog.require('goog.storage.mechanism.ErrorCode');
 
- goog.require('goog.storage.mechanism.IterableMechanism');
 
- goog.require('goog.structs.Map');
 
- goog.require('goog.userAgent');
 
- /**
 
-  * Provides a storage mechanism using IE userData.
 
-  *
 
-  * @param {string} storageKey The key (store name) to store the data under.
 
-  * @param {string=} opt_storageNodeId The ID of the associated HTML element,
 
-  *     one will be created if not provided.
 
-  * @constructor
 
-  * @extends {goog.storage.mechanism.IterableMechanism}
 
-  * @final
 
-  */
 
- goog.storage.mechanism.IEUserData = function(storageKey, opt_storageNodeId) {
 
-   /**
 
-    * The key to store the data under.
 
-    *
 
-    * @private {?string}
 
-    */
 
-   this.storageKey_ = storageKey;
 
-   /**
 
-    * The document element used for storing data.
 
-    *
 
-    * @private {Element}
 
-    */
 
-   this.storageNode_ = null;
 
-   goog.storage.mechanism.IEUserData.base(this, 'constructor');
 
-   // Tested on IE6, IE7 and IE8. It seems that IE9 introduces some security
 
-   // features which make persistent (loaded) node attributes invisible from
 
-   // JavaScript.
 
-   if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9)) {
 
-     if (!goog.storage.mechanism.IEUserData.storageMap_) {
 
-       goog.storage.mechanism.IEUserData.storageMap_ = new goog.structs.Map();
 
-     }
 
-     this.storageNode_ = /** @type {Element} */ (
 
-         goog.storage.mechanism.IEUserData.storageMap_.get(storageKey));
 
-     if (!this.storageNode_) {
 
-       if (opt_storageNodeId) {
 
-         this.storageNode_ = document.getElementById(opt_storageNodeId);
 
-       } else {
 
-         this.storageNode_ = document.createElement('userdata');
 
-         // This is a special IE-only method letting us persist data.
 
-         this.storageNode_['addBehavior']('#default#userData');
 
-         document.body.appendChild(this.storageNode_);
 
-       }
 
-       goog.storage.mechanism.IEUserData.storageMap_.set(
 
-           storageKey, this.storageNode_);
 
-     }
 
-     try {
 
-       // Availability check.
 
-       this.loadNode_();
 
-     } catch (e) {
 
-       this.storageNode_ = null;
 
-     }
 
-   }
 
- };
 
- goog.inherits(
 
-     goog.storage.mechanism.IEUserData,
 
-     goog.storage.mechanism.IterableMechanism);
 
- /**
 
-  * Encoding map for characters which are not encoded by encodeURIComponent().
 
-  * See encodeKey_ documentation for encoding details.
 
-  *
 
-  * @type {!Object}
 
-  * @const
 
-  */
 
- goog.storage.mechanism.IEUserData.ENCODE_MAP = {
 
-   '.': '.2E',
 
-   '!': '.21',
 
-   '~': '.7E',
 
-   '*': '.2A',
 
-   '\'': '.27',
 
-   '(': '.28',
 
-   ')': '.29',
 
-   '%': '.'
 
- };
 
- /**
 
-  * Global storageKey to storageNode map, so we save on reloading the storage.
 
-  *
 
-  * @type {goog.structs.Map}
 
-  * @private
 
-  */
 
- goog.storage.mechanism.IEUserData.storageMap_ = null;
 
- /**
 
-  * Encodes anything other than [-a-zA-Z0-9_] using a dot followed by hex,
 
-  * and prefixes with underscore to form a valid and safe HTML attribute name.
 
-  *
 
-  * We use URI encoding to do the initial heavy lifting, then escape the
 
-  * remaining characters that we can't use. Since a valid attribute name can't
 
-  * contain the percent sign (%), we use a dot (.) as an escape character.
 
-  *
 
-  * @param {string} key The key to be encoded.
 
-  * @return {string} The encoded key.
 
-  * @private
 
-  */
 
- goog.storage.mechanism.IEUserData.encodeKey_ = function(key) {
 
-   // encodeURIComponent leaves - _ . ! ~ * ' ( ) unencoded.
 
-   return '_' + encodeURIComponent(key).replace(/[.!~*'()%]/g, function(c) {
 
-     return goog.storage.mechanism.IEUserData.ENCODE_MAP[c];
 
-   });
 
- };
 
- /**
 
-  * Decodes a dot-encoded and character-prefixed key.
 
-  * See encodeKey_ documentation for encoding details.
 
-  *
 
-  * @param {string} key The key to be decoded.
 
-  * @return {string} The decoded key.
 
-  * @private
 
-  */
 
- goog.storage.mechanism.IEUserData.decodeKey_ = function(key) {
 
-   return decodeURIComponent(key.replace(/\./g, '%')).substr(1);
 
- };
 
- /**
 
-  * Determines whether or not the mechanism is available.
 
-  *
 
-  * @return {boolean} True if the mechanism is available.
 
-  */
 
- goog.storage.mechanism.IEUserData.prototype.isAvailable = function() {
 
-   return !!this.storageNode_;
 
- };
 
- /** @override */
 
- goog.storage.mechanism.IEUserData.prototype.set = function(key, value) {
 
-   this.storageNode_.setAttribute(
 
-       goog.storage.mechanism.IEUserData.encodeKey_(key), value);
 
-   this.saveNode_();
 
- };
 
- /** @override */
 
- goog.storage.mechanism.IEUserData.prototype.get = function(key) {
 
-   // According to Microsoft, values can be strings, numbers or booleans. Since
 
-   // we only save strings, any other type is a storage error. If we returned
 
-   // nulls for such keys, i.e., treated them as non-existent, this would lead
 
-   // to a paradox where a key exists, but it does not when it is retrieved.
 
-   // http://msdn.microsoft.com/en-us/library/ms531348(v=vs.85).aspx
 
-   var value = this.storageNode_.getAttribute(
 
-       goog.storage.mechanism.IEUserData.encodeKey_(key));
 
-   if (!goog.isString(value) && !goog.isNull(value)) {
 
-     throw goog.storage.mechanism.ErrorCode.INVALID_VALUE;
 
-   }
 
-   return value;
 
- };
 
- /** @override */
 
- goog.storage.mechanism.IEUserData.prototype.remove = function(key) {
 
-   this.storageNode_.removeAttribute(
 
-       goog.storage.mechanism.IEUserData.encodeKey_(key));
 
-   this.saveNode_();
 
- };
 
- /** @override */
 
- goog.storage.mechanism.IEUserData.prototype.getCount = function() {
 
-   return this.getNode_().attributes.length;
 
- };
 
- /** @override */
 
- goog.storage.mechanism.IEUserData.prototype.__iterator__ = function(opt_keys) {
 
-   var i = 0;
 
-   var attributes = this.getNode_().attributes;
 
-   var newIter = new goog.iter.Iterator();
 
-   newIter.next = function() {
 
-     if (i >= attributes.length) {
 
-       throw goog.iter.StopIteration;
 
-     }
 
-     var item = goog.asserts.assert(attributes[i++]);
 
-     if (opt_keys) {
 
-       return goog.storage.mechanism.IEUserData.decodeKey_(item.nodeName);
 
-     }
 
-     var value = item.nodeValue;
 
-     // The value must exist and be a string, otherwise it is a storage error.
 
-     if (!goog.isString(value)) {
 
-       throw goog.storage.mechanism.ErrorCode.INVALID_VALUE;
 
-     }
 
-     return value;
 
-   };
 
-   return newIter;
 
- };
 
- /** @override */
 
- goog.storage.mechanism.IEUserData.prototype.clear = function() {
 
-   var node = this.getNode_();
 
-   for (var left = node.attributes.length; left > 0; left--) {
 
-     node.removeAttribute(node.attributes[left - 1].nodeName);
 
-   }
 
-   this.saveNode_();
 
- };
 
- /**
 
-  * Loads the underlying storage node to the state we saved it to before.
 
-  *
 
-  * @private
 
-  */
 
- goog.storage.mechanism.IEUserData.prototype.loadNode_ = function() {
 
-   // This is a special IE-only method on Elements letting us persist data.
 
-   this.storageNode_['load'](this.storageKey_);
 
- };
 
- /**
 
-  * Saves the underlying storage node.
 
-  *
 
-  * @private
 
-  */
 
- goog.storage.mechanism.IEUserData.prototype.saveNode_ = function() {
 
-   try {
 
-     // This is a special IE-only method on Elements letting us persist data.
 
-     // Do not try to assign this.storageNode_['save'] to a variable, it does
 
-     // not work. May throw an exception when the quota is exceeded.
 
-     this.storageNode_['save'](this.storageKey_);
 
-   } catch (e) {
 
-     throw goog.storage.mechanism.ErrorCode.QUOTA_EXCEEDED;
 
-   }
 
- };
 
- /**
 
-  * Returns the storage node.
 
-  *
 
-  * @return {!Element} Storage DOM Element.
 
-  * @private
 
-  */
 
- goog.storage.mechanism.IEUserData.prototype.getNode_ = function() {
 
-   // This is a special IE-only property letting us browse persistent data.
 
-   var doc = /** @type {Document} */ (this.storageNode_['XMLDocument']);
 
-   return doc.documentElement;
 
- };
 
 
  |