Update wmts-hidpi, add nicer-api-docs

This commit is contained in:
Andreas Hocevar
2014-05-06 13:02:46 -05:00
parent b3ac1afd00
commit 1e25fc5585
2239 changed files with 3726515 additions and 37010 deletions

View File

@@ -0,0 +1,31 @@
// 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 Defines error codes to be thrown by storage mechanisms.
*
*/
goog.provide('goog.storage.mechanism.ErrorCode');
/**
* Errors thrown by storage mechanisms.
* @enum {string}
*/
goog.storage.mechanism.ErrorCode = {
INVALID_VALUE: 'Storage mechanism: Invalid value was encountered',
QUOTA_EXCEEDED: 'Storage mechanism: Quota exceeded',
STORAGE_DISABLED: 'Storage mechanism: Storage disabled'
};

View File

@@ -0,0 +1,128 @@
// Copyright 2012 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 Wraps a storage mechanism with a custom error handler.
*
*/
goog.provide('goog.storage.mechanism.ErrorHandlingMechanism');
goog.require('goog.storage.mechanism.Mechanism');
/**
* Wraps a storage mechanism with a custom error handler.
*
* @param {!goog.storage.mechanism.Mechanism} mechanism Underlying storage
* mechanism.
* @param {goog.storage.mechanism.ErrorHandlingMechanism.ErrorHandler}
* errorHandler An error handler.
* @constructor
* @extends {goog.storage.mechanism.Mechanism}
*/
goog.storage.mechanism.ErrorHandlingMechanism = function(mechanism,
errorHandler) {
goog.base(this);
/**
* The mechanism to be wrapped.
* @type {!goog.storage.mechanism.Mechanism}
* @private
*/
this.mechanism_ = mechanism;
/**
* The error handler.
* @type {goog.storage.mechanism.ErrorHandlingMechanism.ErrorHandler}
* @private
*/
this.errorHandler_ = errorHandler;
};
goog.inherits(goog.storage.mechanism.ErrorHandlingMechanism,
goog.storage.mechanism.Mechanism);
/**
* Valid storage mechanism operations.
* @enum {string}
*/
goog.storage.mechanism.ErrorHandlingMechanism.Operation = {
SET: 'set',
GET: 'get',
REMOVE: 'remove'
};
/**
* A function that handles errors raised in goog.storage. Since some places in
* the goog.storage codebase throw strings instead of Error objects, we accept
* these as a valid parameter type. It supports the following arguments:
*
* 1) The raised error (either in Error or string form);
* 2) The operation name which triggered the error, as defined per the
* ErrorHandlingMechanism.Operation enum;
* 3) The key that is passed to a storage method;
* 4) An optional value that is passed to a storage method (only used in set
* operations).
*
* @typedef {function(
* (!Error|string),
* goog.storage.mechanism.ErrorHandlingMechanism.Operation,
* string,
* *=)}
*/
goog.storage.mechanism.ErrorHandlingMechanism.ErrorHandler;
/** @override */
goog.storage.mechanism.ErrorHandlingMechanism.prototype.set = function(key,
value) {
try {
this.mechanism_.set(key, value);
} catch (e) {
this.errorHandler_(
e,
goog.storage.mechanism.ErrorHandlingMechanism.Operation.SET,
key,
value);
}
};
/** @override */
goog.storage.mechanism.ErrorHandlingMechanism.prototype.get = function(key) {
try {
return this.mechanism_.get(key);
} catch (e) {
this.errorHandler_(
e,
goog.storage.mechanism.ErrorHandlingMechanism.Operation.GET,
key);
}
};
/** @override */
goog.storage.mechanism.ErrorHandlingMechanism.prototype.remove = function(key) {
try {
this.mechanism_.remove(key);
} catch (e) {
this.errorHandler_(
e,
goog.storage.mechanism.ErrorHandlingMechanism.Operation.REMOVE,
key);
}
};

View File

@@ -0,0 +1,45 @@
// 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 HTML5 local storage
* mechanism. Local storage must be available under window.localStorage,
* see: http://www.w3.org/TR/webstorage/#the-localstorage-attribute.
*
*/
goog.provide('goog.storage.mechanism.HTML5LocalStorage');
goog.require('goog.storage.mechanism.HTML5WebStorage');
/**
* Provides a storage mechanism that uses HTML5 local storage.
*
* @constructor
* @extends {goog.storage.mechanism.HTML5WebStorage}
*/
goog.storage.mechanism.HTML5LocalStorage = function() {
var storage = null;
/** @preserveTry */
try {
// May throw an exception in cases where the local storage object
// is visible but access to it is disabled.
storage = window.localStorage || null;
} catch (e) {}
goog.base(this, storage);
};
goog.inherits(goog.storage.mechanism.HTML5LocalStorage,
goog.storage.mechanism.HTML5WebStorage);

View File

@@ -0,0 +1,46 @@
// 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 HTML5 session storage
* mechanism. Session storage must be available under window.sessionStorage,
* see: http://www.w3.org/TR/webstorage/#the-sessionstorage-attribute.
*
*/
goog.provide('goog.storage.mechanism.HTML5SessionStorage');
goog.require('goog.storage.mechanism.HTML5WebStorage');
/**
* Provides a storage mechanism that uses HTML5 session storage.
*
* @constructor
* @extends {goog.storage.mechanism.HTML5WebStorage}
*/
goog.storage.mechanism.HTML5SessionStorage = function() {
var storage = null;
/** @preserveTry */
try {
// May throw an exception in cases where the session storage object is
// visible but access to it is disabled. For example, accessing the file
// in local mode in Firefox throws 'Operation is not supported' exception.
storage = window.sessionStorage || null;
} catch (e) {}
goog.base(this, storage);
};
goog.inherits(goog.storage.mechanism.HTML5SessionStorage,
goog.storage.mechanism.HTML5WebStorage);

View File

@@ -0,0 +1,176 @@
// 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 Base class that implements functionality common
* across both session and local web storage mechanisms.
*
*/
goog.provide('goog.storage.mechanism.HTML5WebStorage');
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');
/**
* Provides a storage mechanism that uses HTML5 Web storage.
*
* @param {Storage} storage The Web storage object.
* @constructor
* @extends {goog.storage.mechanism.IterableMechanism}
*/
goog.storage.mechanism.HTML5WebStorage = function(storage) {
goog.base(this);
this.storage_ = storage;
};
goog.inherits(goog.storage.mechanism.HTML5WebStorage,
goog.storage.mechanism.IterableMechanism);
/**
* The key used to check if the storage instance is available.
* @type {string}
* @const
* @private
*/
goog.storage.mechanism.HTML5WebStorage.STORAGE_AVAILABLE_KEY_ = '__sak';
/**
* The web storage object (window.localStorage or window.sessionStorage).
*
* @type {Storage}
* @private
*/
goog.storage.mechanism.HTML5WebStorage.prototype.storage_;
/**
* Determines whether or not the mechanism is available.
* It works only if the provided web storage object exists and is enabled.
*
* @return {boolean} True if the mechanism is available.
*/
goog.storage.mechanism.HTML5WebStorage.prototype.isAvailable = function() {
if (!this.storage_) {
return false;
}
/** @preserveTry */
try {
// setItem will throw an exception if we cannot access WebStorage (e.g.,
// Safari in private mode).
this.storage_.setItem(
goog.storage.mechanism.HTML5WebStorage.STORAGE_AVAILABLE_KEY_, '1');
this.storage_.removeItem(
goog.storage.mechanism.HTML5WebStorage.STORAGE_AVAILABLE_KEY_);
return true;
} catch (e) {
return false;
}
};
/** @override */
goog.storage.mechanism.HTML5WebStorage.prototype.set = function(key, value) {
/** @preserveTry */
try {
// May throw an exception if storage quota is exceeded.
this.storage_.setItem(key, value);
} catch (e) {
// In Safari Private mode, conforming to the W3C spec, invoking
// Storage.prototype.setItem will allways throw a QUOTA_EXCEEDED_ERR
// exception. Since it's impossible to verify if we're in private browsing
// mode, we throw a different exception if the storage is empty.
if (this.storage_.length == 0) {
throw goog.storage.mechanism.ErrorCode.STORAGE_DISABLED;
} else {
throw goog.storage.mechanism.ErrorCode.QUOTA_EXCEEDED;
}
}
};
/** @override */
goog.storage.mechanism.HTML5WebStorage.prototype.get = function(key) {
// According to W3C specs, values can be of any type. 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://www.w3.org/TR/2009/WD-webstorage-20091029/#the-storage-interface
var value = this.storage_.getItem(key);
if (!goog.isString(value) && !goog.isNull(value)) {
throw goog.storage.mechanism.ErrorCode.INVALID_VALUE;
}
return value;
};
/** @override */
goog.storage.mechanism.HTML5WebStorage.prototype.remove = function(key) {
this.storage_.removeItem(key);
};
/** @override */
goog.storage.mechanism.HTML5WebStorage.prototype.getCount = function() {
return this.storage_.length;
};
/** @override */
goog.storage.mechanism.HTML5WebStorage.prototype.__iterator__ = function(
opt_keys) {
var i = 0;
var storage = this.storage_;
var newIter = new goog.iter.Iterator();
newIter.next = function() {
if (i >= storage.length) {
throw goog.iter.StopIteration;
}
var key = goog.asserts.assertString(storage.key(i++));
if (opt_keys) {
return key;
}
var value = storage.getItem(key);
// 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.HTML5WebStorage.prototype.clear = function() {
this.storage_.clear();
};
/**
* Gets the key for a given key index. If an index outside of
* [0..this.getCount()) is specified, this function returns null.
* @param {number} index A key index.
* @return {?string} A storage key, or null if the specified index is out of
* range.
*/
goog.storage.mechanism.HTML5WebStorage.prototype.key = function(index) {
return this.storage_.key(index);
};

View File

@@ -0,0 +1,283 @@
// 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}
*/
goog.storage.mechanism.IEUserData = function(storageKey, opt_storageNodeId) {
goog.base(this);
// 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_);
}
this.storageKey_ = storageKey;
/** @preserveTry */
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;
/**
* The document element used for storing data.
*
* @type {Element}
* @private
*/
goog.storage.mechanism.IEUserData.prototype.storageNode_ = null;
/**
* The key to store the data under.
*
* @type {?string}
* @private
*/
goog.storage.mechanism.IEUserData.prototype.storageKey_ = 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() {
/** @preserveTry */
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;
};

View File

@@ -0,0 +1,86 @@
// 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 Interface for storing, retieving and scanning data using some
* persistence mechanism.
*
*/
goog.provide('goog.storage.mechanism.IterableMechanism');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.iter');
goog.require('goog.iter.Iterator');
goog.require('goog.storage.mechanism.Mechanism');
/**
* Interface for all iterable storage mechanisms.
*
* @constructor
* @extends {goog.storage.mechanism.Mechanism}
*/
goog.storage.mechanism.IterableMechanism = function() {
goog.base(this);
};
goog.inherits(goog.storage.mechanism.IterableMechanism,
goog.storage.mechanism.Mechanism);
/**
* Get the number of stored key-value pairs.
*
* Could be overridden in a subclass, as the default implementation is not very
* efficient - it iterates over all keys.
*
* @return {number} Number of stored elements.
*/
goog.storage.mechanism.IterableMechanism.prototype.getCount = function() {
var count = 0;
goog.iter.forEach(this.__iterator__(true), function(key) {
goog.asserts.assertString(key);
count++;
});
return count;
};
/**
* Returns an iterator that iterates over the elements in the storage. Will
* throw goog.iter.StopIteration after the last element.
*
* @param {boolean=} opt_keys True to iterate over the keys. False to iterate
* over the values. The default value is false.
* @return {!goog.iter.Iterator} The iterator.
*/
goog.storage.mechanism.IterableMechanism.prototype.__iterator__ =
goog.abstractMethod;
/**
* Remove all key-value pairs.
*
* Could be overridden in a subclass, as the default implementation is not very
* efficient - it iterates over all keys.
*/
goog.storage.mechanism.IterableMechanism.prototype.clear = function() {
var keys = goog.iter.toArray(this.__iterator__(true));
var selfObj = this;
goog.array.forEach(keys, function(key) {
selfObj.remove(key);
});
};

View File

@@ -0,0 +1,117 @@
// 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 Unit tests for the iterable storage mechanism interface.
*
* These tests should be included in tests of any class extending
* goog.storage.mechanism.IterableMechanism.
*
*/
goog.provide('goog.storage.mechanism.iterableMechanismTester');
goog.require('goog.iter.Iterator');
goog.require('goog.storage.mechanism.IterableMechanism');
goog.require('goog.testing.asserts');
goog.setTestOnly('iterableMechanismTester');
var mechanism = null;
function testCount() {
if (!mechanism) {
return;
}
assertEquals(0, mechanism.getCount());
mechanism.set('first', 'one');
assertEquals(1, mechanism.getCount());
mechanism.set('second', 'two');
assertEquals(2, mechanism.getCount());
mechanism.set('first', 'three');
assertEquals(2, mechanism.getCount());
}
function testIteratorBasics() {
if (!mechanism) {
return;
}
mechanism.set('first', 'one');
assertEquals('first', mechanism.__iterator__(true).next());
assertEquals('one', mechanism.__iterator__(false).next());
var iterator = mechanism.__iterator__();
assertEquals('one', iterator.next());
assertEquals(goog.iter.StopIteration,
assertThrows(iterator.next));
}
function testIteratorWithTwoValues() {
if (!mechanism) {
return;
}
mechanism.set('first', 'one');
mechanism.set('second', 'two');
assertSameElements(['one', 'two'], goog.iter.toArray(mechanism));
assertSameElements(['first', 'second'],
goog.iter.toArray(mechanism.__iterator__(true)));
}
function testClear() {
if (!mechanism) {
return;
}
mechanism.set('first', 'one');
mechanism.set('second', 'two');
mechanism.clear();
assertNull(mechanism.get('first'));
assertNull(mechanism.get('second'));
assertEquals(0, mechanism.getCount());
assertEquals(goog.iter.StopIteration,
assertThrows(mechanism.__iterator__(true).next));
assertEquals(goog.iter.StopIteration,
assertThrows(mechanism.__iterator__(false).next));
}
function testClearClear() {
if (!mechanism) {
return;
}
mechanism.clear();
mechanism.clear();
assertEquals(0, mechanism.getCount());
}
function testIteratorWithWeirdKeys() {
if (!mechanism) {
return;
}
mechanism.set(' ', 'space');
mechanism.set('=+!@#$%^&*()-_\\|;:\'",./<>?[]{}~`', 'control');
mechanism.set(
'\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341', 'ten');
assertEquals(3, mechanism.getCount());
assertSameElements([
' ',
'=+!@#$%^&*()-_\\|;:\'",./<>?[]{}~`',
'\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341'
], goog.iter.toArray(mechanism.__iterator__(true)));
mechanism.clear();
assertEquals(0, mechanism.getCount());
}

View File

@@ -0,0 +1,56 @@
// 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 Abstract interface for storing and retrieving data using
* some persistence mechanism.
*
*/
goog.provide('goog.storage.mechanism.Mechanism');
/**
* Basic interface for all storage mechanisms.
*
* @constructor
*/
goog.storage.mechanism.Mechanism = function() {};
/**
* Set a value for a key.
*
* @param {string} key The key to set.
* @param {string} value The string to save.
*/
goog.storage.mechanism.Mechanism.prototype.set = goog.abstractMethod;
/**
* Get the value stored under a key.
*
* @param {string} key The key to get.
* @return {?string} The corresponding value, null if not found.
*/
goog.storage.mechanism.Mechanism.prototype.get = goog.abstractMethod;
/**
* Remove a key and its value.
*
* @param {string} key The key to remove.
*/
goog.storage.mechanism.Mechanism.prototype.remove = goog.abstractMethod;

View File

@@ -0,0 +1,113 @@
// 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 factory methods for selecting the best storage
* mechanism, depending on availability and needs.
*
*/
goog.provide('goog.storage.mechanism.mechanismfactory');
goog.require('goog.storage.mechanism.HTML5LocalStorage');
goog.require('goog.storage.mechanism.HTML5SessionStorage');
goog.require('goog.storage.mechanism.IEUserData');
goog.require('goog.storage.mechanism.IterableMechanism');
goog.require('goog.storage.mechanism.PrefixedMechanism');
/**
* The key to shared userData storage.
* @type {string}
*/
goog.storage.mechanism.mechanismfactory.USER_DATA_SHARED_KEY =
'UserDataSharedStore';
/**
* Returns the best local storage mechanism, or null if unavailable.
* Local storage means that the database is placed on user's computer.
* The key-value database is normally shared between all the code paths
* that request it, so using an optional namespace is recommended. This
* provides separation and makes key collisions unlikely.
*
* @param {string=} opt_namespace Restricts the visibility to given namespace.
* @return {goog.storage.mechanism.IterableMechanism} Created mechanism or null.
*/
goog.storage.mechanism.mechanismfactory.create = function(opt_namespace) {
return goog.storage.mechanism.mechanismfactory.createHTML5LocalStorage(
opt_namespace) ||
goog.storage.mechanism.mechanismfactory.createIEUserData(opt_namespace);
};
/**
* Returns an HTML5 local storage mechanism, or null if unavailable.
* Since the HTML5 local storage does not support namespaces natively,
* and the key-value database is shared between all the code paths
* that request it, it is recommended that an optional namespace is
* used to provide key separation employing a prefix.
*
* @param {string=} opt_namespace Restricts the visibility to given namespace.
* @return {goog.storage.mechanism.IterableMechanism} Created mechanism or null.
*/
goog.storage.mechanism.mechanismfactory.createHTML5LocalStorage = function(
opt_namespace) {
var storage = new goog.storage.mechanism.HTML5LocalStorage();
if (storage.isAvailable()) {
return opt_namespace ? new goog.storage.mechanism.PrefixedMechanism(
storage, opt_namespace) : storage;
}
return null;
};
/**
* Returns an HTML5 session storage mechanism, or null if unavailable.
* Since the HTML5 session storage does not support namespaces natively,
* and the key-value database is shared between all the code paths
* that request it, it is recommended that an optional namespace is
* used to provide key separation employing a prefix.
*
* @param {string=} opt_namespace Restricts the visibility to given namespace.
* @return {goog.storage.mechanism.IterableMechanism} Created mechanism or null.
*/
goog.storage.mechanism.mechanismfactory.createHTML5SessionStorage = function(
opt_namespace) {
var storage = new goog.storage.mechanism.HTML5SessionStorage();
if (storage.isAvailable()) {
return opt_namespace ? new goog.storage.mechanism.PrefixedMechanism(
storage, opt_namespace) : storage;
}
return null;
};
/**
* Returns an IE userData local storage mechanism, or null if unavailable.
* Using an optional namespace is recommended to provide separation and
* avoid key collisions.
*
* @param {string=} opt_namespace Restricts the visibility to given namespace.
* @return {goog.storage.mechanism.IterableMechanism} Created mechanism or null.
*/
goog.storage.mechanism.mechanismfactory.createIEUserData = function(
opt_namespace) {
var storage = new goog.storage.mechanism.IEUserData(opt_namespace ||
goog.storage.mechanism.mechanismfactory.USER_DATA_SHARED_KEY);
if (storage.isAvailable()) {
return storage;
}
return null;
};

View File

@@ -0,0 +1,91 @@
// 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 Unit tests for storage mechanism separation.
*
* These tests should be included by tests of any mechanism which natively
* implements namespaces. There is no need to include those tests for mechanisms
* extending goog.storage.mechanism.PrefixedMechanism. Make sure a different
* namespace is used for each object.
*
*/
goog.provide('goog.storage.mechanism.mechanismSeparationTester');
goog.require('goog.iter.Iterator');
goog.require('goog.storage.mechanism.IterableMechanism');
goog.require('goog.testing.asserts');
goog.setTestOnly('goog.storage.mechanism.mechanismSeparationTester');
var mechanism = null;
var mechanism_separate = null;
function testSeparateSet() {
if (!mechanism || !mechanism_separate) {
return;
}
mechanism.set('first', 'one');
assertNull(mechanism_separate.get('first'));
assertEquals(0, mechanism_separate.getCount());
assertEquals(goog.iter.StopIteration,
assertThrows(mechanism_separate.__iterator__().next));
}
function testSeparateSetInverse() {
if (!mechanism || !mechanism_separate) {
return;
}
mechanism.set('first', 'one');
mechanism_separate.set('first', 'two');
assertEquals('one', mechanism.get('first'));
assertEquals(1, mechanism.getCount());
var iterator = mechanism.__iterator__();
assertEquals('one', iterator.next());
assertEquals(goog.iter.StopIteration,
assertThrows(iterator.next));
}
function testSeparateRemove() {
if (!mechanism || !mechanism_separate) {
return;
}
mechanism.set('first', 'one');
mechanism_separate.remove('first');
assertEquals('one', mechanism.get('first'));
assertEquals(1, mechanism.getCount());
var iterator = mechanism.__iterator__();
assertEquals('one', iterator.next());
assertEquals(goog.iter.StopIteration,
assertThrows(iterator.next));
}
function testSeparateClean() {
if (!mechanism || !mechanism_separate) {
return;
}
mechanism_separate.set('first', 'two');
mechanism.clear();
assertEquals('two', mechanism_separate.get('first'));
assertEquals(1, mechanism_separate.getCount());
var iterator = mechanism_separate.__iterator__();
assertEquals('two', iterator.next());
assertEquals(goog.iter.StopIteration,
assertThrows(iterator.next));
}

View File

@@ -0,0 +1,87 @@
// 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 Unit tests for storage mechanism sharing.
*
* These tests should be included in tests of any storage mechanism in which
* separate mechanism instances share the same underlying storage. Most (if
* not all) storage mechanisms should have this property. If the mechanism
* employs namespaces, make sure the same namespace is used for both objects.
*
*/
goog.provide('goog.storage.mechanism.mechanismSharingTester');
goog.require('goog.iter.Iterator');
goog.require('goog.storage.mechanism.IterableMechanism');
goog.require('goog.testing.asserts');
goog.setTestOnly('goog.storage.mechanism.mechanismSharingTester');
var mechanism = null;
var mechanism_shared = null;
function testSharedSet() {
if (!mechanism || !mechanism_shared) {
return;
}
mechanism.set('first', 'one');
assertEquals('one', mechanism_shared.get('first'));
assertEquals(1, mechanism_shared.getCount());
var iterator = mechanism_shared.__iterator__();
assertEquals('one', iterator.next());
assertEquals(goog.iter.StopIteration,
assertThrows(iterator.next));
}
function testSharedSetInverse() {
if (!mechanism || !mechanism_shared) {
return;
}
mechanism_shared.set('first', 'two');
assertEquals('two', mechanism.get('first'));
assertEquals(1, mechanism.getCount());
var iterator = mechanism.__iterator__();
assertEquals('two', iterator.next());
assertEquals(goog.iter.StopIteration,
assertThrows(iterator.next));
}
function testSharedRemove() {
if (!mechanism || !mechanism_shared) {
return;
}
mechanism_shared.set('first', 'three');
mechanism.remove('first');
assertNull(mechanism_shared.get('first'));
assertEquals(0, mechanism_shared.getCount());
assertEquals(goog.iter.StopIteration,
assertThrows(mechanism_shared.__iterator__().next));
}
function testSharedClean() {
if (!mechanism || !mechanism_shared) {
return;
}
mechanism.set('first', 'four');
mechanism_shared.clear();
assertEquals(0, mechanism.getCount());
assertEquals(goog.iter.StopIteration,
assertThrows(mechanism.__iterator__().next));
}

View File

@@ -0,0 +1,200 @@
// 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 Unit tests for the abstract storage mechanism interface.
*
* These tests should be included in tests of any class extending
* goog.storage.mechanism.Mechanism.
*
*/
goog.provide('goog.storage.mechanism.mechanismTester');
goog.require('goog.storage.mechanism.ErrorCode');
goog.require('goog.storage.mechanism.HTML5LocalStorage');
goog.require('goog.storage.mechanism.Mechanism');
goog.require('goog.testing.asserts');
goog.require('goog.userAgent.product');
goog.require('goog.userAgent.product.isVersion');
goog.setTestOnly('goog.storage.mechanism.mechanismTester');
var mechanism = null;
var minimumQuota = 0;
function testSetGet() {
if (!mechanism) {
return;
}
mechanism.set('first', 'one');
assertEquals('one', mechanism.get('first'));
}
function testChange() {
if (!mechanism) {
return;
}
mechanism.set('first', 'one');
mechanism.set('first', 'two');
assertEquals('two', mechanism.get('first'));
}
function testRemove() {
if (!mechanism) {
return;
}
mechanism.set('first', 'one');
mechanism.remove('first');
assertNull(mechanism.get('first'));
}
function testSetRemoveSet() {
if (!mechanism) {
return;
}
mechanism.set('first', 'one');
mechanism.remove('first');
mechanism.set('first', 'one');
assertEquals('one', mechanism.get('first'));
}
function testRemoveRemove() {
if (!mechanism) {
return;
}
mechanism.remove('first');
mechanism.remove('first');
assertNull(mechanism.get('first'));
}
function testSetTwo() {
if (!mechanism) {
return;
}
mechanism.set('first', 'one');
mechanism.set('second', 'two');
assertEquals('one', mechanism.get('first'));
assertEquals('two', mechanism.get('second'));
}
function testChangeTwo() {
if (!mechanism) {
return;
}
mechanism.set('first', 'one');
mechanism.set('second', 'two');
mechanism.set('second', 'three');
mechanism.set('first', 'four');
assertEquals('four', mechanism.get('first'));
assertEquals('three', mechanism.get('second'));
}
function testSetRemoveThree() {
if (!mechanism) {
return;
}
mechanism.set('first', 'one');
mechanism.set('second', 'two');
mechanism.set('third', 'three');
mechanism.remove('second');
assertNull(mechanism.get('second'));
assertEquals('one', mechanism.get('first'));
assertEquals('three', mechanism.get('third'));
mechanism.remove('first');
assertNull(mechanism.get('first'));
assertEquals('three', mechanism.get('third'));
mechanism.remove('third');
assertNull(mechanism.get('third'));
}
function testEmptyValue() {
if (!mechanism) {
return;
}
mechanism.set('third', '');
assertEquals('', mechanism.get('third'));
}
function testWeirdKeys() {
if (!mechanism) {
return;
}
// Some weird keys. We leave out some tests for some browsers where they
// trigger browser bugs, and where the keys are too obscure to prepare a
// workaround.
mechanism.set(' ', 'space');
mechanism.set('=+!@#$%^&*()-_\\|;:\'",./<>?[]{}~`', 'control');
mechanism.set(
'\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341', 'ten');
mechanism.set('\0', 'null');
mechanism.set('\0\0', 'double null');
mechanism.set('\0A', 'null A');
mechanism.set('', 'zero');
assertEquals('space', mechanism.get(' '));
assertEquals('control', mechanism.get('=+!@#$%^&*()-_\\|;:\'",./<>?[]{}~`'));
assertEquals('ten', mechanism.get(
'\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341'));
if (!goog.userAgent.IE) {
// IE does not properly handle nulls in HTML5 localStorage keys (IE8, IE9).
// https://connect.microsoft.com/IE/feedback/details/667799/
assertEquals('null', mechanism.get('\0'));
assertEquals('double null', mechanism.get('\0\0'));
assertEquals('null A', mechanism.get('\0A'));
}
if (!goog.userAgent.GECKO) {
// Firefox does not properly handle the empty key (FF 3.5, 3.6, 4.0).
// https://bugzilla.mozilla.org/show_bug.cgi?id=510849
assertEquals('zero', mechanism.get(''));
}
}
function testQuota() {
if (!mechanism) {
return;
}
// This test might crash Safari 4, so it is disabled for this version.
// It works fine on Safari 3 and Safari 5.
if (goog.userAgent.product.SAFARI &&
goog.userAgent.product.isVersion(4) &&
!goog.userAgent.product.isVersion(5)) {
return;
}
var buffer = '\u03ff'; // 2 bytes
var savedBytes = 0;
try {
while (buffer.length < minimumQuota) {
buffer = buffer + buffer;
mechanism.set('foo', buffer);
savedBytes = buffer.length;
}
} catch (ex) {
if (ex != goog.storage.mechanism.ErrorCode.QUOTA_EXCEEDED) {
throw ex;
}
}
mechanism.remove('foo');
assertTrue(savedBytes >= minimumQuota);
}

View File

@@ -0,0 +1,97 @@
// 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 Wraps an iterable storage mechanism and creates artificial
* namespaces using a prefix in the global namespace.
*
*/
goog.provide('goog.storage.mechanism.PrefixedMechanism');
goog.require('goog.iter.Iterator');
goog.require('goog.storage.mechanism.IterableMechanism');
/**
* Wraps an iterable storage mechanism and creates artificial namespaces.
*
* @param {!goog.storage.mechanism.IterableMechanism} mechanism Underlying
* iterable storage mechanism.
* @param {string} prefix Prefix for creating an artificial namespace.
* @constructor
* @extends {goog.storage.mechanism.IterableMechanism}
*/
goog.storage.mechanism.PrefixedMechanism = function(mechanism, prefix) {
goog.base(this);
this.mechanism_ = mechanism;
this.prefix_ = prefix + '::';
};
goog.inherits(goog.storage.mechanism.PrefixedMechanism,
goog.storage.mechanism.IterableMechanism);
/**
* The mechanism to be prefixed.
*
* @type {goog.storage.mechanism.IterableMechanism}
* @private
*/
goog.storage.mechanism.PrefixedMechanism.prototype.mechanism_ = null;
/**
* The prefix for creating artificial namespaces.
*
* @type {string}
* @private
*/
goog.storage.mechanism.PrefixedMechanism.prototype.prefix_ = '';
/** @override */
goog.storage.mechanism.PrefixedMechanism.prototype.set = function(key, value) {
this.mechanism_.set(this.prefix_ + key, value);
};
/** @override */
goog.storage.mechanism.PrefixedMechanism.prototype.get = function(key) {
return this.mechanism_.get(this.prefix_ + key);
};
/** @override */
goog.storage.mechanism.PrefixedMechanism.prototype.remove = function(key) {
this.mechanism_.remove(this.prefix_ + key);
};
/** @override */
goog.storage.mechanism.PrefixedMechanism.prototype.__iterator__ = function(
opt_keys) {
var subIter = this.mechanism_.__iterator__(true);
var selfObj = this;
var newIter = new goog.iter.Iterator();
newIter.next = function() {
var key = /** @type {string} */ (subIter.next());
while (key.substr(0, selfObj.prefix_.length) != selfObj.prefix_) {
key = /** @type {string} */ (subIter.next());
}
return opt_keys ? key.substr(selfObj.prefix_.length) :
selfObj.mechanism_.get(key);
};
return newIter;
};