Working production build in docs subdirectory.
This commit is contained in:
parent
bb7be028e6
commit
a5204c66b9
644 changed files with 134256 additions and 53616 deletions
1665
resources/public/target/cljsbuild-compiler-1/goog/array/array.js
Normal file
1665
resources/public/target/cljsbuild-compiler-1/goog/array/array.js
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,369 @@
|
|||
// Copyright 2008 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 Utilities to check the preconditions, postconditions and
|
||||
* invariants runtime.
|
||||
*
|
||||
* Methods in this package should be given special treatment by the compiler
|
||||
* for type-inference. For example, <code>goog.asserts.assert(foo)</code>
|
||||
* will restrict <code>foo</code> to a truthy value.
|
||||
*
|
||||
* The compiler has an option to disable asserts. So code like:
|
||||
* <code>
|
||||
* var x = goog.asserts.assert(foo()); goog.asserts.assert(bar());
|
||||
* </code>
|
||||
* will be transformed into:
|
||||
* <code>
|
||||
* var x = foo();
|
||||
* </code>
|
||||
* The compiler will leave in foo() (because its return value is used),
|
||||
* but it will remove bar() because it assumes it does not have side-effects.
|
||||
*
|
||||
* @author agrieve@google.com (Andrew Grieve)
|
||||
*/
|
||||
|
||||
goog.provide('goog.asserts');
|
||||
goog.provide('goog.asserts.AssertionError');
|
||||
|
||||
goog.require('goog.debug.Error');
|
||||
goog.require('goog.dom.NodeType');
|
||||
goog.require('goog.string');
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Whether to strip out asserts or to leave them in.
|
||||
*/
|
||||
goog.define('goog.asserts.ENABLE_ASSERTS', goog.DEBUG);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Error object for failed assertions.
|
||||
* @param {string} messagePattern The pattern that was used to form message.
|
||||
* @param {!Array<*>} messageArgs The items to substitute into the pattern.
|
||||
* @constructor
|
||||
* @extends {goog.debug.Error}
|
||||
* @final
|
||||
*/
|
||||
goog.asserts.AssertionError = function(messagePattern, messageArgs) {
|
||||
messageArgs.unshift(messagePattern);
|
||||
goog.debug.Error.call(this, goog.string.subs.apply(null, messageArgs));
|
||||
// Remove the messagePattern afterwards to avoid permanently modifying the
|
||||
// passed in array.
|
||||
messageArgs.shift();
|
||||
|
||||
/**
|
||||
* The message pattern used to format the error message. Error handlers can
|
||||
* use this to uniquely identify the assertion.
|
||||
* @type {string}
|
||||
*/
|
||||
this.messagePattern = messagePattern;
|
||||
};
|
||||
goog.inherits(goog.asserts.AssertionError, goog.debug.Error);
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.asserts.AssertionError.prototype.name = 'AssertionError';
|
||||
|
||||
|
||||
/**
|
||||
* The default error handler.
|
||||
* @param {!goog.asserts.AssertionError} e The exception to be handled.
|
||||
*/
|
||||
goog.asserts.DEFAULT_ERROR_HANDLER = function(e) {
|
||||
throw e;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The handler responsible for throwing or logging assertion errors.
|
||||
* @private {function(!goog.asserts.AssertionError)}
|
||||
*/
|
||||
goog.asserts.errorHandler_ = goog.asserts.DEFAULT_ERROR_HANDLER;
|
||||
|
||||
|
||||
/**
|
||||
* Throws an exception with the given message and "Assertion failed" prefixed
|
||||
* onto it.
|
||||
* @param {string} defaultMessage The message to use if givenMessage is empty.
|
||||
* @param {Array<*>} defaultArgs The substitution arguments for defaultMessage.
|
||||
* @param {string|undefined} givenMessage Message supplied by the caller.
|
||||
* @param {Array<*>} givenArgs The substitution arguments for givenMessage.
|
||||
* @throws {goog.asserts.AssertionError} When the value is not a number.
|
||||
* @private
|
||||
*/
|
||||
goog.asserts.doAssertFailure_ = function(
|
||||
defaultMessage, defaultArgs, givenMessage, givenArgs) {
|
||||
var message = 'Assertion failed';
|
||||
if (givenMessage) {
|
||||
message += ': ' + givenMessage;
|
||||
var args = givenArgs;
|
||||
} else if (defaultMessage) {
|
||||
message += ': ' + defaultMessage;
|
||||
args = defaultArgs;
|
||||
}
|
||||
// The '' + works around an Opera 10 bug in the unit tests. Without it,
|
||||
// a stack trace is added to var message above. With this, a stack trace is
|
||||
// not added until this line (it causes the extra garbage to be added after
|
||||
// the assertion message instead of in the middle of it).
|
||||
var e = new goog.asserts.AssertionError('' + message, args || []);
|
||||
goog.asserts.errorHandler_(e);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets a custom error handler that can be used to customize the behavior of
|
||||
* assertion failures, for example by turning all assertion failures into log
|
||||
* messages.
|
||||
* @param {function(!goog.asserts.AssertionError)} errorHandler
|
||||
*/
|
||||
goog.asserts.setErrorHandler = function(errorHandler) {
|
||||
if (goog.asserts.ENABLE_ASSERTS) {
|
||||
goog.asserts.errorHandler_ = errorHandler;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the condition evaluates to true if goog.asserts.ENABLE_ASSERTS is
|
||||
* true.
|
||||
* @template T
|
||||
* @param {T} condition The condition to check.
|
||||
* @param {string=} opt_message Error message in case of failure.
|
||||
* @param {...*} var_args The items to substitute into the failure message.
|
||||
* @return {T} The value of the condition.
|
||||
* @throws {goog.asserts.AssertionError} When the condition evaluates to false.
|
||||
*/
|
||||
goog.asserts.assert = function(condition, opt_message, var_args) {
|
||||
if (goog.asserts.ENABLE_ASSERTS && !condition) {
|
||||
goog.asserts.doAssertFailure_(
|
||||
'', null, opt_message, Array.prototype.slice.call(arguments, 2));
|
||||
}
|
||||
return condition;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Fails if goog.asserts.ENABLE_ASSERTS is true. This function is useful in case
|
||||
* when we want to add a check in the unreachable area like switch-case
|
||||
* statement:
|
||||
*
|
||||
* <pre>
|
||||
* switch(type) {
|
||||
* case FOO: doSomething(); break;
|
||||
* case BAR: doSomethingElse(); break;
|
||||
* default: goog.asserts.fail('Unrecognized type: ' + type);
|
||||
* // We have only 2 types - "default:" section is unreachable code.
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @param {string=} opt_message Error message in case of failure.
|
||||
* @param {...*} var_args The items to substitute into the failure message.
|
||||
* @throws {goog.asserts.AssertionError} Failure.
|
||||
*/
|
||||
goog.asserts.fail = function(opt_message, var_args) {
|
||||
if (goog.asserts.ENABLE_ASSERTS) {
|
||||
goog.asserts.errorHandler_(
|
||||
new goog.asserts.AssertionError(
|
||||
'Failure' + (opt_message ? ': ' + opt_message : ''),
|
||||
Array.prototype.slice.call(arguments, 1)));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the value is a number if goog.asserts.ENABLE_ASSERTS is true.
|
||||
* @param {*} value The value to check.
|
||||
* @param {string=} opt_message Error message in case of failure.
|
||||
* @param {...*} var_args The items to substitute into the failure message.
|
||||
* @return {number} The value, guaranteed to be a number when asserts enabled.
|
||||
* @throws {goog.asserts.AssertionError} When the value is not a number.
|
||||
*/
|
||||
goog.asserts.assertNumber = function(value, opt_message, var_args) {
|
||||
if (goog.asserts.ENABLE_ASSERTS && !goog.isNumber(value)) {
|
||||
goog.asserts.doAssertFailure_(
|
||||
'Expected number but got %s: %s.', [goog.typeOf(value), value],
|
||||
opt_message, Array.prototype.slice.call(arguments, 2));
|
||||
}
|
||||
return /** @type {number} */ (value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the value is a string if goog.asserts.ENABLE_ASSERTS is true.
|
||||
* @param {*} value The value to check.
|
||||
* @param {string=} opt_message Error message in case of failure.
|
||||
* @param {...*} var_args The items to substitute into the failure message.
|
||||
* @return {string} The value, guaranteed to be a string when asserts enabled.
|
||||
* @throws {goog.asserts.AssertionError} When the value is not a string.
|
||||
*/
|
||||
goog.asserts.assertString = function(value, opt_message, var_args) {
|
||||
if (goog.asserts.ENABLE_ASSERTS && !goog.isString(value)) {
|
||||
goog.asserts.doAssertFailure_(
|
||||
'Expected string but got %s: %s.', [goog.typeOf(value), value],
|
||||
opt_message, Array.prototype.slice.call(arguments, 2));
|
||||
}
|
||||
return /** @type {string} */ (value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the value is a function if goog.asserts.ENABLE_ASSERTS is true.
|
||||
* @param {*} value The value to check.
|
||||
* @param {string=} opt_message Error message in case of failure.
|
||||
* @param {...*} var_args The items to substitute into the failure message.
|
||||
* @return {!Function} The value, guaranteed to be a function when asserts
|
||||
* enabled.
|
||||
* @throws {goog.asserts.AssertionError} When the value is not a function.
|
||||
*/
|
||||
goog.asserts.assertFunction = function(value, opt_message, var_args) {
|
||||
if (goog.asserts.ENABLE_ASSERTS && !goog.isFunction(value)) {
|
||||
goog.asserts.doAssertFailure_(
|
||||
'Expected function but got %s: %s.', [goog.typeOf(value), value],
|
||||
opt_message, Array.prototype.slice.call(arguments, 2));
|
||||
}
|
||||
return /** @type {!Function} */ (value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the value is an Object if goog.asserts.ENABLE_ASSERTS is true.
|
||||
* @param {*} value The value to check.
|
||||
* @param {string=} opt_message Error message in case of failure.
|
||||
* @param {...*} var_args The items to substitute into the failure message.
|
||||
* @return {!Object} The value, guaranteed to be a non-null object.
|
||||
* @throws {goog.asserts.AssertionError} When the value is not an object.
|
||||
*/
|
||||
goog.asserts.assertObject = function(value, opt_message, var_args) {
|
||||
if (goog.asserts.ENABLE_ASSERTS && !goog.isObject(value)) {
|
||||
goog.asserts.doAssertFailure_(
|
||||
'Expected object but got %s: %s.', [goog.typeOf(value), value],
|
||||
opt_message, Array.prototype.slice.call(arguments, 2));
|
||||
}
|
||||
return /** @type {!Object} */ (value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the value is an Array if goog.asserts.ENABLE_ASSERTS is true.
|
||||
* @param {*} value The value to check.
|
||||
* @param {string=} opt_message Error message in case of failure.
|
||||
* @param {...*} var_args The items to substitute into the failure message.
|
||||
* @return {!Array<?>} The value, guaranteed to be a non-null array.
|
||||
* @throws {goog.asserts.AssertionError} When the value is not an array.
|
||||
*/
|
||||
goog.asserts.assertArray = function(value, opt_message, var_args) {
|
||||
if (goog.asserts.ENABLE_ASSERTS && !goog.isArray(value)) {
|
||||
goog.asserts.doAssertFailure_(
|
||||
'Expected array but got %s: %s.', [goog.typeOf(value), value],
|
||||
opt_message, Array.prototype.slice.call(arguments, 2));
|
||||
}
|
||||
return /** @type {!Array<?>} */ (value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the value is a boolean if goog.asserts.ENABLE_ASSERTS is true.
|
||||
* @param {*} value The value to check.
|
||||
* @param {string=} opt_message Error message in case of failure.
|
||||
* @param {...*} var_args The items to substitute into the failure message.
|
||||
* @return {boolean} The value, guaranteed to be a boolean when asserts are
|
||||
* enabled.
|
||||
* @throws {goog.asserts.AssertionError} When the value is not a boolean.
|
||||
*/
|
||||
goog.asserts.assertBoolean = function(value, opt_message, var_args) {
|
||||
if (goog.asserts.ENABLE_ASSERTS && !goog.isBoolean(value)) {
|
||||
goog.asserts.doAssertFailure_(
|
||||
'Expected boolean but got %s: %s.', [goog.typeOf(value), value],
|
||||
opt_message, Array.prototype.slice.call(arguments, 2));
|
||||
}
|
||||
return /** @type {boolean} */ (value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the value is a DOM Element if goog.asserts.ENABLE_ASSERTS is true.
|
||||
* @param {*} value The value to check.
|
||||
* @param {string=} opt_message Error message in case of failure.
|
||||
* @param {...*} var_args The items to substitute into the failure message.
|
||||
* @return {!Element} The value, likely to be a DOM Element when asserts are
|
||||
* enabled.
|
||||
* @throws {goog.asserts.AssertionError} When the value is not an Element.
|
||||
*/
|
||||
goog.asserts.assertElement = function(value, opt_message, var_args) {
|
||||
if (goog.asserts.ENABLE_ASSERTS &&
|
||||
(!goog.isObject(value) || value.nodeType != goog.dom.NodeType.ELEMENT)) {
|
||||
goog.asserts.doAssertFailure_(
|
||||
'Expected Element but got %s: %s.', [goog.typeOf(value), value],
|
||||
opt_message, Array.prototype.slice.call(arguments, 2));
|
||||
}
|
||||
return /** @type {!Element} */ (value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the value is an instance of the user-defined type if
|
||||
* goog.asserts.ENABLE_ASSERTS is true.
|
||||
*
|
||||
* The compiler may tighten the type returned by this function.
|
||||
*
|
||||
* @param {?} value The value to check.
|
||||
* @param {function(new: T, ...)} type A user-defined constructor.
|
||||
* @param {string=} opt_message Error message in case of failure.
|
||||
* @param {...*} var_args The items to substitute into the failure message.
|
||||
* @throws {goog.asserts.AssertionError} When the value is not an instance of
|
||||
* type.
|
||||
* @return {T}
|
||||
* @template T
|
||||
*/
|
||||
goog.asserts.assertInstanceof = function(value, type, opt_message, var_args) {
|
||||
if (goog.asserts.ENABLE_ASSERTS && !(value instanceof type)) {
|
||||
goog.asserts.doAssertFailure_(
|
||||
'Expected instanceof %s but got %s.',
|
||||
[goog.asserts.getType_(type), goog.asserts.getType_(value)],
|
||||
opt_message, Array.prototype.slice.call(arguments, 3));
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Checks that no enumerable keys are present in Object.prototype. Such keys
|
||||
* would break most code that use {@code for (var ... in ...)} loops.
|
||||
*/
|
||||
goog.asserts.assertObjectPrototypeIsIntact = function() {
|
||||
for (var key in Object.prototype) {
|
||||
goog.asserts.fail(key + ' should not be enumerable in Object.prototype.');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the type of a value. If a constructor is passed, and a suitable
|
||||
* string cannot be found, 'unknown type name' will be returned.
|
||||
* @param {*} value A constructor, object, or primitive.
|
||||
* @return {string} The best display name for the value, or 'unknown type name'.
|
||||
* @private
|
||||
*/
|
||||
goog.asserts.getType_ = function(value) {
|
||||
if (value instanceof Function) {
|
||||
return value.displayName || value.name || 'unknown type name';
|
||||
} else if (value instanceof Object) {
|
||||
return value.constructor.displayName || value.constructor.name ||
|
||||
Object.prototype.toString.call(value);
|
||||
} else {
|
||||
return value === null ? 'null' : typeof value;
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
// Copyright 2015 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 Simple freelist.
|
||||
*
|
||||
* An anterative to goog.structs.SimplePool, it imposes the requirement that the
|
||||
* objects in the list contain a "next" property that can be used to maintain
|
||||
* the pool.
|
||||
*/
|
||||
|
||||
goog.provide('goog.async.FreeList');
|
||||
|
||||
|
||||
/**
|
||||
* @template ITEM
|
||||
*/
|
||||
goog.async.FreeList = goog.defineClass(null, {
|
||||
/**
|
||||
* @param {function():ITEM} create
|
||||
* @param {function(ITEM):void} reset
|
||||
* @param {number} limit
|
||||
*/
|
||||
constructor: function(create, reset, limit) {
|
||||
/** @private @const {number} */
|
||||
this.limit_ = limit;
|
||||
/** @private @const {function()} */
|
||||
this.create_ = create;
|
||||
/** @private @const {function(ITEM):void} */
|
||||
this.reset_ = reset;
|
||||
|
||||
/** @private {number} */
|
||||
this.occupants_ = 0;
|
||||
/** @private {ITEM} */
|
||||
this.head_ = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {ITEM}
|
||||
*/
|
||||
get: function() {
|
||||
var item;
|
||||
if (this.occupants_ > 0) {
|
||||
this.occupants_--;
|
||||
item = this.head_;
|
||||
this.head_ = item.next;
|
||||
item.next = null;
|
||||
} else {
|
||||
item = this.create_();
|
||||
}
|
||||
return item;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {ITEM} item An item available for possible future reuse.
|
||||
*/
|
||||
put: function(item) {
|
||||
this.reset_(item);
|
||||
if (this.occupants_ < this.limit_) {
|
||||
this.occupants_++;
|
||||
item.next = this.head_;
|
||||
this.head_ = item;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Visible for testing.
|
||||
* @package
|
||||
* @return {number}
|
||||
*/
|
||||
occupants: function() { return this.occupants_; }
|
||||
});
|
||||
|
|
@ -0,0 +1,265 @@
|
|||
// Copyright 2013 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 a function to schedule running a function as soon
|
||||
* as possible after the current JS execution stops and yields to the event
|
||||
* loop.
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.async.nextTick');
|
||||
goog.provide('goog.async.throwException');
|
||||
|
||||
goog.require('goog.debug.entryPointRegistry');
|
||||
goog.require('goog.dom.TagName');
|
||||
goog.require('goog.functions');
|
||||
goog.require('goog.labs.userAgent.browser');
|
||||
goog.require('goog.labs.userAgent.engine');
|
||||
|
||||
|
||||
/**
|
||||
* Throw an item without interrupting the current execution context. For
|
||||
* example, if processing a group of items in a loop, sometimes it is useful
|
||||
* to report an error while still allowing the rest of the batch to be
|
||||
* processed.
|
||||
* @param {*} exception
|
||||
*/
|
||||
goog.async.throwException = function(exception) {
|
||||
// Each throw needs to be in its own context.
|
||||
goog.global.setTimeout(function() { throw exception; }, 0);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Fires the provided callbacks as soon as possible after the current JS
|
||||
* execution context. setTimeout(…, 0) takes at least 4ms when called from
|
||||
* within another setTimeout(…, 0) for legacy reasons.
|
||||
*
|
||||
* This will not schedule the callback as a microtask (i.e. a task that can
|
||||
* preempt user input or networking callbacks). It is meant to emulate what
|
||||
* setTimeout(_, 0) would do if it were not throttled. If you desire microtask
|
||||
* behavior, use {@see goog.Promise} instead.
|
||||
*
|
||||
* @param {function(this:SCOPE)} callback Callback function to fire as soon as
|
||||
* possible.
|
||||
* @param {SCOPE=} opt_context Object in whose scope to call the listener.
|
||||
* @param {boolean=} opt_useSetImmediate Avoid the IE workaround that
|
||||
* ensures correctness at the cost of speed. See comments for details.
|
||||
* @template SCOPE
|
||||
*/
|
||||
goog.async.nextTick = function(callback, opt_context, opt_useSetImmediate) {
|
||||
var cb = callback;
|
||||
if (opt_context) {
|
||||
cb = goog.bind(callback, opt_context);
|
||||
}
|
||||
cb = goog.async.nextTick.wrapCallback_(cb);
|
||||
// Note we do allow callers to also request setImmediate if they are willing
|
||||
// to accept the possible tradeoffs of incorrectness in exchange for speed.
|
||||
// The IE fallback of readystate change is much slower. See useSetImmediate_
|
||||
// for details.
|
||||
if (goog.isFunction(goog.global.setImmediate) &&
|
||||
(opt_useSetImmediate || goog.async.nextTick.useSetImmediate_())) {
|
||||
goog.global.setImmediate(cb);
|
||||
return;
|
||||
}
|
||||
|
||||
// Look for and cache the custom fallback version of setImmediate.
|
||||
if (!goog.async.nextTick.setImmediate_) {
|
||||
goog.async.nextTick.setImmediate_ =
|
||||
goog.async.nextTick.getSetImmediateEmulator_();
|
||||
}
|
||||
goog.async.nextTick.setImmediate_(cb);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns whether should use setImmediate implementation currently on window.
|
||||
*
|
||||
* window.setImmediate was introduced and currently only supported by IE10+,
|
||||
* but due to a bug in the implementation it is not guaranteed that
|
||||
* setImmediate is faster than setTimeout nor that setImmediate N is before
|
||||
* setImmediate N+1. That is why we do not use the native version if
|
||||
* available. We do, however, call setImmediate if it is a non-native function
|
||||
* because that indicates that it has been replaced by goog.testing.MockClock
|
||||
* which we do want to support.
|
||||
* See
|
||||
* http://connect.microsoft.com/IE/feedback/details/801823/setimmediate-and-messagechannel-are-broken-in-ie10
|
||||
*
|
||||
* @return {boolean} Whether to use the implementation of setImmediate defined
|
||||
* on Window.
|
||||
* @private
|
||||
*/
|
||||
goog.async.nextTick.useSetImmediate_ = function() {
|
||||
// Not a browser environment.
|
||||
if (!goog.global.Window || !goog.global.Window.prototype) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// MS Edge has window.setImmediate natively, but it's not on Window.prototype.
|
||||
// Also, there's no clean way to detect if the goog.global.setImmediate has
|
||||
// been replaced by mockClock as its replacement also shows up as "[native
|
||||
// code]" when using toString. Therefore, just always use
|
||||
// goog.global.setImmediate for Edge. It's unclear if it suffers the same
|
||||
// issues as IE10/11, but based on
|
||||
// https://dev.modern.ie/testdrive/demos/setimmediatesorting/
|
||||
// it seems they've been working to ensure it's WAI.
|
||||
if (goog.labs.userAgent.browser.isEdge() ||
|
||||
goog.global.Window.prototype.setImmediate != goog.global.setImmediate) {
|
||||
// Something redefined setImmediate in which case we decide to use it (This
|
||||
// is so that we use the mockClock setImmediate).
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Cache for the setImmediate implementation.
|
||||
* @type {function(function())}
|
||||
* @private
|
||||
*/
|
||||
goog.async.nextTick.setImmediate_;
|
||||
|
||||
|
||||
/**
|
||||
* Determines the best possible implementation to run a function as soon as
|
||||
* the JS event loop is idle.
|
||||
* @return {function(function())} The "setImmediate" implementation.
|
||||
* @private
|
||||
*/
|
||||
goog.async.nextTick.getSetImmediateEmulator_ = function() {
|
||||
// Create a private message channel and use it to postMessage empty messages
|
||||
// to ourselves.
|
||||
/** @type {!Function|undefined} */
|
||||
var Channel = goog.global['MessageChannel'];
|
||||
// If MessageChannel is not available and we are in a browser, implement
|
||||
// an iframe based polyfill in browsers that have postMessage and
|
||||
// document.addEventListener. The latter excludes IE8 because it has a
|
||||
// synchronous postMessage implementation.
|
||||
if (typeof Channel === 'undefined' && typeof window !== 'undefined' &&
|
||||
window.postMessage && window.addEventListener &&
|
||||
// Presto (The old pre-blink Opera engine) has problems with iframes
|
||||
// and contentWindow.
|
||||
!goog.labs.userAgent.engine.isPresto()) {
|
||||
/** @constructor */
|
||||
Channel = function() {
|
||||
// Make an empty, invisible iframe.
|
||||
var iframe = /** @type {!HTMLIFrameElement} */ (
|
||||
document.createElement(String(goog.dom.TagName.IFRAME)));
|
||||
iframe.style.display = 'none';
|
||||
iframe.src = '';
|
||||
document.documentElement.appendChild(iframe);
|
||||
var win = iframe.contentWindow;
|
||||
var doc = win.document;
|
||||
doc.open();
|
||||
doc.write('');
|
||||
doc.close();
|
||||
// Do not post anything sensitive over this channel, as the workaround for
|
||||
// pages with file: origin could allow that information to be modified or
|
||||
// intercepted.
|
||||
var message = 'callImmediate' + Math.random();
|
||||
// The same origin policy rejects attempts to postMessage from file: urls
|
||||
// unless the origin is '*'.
|
||||
var origin = win.location.protocol == 'file:' ?
|
||||
'*' :
|
||||
win.location.protocol + '//' + win.location.host;
|
||||
var onmessage = goog.bind(function(e) {
|
||||
// Validate origin and message to make sure that this message was
|
||||
// intended for us. If the origin is set to '*' (see above) only the
|
||||
// message needs to match since, for example, '*' != 'file://'. Allowing
|
||||
// the wildcard is ok, as we are not concerned with security here.
|
||||
if ((origin != '*' && e.origin != origin) || e.data != message) {
|
||||
return;
|
||||
}
|
||||
this['port1'].onmessage();
|
||||
}, this);
|
||||
win.addEventListener('message', onmessage, false);
|
||||
this['port1'] = {};
|
||||
this['port2'] = {
|
||||
postMessage: function() { win.postMessage(message, origin); }
|
||||
};
|
||||
};
|
||||
}
|
||||
if (typeof Channel !== 'undefined' && !goog.labs.userAgent.browser.isIE()) {
|
||||
// Exclude all of IE due to
|
||||
// http://codeforhire.com/2013/09/21/setimmediate-and-messagechannel-broken-on-internet-explorer-10/
|
||||
// which allows starving postMessage with a busy setTimeout loop.
|
||||
// This currently affects IE10 and IE11 which would otherwise be able
|
||||
// to use the postMessage based fallbacks.
|
||||
var channel = new Channel();
|
||||
// Use a fifo linked list to call callbacks in the right order.
|
||||
var head = {};
|
||||
var tail = head;
|
||||
channel['port1'].onmessage = function() {
|
||||
if (goog.isDef(head.next)) {
|
||||
head = head.next;
|
||||
var cb = head.cb;
|
||||
head.cb = null;
|
||||
cb();
|
||||
}
|
||||
};
|
||||
return function(cb) {
|
||||
tail.next = {cb: cb};
|
||||
tail = tail.next;
|
||||
channel['port2'].postMessage(0);
|
||||
};
|
||||
}
|
||||
// Implementation for IE6 to IE10: Script elements fire an asynchronous
|
||||
// onreadystatechange event when inserted into the DOM.
|
||||
if (typeof document !== 'undefined' &&
|
||||
'onreadystatechange' in
|
||||
document.createElement(String(goog.dom.TagName.SCRIPT))) {
|
||||
return function(cb) {
|
||||
var script = document.createElement(String(goog.dom.TagName.SCRIPT));
|
||||
script.onreadystatechange = function() {
|
||||
// Clean up and call the callback.
|
||||
script.onreadystatechange = null;
|
||||
script.parentNode.removeChild(script);
|
||||
script = null;
|
||||
cb();
|
||||
cb = null;
|
||||
};
|
||||
document.documentElement.appendChild(script);
|
||||
};
|
||||
}
|
||||
// Fall back to setTimeout with 0. In browsers this creates a delay of 5ms
|
||||
// or more.
|
||||
// NOTE(user): This fallback is used for IE11.
|
||||
return function(cb) {
|
||||
goog.global.setTimeout(/** @type {function()} */ (cb), 0);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Helper function that is overrided to protect callbacks with entry point
|
||||
* monitor if the application monitors entry points.
|
||||
* @param {function()} callback Callback function to fire as soon as possible.
|
||||
* @return {function()} The wrapped callback.
|
||||
* @private
|
||||
*/
|
||||
goog.async.nextTick.wrapCallback_ = goog.functions.identity;
|
||||
|
||||
|
||||
// Register the callback function as an entry point, so that it can be
|
||||
// monitored for exception handling, etc. This has to be done in this file
|
||||
// since it requires special code to handle all browsers.
|
||||
goog.debug.entryPointRegistry.register(
|
||||
/**
|
||||
* @param {function(!Function): !Function} transformer The transforming
|
||||
* function.
|
||||
*/
|
||||
function(transformer) { goog.async.nextTick.wrapCallback_ = transformer; });
|
||||
136
resources/public/target/cljsbuild-compiler-1/goog/async/run.js
Normal file
136
resources/public/target/cljsbuild-compiler-1/goog/async/run.js
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
// Copyright 2013 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.
|
||||
|
||||
goog.provide('goog.async.run');
|
||||
|
||||
goog.require('goog.async.WorkQueue');
|
||||
goog.require('goog.async.nextTick');
|
||||
goog.require('goog.async.throwException');
|
||||
|
||||
|
||||
/**
|
||||
* Fires the provided callback just before the current callstack unwinds, or as
|
||||
* soon as possible after the current JS execution context.
|
||||
* @param {function(this:THIS)} callback
|
||||
* @param {THIS=} opt_context Object to use as the "this value" when calling
|
||||
* the provided function.
|
||||
* @template THIS
|
||||
*/
|
||||
goog.async.run = function(callback, opt_context) {
|
||||
if (!goog.async.run.schedule_) {
|
||||
goog.async.run.initializeRunner_();
|
||||
}
|
||||
if (!goog.async.run.workQueueScheduled_) {
|
||||
// Nothing is currently scheduled, schedule it now.
|
||||
goog.async.run.schedule_();
|
||||
goog.async.run.workQueueScheduled_ = true;
|
||||
}
|
||||
|
||||
goog.async.run.workQueue_.add(callback, opt_context);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the function to use to process the work queue.
|
||||
* @private
|
||||
*/
|
||||
goog.async.run.initializeRunner_ = function() {
|
||||
// If native Promises are available in the browser, just schedule the callback
|
||||
// on a fulfilled promise, which is specified to be async, but as fast as
|
||||
// possible. Use goog.global.Promise instead of just Promise because the
|
||||
// relevant externs may be missing, and don't alias it because this could
|
||||
// confuse the compiler into thinking the polyfill is required when it should
|
||||
// be treated as optional.
|
||||
if (String(goog.global.Promise).indexOf('[native code]') != -1) {
|
||||
var promise = goog.global.Promise.resolve(undefined);
|
||||
goog.async.run.schedule_ = function() {
|
||||
promise.then(goog.async.run.processWorkQueue);
|
||||
};
|
||||
} else {
|
||||
goog.async.run.schedule_ = function() {
|
||||
goog.async.nextTick(goog.async.run.processWorkQueue);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Forces goog.async.run to use nextTick instead of Promise.
|
||||
*
|
||||
* This should only be done in unit tests. It's useful because MockClock
|
||||
* replaces nextTick, but not the browser Promise implementation, so it allows
|
||||
* Promise-based code to be tested with MockClock.
|
||||
*
|
||||
* However, we also want to run promises if the MockClock is no longer in
|
||||
* control so we schedule a backup "setTimeout" to the unmocked timeout if
|
||||
* provided.
|
||||
*
|
||||
* @param {function(function())=} opt_realSetTimeout
|
||||
*/
|
||||
goog.async.run.forceNextTick = function(opt_realSetTimeout) {
|
||||
goog.async.run.schedule_ = function() {
|
||||
goog.async.nextTick(goog.async.run.processWorkQueue);
|
||||
if (opt_realSetTimeout) {
|
||||
opt_realSetTimeout(goog.async.run.processWorkQueue);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The function used to schedule work asynchronousely.
|
||||
* @private {function()}
|
||||
*/
|
||||
goog.async.run.schedule_;
|
||||
|
||||
|
||||
/** @private {boolean} */
|
||||
goog.async.run.workQueueScheduled_ = false;
|
||||
|
||||
|
||||
/** @private {!goog.async.WorkQueue} */
|
||||
goog.async.run.workQueue_ = new goog.async.WorkQueue();
|
||||
|
||||
|
||||
if (goog.DEBUG) {
|
||||
/**
|
||||
* Reset the work queue. Only available for tests in debug mode.
|
||||
*/
|
||||
goog.async.run.resetQueue = function() {
|
||||
goog.async.run.workQueueScheduled_ = false;
|
||||
goog.async.run.workQueue_ = new goog.async.WorkQueue();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Run any pending goog.async.run work items. This function is not intended
|
||||
* for general use, but for use by entry point handlers to run items ahead of
|
||||
* goog.async.nextTick.
|
||||
*/
|
||||
goog.async.run.processWorkQueue = function() {
|
||||
// NOTE: additional work queue items may be added while processing.
|
||||
var item = null;
|
||||
while (item = goog.async.run.workQueue_.remove()) {
|
||||
try {
|
||||
item.fn.call(item.scope);
|
||||
} catch (e) {
|
||||
goog.async.throwException(e);
|
||||
}
|
||||
goog.async.run.workQueue_.returnUnused(item);
|
||||
}
|
||||
|
||||
// There are no more work items, allow processing to be scheduled again.
|
||||
goog.async.run.workQueueScheduled_ = false;
|
||||
};
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
// Copyright 2015 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.
|
||||
|
||||
goog.provide('goog.async.WorkItem');
|
||||
goog.provide('goog.async.WorkQueue');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.async.FreeList');
|
||||
|
||||
|
||||
// TODO(johnlenz): generalize the WorkQueue if this is used by more
|
||||
// than goog.async.run.
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A low GC workqueue. The key elements of this design:
|
||||
* - avoids the need for goog.bind or equivalent by carrying scope
|
||||
* - avoids the need for array reallocation by using a linked list
|
||||
* - minimizes work entry objects allocation by recycling objects
|
||||
* @constructor
|
||||
* @final
|
||||
* @struct
|
||||
*/
|
||||
goog.async.WorkQueue = function() {
|
||||
this.workHead_ = null;
|
||||
this.workTail_ = null;
|
||||
};
|
||||
|
||||
|
||||
/** @define {number} The maximum number of entries to keep for recycling. */
|
||||
goog.define('goog.async.WorkQueue.DEFAULT_MAX_UNUSED', 100);
|
||||
|
||||
|
||||
/** @const @private {goog.async.FreeList<goog.async.WorkItem>} */
|
||||
goog.async.WorkQueue.freelist_ = new goog.async.FreeList(
|
||||
function() { return new goog.async.WorkItem(); },
|
||||
function(item) { item.reset(); }, goog.async.WorkQueue.DEFAULT_MAX_UNUSED);
|
||||
|
||||
|
||||
/**
|
||||
* @param {function()} fn
|
||||
* @param {Object|null|undefined} scope
|
||||
*/
|
||||
goog.async.WorkQueue.prototype.add = function(fn, scope) {
|
||||
var item = this.getUnusedItem_();
|
||||
item.set(fn, scope);
|
||||
|
||||
if (this.workTail_) {
|
||||
this.workTail_.next = item;
|
||||
this.workTail_ = item;
|
||||
} else {
|
||||
goog.asserts.assert(!this.workHead_);
|
||||
this.workHead_ = item;
|
||||
this.workTail_ = item;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {goog.async.WorkItem}
|
||||
*/
|
||||
goog.async.WorkQueue.prototype.remove = function() {
|
||||
var item = null;
|
||||
|
||||
if (this.workHead_) {
|
||||
item = this.workHead_;
|
||||
this.workHead_ = this.workHead_.next;
|
||||
if (!this.workHead_) {
|
||||
this.workTail_ = null;
|
||||
}
|
||||
item.next = null;
|
||||
}
|
||||
return item;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {goog.async.WorkItem} item
|
||||
*/
|
||||
goog.async.WorkQueue.prototype.returnUnused = function(item) {
|
||||
goog.async.WorkQueue.freelist_.put(item);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {goog.async.WorkItem}
|
||||
* @private
|
||||
*/
|
||||
goog.async.WorkQueue.prototype.getUnusedItem_ = function() {
|
||||
return goog.async.WorkQueue.freelist_.get();
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @final
|
||||
* @struct
|
||||
*/
|
||||
goog.async.WorkItem = function() {
|
||||
/** @type {?function()} */
|
||||
this.fn = null;
|
||||
/** @type {Object|null|undefined} */
|
||||
this.scope = null;
|
||||
/** @type {?goog.async.WorkItem} */
|
||||
this.next = null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {function()} fn
|
||||
* @param {Object|null|undefined} scope
|
||||
*/
|
||||
goog.async.WorkItem.prototype.set = function(fn, scope) {
|
||||
this.fn = fn;
|
||||
this.scope = scope;
|
||||
this.next = null;
|
||||
};
|
||||
|
||||
|
||||
/** Reset the work item so they don't prevent GC before reuse */
|
||||
goog.async.WorkItem.prototype.reset = function() {
|
||||
this.fn = null;
|
||||
this.scope = null;
|
||||
this.next = null;
|
||||
};
|
||||
2921
resources/public/target/cljsbuild-compiler-1/goog/base.js
Normal file
2921
resources/public/target/cljsbuild-compiler-1/goog/base.js
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,359 @@
|
|||
// Copyright 2007 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 Base64 en/decoding. Not much to say here except that we
|
||||
* work with decoded values in arrays of bytes. By "byte" I mean a number
|
||||
* in [0, 255].
|
||||
*
|
||||
* @author doughtie@google.com (Gavin Doughtie)
|
||||
*/
|
||||
|
||||
goog.provide('goog.crypt.base64');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.crypt');
|
||||
goog.require('goog.string');
|
||||
goog.require('goog.userAgent');
|
||||
goog.require('goog.userAgent.product');
|
||||
|
||||
// Static lookup maps, lazily populated by init_()
|
||||
|
||||
|
||||
/**
|
||||
* Maps bytes to characters.
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
goog.crypt.base64.byteToCharMap_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* Maps characters to bytes. Used for normal and websafe characters.
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
goog.crypt.base64.charToByteMap_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* Maps bytes to websafe characters.
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
goog.crypt.base64.byteToCharMapWebSafe_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* Our default alphabet, shared between
|
||||
* ENCODED_VALS and ENCODED_VALS_WEBSAFE
|
||||
* @type {string}
|
||||
*/
|
||||
goog.crypt.base64.ENCODED_VALS_BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +
|
||||
'abcdefghijklmnopqrstuvwxyz' +
|
||||
'0123456789';
|
||||
|
||||
|
||||
/**
|
||||
* Our default alphabet. Value 64 (=) is special; it means "nothing."
|
||||
* @type {string}
|
||||
*/
|
||||
goog.crypt.base64.ENCODED_VALS = goog.crypt.base64.ENCODED_VALS_BASE + '+/=';
|
||||
|
||||
|
||||
/**
|
||||
* Our websafe alphabet.
|
||||
* @type {string}
|
||||
*/
|
||||
goog.crypt.base64.ENCODED_VALS_WEBSAFE =
|
||||
goog.crypt.base64.ENCODED_VALS_BASE + '-_.';
|
||||
|
||||
|
||||
/**
|
||||
* White list of implementations with known-good native atob and btoa functions.
|
||||
* Listing these explicitly (via the ASSUME_* wrappers) benefits dead-code
|
||||
* removal in per-browser compilations.
|
||||
* @private {boolean}
|
||||
*/
|
||||
goog.crypt.base64.ASSUME_NATIVE_SUPPORT_ = goog.userAgent.GECKO ||
|
||||
(goog.userAgent.WEBKIT && !goog.userAgent.product.SAFARI) ||
|
||||
goog.userAgent.OPERA;
|
||||
|
||||
|
||||
/**
|
||||
* Does this browser have a working btoa function?
|
||||
* @private {boolean}
|
||||
*/
|
||||
goog.crypt.base64.HAS_NATIVE_ENCODE_ =
|
||||
goog.crypt.base64.ASSUME_NATIVE_SUPPORT_ ||
|
||||
typeof(goog.global.btoa) == 'function';
|
||||
|
||||
|
||||
/**
|
||||
* Does this browser have a working atob function?
|
||||
* We blacklist known-bad implementations:
|
||||
* - IE (10+) added atob() but it does not tolerate whitespace on the input.
|
||||
* @private {boolean}
|
||||
*/
|
||||
goog.crypt.base64.HAS_NATIVE_DECODE_ =
|
||||
goog.crypt.base64.ASSUME_NATIVE_SUPPORT_ ||
|
||||
(!goog.userAgent.product.SAFARI && !goog.userAgent.IE &&
|
||||
typeof(goog.global.atob) == 'function');
|
||||
|
||||
|
||||
/**
|
||||
* Base64-encode an array of bytes.
|
||||
*
|
||||
* @param {Array<number>|Uint8Array} input An array of bytes (numbers with
|
||||
* value in [0, 255]) to encode.
|
||||
* @param {boolean=} opt_webSafe True indicates we should use the alternative
|
||||
* alphabet, which does not require escaping for use in URLs.
|
||||
* @return {string} The base64 encoded string.
|
||||
*/
|
||||
goog.crypt.base64.encodeByteArray = function(input, opt_webSafe) {
|
||||
// Assert avoids runtime dependency on goog.isArrayLike, which helps reduce
|
||||
// size of jscompiler output, and which yields slight performance increase.
|
||||
goog.asserts.assert(
|
||||
goog.isArrayLike(input), 'encodeByteArray takes an array as a parameter');
|
||||
|
||||
goog.crypt.base64.init_();
|
||||
|
||||
var byteToCharMap = opt_webSafe ? goog.crypt.base64.byteToCharMapWebSafe_ :
|
||||
goog.crypt.base64.byteToCharMap_;
|
||||
|
||||
var output = [];
|
||||
|
||||
for (var i = 0; i < input.length; i += 3) {
|
||||
var byte1 = input[i];
|
||||
var haveByte2 = i + 1 < input.length;
|
||||
var byte2 = haveByte2 ? input[i + 1] : 0;
|
||||
var haveByte3 = i + 2 < input.length;
|
||||
var byte3 = haveByte3 ? input[i + 2] : 0;
|
||||
|
||||
var outByte1 = byte1 >> 2;
|
||||
var outByte2 = ((byte1 & 0x03) << 4) | (byte2 >> 4);
|
||||
var outByte3 = ((byte2 & 0x0F) << 2) | (byte3 >> 6);
|
||||
var outByte4 = byte3 & 0x3F;
|
||||
|
||||
if (!haveByte3) {
|
||||
outByte4 = 64;
|
||||
|
||||
if (!haveByte2) {
|
||||
outByte3 = 64;
|
||||
}
|
||||
}
|
||||
|
||||
output.push(
|
||||
byteToCharMap[outByte1], byteToCharMap[outByte2],
|
||||
byteToCharMap[outByte3], byteToCharMap[outByte4]);
|
||||
}
|
||||
|
||||
return output.join('');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Base64-encode a string.
|
||||
*
|
||||
* @param {string} input A string to encode.
|
||||
* @param {boolean=} opt_webSafe True indicates we should use the alternative
|
||||
* alphabet, which does not require escaping for use in URLs.
|
||||
* @return {string} The base64 encoded string.
|
||||
*/
|
||||
goog.crypt.base64.encodeString = function(input, opt_webSafe) {
|
||||
// Shortcut for browsers that implement
|
||||
// a native base64 encoder in the form of "btoa/atob"
|
||||
if (goog.crypt.base64.HAS_NATIVE_ENCODE_ && !opt_webSafe) {
|
||||
return goog.global.btoa(input);
|
||||
}
|
||||
return goog.crypt.base64.encodeByteArray(
|
||||
goog.crypt.stringToByteArray(input), opt_webSafe);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Base64-decode a string.
|
||||
*
|
||||
* @param {string} input Input to decode. Any whitespace is ignored, and the
|
||||
* input maybe encoded with either supported alphabet (or a mix thereof).
|
||||
* @param {boolean=} opt_webSafe True indicates we should use the alternative
|
||||
* alphabet, which does not require escaping for use in URLs. Note that
|
||||
* passing false may also still allow webSafe input decoding, when the
|
||||
* fallback decoder is used on browsers without native support.
|
||||
* @return {string} string representing the decoded value.
|
||||
*/
|
||||
goog.crypt.base64.decodeString = function(input, opt_webSafe) {
|
||||
// Shortcut for browsers that implement
|
||||
// a native base64 encoder in the form of "btoa/atob"
|
||||
if (goog.crypt.base64.HAS_NATIVE_DECODE_ && !opt_webSafe) {
|
||||
return goog.global.atob(input);
|
||||
}
|
||||
var output = '';
|
||||
function pushByte(b) { output += String.fromCharCode(b); }
|
||||
|
||||
goog.crypt.base64.decodeStringInternal_(input, pushByte);
|
||||
|
||||
return output;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Base64-decode a string to an Array of numbers.
|
||||
*
|
||||
* In base-64 decoding, groups of four characters are converted into three
|
||||
* bytes. If the encoder did not apply padding, the input length may not
|
||||
* be a multiple of 4.
|
||||
*
|
||||
* In this case, the last group will have fewer than 4 characters, and
|
||||
* padding will be inferred. If the group has one or two characters, it decodes
|
||||
* to one byte. If the group has three characters, it decodes to two bytes.
|
||||
*
|
||||
* @param {string} input Input to decode. Any whitespace is ignored, and the
|
||||
* input maybe encoded with either supported alphabet (or a mix thereof).
|
||||
* @param {boolean=} opt_ignored Unused parameter, retained for compatibility.
|
||||
* @return {!Array<number>} bytes representing the decoded value.
|
||||
*/
|
||||
goog.crypt.base64.decodeStringToByteArray = function(input, opt_ignored) {
|
||||
var output = [];
|
||||
function pushByte(b) { output.push(b); }
|
||||
|
||||
goog.crypt.base64.decodeStringInternal_(input, pushByte);
|
||||
|
||||
return output;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Base64-decode a string to a Uint8Array.
|
||||
*
|
||||
* Note that Uint8Array is not supported on older browsers, e.g. IE < 10.
|
||||
* @see http://caniuse.com/uint8array
|
||||
*
|
||||
* In base-64 decoding, groups of four characters are converted into three
|
||||
* bytes. If the encoder did not apply padding, the input length may not
|
||||
* be a multiple of 4.
|
||||
*
|
||||
* In this case, the last group will have fewer than 4 characters, and
|
||||
* padding will be inferred. If the group has one or two characters, it decodes
|
||||
* to one byte. If the group has three characters, it decodes to two bytes.
|
||||
*
|
||||
* @param {string} input Input to decode. Any whitespace is ignored, and the
|
||||
* input maybe encoded with either supported alphabet (or a mix thereof).
|
||||
* @return {!Uint8Array} bytes representing the decoded value.
|
||||
*/
|
||||
goog.crypt.base64.decodeStringToUint8Array = function(input) {
|
||||
goog.asserts.assert(
|
||||
!goog.userAgent.IE || goog.userAgent.isVersionOrHigher('10'),
|
||||
'Browser does not support typed arrays');
|
||||
var output = new Uint8Array(Math.ceil(input.length * 3 / 4));
|
||||
var outLen = 0;
|
||||
function pushByte(b) { output[outLen++] = b; }
|
||||
|
||||
goog.crypt.base64.decodeStringInternal_(input, pushByte);
|
||||
|
||||
return output.subarray(0, outLen);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} input Input to decode.
|
||||
* @param {function(number):void} pushByte result accumulator.
|
||||
* @private
|
||||
*/
|
||||
goog.crypt.base64.decodeStringInternal_ = function(input, pushByte) {
|
||||
goog.crypt.base64.init_();
|
||||
|
||||
var nextCharIndex = 0;
|
||||
/**
|
||||
* @param {number} default_val Used for end-of-input.
|
||||
* @return {number} The next 6-bit value, or the default for end-of-input.
|
||||
*/
|
||||
function getByte(default_val) {
|
||||
while (nextCharIndex < input.length) {
|
||||
var ch = input.charAt(nextCharIndex++);
|
||||
var b = goog.crypt.base64.charToByteMap_[ch];
|
||||
if (b != null) {
|
||||
return b; // Common case: decoded the char.
|
||||
}
|
||||
if (!goog.string.isEmptyOrWhitespace(ch)) {
|
||||
throw Error('Unknown base64 encoding at char: ' + ch);
|
||||
}
|
||||
// We encountered whitespace: loop around to the next input char.
|
||||
}
|
||||
return default_val; // No more input remaining.
|
||||
}
|
||||
|
||||
while (true) {
|
||||
var byte1 = getByte(-1);
|
||||
var byte2 = getByte(0);
|
||||
var byte3 = getByte(64);
|
||||
var byte4 = getByte(64);
|
||||
|
||||
// The common case is that all four bytes are present, so if we have byte4
|
||||
// we can skip over the truncated input special case handling.
|
||||
if (byte4 === 64) {
|
||||
if (byte1 === -1) {
|
||||
return; // Terminal case: no input left to decode.
|
||||
}
|
||||
// Here we know an intermediate number of bytes are missing.
|
||||
// The defaults for byte2, byte3 and byte4 apply the inferred padding
|
||||
// rules per the public API documentation. i.e: 1 byte
|
||||
// missing should yield 2 bytes of output, but 2 or 3 missing bytes yield
|
||||
// a single byte of output. (Recall that 64 corresponds the padding char).
|
||||
}
|
||||
|
||||
var outByte1 = (byte1 << 2) | (byte2 >> 4);
|
||||
pushByte(outByte1);
|
||||
|
||||
if (byte3 != 64) {
|
||||
var outByte2 = ((byte2 << 4) & 0xF0) | (byte3 >> 2);
|
||||
pushByte(outByte2);
|
||||
|
||||
if (byte4 != 64) {
|
||||
var outByte3 = ((byte3 << 6) & 0xC0) | byte4;
|
||||
pushByte(outByte3);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Lazy static initialization function. Called before
|
||||
* accessing any of the static map variables.
|
||||
* @private
|
||||
*/
|
||||
goog.crypt.base64.init_ = function() {
|
||||
if (!goog.crypt.base64.byteToCharMap_) {
|
||||
goog.crypt.base64.byteToCharMap_ = {};
|
||||
goog.crypt.base64.charToByteMap_ = {};
|
||||
goog.crypt.base64.byteToCharMapWebSafe_ = {};
|
||||
|
||||
// We want quick mappings back and forth, so we precompute two maps.
|
||||
for (var i = 0; i < goog.crypt.base64.ENCODED_VALS.length; i++) {
|
||||
goog.crypt.base64.byteToCharMap_[i] =
|
||||
goog.crypt.base64.ENCODED_VALS.charAt(i);
|
||||
goog.crypt.base64.charToByteMap_[goog.crypt.base64.byteToCharMap_[i]] = i;
|
||||
goog.crypt.base64.byteToCharMapWebSafe_[i] =
|
||||
goog.crypt.base64.ENCODED_VALS_WEBSAFE.charAt(i);
|
||||
|
||||
// Be forgiving when decoding and correctly decode both encodings.
|
||||
if (i >= goog.crypt.base64.ENCODED_VALS_BASE.length) {
|
||||
goog.crypt.base64
|
||||
.charToByteMap_[goog.crypt.base64.ENCODED_VALS_WEBSAFE.charAt(i)] =
|
||||
i;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
195
resources/public/target/cljsbuild-compiler-1/goog/crypt/crypt.js
Normal file
195
resources/public/target/cljsbuild-compiler-1/goog/crypt/crypt.js
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
// Copyright 2008 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 Namespace with crypto related helper functions.
|
||||
*/
|
||||
|
||||
goog.provide('goog.crypt');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.asserts');
|
||||
|
||||
|
||||
/**
|
||||
* Turns a string into an array of bytes; a "byte" being a JS number in the
|
||||
* range 0-255. Multi-byte characters are written as little-endian.
|
||||
* @param {string} str String value to arrify.
|
||||
* @return {!Array<number>} Array of numbers corresponding to the
|
||||
* UCS character codes of each character in str.
|
||||
*/
|
||||
goog.crypt.stringToByteArray = function(str) {
|
||||
var output = [], p = 0;
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
var c = str.charCodeAt(i);
|
||||
// NOTE: c <= 0xffff since JavaScript strings are UTF-16.
|
||||
if (c > 0xff) {
|
||||
output[p++] = c & 0xff;
|
||||
c >>= 8;
|
||||
}
|
||||
output[p++] = c;
|
||||
}
|
||||
return output;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Turns an array of numbers into the string given by the concatenation of the
|
||||
* characters to which the numbers correspond.
|
||||
* @param {!Uint8Array|!Array<number>} bytes Array of numbers representing
|
||||
* characters.
|
||||
* @return {string} Stringification of the array.
|
||||
*/
|
||||
goog.crypt.byteArrayToString = function(bytes) {
|
||||
var CHUNK_SIZE = 8192;
|
||||
|
||||
// Special-case the simple case for speed's sake.
|
||||
if (bytes.length <= CHUNK_SIZE) {
|
||||
return String.fromCharCode.apply(null, bytes);
|
||||
}
|
||||
|
||||
// The remaining logic splits conversion by chunks since
|
||||
// Function#apply() has a maximum parameter count.
|
||||
// See discussion: http://goo.gl/LrWmZ9
|
||||
|
||||
var str = '';
|
||||
for (var i = 0; i < bytes.length; i += CHUNK_SIZE) {
|
||||
var chunk = goog.array.slice(bytes, i, i + CHUNK_SIZE);
|
||||
str += String.fromCharCode.apply(null, chunk);
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Turns an array of numbers into the hex string given by the concatenation of
|
||||
* the hex values to which the numbers correspond.
|
||||
* @param {Uint8Array|Array<number>} array Array of numbers representing
|
||||
* characters.
|
||||
* @return {string} Hex string.
|
||||
*/
|
||||
goog.crypt.byteArrayToHex = function(array) {
|
||||
return goog.array
|
||||
.map(
|
||||
array,
|
||||
function(numByte) {
|
||||
var hexByte = numByte.toString(16);
|
||||
return hexByte.length > 1 ? hexByte : '0' + hexByte;
|
||||
})
|
||||
.join('');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Converts a hex string into an integer array.
|
||||
* @param {string} hexString Hex string of 16-bit integers (two characters
|
||||
* per integer).
|
||||
* @return {!Array<number>} Array of {0,255} integers for the given string.
|
||||
*/
|
||||
goog.crypt.hexToByteArray = function(hexString) {
|
||||
goog.asserts.assert(
|
||||
hexString.length % 2 == 0, 'Key string length must be multiple of 2');
|
||||
var arr = [];
|
||||
for (var i = 0; i < hexString.length; i += 2) {
|
||||
arr.push(parseInt(hexString.substring(i, i + 2), 16));
|
||||
}
|
||||
return arr;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Converts a JS string to a UTF-8 "byte" array.
|
||||
* @param {string} str 16-bit unicode string.
|
||||
* @return {!Array<number>} UTF-8 byte array.
|
||||
*/
|
||||
goog.crypt.stringToUtf8ByteArray = function(str) {
|
||||
// TODO(user): Use native implementations if/when available
|
||||
var out = [], p = 0;
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
var c = str.charCodeAt(i);
|
||||
if (c < 128) {
|
||||
out[p++] = c;
|
||||
} else if (c < 2048) {
|
||||
out[p++] = (c >> 6) | 192;
|
||||
out[p++] = (c & 63) | 128;
|
||||
} else if (
|
||||
((c & 0xFC00) == 0xD800) && (i + 1) < str.length &&
|
||||
((str.charCodeAt(i + 1) & 0xFC00) == 0xDC00)) {
|
||||
// Surrogate Pair
|
||||
c = 0x10000 + ((c & 0x03FF) << 10) + (str.charCodeAt(++i) & 0x03FF);
|
||||
out[p++] = (c >> 18) | 240;
|
||||
out[p++] = ((c >> 12) & 63) | 128;
|
||||
out[p++] = ((c >> 6) & 63) | 128;
|
||||
out[p++] = (c & 63) | 128;
|
||||
} else {
|
||||
out[p++] = (c >> 12) | 224;
|
||||
out[p++] = ((c >> 6) & 63) | 128;
|
||||
out[p++] = (c & 63) | 128;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Converts a UTF-8 byte array to JavaScript's 16-bit Unicode.
|
||||
* @param {Uint8Array|Array<number>} bytes UTF-8 byte array.
|
||||
* @return {string} 16-bit Unicode string.
|
||||
*/
|
||||
goog.crypt.utf8ByteArrayToString = function(bytes) {
|
||||
// TODO(user): Use native implementations if/when available
|
||||
var out = [], pos = 0, c = 0;
|
||||
while (pos < bytes.length) {
|
||||
var c1 = bytes[pos++];
|
||||
if (c1 < 128) {
|
||||
out[c++] = String.fromCharCode(c1);
|
||||
} else if (c1 > 191 && c1 < 224) {
|
||||
var c2 = bytes[pos++];
|
||||
out[c++] = String.fromCharCode((c1 & 31) << 6 | c2 & 63);
|
||||
} else if (c1 > 239 && c1 < 365) {
|
||||
// Surrogate Pair
|
||||
var c2 = bytes[pos++];
|
||||
var c3 = bytes[pos++];
|
||||
var c4 = bytes[pos++];
|
||||
var u = ((c1 & 7) << 18 | (c2 & 63) << 12 | (c3 & 63) << 6 | c4 & 63) -
|
||||
0x10000;
|
||||
out[c++] = String.fromCharCode(0xD800 + (u >> 10));
|
||||
out[c++] = String.fromCharCode(0xDC00 + (u & 1023));
|
||||
} else {
|
||||
var c2 = bytes[pos++];
|
||||
var c3 = bytes[pos++];
|
||||
out[c++] =
|
||||
String.fromCharCode((c1 & 15) << 12 | (c2 & 63) << 6 | c3 & 63);
|
||||
}
|
||||
}
|
||||
return out.join('');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* XOR two byte arrays.
|
||||
* @param {!Uint8Array|!Int8Array|!Array<number>} bytes1 Byte array 1.
|
||||
* @param {!Uint8Array|!Int8Array|!Array<number>} bytes2 Byte array 2.
|
||||
* @return {!Array<number>} Resulting XOR of the two byte arrays.
|
||||
*/
|
||||
goog.crypt.xorByteArray = function(bytes1, bytes2) {
|
||||
goog.asserts.assert(
|
||||
bytes1.length == bytes2.length, 'XOR array lengths must match');
|
||||
|
||||
var result = [];
|
||||
for (var i = 0; i < bytes1.length; i++) {
|
||||
result.push(bytes1[i] ^ bytes2[i]);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
632
resources/public/target/cljsbuild-compiler-1/goog/debug/debug.js
Normal file
632
resources/public/target/cljsbuild-compiler-1/goog/debug/debug.js
Normal file
|
|
@ -0,0 +1,632 @@
|
|||
// Copyright 2006 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 Logging and debugging utilities.
|
||||
*
|
||||
* @see ../demos/debug.html
|
||||
*/
|
||||
|
||||
goog.provide('goog.debug');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.debug.errorcontext');
|
||||
goog.require('goog.userAgent');
|
||||
|
||||
|
||||
/** @define {boolean} Whether logging should be enabled. */
|
||||
goog.define('goog.debug.LOGGING_ENABLED', goog.DEBUG);
|
||||
|
||||
|
||||
/** @define {boolean} Whether to force "sloppy" stack building. */
|
||||
goog.define('goog.debug.FORCE_SLOPPY_STACKS', false);
|
||||
|
||||
|
||||
/**
|
||||
* Catches onerror events fired by windows and similar objects.
|
||||
* @param {function(Object)} logFunc The function to call with the error
|
||||
* information.
|
||||
* @param {boolean=} opt_cancel Whether to stop the error from reaching the
|
||||
* browser.
|
||||
* @param {Object=} opt_target Object that fires onerror events.
|
||||
*/
|
||||
goog.debug.catchErrors = function(logFunc, opt_cancel, opt_target) {
|
||||
var target = opt_target || goog.global;
|
||||
var oldErrorHandler = target.onerror;
|
||||
var retVal = !!opt_cancel;
|
||||
|
||||
// Chrome interprets onerror return value backwards (http://crbug.com/92062)
|
||||
// until it was fixed in webkit revision r94061 (Webkit 535.3). This
|
||||
// workaround still needs to be skipped in Safari after the webkit change
|
||||
// gets pushed out in Safari.
|
||||
// See https://bugs.webkit.org/show_bug.cgi?id=67119
|
||||
if (goog.userAgent.WEBKIT && !goog.userAgent.isVersionOrHigher('535.3')) {
|
||||
retVal = !retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* New onerror handler for this target. This onerror handler follows the spec
|
||||
* according to
|
||||
* http://www.whatwg.org/specs/web-apps/current-work/#runtime-script-errors
|
||||
* The spec was changed in August 2013 to support receiving column information
|
||||
* and an error object for all scripts on the same origin or cross origin
|
||||
* scripts with the proper headers. See
|
||||
* https://mikewest.org/2013/08/debugging-runtime-errors-with-window-onerror
|
||||
*
|
||||
* @param {string} message The error message. For cross-origin errors, this
|
||||
* will be scrubbed to just "Script error.". For new browsers that have
|
||||
* updated to follow the latest spec, errors that come from origins that
|
||||
* have proper cross origin headers will not be scrubbed.
|
||||
* @param {string} url The URL of the script that caused the error. The URL
|
||||
* will be scrubbed to "" for cross origin scripts unless the script has
|
||||
* proper cross origin headers and the browser has updated to the latest
|
||||
* spec.
|
||||
* @param {number} line The line number in the script that the error
|
||||
* occurred on.
|
||||
* @param {number=} opt_col The optional column number that the error
|
||||
* occurred on. Only browsers that have updated to the latest spec will
|
||||
* include this.
|
||||
* @param {Error=} opt_error The optional actual error object for this
|
||||
* error that should include the stack. Only browsers that have updated
|
||||
* to the latest spec will inlude this parameter.
|
||||
* @return {boolean} Whether to prevent the error from reaching the browser.
|
||||
*/
|
||||
target.onerror = function(message, url, line, opt_col, opt_error) {
|
||||
if (oldErrorHandler) {
|
||||
oldErrorHandler(message, url, line, opt_col, opt_error);
|
||||
}
|
||||
logFunc({
|
||||
message: message,
|
||||
fileName: url,
|
||||
line: line,
|
||||
col: opt_col,
|
||||
error: opt_error
|
||||
});
|
||||
return retVal;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a string representing an object and all its properties.
|
||||
* @param {Object|null|undefined} obj Object to expose.
|
||||
* @param {boolean=} opt_showFn Show the functions as well as the properties,
|
||||
* default is false.
|
||||
* @return {string} The string representation of {@code obj}.
|
||||
*/
|
||||
goog.debug.expose = function(obj, opt_showFn) {
|
||||
if (typeof obj == 'undefined') {
|
||||
return 'undefined';
|
||||
}
|
||||
if (obj == null) {
|
||||
return 'NULL';
|
||||
}
|
||||
var str = [];
|
||||
|
||||
for (var x in obj) {
|
||||
if (!opt_showFn && goog.isFunction(obj[x])) {
|
||||
continue;
|
||||
}
|
||||
var s = x + ' = ';
|
||||
|
||||
try {
|
||||
s += obj[x];
|
||||
} catch (e) {
|
||||
s += '*** ' + e + ' ***';
|
||||
}
|
||||
str.push(s);
|
||||
}
|
||||
return str.join('\n');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a string representing a given primitive or object, and for an
|
||||
* object, all its properties and nested objects. NOTE: The output will include
|
||||
* Uids on all objects that were exposed. Any added Uids will be removed before
|
||||
* returning.
|
||||
* @param {*} obj Object to expose.
|
||||
* @param {boolean=} opt_showFn Also show properties that are functions (by
|
||||
* default, functions are omitted).
|
||||
* @return {string} A string representation of {@code obj}.
|
||||
*/
|
||||
goog.debug.deepExpose = function(obj, opt_showFn) {
|
||||
var str = [];
|
||||
|
||||
// Track any objects where deepExpose added a Uid, so they can be cleaned up
|
||||
// before return. We do this globally, rather than only on ancestors so that
|
||||
// if the same object appears in the output, you can see it.
|
||||
var uidsToCleanup = [];
|
||||
var ancestorUids = {};
|
||||
|
||||
var helper = function(obj, space) {
|
||||
var nestspace = space + ' ';
|
||||
|
||||
var indentMultiline = function(str) {
|
||||
return str.replace(/\n/g, '\n' + space);
|
||||
};
|
||||
|
||||
|
||||
try {
|
||||
if (!goog.isDef(obj)) {
|
||||
str.push('undefined');
|
||||
} else if (goog.isNull(obj)) {
|
||||
str.push('NULL');
|
||||
} else if (goog.isString(obj)) {
|
||||
str.push('"' + indentMultiline(obj) + '"');
|
||||
} else if (goog.isFunction(obj)) {
|
||||
str.push(indentMultiline(String(obj)));
|
||||
} else if (goog.isObject(obj)) {
|
||||
// Add a Uid if needed. The struct calls implicitly adds them.
|
||||
if (!goog.hasUid(obj)) {
|
||||
uidsToCleanup.push(obj);
|
||||
}
|
||||
var uid = goog.getUid(obj);
|
||||
if (ancestorUids[uid]) {
|
||||
str.push('*** reference loop detected (id=' + uid + ') ***');
|
||||
} else {
|
||||
ancestorUids[uid] = true;
|
||||
str.push('{');
|
||||
for (var x in obj) {
|
||||
if (!opt_showFn && goog.isFunction(obj[x])) {
|
||||
continue;
|
||||
}
|
||||
str.push('\n');
|
||||
str.push(nestspace);
|
||||
str.push(x + ' = ');
|
||||
helper(obj[x], nestspace);
|
||||
}
|
||||
str.push('\n' + space + '}');
|
||||
delete ancestorUids[uid];
|
||||
}
|
||||
} else {
|
||||
str.push(obj);
|
||||
}
|
||||
} catch (e) {
|
||||
str.push('*** ' + e + ' ***');
|
||||
}
|
||||
};
|
||||
|
||||
helper(obj, '');
|
||||
|
||||
// Cleanup any Uids that were added by the deepExpose.
|
||||
for (var i = 0; i < uidsToCleanup.length; i++) {
|
||||
goog.removeUid(uidsToCleanup[i]);
|
||||
}
|
||||
|
||||
return str.join('');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Recursively outputs a nested array as a string.
|
||||
* @param {Array<?>} arr The array.
|
||||
* @return {string} String representing nested array.
|
||||
*/
|
||||
goog.debug.exposeArray = function(arr) {
|
||||
var str = [];
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
if (goog.isArray(arr[i])) {
|
||||
str.push(goog.debug.exposeArray(arr[i]));
|
||||
} else {
|
||||
str.push(arr[i]);
|
||||
}
|
||||
}
|
||||
return '[ ' + str.join(', ') + ' ]';
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Normalizes the error/exception object between browsers.
|
||||
* @param {*} err Raw error object.
|
||||
* @return {!{
|
||||
* message: (?|undefined),
|
||||
* name: (?|undefined),
|
||||
* lineNumber: (?|undefined),
|
||||
* fileName: (?|undefined),
|
||||
* stack: (?|undefined)
|
||||
* }} Normalized error object.
|
||||
*/
|
||||
goog.debug.normalizeErrorObject = function(err) {
|
||||
var href = goog.getObjectByName('window.location.href');
|
||||
if (goog.isString(err)) {
|
||||
return {
|
||||
'message': err,
|
||||
'name': 'Unknown error',
|
||||
'lineNumber': 'Not available',
|
||||
'fileName': href,
|
||||
'stack': 'Not available'
|
||||
};
|
||||
}
|
||||
|
||||
var lineNumber, fileName;
|
||||
var threwError = false;
|
||||
|
||||
try {
|
||||
lineNumber = err.lineNumber || err.line || 'Not available';
|
||||
} catch (e) {
|
||||
// Firefox 2 sometimes throws an error when accessing 'lineNumber':
|
||||
// Message: Permission denied to get property UnnamedClass.lineNumber
|
||||
lineNumber = 'Not available';
|
||||
threwError = true;
|
||||
}
|
||||
|
||||
try {
|
||||
fileName = err.fileName || err.filename || err.sourceURL ||
|
||||
// $googDebugFname may be set before a call to eval to set the filename
|
||||
// that the eval is supposed to present.
|
||||
goog.global['$googDebugFname'] || href;
|
||||
} catch (e) {
|
||||
// Firefox 2 may also throw an error when accessing 'filename'.
|
||||
fileName = 'Not available';
|
||||
threwError = true;
|
||||
}
|
||||
|
||||
// The IE Error object contains only the name and the message.
|
||||
// The Safari Error object uses the line and sourceURL fields.
|
||||
if (threwError || !err.lineNumber || !err.fileName || !err.stack ||
|
||||
!err.message || !err.name) {
|
||||
return {
|
||||
'message': err.message || 'Not available',
|
||||
'name': err.name || 'UnknownError',
|
||||
'lineNumber': lineNumber,
|
||||
'fileName': fileName,
|
||||
'stack': err.stack || 'Not available'
|
||||
};
|
||||
}
|
||||
|
||||
// Standards error object
|
||||
// Typed !Object. Should be a subtype of the return type, but it's not.
|
||||
return /** @type {?} */ (err);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Converts an object to an Error using the object's toString if it's not
|
||||
* already an Error, adds a stacktrace if there isn't one, and optionally adds
|
||||
* an extra message.
|
||||
* @param {*} err The original thrown error, object, or string.
|
||||
* @param {string=} opt_message optional additional message to add to the
|
||||
* error.
|
||||
* @return {!Error} If err is an Error, it is enhanced and returned. Otherwise,
|
||||
* it is converted to an Error which is enhanced and returned.
|
||||
*/
|
||||
goog.debug.enhanceError = function(err, opt_message) {
|
||||
var error;
|
||||
if (!(err instanceof Error)) {
|
||||
error = Error(err);
|
||||
if (Error.captureStackTrace) {
|
||||
// Trim this function off the call stack, if we can.
|
||||
Error.captureStackTrace(error, goog.debug.enhanceError);
|
||||
}
|
||||
} else {
|
||||
error = err;
|
||||
}
|
||||
|
||||
if (!error.stack) {
|
||||
error.stack = goog.debug.getStacktrace(goog.debug.enhanceError);
|
||||
}
|
||||
if (opt_message) {
|
||||
// find the first unoccupied 'messageX' property
|
||||
var x = 0;
|
||||
while (error['message' + x]) {
|
||||
++x;
|
||||
}
|
||||
error['message' + x] = String(opt_message);
|
||||
}
|
||||
return error;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Converts an object to an Error using the object's toString if it's not
|
||||
* already an Error, adds a stacktrace if there isn't one, and optionally adds
|
||||
* context to the Error, which is reported by the closure error reporter.
|
||||
* @param {*} err The original thrown error, object, or string.
|
||||
* @param {!Object<string, string>=} opt_context Key-value context to add to the
|
||||
* Error.
|
||||
* @return {!Error} If err is an Error, it is enhanced and returned. Otherwise,
|
||||
* it is converted to an Error which is enhanced and returned.
|
||||
*/
|
||||
goog.debug.enhanceErrorWithContext = function(err, opt_context) {
|
||||
var error = goog.debug.enhanceError(err);
|
||||
if (opt_context) {
|
||||
for (var key in opt_context) {
|
||||
goog.debug.errorcontext.addErrorContext(error, key, opt_context[key]);
|
||||
}
|
||||
}
|
||||
return error;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the current stack trace. Simple and iterative - doesn't worry about
|
||||
* catching circular references or getting the args.
|
||||
* @param {number=} opt_depth Optional maximum depth to trace back to.
|
||||
* @return {string} A string with the function names of all functions in the
|
||||
* stack, separated by \n.
|
||||
* @suppress {es5Strict}
|
||||
*/
|
||||
goog.debug.getStacktraceSimple = function(opt_depth) {
|
||||
if (!goog.debug.FORCE_SLOPPY_STACKS) {
|
||||
var stack = goog.debug.getNativeStackTrace_(goog.debug.getStacktraceSimple);
|
||||
if (stack) {
|
||||
return stack;
|
||||
}
|
||||
// NOTE: browsers that have strict mode support also have native "stack"
|
||||
// properties. Fall-through for legacy browser support.
|
||||
}
|
||||
|
||||
var sb = [];
|
||||
var fn = arguments.callee.caller;
|
||||
var depth = 0;
|
||||
|
||||
while (fn && (!opt_depth || depth < opt_depth)) {
|
||||
sb.push(goog.debug.getFunctionName(fn));
|
||||
sb.push('()\n');
|
||||
|
||||
try {
|
||||
fn = fn.caller;
|
||||
} catch (e) {
|
||||
sb.push('[exception trying to get caller]\n');
|
||||
break;
|
||||
}
|
||||
depth++;
|
||||
if (depth >= goog.debug.MAX_STACK_DEPTH) {
|
||||
sb.push('[...long stack...]');
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (opt_depth && depth >= opt_depth) {
|
||||
sb.push('[...reached max depth limit...]');
|
||||
} else {
|
||||
sb.push('[end]');
|
||||
}
|
||||
|
||||
return sb.join('');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Max length of stack to try and output
|
||||
* @type {number}
|
||||
*/
|
||||
goog.debug.MAX_STACK_DEPTH = 50;
|
||||
|
||||
|
||||
/**
|
||||
* @param {Function} fn The function to start getting the trace from.
|
||||
* @return {?string}
|
||||
* @private
|
||||
*/
|
||||
goog.debug.getNativeStackTrace_ = function(fn) {
|
||||
var tempErr = new Error();
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(tempErr, fn);
|
||||
return String(tempErr.stack);
|
||||
} else {
|
||||
// IE10, only adds stack traces when an exception is thrown.
|
||||
try {
|
||||
throw tempErr;
|
||||
} catch (e) {
|
||||
tempErr = e;
|
||||
}
|
||||
var stack = tempErr.stack;
|
||||
if (stack) {
|
||||
return String(stack);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the current stack trace, either starting from the caller or starting
|
||||
* from a specified function that's currently on the call stack.
|
||||
* @param {?Function=} fn If provided, when collecting the stack trace all
|
||||
* frames above the topmost call to this function, including that call,
|
||||
* will be left out of the stack trace.
|
||||
* @return {string} Stack trace.
|
||||
* @suppress {es5Strict}
|
||||
*/
|
||||
goog.debug.getStacktrace = function(fn) {
|
||||
var stack;
|
||||
if (!goog.debug.FORCE_SLOPPY_STACKS) {
|
||||
// Try to get the stack trace from the environment if it is available.
|
||||
var contextFn = fn || goog.debug.getStacktrace;
|
||||
stack = goog.debug.getNativeStackTrace_(contextFn);
|
||||
}
|
||||
if (!stack) {
|
||||
// NOTE: browsers that have strict mode support also have native "stack"
|
||||
// properties. This function will throw in strict mode.
|
||||
stack = goog.debug.getStacktraceHelper_(fn || arguments.callee.caller, []);
|
||||
}
|
||||
return stack;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Private helper for getStacktrace().
|
||||
* @param {?Function} fn If provided, when collecting the stack trace all
|
||||
* frames above the topmost call to this function, including that call,
|
||||
* will be left out of the stack trace.
|
||||
* @param {Array<!Function>} visited List of functions visited so far.
|
||||
* @return {string} Stack trace starting from function fn.
|
||||
* @suppress {es5Strict}
|
||||
* @private
|
||||
*/
|
||||
goog.debug.getStacktraceHelper_ = function(fn, visited) {
|
||||
var sb = [];
|
||||
|
||||
// Circular reference, certain functions like bind seem to cause a recursive
|
||||
// loop so we need to catch circular references
|
||||
if (goog.array.contains(visited, fn)) {
|
||||
sb.push('[...circular reference...]');
|
||||
|
||||
// Traverse the call stack until function not found or max depth is reached
|
||||
} else if (fn && visited.length < goog.debug.MAX_STACK_DEPTH) {
|
||||
sb.push(goog.debug.getFunctionName(fn) + '(');
|
||||
var args = fn.arguments;
|
||||
// Args may be null for some special functions such as host objects or eval.
|
||||
for (var i = 0; args && i < args.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.push(', ');
|
||||
}
|
||||
var argDesc;
|
||||
var arg = args[i];
|
||||
switch (typeof arg) {
|
||||
case 'object':
|
||||
argDesc = arg ? 'object' : 'null';
|
||||
break;
|
||||
|
||||
case 'string':
|
||||
argDesc = arg;
|
||||
break;
|
||||
|
||||
case 'number':
|
||||
argDesc = String(arg);
|
||||
break;
|
||||
|
||||
case 'boolean':
|
||||
argDesc = arg ? 'true' : 'false';
|
||||
break;
|
||||
|
||||
case 'function':
|
||||
argDesc = goog.debug.getFunctionName(arg);
|
||||
argDesc = argDesc ? argDesc : '[fn]';
|
||||
break;
|
||||
|
||||
case 'undefined':
|
||||
default:
|
||||
argDesc = typeof arg;
|
||||
break;
|
||||
}
|
||||
|
||||
if (argDesc.length > 40) {
|
||||
argDesc = argDesc.substr(0, 40) + '...';
|
||||
}
|
||||
sb.push(argDesc);
|
||||
}
|
||||
visited.push(fn);
|
||||
sb.push(')\n');
|
||||
|
||||
try {
|
||||
sb.push(goog.debug.getStacktraceHelper_(fn.caller, visited));
|
||||
} catch (e) {
|
||||
sb.push('[exception trying to get caller]\n');
|
||||
}
|
||||
|
||||
} else if (fn) {
|
||||
sb.push('[...long stack...]');
|
||||
} else {
|
||||
sb.push('[end]');
|
||||
}
|
||||
return sb.join('');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set a custom function name resolver.
|
||||
* @param {function(Function): string} resolver Resolves functions to their
|
||||
* names.
|
||||
*/
|
||||
goog.debug.setFunctionResolver = function(resolver) {
|
||||
goog.debug.fnNameResolver_ = resolver;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets a function name
|
||||
* @param {Function} fn Function to get name of.
|
||||
* @return {string} Function's name.
|
||||
*/
|
||||
goog.debug.getFunctionName = function(fn) {
|
||||
if (goog.debug.fnNameCache_[fn]) {
|
||||
return goog.debug.fnNameCache_[fn];
|
||||
}
|
||||
if (goog.debug.fnNameResolver_) {
|
||||
var name = goog.debug.fnNameResolver_(fn);
|
||||
if (name) {
|
||||
goog.debug.fnNameCache_[fn] = name;
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
// Heuristically determine function name based on code.
|
||||
var functionSource = String(fn);
|
||||
if (!goog.debug.fnNameCache_[functionSource]) {
|
||||
var matches = /function ([^\(]+)/.exec(functionSource);
|
||||
if (matches) {
|
||||
var method = matches[1];
|
||||
goog.debug.fnNameCache_[functionSource] = method;
|
||||
} else {
|
||||
goog.debug.fnNameCache_[functionSource] = '[Anonymous]';
|
||||
}
|
||||
}
|
||||
|
||||
return goog.debug.fnNameCache_[functionSource];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Makes whitespace visible by replacing it with printable characters.
|
||||
* This is useful in finding diffrences between the expected and the actual
|
||||
* output strings of a testcase.
|
||||
* @param {string} string whose whitespace needs to be made visible.
|
||||
* @return {string} string whose whitespace is made visible.
|
||||
*/
|
||||
goog.debug.makeWhitespaceVisible = function(string) {
|
||||
return string.replace(/ /g, '[_]')
|
||||
.replace(/\f/g, '[f]')
|
||||
.replace(/\n/g, '[n]\n')
|
||||
.replace(/\r/g, '[r]')
|
||||
.replace(/\t/g, '[t]');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the type of a value. If a constructor is passed, and a suitable
|
||||
* string cannot be found, 'unknown type name' will be returned.
|
||||
*
|
||||
* <p>Forked rather than moved from {@link goog.asserts.getType_}
|
||||
* to avoid adding a dependency to goog.asserts.
|
||||
* @param {*} value A constructor, object, or primitive.
|
||||
* @return {string} The best display name for the value, or 'unknown type name'.
|
||||
*/
|
||||
goog.debug.runtimeType = function(value) {
|
||||
if (value instanceof Function) {
|
||||
return value.displayName || value.name || 'unknown type name';
|
||||
} else if (value instanceof Object) {
|
||||
return value.constructor.displayName || value.constructor.name ||
|
||||
Object.prototype.toString.call(value);
|
||||
} else {
|
||||
return value === null ? 'null' : typeof value;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Hash map for storing function names that have already been looked up.
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
goog.debug.fnNameCache_ = {};
|
||||
|
||||
|
||||
/**
|
||||
* Resolves functions to their names. Resolved function names will be cached.
|
||||
* @type {function(Function):string}
|
||||
* @private
|
||||
*/
|
||||
goog.debug.fnNameResolver_;
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
// Copyright 2010 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 A global registry for entry points into a program,
|
||||
* so that they can be instrumented. Each module should register their
|
||||
* entry points with this registry. Designed to be compiled out
|
||||
* if no instrumentation is requested.
|
||||
*
|
||||
* Entry points may be registered before or after a call to
|
||||
* goog.debug.entryPointRegistry.monitorAll. If an entry point is registered
|
||||
* later, the existing monitor will instrument the new entry point.
|
||||
*
|
||||
* @author nicksantos@google.com (Nick Santos)
|
||||
*/
|
||||
|
||||
goog.provide('goog.debug.EntryPointMonitor');
|
||||
goog.provide('goog.debug.entryPointRegistry');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @interface
|
||||
*/
|
||||
goog.debug.EntryPointMonitor = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Instruments a function.
|
||||
*
|
||||
* @param {!Function} fn A function to instrument.
|
||||
* @return {!Function} The instrumented function.
|
||||
*/
|
||||
goog.debug.EntryPointMonitor.prototype.wrap;
|
||||
|
||||
|
||||
/**
|
||||
* Try to remove an instrumentation wrapper created by this monitor.
|
||||
* If the function passed to unwrap is not a wrapper created by this
|
||||
* monitor, then we will do nothing.
|
||||
*
|
||||
* Notice that some wrappers may not be unwrappable. For example, if other
|
||||
* monitors have applied their own wrappers, then it will be impossible to
|
||||
* unwrap them because their wrappers will have captured our wrapper.
|
||||
*
|
||||
* So it is important that entry points are unwrapped in the reverse
|
||||
* order that they were wrapped.
|
||||
*
|
||||
* @param {!Function} fn A function to unwrap.
|
||||
* @return {!Function} The unwrapped function, or {@code fn} if it was not
|
||||
* a wrapped function created by this monitor.
|
||||
*/
|
||||
goog.debug.EntryPointMonitor.prototype.unwrap;
|
||||
|
||||
|
||||
/**
|
||||
* An array of entry point callbacks.
|
||||
* @type {!Array<function(!Function)>}
|
||||
* @private
|
||||
*/
|
||||
goog.debug.entryPointRegistry.refList_ = [];
|
||||
|
||||
|
||||
/**
|
||||
* Monitors that should wrap all the entry points.
|
||||
* @type {!Array<!goog.debug.EntryPointMonitor>}
|
||||
* @private
|
||||
*/
|
||||
goog.debug.entryPointRegistry.monitors_ = [];
|
||||
|
||||
|
||||
/**
|
||||
* Whether goog.debug.entryPointRegistry.monitorAll has ever been called.
|
||||
* Checking this allows the compiler to optimize out the registrations.
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
goog.debug.entryPointRegistry.monitorsMayExist_ = false;
|
||||
|
||||
|
||||
/**
|
||||
* Register an entry point with this module.
|
||||
*
|
||||
* The entry point will be instrumented when a monitor is passed to
|
||||
* goog.debug.entryPointRegistry.monitorAll. If this has already occurred, the
|
||||
* entry point is instrumented immediately.
|
||||
*
|
||||
* @param {function(!Function)} callback A callback function which is called
|
||||
* with a transforming function to instrument the entry point. The callback
|
||||
* is responsible for wrapping the relevant entry point with the
|
||||
* transforming function.
|
||||
*/
|
||||
goog.debug.entryPointRegistry.register = function(callback) {
|
||||
// Don't use push(), so that this can be compiled out.
|
||||
goog.debug.entryPointRegistry
|
||||
.refList_[goog.debug.entryPointRegistry.refList_.length] = callback;
|
||||
// If no one calls monitorAll, this can be compiled out.
|
||||
if (goog.debug.entryPointRegistry.monitorsMayExist_) {
|
||||
var monitors = goog.debug.entryPointRegistry.monitors_;
|
||||
for (var i = 0; i < monitors.length; i++) {
|
||||
callback(goog.bind(monitors[i].wrap, monitors[i]));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Configures a monitor to wrap all entry points.
|
||||
*
|
||||
* Entry points that have already been registered are immediately wrapped by
|
||||
* the monitor. When an entry point is registered in the future, it will also
|
||||
* be wrapped by the monitor when it is registered.
|
||||
*
|
||||
* @param {!goog.debug.EntryPointMonitor} monitor An entry point monitor.
|
||||
*/
|
||||
goog.debug.entryPointRegistry.monitorAll = function(monitor) {
|
||||
goog.debug.entryPointRegistry.monitorsMayExist_ = true;
|
||||
var transformer = goog.bind(monitor.wrap, monitor);
|
||||
for (var i = 0; i < goog.debug.entryPointRegistry.refList_.length; i++) {
|
||||
goog.debug.entryPointRegistry.refList_[i](transformer);
|
||||
}
|
||||
goog.debug.entryPointRegistry.monitors_.push(monitor);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Try to unmonitor all the entry points that have already been registered. If
|
||||
* an entry point is registered in the future, it will not be wrapped by the
|
||||
* monitor when it is registered. Note that this may fail if the entry points
|
||||
* have additional wrapping.
|
||||
*
|
||||
* @param {!goog.debug.EntryPointMonitor} monitor The last monitor to wrap
|
||||
* the entry points.
|
||||
* @throws {Error} If the monitor is not the most recently configured monitor.
|
||||
*/
|
||||
goog.debug.entryPointRegistry.unmonitorAllIfPossible = function(monitor) {
|
||||
var monitors = goog.debug.entryPointRegistry.monitors_;
|
||||
goog.asserts.assert(
|
||||
monitor == monitors[monitors.length - 1],
|
||||
'Only the most recent monitor can be unwrapped.');
|
||||
var transformer = goog.bind(monitor.unwrap, monitor);
|
||||
for (var i = 0; i < goog.debug.entryPointRegistry.refList_.length; i++) {
|
||||
goog.debug.entryPointRegistry.refList_[i](transformer);
|
||||
}
|
||||
monitors.length--;
|
||||
};
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright 2009 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 a base class for custom Error objects such that the
|
||||
* stack is correctly maintained.
|
||||
*
|
||||
* You should never need to throw goog.debug.Error(msg) directly, Error(msg) is
|
||||
* sufficient.
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.debug.Error');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Base class for custom error objects.
|
||||
* @param {*=} opt_msg The message associated with the error.
|
||||
* @constructor
|
||||
* @extends {Error}
|
||||
*/
|
||||
goog.debug.Error = function(opt_msg) {
|
||||
|
||||
// Attempt to ensure there is a stack trace.
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(this, goog.debug.Error);
|
||||
} else {
|
||||
var stack = new Error().stack;
|
||||
if (stack) {
|
||||
this.stack = stack;
|
||||
}
|
||||
}
|
||||
|
||||
if (opt_msg) {
|
||||
this.message = String(opt_msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to report this error to the server. Setting this to false will
|
||||
* cause the error reporter to not report the error back to the server,
|
||||
* which can be useful if the client knows that the error has already been
|
||||
* logged on the server.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.reportErrorToServer = true;
|
||||
};
|
||||
goog.inherits(goog.debug.Error, Error);
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.debug.Error.prototype.name = 'CustomError';
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
// Copyright 2017 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 methods dealing with context on error objects.
|
||||
*/
|
||||
|
||||
goog.provide('goog.debug.errorcontext');
|
||||
|
||||
|
||||
/**
|
||||
* Adds key-value context to the error.
|
||||
* @param {!Error} err The error to add context to.
|
||||
* @param {string} contextKey Key for the context to be added.
|
||||
* @param {string} contextValue Value for the context to be added.
|
||||
*/
|
||||
goog.debug.errorcontext.addErrorContext = function(
|
||||
err, contextKey, contextValue) {
|
||||
if (!err[goog.debug.errorcontext.CONTEXT_KEY_]) {
|
||||
err[goog.debug.errorcontext.CONTEXT_KEY_] = {};
|
||||
}
|
||||
err[goog.debug.errorcontext.CONTEXT_KEY_][contextKey] = contextValue;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {!Error} err The error to get context from.
|
||||
* @return {!Object<string, string>} The context of the provided error.
|
||||
*/
|
||||
goog.debug.errorcontext.getErrorContext = function(err) {
|
||||
return err[goog.debug.errorcontext.CONTEXT_KEY_] || {};
|
||||
};
|
||||
|
||||
|
||||
// TODO(user): convert this to a Symbol once goog.debug.ErrorReporter is
|
||||
// able to use ES6.
|
||||
/** @private @const {string} */
|
||||
goog.debug.errorcontext.CONTEXT_KEY_ = '__closure__error__context__984382';
|
||||
|
|
@ -0,0 +1,148 @@
|
|||
// Copyright 2010 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 A buffer for log records. The purpose of this is to improve
|
||||
* logging performance by re-using old objects when the buffer becomes full and
|
||||
* to eliminate the need for each app to implement their own log buffer. The
|
||||
* disadvantage to doing this is that log handlers cannot maintain references to
|
||||
* log records and expect that they are not overwriten at a later point.
|
||||
*
|
||||
* @author agrieve@google.com (Andrew Grieve)
|
||||
*/
|
||||
|
||||
goog.provide('goog.debug.LogBuffer');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.debug.LogRecord');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates the log buffer.
|
||||
* @constructor
|
||||
* @final
|
||||
*/
|
||||
goog.debug.LogBuffer = function() {
|
||||
goog.asserts.assert(
|
||||
goog.debug.LogBuffer.isBufferingEnabled(),
|
||||
'Cannot use goog.debug.LogBuffer without defining ' +
|
||||
'goog.debug.LogBuffer.CAPACITY.');
|
||||
this.clear();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A static method that always returns the same instance of LogBuffer.
|
||||
* @return {!goog.debug.LogBuffer} The LogBuffer singleton instance.
|
||||
*/
|
||||
goog.debug.LogBuffer.getInstance = function() {
|
||||
if (!goog.debug.LogBuffer.instance_) {
|
||||
// This function is written with the return statement after the assignment
|
||||
// to avoid the jscompiler StripCode bug described in http://b/2608064.
|
||||
// After that bug is fixed this can be refactored.
|
||||
goog.debug.LogBuffer.instance_ = new goog.debug.LogBuffer();
|
||||
}
|
||||
return goog.debug.LogBuffer.instance_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @define {number} The number of log records to buffer. 0 means disable
|
||||
* buffering.
|
||||
*/
|
||||
goog.define('goog.debug.LogBuffer.CAPACITY', 0);
|
||||
|
||||
|
||||
/**
|
||||
* The array to store the records.
|
||||
* @type {!Array<!goog.debug.LogRecord|undefined>}
|
||||
* @private
|
||||
*/
|
||||
goog.debug.LogBuffer.prototype.buffer_;
|
||||
|
||||
|
||||
/**
|
||||
* The index of the most recently added record or -1 if there are no records.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
goog.debug.LogBuffer.prototype.curIndex_;
|
||||
|
||||
|
||||
/**
|
||||
* Whether the buffer is at capacity.
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
goog.debug.LogBuffer.prototype.isFull_;
|
||||
|
||||
|
||||
/**
|
||||
* Adds a log record to the buffer, possibly overwriting the oldest record.
|
||||
* @param {goog.debug.Logger.Level} level One of the level identifiers.
|
||||
* @param {string} msg The string message.
|
||||
* @param {string} loggerName The name of the source logger.
|
||||
* @return {!goog.debug.LogRecord} The log record.
|
||||
*/
|
||||
goog.debug.LogBuffer.prototype.addRecord = function(level, msg, loggerName) {
|
||||
var curIndex = (this.curIndex_ + 1) % goog.debug.LogBuffer.CAPACITY;
|
||||
this.curIndex_ = curIndex;
|
||||
if (this.isFull_) {
|
||||
var ret = this.buffer_[curIndex];
|
||||
ret.reset(level, msg, loggerName);
|
||||
return ret;
|
||||
}
|
||||
this.isFull_ = curIndex == goog.debug.LogBuffer.CAPACITY - 1;
|
||||
return this.buffer_[curIndex] =
|
||||
new goog.debug.LogRecord(level, msg, loggerName);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the log buffer is enabled.
|
||||
*/
|
||||
goog.debug.LogBuffer.isBufferingEnabled = function() {
|
||||
return goog.debug.LogBuffer.CAPACITY > 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes all buffered log records.
|
||||
*/
|
||||
goog.debug.LogBuffer.prototype.clear = function() {
|
||||
this.buffer_ = new Array(goog.debug.LogBuffer.CAPACITY);
|
||||
this.curIndex_ = -1;
|
||||
this.isFull_ = false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls the given function for each buffered log record, starting with the
|
||||
* oldest one.
|
||||
* @param {function(!goog.debug.LogRecord)} func The function to call.
|
||||
*/
|
||||
goog.debug.LogBuffer.prototype.forEachRecord = function(func) {
|
||||
var buffer = this.buffer_;
|
||||
// Corner case: no records.
|
||||
if (!buffer[0]) {
|
||||
return;
|
||||
}
|
||||
var curIndex = this.curIndex_;
|
||||
var i = this.isFull_ ? curIndex : -1;
|
||||
do {
|
||||
i = (i + 1) % goog.debug.LogBuffer.CAPACITY;
|
||||
func(/** @type {!goog.debug.LogRecord} */ (buffer[i]));
|
||||
} while (i != curIndex);
|
||||
};
|
||||
|
|
@ -0,0 +1,865 @@
|
|||
// Copyright 2006 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 Definition of the Logger class. Please minimize dependencies
|
||||
* this file has on other closure classes as any dependency it takes won't be
|
||||
* able to use the logging infrastructure.
|
||||
*
|
||||
* @see ../demos/debug.html
|
||||
*/
|
||||
|
||||
goog.provide('goog.debug.LogManager');
|
||||
goog.provide('goog.debug.Loggable');
|
||||
goog.provide('goog.debug.Logger');
|
||||
goog.provide('goog.debug.Logger.Level');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.debug');
|
||||
goog.require('goog.debug.LogBuffer');
|
||||
goog.require('goog.debug.LogRecord');
|
||||
|
||||
|
||||
/**
|
||||
* A message value that can be handled by a Logger.
|
||||
*
|
||||
* Functions are treated like callbacks, but are only called when the event's
|
||||
* log level is enabled. This is useful for logging messages that are expensive
|
||||
* to construct.
|
||||
*
|
||||
* @typedef {string|function(): string}
|
||||
*/
|
||||
goog.debug.Loggable;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The Logger is an object used for logging debug messages. Loggers are
|
||||
* normally named, using a hierarchical dot-separated namespace. Logger names
|
||||
* can be arbitrary strings, but they should normally be based on the package
|
||||
* name or class name of the logged component, such as goog.net.BrowserChannel.
|
||||
*
|
||||
* The Logger object is loosely based on the java class
|
||||
* java.util.logging.Logger. It supports different levels of filtering for
|
||||
* different loggers.
|
||||
*
|
||||
* The logger object should never be instantiated by application code. It
|
||||
* should always use the goog.debug.Logger.getLogger function.
|
||||
*
|
||||
* @constructor
|
||||
* @param {string} name The name of the Logger.
|
||||
* @final
|
||||
*/
|
||||
goog.debug.Logger = function(name) {
|
||||
/**
|
||||
* Name of the Logger. Generally a dot-separated namespace
|
||||
* @private {string}
|
||||
*/
|
||||
this.name_ = name;
|
||||
|
||||
/**
|
||||
* Parent Logger.
|
||||
* @private {goog.debug.Logger}
|
||||
*/
|
||||
this.parent_ = null;
|
||||
|
||||
/**
|
||||
* Level that this logger only filters above. Null indicates it should
|
||||
* inherit from the parent.
|
||||
* @private {goog.debug.Logger.Level}
|
||||
*/
|
||||
this.level_ = null;
|
||||
|
||||
/**
|
||||
* Map of children loggers. The keys are the leaf names of the children and
|
||||
* the values are the child loggers.
|
||||
* @private {Object}
|
||||
*/
|
||||
this.children_ = null;
|
||||
|
||||
/**
|
||||
* Handlers that are listening to this logger.
|
||||
* @private {Array<Function>}
|
||||
*/
|
||||
this.handlers_ = null;
|
||||
};
|
||||
|
||||
|
||||
/** @const */
|
||||
goog.debug.Logger.ROOT_LOGGER_NAME = '';
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Toggles whether loggers other than the root logger can have
|
||||
* log handlers attached to them and whether they can have their log level
|
||||
* set. Logging is a bit faster when this is set to false.
|
||||
*/
|
||||
goog.define('goog.debug.Logger.ENABLE_HIERARCHY', true);
|
||||
|
||||
|
||||
if (!goog.debug.Logger.ENABLE_HIERARCHY) {
|
||||
/**
|
||||
* @type {!Array<Function>}
|
||||
* @private
|
||||
*/
|
||||
goog.debug.Logger.rootHandlers_ = [];
|
||||
|
||||
|
||||
/**
|
||||
* @type {goog.debug.Logger.Level}
|
||||
* @private
|
||||
*/
|
||||
goog.debug.Logger.rootLevel_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The Level class defines a set of standard logging levels that
|
||||
* can be used to control logging output. The logging Level objects
|
||||
* are ordered and are specified by ordered integers. Enabling logging
|
||||
* at a given level also enables logging at all higher levels.
|
||||
* <p>
|
||||
* Clients should normally use the predefined Level constants such
|
||||
* as Level.SEVERE.
|
||||
* <p>
|
||||
* The levels in descending order are:
|
||||
* <ul>
|
||||
* <li>SEVERE (highest value)
|
||||
* <li>WARNING
|
||||
* <li>INFO
|
||||
* <li>CONFIG
|
||||
* <li>FINE
|
||||
* <li>FINER
|
||||
* <li>FINEST (lowest value)
|
||||
* </ul>
|
||||
* In addition there is a level OFF that can be used to turn
|
||||
* off logging, and a level ALL that can be used to enable
|
||||
* logging of all messages.
|
||||
*
|
||||
* @param {string} name The name of the level.
|
||||
* @param {number} value The numeric value of the level.
|
||||
* @constructor
|
||||
* @final
|
||||
*/
|
||||
goog.debug.Logger.Level = function(name, value) {
|
||||
/**
|
||||
* The name of the level
|
||||
* @type {string}
|
||||
*/
|
||||
this.name = name;
|
||||
|
||||
/**
|
||||
* The numeric value of the level
|
||||
* @type {number}
|
||||
*/
|
||||
this.value = value;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {string} String representation of the logger level.
|
||||
* @override
|
||||
*/
|
||||
goog.debug.Logger.Level.prototype.toString = function() {
|
||||
return this.name;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* OFF is a special level that can be used to turn off logging.
|
||||
* This level is initialized to <CODE>Infinity</CODE>.
|
||||
* @type {!goog.debug.Logger.Level}
|
||||
*/
|
||||
goog.debug.Logger.Level.OFF = new goog.debug.Logger.Level('OFF', Infinity);
|
||||
|
||||
|
||||
/**
|
||||
* SHOUT is a message level for extra debugging loudness.
|
||||
* This level is initialized to <CODE>1200</CODE>.
|
||||
* @type {!goog.debug.Logger.Level}
|
||||
*/
|
||||
goog.debug.Logger.Level.SHOUT = new goog.debug.Logger.Level('SHOUT', 1200);
|
||||
|
||||
|
||||
/**
|
||||
* SEVERE is a message level indicating a serious failure.
|
||||
* This level is initialized to <CODE>1000</CODE>.
|
||||
* @type {!goog.debug.Logger.Level}
|
||||
*/
|
||||
goog.debug.Logger.Level.SEVERE = new goog.debug.Logger.Level('SEVERE', 1000);
|
||||
|
||||
|
||||
/**
|
||||
* WARNING is a message level indicating a potential problem.
|
||||
* This level is initialized to <CODE>900</CODE>.
|
||||
* @type {!goog.debug.Logger.Level}
|
||||
*/
|
||||
goog.debug.Logger.Level.WARNING = new goog.debug.Logger.Level('WARNING', 900);
|
||||
|
||||
|
||||
/**
|
||||
* INFO is a message level for informational messages.
|
||||
* This level is initialized to <CODE>800</CODE>.
|
||||
* @type {!goog.debug.Logger.Level}
|
||||
*/
|
||||
goog.debug.Logger.Level.INFO = new goog.debug.Logger.Level('INFO', 800);
|
||||
|
||||
|
||||
/**
|
||||
* CONFIG is a message level for static configuration messages.
|
||||
* This level is initialized to <CODE>700</CODE>.
|
||||
* @type {!goog.debug.Logger.Level}
|
||||
*/
|
||||
goog.debug.Logger.Level.CONFIG = new goog.debug.Logger.Level('CONFIG', 700);
|
||||
|
||||
|
||||
/**
|
||||
* FINE is a message level providing tracing information.
|
||||
* This level is initialized to <CODE>500</CODE>.
|
||||
* @type {!goog.debug.Logger.Level}
|
||||
*/
|
||||
goog.debug.Logger.Level.FINE = new goog.debug.Logger.Level('FINE', 500);
|
||||
|
||||
|
||||
/**
|
||||
* FINER indicates a fairly detailed tracing message.
|
||||
* This level is initialized to <CODE>400</CODE>.
|
||||
* @type {!goog.debug.Logger.Level}
|
||||
*/
|
||||
goog.debug.Logger.Level.FINER = new goog.debug.Logger.Level('FINER', 400);
|
||||
|
||||
/**
|
||||
* FINEST indicates a highly detailed tracing message.
|
||||
* This level is initialized to <CODE>300</CODE>.
|
||||
* @type {!goog.debug.Logger.Level}
|
||||
*/
|
||||
|
||||
goog.debug.Logger.Level.FINEST = new goog.debug.Logger.Level('FINEST', 300);
|
||||
|
||||
|
||||
/**
|
||||
* ALL indicates that all messages should be logged.
|
||||
* This level is initialized to <CODE>0</CODE>.
|
||||
* @type {!goog.debug.Logger.Level}
|
||||
*/
|
||||
goog.debug.Logger.Level.ALL = new goog.debug.Logger.Level('ALL', 0);
|
||||
|
||||
|
||||
/**
|
||||
* The predefined levels.
|
||||
* @type {!Array<!goog.debug.Logger.Level>}
|
||||
* @final
|
||||
*/
|
||||
goog.debug.Logger.Level.PREDEFINED_LEVELS = [
|
||||
goog.debug.Logger.Level.OFF, goog.debug.Logger.Level.SHOUT,
|
||||
goog.debug.Logger.Level.SEVERE, goog.debug.Logger.Level.WARNING,
|
||||
goog.debug.Logger.Level.INFO, goog.debug.Logger.Level.CONFIG,
|
||||
goog.debug.Logger.Level.FINE, goog.debug.Logger.Level.FINER,
|
||||
goog.debug.Logger.Level.FINEST, goog.debug.Logger.Level.ALL
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* A lookup map used to find the level object based on the name or value of
|
||||
* the level object.
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
goog.debug.Logger.Level.predefinedLevelsCache_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* Creates the predefined levels cache and populates it.
|
||||
* @private
|
||||
*/
|
||||
goog.debug.Logger.Level.createPredefinedLevelsCache_ = function() {
|
||||
goog.debug.Logger.Level.predefinedLevelsCache_ = {};
|
||||
for (var i = 0, level; level = goog.debug.Logger.Level.PREDEFINED_LEVELS[i];
|
||||
i++) {
|
||||
goog.debug.Logger.Level.predefinedLevelsCache_[level.value] = level;
|
||||
goog.debug.Logger.Level.predefinedLevelsCache_[level.name] = level;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the predefined level with the given name.
|
||||
* @param {string} name The name of the level.
|
||||
* @return {goog.debug.Logger.Level} The level, or null if none found.
|
||||
*/
|
||||
goog.debug.Logger.Level.getPredefinedLevel = function(name) {
|
||||
if (!goog.debug.Logger.Level.predefinedLevelsCache_) {
|
||||
goog.debug.Logger.Level.createPredefinedLevelsCache_();
|
||||
}
|
||||
|
||||
return goog.debug.Logger.Level.predefinedLevelsCache_[name] || null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the highest predefined level <= #value.
|
||||
* @param {number} value Level value.
|
||||
* @return {goog.debug.Logger.Level} The level, or null if none found.
|
||||
*/
|
||||
goog.debug.Logger.Level.getPredefinedLevelByValue = function(value) {
|
||||
if (!goog.debug.Logger.Level.predefinedLevelsCache_) {
|
||||
goog.debug.Logger.Level.createPredefinedLevelsCache_();
|
||||
}
|
||||
|
||||
if (value in /** @type {!Object} */ (
|
||||
goog.debug.Logger.Level.predefinedLevelsCache_)) {
|
||||
return goog.debug.Logger.Level.predefinedLevelsCache_[value];
|
||||
}
|
||||
|
||||
for (var i = 0; i < goog.debug.Logger.Level.PREDEFINED_LEVELS.length; ++i) {
|
||||
var level = goog.debug.Logger.Level.PREDEFINED_LEVELS[i];
|
||||
if (level.value <= value) {
|
||||
return level;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Finds or creates a logger for a named subsystem. If a logger has already been
|
||||
* created with the given name it is returned. Otherwise a new logger is
|
||||
* created. If a new logger is created its log level will be configured based
|
||||
* on the LogManager configuration and it will configured to also send logging
|
||||
* output to its parent's handlers. It will be registered in the LogManager
|
||||
* global namespace.
|
||||
*
|
||||
* @param {string} name A name for the logger. This should be a dot-separated
|
||||
* name and should normally be based on the package name or class name of the
|
||||
* subsystem, such as goog.net.BrowserChannel.
|
||||
* @return {!goog.debug.Logger} The named logger.
|
||||
* @deprecated use {@link goog.log} instead.
|
||||
*/
|
||||
goog.debug.Logger.getLogger = function(name) {
|
||||
return goog.debug.LogManager.getLogger(name);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Logs a message to profiling tools, if available.
|
||||
* {@see https://developers.google.com/web-toolkit/speedtracer/logging-api}
|
||||
* {@see http://msdn.microsoft.com/en-us/library/dd433074(VS.85).aspx}
|
||||
* @param {string} msg The message to log.
|
||||
*/
|
||||
goog.debug.Logger.logToProfilers = function(msg) {
|
||||
// Using goog.global, as loggers might be used in window-less contexts.
|
||||
var console = goog.global['console'];
|
||||
if (console && console['timeStamp']) {
|
||||
// Logs a message to Firebug, Web Inspector, SpeedTracer, etc.
|
||||
console['timeStamp'](msg);
|
||||
}
|
||||
|
||||
var msWriteProfilerMark = goog.global['msWriteProfilerMark'];
|
||||
if (msWriteProfilerMark) {
|
||||
// Logs a message to the Microsoft profiler
|
||||
msWriteProfilerMark(msg);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the name of this logger.
|
||||
* @return {string} The name of this logger.
|
||||
*/
|
||||
goog.debug.Logger.prototype.getName = function() {
|
||||
return this.name_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds a handler to the logger. This doesn't use the event system because
|
||||
* we want to be able to add logging to the event system.
|
||||
* @param {Function} handler Handler function to add.
|
||||
*/
|
||||
goog.debug.Logger.prototype.addHandler = function(handler) {
|
||||
if (goog.debug.LOGGING_ENABLED) {
|
||||
if (goog.debug.Logger.ENABLE_HIERARCHY) {
|
||||
if (!this.handlers_) {
|
||||
this.handlers_ = [];
|
||||
}
|
||||
this.handlers_.push(handler);
|
||||
} else {
|
||||
goog.asserts.assert(
|
||||
!this.name_, 'Cannot call addHandler on a non-root logger when ' +
|
||||
'goog.debug.Logger.ENABLE_HIERARCHY is false.');
|
||||
goog.debug.Logger.rootHandlers_.push(handler);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes a handler from the logger. This doesn't use the event system because
|
||||
* we want to be able to add logging to the event system.
|
||||
* @param {Function} handler Handler function to remove.
|
||||
* @return {boolean} Whether the handler was removed.
|
||||
*/
|
||||
goog.debug.Logger.prototype.removeHandler = function(handler) {
|
||||
if (goog.debug.LOGGING_ENABLED) {
|
||||
var handlers = goog.debug.Logger.ENABLE_HIERARCHY ?
|
||||
this.handlers_ :
|
||||
goog.debug.Logger.rootHandlers_;
|
||||
return !!handlers && goog.array.remove(handlers, handler);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the parent of this logger.
|
||||
* @return {goog.debug.Logger} The parent logger or null if this is the root.
|
||||
*/
|
||||
goog.debug.Logger.prototype.getParent = function() {
|
||||
return this.parent_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the children of this logger as a map of the child name to the logger.
|
||||
* @return {!Object} The map where the keys are the child leaf names and the
|
||||
* values are the Logger objects.
|
||||
*/
|
||||
goog.debug.Logger.prototype.getChildren = function() {
|
||||
if (!this.children_) {
|
||||
this.children_ = {};
|
||||
}
|
||||
return this.children_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the log level specifying which message levels will be logged by this
|
||||
* logger. Message levels lower than this value will be discarded.
|
||||
* The level value Level.OFF can be used to turn off logging. If the new level
|
||||
* is null, it means that this node should inherit its level from its nearest
|
||||
* ancestor with a specific (non-null) level value.
|
||||
*
|
||||
* @param {goog.debug.Logger.Level} level The new level.
|
||||
*/
|
||||
goog.debug.Logger.prototype.setLevel = function(level) {
|
||||
if (goog.debug.LOGGING_ENABLED) {
|
||||
if (goog.debug.Logger.ENABLE_HIERARCHY) {
|
||||
this.level_ = level;
|
||||
} else {
|
||||
goog.asserts.assert(
|
||||
!this.name_, 'Cannot call setLevel() on a non-root logger when ' +
|
||||
'goog.debug.Logger.ENABLE_HIERARCHY is false.');
|
||||
goog.debug.Logger.rootLevel_ = level;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the log level specifying which message levels will be logged by this
|
||||
* logger. Message levels lower than this value will be discarded.
|
||||
* The level value Level.OFF can be used to turn off logging. If the level
|
||||
* is null, it means that this node should inherit its level from its nearest
|
||||
* ancestor with a specific (non-null) level value.
|
||||
*
|
||||
* @return {goog.debug.Logger.Level} The level.
|
||||
*/
|
||||
goog.debug.Logger.prototype.getLevel = function() {
|
||||
return goog.debug.LOGGING_ENABLED ? this.level_ : goog.debug.Logger.Level.OFF;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the effective level of the logger based on its ancestors' levels.
|
||||
* @return {goog.debug.Logger.Level} The level.
|
||||
*/
|
||||
goog.debug.Logger.prototype.getEffectiveLevel = function() {
|
||||
if (!goog.debug.LOGGING_ENABLED) {
|
||||
return goog.debug.Logger.Level.OFF;
|
||||
}
|
||||
|
||||
if (!goog.debug.Logger.ENABLE_HIERARCHY) {
|
||||
return goog.debug.Logger.rootLevel_;
|
||||
}
|
||||
if (this.level_) {
|
||||
return this.level_;
|
||||
}
|
||||
if (this.parent_) {
|
||||
return this.parent_.getEffectiveLevel();
|
||||
}
|
||||
goog.asserts.fail('Root logger has no level set.');
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Checks if a message of the given level would actually be logged by this
|
||||
* logger. This check is based on the Loggers effective level, which may be
|
||||
* inherited from its parent.
|
||||
* @param {goog.debug.Logger.Level} level The level to check.
|
||||
* @return {boolean} Whether the message would be logged.
|
||||
*/
|
||||
goog.debug.Logger.prototype.isLoggable = function(level) {
|
||||
return goog.debug.LOGGING_ENABLED &&
|
||||
level.value >= this.getEffectiveLevel().value;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Logs a message. If the logger is currently enabled for the
|
||||
* given message level then the given message is forwarded to all the
|
||||
* registered output Handler objects.
|
||||
* @param {goog.debug.Logger.Level} level One of the level identifiers.
|
||||
* @param {goog.debug.Loggable} msg The message to log.
|
||||
* @param {Error|Object=} opt_exception An exception associated with the
|
||||
* message.
|
||||
*/
|
||||
goog.debug.Logger.prototype.log = function(level, msg, opt_exception) {
|
||||
// java caches the effective level, not sure it's necessary here
|
||||
if (goog.debug.LOGGING_ENABLED && this.isLoggable(level)) {
|
||||
// Message callbacks can be useful when a log message is expensive to build.
|
||||
if (goog.isFunction(msg)) {
|
||||
msg = msg();
|
||||
}
|
||||
|
||||
this.doLogRecord_(this.getLogRecord(level, msg, opt_exception));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new log record and adds the exception (if present) to it.
|
||||
* @param {goog.debug.Logger.Level} level One of the level identifiers.
|
||||
* @param {string} msg The string message.
|
||||
* @param {Error|Object=} opt_exception An exception associated with the
|
||||
* message.
|
||||
* @return {!goog.debug.LogRecord} A log record.
|
||||
* @suppress {es5Strict}
|
||||
*/
|
||||
goog.debug.Logger.prototype.getLogRecord = function(level, msg, opt_exception) {
|
||||
if (goog.debug.LogBuffer.isBufferingEnabled()) {
|
||||
var logRecord =
|
||||
goog.debug.LogBuffer.getInstance().addRecord(level, msg, this.name_);
|
||||
} else {
|
||||
logRecord = new goog.debug.LogRecord(level, String(msg), this.name_);
|
||||
}
|
||||
if (opt_exception) {
|
||||
logRecord.setException(opt_exception);
|
||||
}
|
||||
return logRecord;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Logs a message at the Logger.Level.SHOUT level.
|
||||
* If the logger is currently enabled for the given message level then the
|
||||
* given message is forwarded to all the registered output Handler objects.
|
||||
* @param {goog.debug.Loggable} msg The message to log.
|
||||
* @param {Error=} opt_exception An exception associated with the message.
|
||||
*/
|
||||
goog.debug.Logger.prototype.shout = function(msg, opt_exception) {
|
||||
if (goog.debug.LOGGING_ENABLED) {
|
||||
this.log(goog.debug.Logger.Level.SHOUT, msg, opt_exception);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Logs a message at the Logger.Level.SEVERE level.
|
||||
* If the logger is currently enabled for the given message level then the
|
||||
* given message is forwarded to all the registered output Handler objects.
|
||||
* @param {goog.debug.Loggable} msg The message to log.
|
||||
* @param {Error=} opt_exception An exception associated with the message.
|
||||
*/
|
||||
goog.debug.Logger.prototype.severe = function(msg, opt_exception) {
|
||||
if (goog.debug.LOGGING_ENABLED) {
|
||||
this.log(goog.debug.Logger.Level.SEVERE, msg, opt_exception);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Logs a message at the Logger.Level.WARNING level.
|
||||
* If the logger is currently enabled for the given message level then the
|
||||
* given message is forwarded to all the registered output Handler objects.
|
||||
* @param {goog.debug.Loggable} msg The message to log.
|
||||
* @param {Error=} opt_exception An exception associated with the message.
|
||||
*/
|
||||
goog.debug.Logger.prototype.warning = function(msg, opt_exception) {
|
||||
if (goog.debug.LOGGING_ENABLED) {
|
||||
this.log(goog.debug.Logger.Level.WARNING, msg, opt_exception);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Logs a message at the Logger.Level.INFO level.
|
||||
* If the logger is currently enabled for the given message level then the
|
||||
* given message is forwarded to all the registered output Handler objects.
|
||||
* @param {goog.debug.Loggable} msg The message to log.
|
||||
* @param {Error=} opt_exception An exception associated with the message.
|
||||
*/
|
||||
goog.debug.Logger.prototype.info = function(msg, opt_exception) {
|
||||
if (goog.debug.LOGGING_ENABLED) {
|
||||
this.log(goog.debug.Logger.Level.INFO, msg, opt_exception);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Logs a message at the Logger.Level.CONFIG level.
|
||||
* If the logger is currently enabled for the given message level then the
|
||||
* given message is forwarded to all the registered output Handler objects.
|
||||
* @param {goog.debug.Loggable} msg The message to log.
|
||||
* @param {Error=} opt_exception An exception associated with the message.
|
||||
*/
|
||||
goog.debug.Logger.prototype.config = function(msg, opt_exception) {
|
||||
if (goog.debug.LOGGING_ENABLED) {
|
||||
this.log(goog.debug.Logger.Level.CONFIG, msg, opt_exception);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Logs a message at the Logger.Level.FINE level.
|
||||
* If the logger is currently enabled for the given message level then the
|
||||
* given message is forwarded to all the registered output Handler objects.
|
||||
* @param {goog.debug.Loggable} msg The message to log.
|
||||
* @param {Error=} opt_exception An exception associated with the message.
|
||||
*/
|
||||
goog.debug.Logger.prototype.fine = function(msg, opt_exception) {
|
||||
if (goog.debug.LOGGING_ENABLED) {
|
||||
this.log(goog.debug.Logger.Level.FINE, msg, opt_exception);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Logs a message at the Logger.Level.FINER level.
|
||||
* If the logger is currently enabled for the given message level then the
|
||||
* given message is forwarded to all the registered output Handler objects.
|
||||
* @param {goog.debug.Loggable} msg The message to log.
|
||||
* @param {Error=} opt_exception An exception associated with the message.
|
||||
*/
|
||||
goog.debug.Logger.prototype.finer = function(msg, opt_exception) {
|
||||
if (goog.debug.LOGGING_ENABLED) {
|
||||
this.log(goog.debug.Logger.Level.FINER, msg, opt_exception);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Logs a message at the Logger.Level.FINEST level.
|
||||
* If the logger is currently enabled for the given message level then the
|
||||
* given message is forwarded to all the registered output Handler objects.
|
||||
* @param {goog.debug.Loggable} msg The message to log.
|
||||
* @param {Error=} opt_exception An exception associated with the message.
|
||||
*/
|
||||
goog.debug.Logger.prototype.finest = function(msg, opt_exception) {
|
||||
if (goog.debug.LOGGING_ENABLED) {
|
||||
this.log(goog.debug.Logger.Level.FINEST, msg, opt_exception);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Logs a LogRecord. If the logger is currently enabled for the
|
||||
* given message level then the given message is forwarded to all the
|
||||
* registered output Handler objects.
|
||||
* @param {goog.debug.LogRecord} logRecord A log record to log.
|
||||
*/
|
||||
goog.debug.Logger.prototype.logRecord = function(logRecord) {
|
||||
if (goog.debug.LOGGING_ENABLED && this.isLoggable(logRecord.getLevel())) {
|
||||
this.doLogRecord_(logRecord);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Logs a LogRecord.
|
||||
* @param {goog.debug.LogRecord} logRecord A log record to log.
|
||||
* @private
|
||||
*/
|
||||
goog.debug.Logger.prototype.doLogRecord_ = function(logRecord) {
|
||||
goog.debug.Logger.logToProfilers('log:' + logRecord.getMessage());
|
||||
if (goog.debug.Logger.ENABLE_HIERARCHY) {
|
||||
var target = this;
|
||||
while (target) {
|
||||
target.callPublish_(logRecord);
|
||||
target = target.getParent();
|
||||
}
|
||||
} else {
|
||||
for (var i = 0, handler; handler = goog.debug.Logger.rootHandlers_[i++];) {
|
||||
handler(logRecord);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls the handlers for publish.
|
||||
* @param {goog.debug.LogRecord} logRecord The log record to publish.
|
||||
* @private
|
||||
*/
|
||||
goog.debug.Logger.prototype.callPublish_ = function(logRecord) {
|
||||
if (this.handlers_) {
|
||||
for (var i = 0, handler; handler = this.handlers_[i]; i++) {
|
||||
handler(logRecord);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the parent of this logger. This is used for setting up the logger tree.
|
||||
* @param {goog.debug.Logger} parent The parent logger.
|
||||
* @private
|
||||
*/
|
||||
goog.debug.Logger.prototype.setParent_ = function(parent) {
|
||||
this.parent_ = parent;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds a child to this logger. This is used for setting up the logger tree.
|
||||
* @param {string} name The leaf name of the child.
|
||||
* @param {goog.debug.Logger} logger The child logger.
|
||||
* @private
|
||||
*/
|
||||
goog.debug.Logger.prototype.addChild_ = function(name, logger) {
|
||||
this.getChildren()[name] = logger;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* There is a single global LogManager object that is used to maintain a set of
|
||||
* shared state about Loggers and log services. This is loosely based on the
|
||||
* java class java.util.logging.LogManager.
|
||||
* @const
|
||||
*/
|
||||
goog.debug.LogManager = {};
|
||||
|
||||
|
||||
/**
|
||||
* Map of logger names to logger objects.
|
||||
*
|
||||
* @type {!Object<string, !goog.debug.Logger>}
|
||||
* @private
|
||||
*/
|
||||
goog.debug.LogManager.loggers_ = {};
|
||||
|
||||
|
||||
/**
|
||||
* The root logger which is the root of the logger tree.
|
||||
* @type {goog.debug.Logger}
|
||||
* @private
|
||||
*/
|
||||
goog.debug.LogManager.rootLogger_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the LogManager if not already initialized.
|
||||
*/
|
||||
goog.debug.LogManager.initialize = function() {
|
||||
if (!goog.debug.LogManager.rootLogger_) {
|
||||
goog.debug.LogManager.rootLogger_ =
|
||||
new goog.debug.Logger(goog.debug.Logger.ROOT_LOGGER_NAME);
|
||||
goog.debug.LogManager.loggers_[goog.debug.Logger.ROOT_LOGGER_NAME] =
|
||||
goog.debug.LogManager.rootLogger_;
|
||||
goog.debug.LogManager.rootLogger_.setLevel(goog.debug.Logger.Level.CONFIG);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns all the loggers.
|
||||
* @return {!Object<string, !goog.debug.Logger>} Map of logger names to logger
|
||||
* objects.
|
||||
*/
|
||||
goog.debug.LogManager.getLoggers = function() {
|
||||
return goog.debug.LogManager.loggers_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the root of the logger tree namespace, the logger with the empty
|
||||
* string as its name.
|
||||
*
|
||||
* @return {!goog.debug.Logger} The root logger.
|
||||
*/
|
||||
goog.debug.LogManager.getRoot = function() {
|
||||
goog.debug.LogManager.initialize();
|
||||
return /** @type {!goog.debug.Logger} */ (goog.debug.LogManager.rootLogger_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Finds a named logger.
|
||||
*
|
||||
* @param {string} name A name for the logger. This should be a dot-separated
|
||||
* name and should normally be based on the package name or class name of the
|
||||
* subsystem, such as goog.net.BrowserChannel.
|
||||
* @return {!goog.debug.Logger} The named logger.
|
||||
*/
|
||||
goog.debug.LogManager.getLogger = function(name) {
|
||||
goog.debug.LogManager.initialize();
|
||||
var ret = goog.debug.LogManager.loggers_[name];
|
||||
return ret || goog.debug.LogManager.createLogger_(name);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a function that can be passed to goog.debug.catchErrors. The function
|
||||
* will log all reported errors using the given logger.
|
||||
* @param {goog.debug.Logger=} opt_logger The logger to log the errors to.
|
||||
* Defaults to the root logger.
|
||||
* @return {function(Object)} The created function.
|
||||
*/
|
||||
goog.debug.LogManager.createFunctionForCatchErrors = function(opt_logger) {
|
||||
return function(info) {
|
||||
var logger = opt_logger || goog.debug.LogManager.getRoot();
|
||||
logger.severe(
|
||||
'Error: ' + info.message + ' (' + info.fileName + ' @ Line: ' +
|
||||
info.line + ')');
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates the named logger. Will also create the parents of the named logger
|
||||
* if they don't yet exist.
|
||||
* @param {string} name The name of the logger.
|
||||
* @return {!goog.debug.Logger} The named logger.
|
||||
* @private
|
||||
*/
|
||||
goog.debug.LogManager.createLogger_ = function(name) {
|
||||
// find parent logger
|
||||
var logger = new goog.debug.Logger(name);
|
||||
if (goog.debug.Logger.ENABLE_HIERARCHY) {
|
||||
var lastDotIndex = name.lastIndexOf('.');
|
||||
var parentName = name.substr(0, lastDotIndex);
|
||||
var leafName = name.substr(lastDotIndex + 1);
|
||||
var parentLogger = goog.debug.LogManager.getLogger(parentName);
|
||||
|
||||
// tell the parent about the child and the child about the parent
|
||||
parentLogger.addChild_(leafName, logger);
|
||||
logger.setParent_(parentLogger);
|
||||
}
|
||||
|
||||
goog.debug.LogManager.loggers_[name] = logger;
|
||||
return logger;
|
||||
};
|
||||
|
|
@ -0,0 +1,242 @@
|
|||
// Copyright 2006 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 Definition of the LogRecord class. Please minimize
|
||||
* dependencies this file has on other closure classes as any dependency it
|
||||
* takes won't be able to use the logging infrastructure.
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.debug.LogRecord');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* LogRecord objects are used to pass logging requests between
|
||||
* the logging framework and individual log Handlers.
|
||||
* @constructor
|
||||
* @param {goog.debug.Logger.Level} level One of the level identifiers.
|
||||
* @param {string} msg The string message.
|
||||
* @param {string} loggerName The name of the source logger.
|
||||
* @param {number=} opt_time Time this log record was created if other than now.
|
||||
* If 0, we use #goog.now.
|
||||
* @param {number=} opt_sequenceNumber Sequence number of this log record. This
|
||||
* should only be passed in when restoring a log record from persistence.
|
||||
*/
|
||||
goog.debug.LogRecord = function(
|
||||
level, msg, loggerName, opt_time, opt_sequenceNumber) {
|
||||
this.reset(level, msg, loggerName, opt_time, opt_sequenceNumber);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Time the LogRecord was created.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
goog.debug.LogRecord.prototype.time_;
|
||||
|
||||
|
||||
/**
|
||||
* Level of the LogRecord
|
||||
* @type {goog.debug.Logger.Level}
|
||||
* @private
|
||||
*/
|
||||
goog.debug.LogRecord.prototype.level_;
|
||||
|
||||
|
||||
/**
|
||||
* Message associated with the record
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
goog.debug.LogRecord.prototype.msg_;
|
||||
|
||||
|
||||
/**
|
||||
* Name of the logger that created the record.
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
goog.debug.LogRecord.prototype.loggerName_;
|
||||
|
||||
|
||||
/**
|
||||
* Sequence number for the LogRecord. Each record has a unique sequence number
|
||||
* that is greater than all log records created before it.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
goog.debug.LogRecord.prototype.sequenceNumber_ = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Exception associated with the record
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
goog.debug.LogRecord.prototype.exception_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Whether to enable log sequence numbers.
|
||||
*/
|
||||
goog.define('goog.debug.LogRecord.ENABLE_SEQUENCE_NUMBERS', true);
|
||||
|
||||
|
||||
/**
|
||||
* A sequence counter for assigning increasing sequence numbers to LogRecord
|
||||
* objects.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
goog.debug.LogRecord.nextSequenceNumber_ = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Sets all fields of the log record.
|
||||
* @param {goog.debug.Logger.Level} level One of the level identifiers.
|
||||
* @param {string} msg The string message.
|
||||
* @param {string} loggerName The name of the source logger.
|
||||
* @param {number=} opt_time Time this log record was created if other than now.
|
||||
* If 0, we use #goog.now.
|
||||
* @param {number=} opt_sequenceNumber Sequence number of this log record. This
|
||||
* should only be passed in when restoring a log record from persistence.
|
||||
*/
|
||||
goog.debug.LogRecord.prototype.reset = function(
|
||||
level, msg, loggerName, opt_time, opt_sequenceNumber) {
|
||||
if (goog.debug.LogRecord.ENABLE_SEQUENCE_NUMBERS) {
|
||||
this.sequenceNumber_ = typeof opt_sequenceNumber == 'number' ?
|
||||
opt_sequenceNumber :
|
||||
goog.debug.LogRecord.nextSequenceNumber_++;
|
||||
}
|
||||
|
||||
this.time_ = opt_time || goog.now();
|
||||
this.level_ = level;
|
||||
this.msg_ = msg;
|
||||
this.loggerName_ = loggerName;
|
||||
delete this.exception_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the source Logger's name.
|
||||
*
|
||||
* @return {string} source logger name (may be null).
|
||||
*/
|
||||
goog.debug.LogRecord.prototype.getLoggerName = function() {
|
||||
return this.loggerName_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the exception that is part of the log record.
|
||||
*
|
||||
* @return {Object} the exception.
|
||||
*/
|
||||
goog.debug.LogRecord.prototype.getException = function() {
|
||||
return this.exception_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the exception that is part of the log record.
|
||||
*
|
||||
* @param {Object} exception the exception.
|
||||
*/
|
||||
goog.debug.LogRecord.prototype.setException = function(exception) {
|
||||
this.exception_ = exception;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the source Logger's name.
|
||||
*
|
||||
* @param {string} loggerName source logger name (may be null).
|
||||
*/
|
||||
goog.debug.LogRecord.prototype.setLoggerName = function(loggerName) {
|
||||
this.loggerName_ = loggerName;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the logging message level, for example Level.SEVERE.
|
||||
* @return {goog.debug.Logger.Level} the logging message level.
|
||||
*/
|
||||
goog.debug.LogRecord.prototype.getLevel = function() {
|
||||
return this.level_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the logging message level, for example Level.SEVERE.
|
||||
* @param {goog.debug.Logger.Level} level the logging message level.
|
||||
*/
|
||||
goog.debug.LogRecord.prototype.setLevel = function(level) {
|
||||
this.level_ = level;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the "raw" log message, before localization or formatting.
|
||||
*
|
||||
* @return {string} the raw message string.
|
||||
*/
|
||||
goog.debug.LogRecord.prototype.getMessage = function() {
|
||||
return this.msg_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the "raw" log message, before localization or formatting.
|
||||
*
|
||||
* @param {string} msg the raw message string.
|
||||
*/
|
||||
goog.debug.LogRecord.prototype.setMessage = function(msg) {
|
||||
this.msg_ = msg;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get event time in milliseconds since 1970.
|
||||
*
|
||||
* @return {number} event time in millis since 1970.
|
||||
*/
|
||||
goog.debug.LogRecord.prototype.getMillis = function() {
|
||||
return this.time_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set event time in milliseconds since 1970.
|
||||
*
|
||||
* @param {number} time event time in millis since 1970.
|
||||
*/
|
||||
goog.debug.LogRecord.prototype.setMillis = function(time) {
|
||||
this.time_ = time;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the sequence number.
|
||||
* <p>
|
||||
* Sequence numbers are normally assigned in the LogRecord
|
||||
* constructor, which assigns unique sequence numbers to
|
||||
* each new LogRecord in increasing order.
|
||||
* @return {number} the sequence number.
|
||||
*/
|
||||
goog.debug.LogRecord.prototype.getSequenceNumber = function() {
|
||||
return this.sequenceNumber_;
|
||||
};
|
||||
1564
resources/public/target/cljsbuild-compiler-1/goog/deps.js
Normal file
1564
resources/public/target/cljsbuild-compiler-1/goog/deps.js
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,305 @@
|
|||
// Copyright 2005 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 Implements the disposable interface. The dispose method is used
|
||||
* to clean up references and resources.
|
||||
* @author arv@google.com (Erik Arvidsson)
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.Disposable');
|
||||
goog.provide('goog.dispose');
|
||||
goog.provide('goog.disposeAll');
|
||||
|
||||
goog.require('goog.disposable.IDisposable');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Class that provides the basic implementation for disposable objects. If your
|
||||
* class holds one or more references to COM objects, DOM nodes, or other
|
||||
* disposable objects, it should extend this class or implement the disposable
|
||||
* interface (defined in goog.disposable.IDisposable).
|
||||
* @constructor
|
||||
* @implements {goog.disposable.IDisposable}
|
||||
*/
|
||||
goog.Disposable = function() {
|
||||
/**
|
||||
* If monitoring the goog.Disposable instances is enabled, stores the creation
|
||||
* stack trace of the Disposable instance.
|
||||
* @type {string|undefined}
|
||||
*/
|
||||
this.creationStack;
|
||||
|
||||
if (goog.Disposable.MONITORING_MODE != goog.Disposable.MonitoringMode.OFF) {
|
||||
if (goog.Disposable.INCLUDE_STACK_ON_CREATION) {
|
||||
this.creationStack = new Error().stack;
|
||||
}
|
||||
goog.Disposable.instances_[goog.getUid(this)] = this;
|
||||
}
|
||||
// Support sealing
|
||||
this.disposed_ = this.disposed_;
|
||||
this.onDisposeCallbacks_ = this.onDisposeCallbacks_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @enum {number} Different monitoring modes for Disposable.
|
||||
*/
|
||||
goog.Disposable.MonitoringMode = {
|
||||
/**
|
||||
* No monitoring.
|
||||
*/
|
||||
OFF: 0,
|
||||
/**
|
||||
* Creating and disposing the goog.Disposable instances is monitored. All
|
||||
* disposable objects need to call the {@code goog.Disposable} base
|
||||
* constructor. The PERMANENT mode must be switched on before creating any
|
||||
* goog.Disposable instances.
|
||||
*/
|
||||
PERMANENT: 1,
|
||||
/**
|
||||
* INTERACTIVE mode can be switched on and off on the fly without producing
|
||||
* errors. It also doesn't warn if the disposable objects don't call the
|
||||
* {@code goog.Disposable} base constructor.
|
||||
*/
|
||||
INTERACTIVE: 2
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @define {number} The monitoring mode of the goog.Disposable
|
||||
* instances. Default is OFF. Switching on the monitoring is only
|
||||
* recommended for debugging because it has a significant impact on
|
||||
* performance and memory usage. If switched off, the monitoring code
|
||||
* compiles down to 0 bytes.
|
||||
*/
|
||||
goog.define('goog.Disposable.MONITORING_MODE', 0);
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Whether to attach creation stack to each created disposable
|
||||
* instance; This is only relevant for when MonitoringMode != OFF.
|
||||
*/
|
||||
goog.define('goog.Disposable.INCLUDE_STACK_ON_CREATION', true);
|
||||
|
||||
|
||||
/**
|
||||
* Maps the unique ID of every undisposed {@code goog.Disposable} object to
|
||||
* the object itself.
|
||||
* @type {!Object<number, !goog.Disposable>}
|
||||
* @private
|
||||
*/
|
||||
goog.Disposable.instances_ = {};
|
||||
|
||||
|
||||
/**
|
||||
* @return {!Array<!goog.Disposable>} All {@code goog.Disposable} objects that
|
||||
* haven't been disposed of.
|
||||
*/
|
||||
goog.Disposable.getUndisposedObjects = function() {
|
||||
var ret = [];
|
||||
for (var id in goog.Disposable.instances_) {
|
||||
if (goog.Disposable.instances_.hasOwnProperty(id)) {
|
||||
ret.push(goog.Disposable.instances_[Number(id)]);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clears the registry of undisposed objects but doesn't dispose of them.
|
||||
*/
|
||||
goog.Disposable.clearUndisposedObjects = function() {
|
||||
goog.Disposable.instances_ = {};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether the object has been disposed of.
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
goog.Disposable.prototype.disposed_ = false;
|
||||
|
||||
|
||||
/**
|
||||
* Callbacks to invoke when this object is disposed.
|
||||
* @type {Array<!Function>}
|
||||
* @private
|
||||
*/
|
||||
goog.Disposable.prototype.onDisposeCallbacks_;
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the object has been disposed of.
|
||||
* @override
|
||||
*/
|
||||
goog.Disposable.prototype.isDisposed = function() {
|
||||
return this.disposed_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the object has been disposed of.
|
||||
* @deprecated Use {@link #isDisposed} instead.
|
||||
*/
|
||||
goog.Disposable.prototype.getDisposed = goog.Disposable.prototype.isDisposed;
|
||||
|
||||
|
||||
/**
|
||||
* Disposes of the object. If the object hasn't already been disposed of, calls
|
||||
* {@link #disposeInternal}. Classes that extend {@code goog.Disposable} should
|
||||
* override {@link #disposeInternal} in order to delete references to COM
|
||||
* objects, DOM nodes, and other disposable objects. Reentrant.
|
||||
*
|
||||
* @return {void} Nothing.
|
||||
* @override
|
||||
*/
|
||||
goog.Disposable.prototype.dispose = function() {
|
||||
if (!this.disposed_) {
|
||||
// Set disposed_ to true first, in case during the chain of disposal this
|
||||
// gets disposed recursively.
|
||||
this.disposed_ = true;
|
||||
this.disposeInternal();
|
||||
if (goog.Disposable.MONITORING_MODE != goog.Disposable.MonitoringMode.OFF) {
|
||||
var uid = goog.getUid(this);
|
||||
if (goog.Disposable.MONITORING_MODE ==
|
||||
goog.Disposable.MonitoringMode.PERMANENT &&
|
||||
!goog.Disposable.instances_.hasOwnProperty(uid)) {
|
||||
throw Error(
|
||||
this + ' did not call the goog.Disposable base ' +
|
||||
'constructor or was disposed of after a clearUndisposedObjects ' +
|
||||
'call');
|
||||
}
|
||||
delete goog.Disposable.instances_[uid];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Associates a disposable object with this object so that they will be disposed
|
||||
* together.
|
||||
* @param {goog.disposable.IDisposable} disposable that will be disposed when
|
||||
* this object is disposed.
|
||||
*/
|
||||
goog.Disposable.prototype.registerDisposable = function(disposable) {
|
||||
this.addOnDisposeCallback(goog.partial(goog.dispose, disposable));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Invokes a callback function when this object is disposed. Callbacks are
|
||||
* invoked in the order in which they were added. If a callback is added to
|
||||
* an already disposed Disposable, it will be called immediately.
|
||||
* @param {function(this:T):?} callback The callback function.
|
||||
* @param {T=} opt_scope An optional scope to call the callback in.
|
||||
* @template T
|
||||
*/
|
||||
goog.Disposable.prototype.addOnDisposeCallback = function(callback, opt_scope) {
|
||||
if (this.disposed_) {
|
||||
goog.isDef(opt_scope) ? callback.call(opt_scope) : callback();
|
||||
return;
|
||||
}
|
||||
if (!this.onDisposeCallbacks_) {
|
||||
this.onDisposeCallbacks_ = [];
|
||||
}
|
||||
|
||||
this.onDisposeCallbacks_.push(
|
||||
goog.isDef(opt_scope) ? goog.bind(callback, opt_scope) : callback);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Deletes or nulls out any references to COM objects, DOM nodes, or other
|
||||
* disposable objects. Classes that extend {@code goog.Disposable} should
|
||||
* override this method.
|
||||
* Not reentrant. To avoid calling it twice, it must only be called from the
|
||||
* subclass' {@code disposeInternal} method. Everywhere else the public
|
||||
* {@code dispose} method must be used.
|
||||
* For example:
|
||||
* <pre>
|
||||
* mypackage.MyClass = function() {
|
||||
* mypackage.MyClass.base(this, 'constructor');
|
||||
* // Constructor logic specific to MyClass.
|
||||
* ...
|
||||
* };
|
||||
* goog.inherits(mypackage.MyClass, goog.Disposable);
|
||||
*
|
||||
* mypackage.MyClass.prototype.disposeInternal = function() {
|
||||
* // Dispose logic specific to MyClass.
|
||||
* ...
|
||||
* // Call superclass's disposeInternal at the end of the subclass's, like
|
||||
* // in C++, to avoid hard-to-catch issues.
|
||||
* mypackage.MyClass.base(this, 'disposeInternal');
|
||||
* };
|
||||
* </pre>
|
||||
* @protected
|
||||
*/
|
||||
goog.Disposable.prototype.disposeInternal = function() {
|
||||
if (this.onDisposeCallbacks_) {
|
||||
while (this.onDisposeCallbacks_.length) {
|
||||
this.onDisposeCallbacks_.shift()();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns True if we can verify the object is disposed.
|
||||
* Calls {@code isDisposed} on the argument if it supports it. If obj
|
||||
* is not an object with an isDisposed() method, return false.
|
||||
* @param {*} obj The object to investigate.
|
||||
* @return {boolean} True if we can verify the object is disposed.
|
||||
*/
|
||||
goog.Disposable.isDisposed = function(obj) {
|
||||
if (obj && typeof obj.isDisposed == 'function') {
|
||||
return obj.isDisposed();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls {@code dispose} on the argument if it supports it. If obj is not an
|
||||
* object with a dispose() method, this is a no-op.
|
||||
* @param {*} obj The object to dispose of.
|
||||
*/
|
||||
goog.dispose = function(obj) {
|
||||
if (obj && typeof obj.dispose == 'function') {
|
||||
obj.dispose();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls {@code dispose} on each member of the list that supports it. (If the
|
||||
* member is an ArrayLike, then {@code goog.disposeAll()} will be called
|
||||
* recursively on each of its members.) If the member is not an object with a
|
||||
* {@code dispose()} method, then it is ignored.
|
||||
* @param {...*} var_args The list.
|
||||
*/
|
||||
goog.disposeAll = function(var_args) {
|
||||
for (var i = 0, len = arguments.length; i < len; ++i) {
|
||||
var disposable = arguments[i];
|
||||
if (goog.isArrayLike(disposable)) {
|
||||
goog.disposeAll.apply(null, disposable);
|
||||
} else {
|
||||
goog.dispose(disposable);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -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 Definition of the disposable interface. A disposable object
|
||||
* has a dispose method to to clean up references and resources.
|
||||
* @author nnaze@google.com (Nathan Naze)
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.disposable.IDisposable');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Interface for a disposable object. If a instance requires cleanup
|
||||
* (references COM objects, DOM nodes, or other disposable objects), it should
|
||||
* implement this interface (it may subclass goog.Disposable).
|
||||
* @record
|
||||
*/
|
||||
goog.disposable.IDisposable = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Disposes of the object and its resources.
|
||||
* @return {void} Nothing.
|
||||
*/
|
||||
goog.disposable.IDisposable.prototype.dispose = goog.abstractMethod;
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the object has been disposed of.
|
||||
*/
|
||||
goog.disposable.IDisposable.prototype.isDisposed = goog.abstractMethod;
|
||||
311
resources/public/target/cljsbuild-compiler-1/goog/dom/asserts.js
Normal file
311
resources/public/target/cljsbuild-compiler-1/goog/dom/asserts.js
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
// Copyright 2017 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.
|
||||
|
||||
goog.provide('goog.dom.asserts');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
|
||||
/**
|
||||
* @fileoverview Custom assertions to ensure that an element has the appropriate
|
||||
* type.
|
||||
*
|
||||
* Using a goog.dom.safe wrapper on an object on the incorrect type (via an
|
||||
* incorrect static type cast) can result in security bugs: For instance,
|
||||
* g.d.s.setAnchorHref ensures that the URL assigned to the .href attribute
|
||||
* satisfies the SafeUrl contract, i.e., is safe to dereference as a hyperlink.
|
||||
* However, the value assigned to a HTMLLinkElement's .href property requires
|
||||
* the stronger TrustedResourceUrl contract, since it can refer to a stylesheet.
|
||||
* Thus, using g.d.s.setAnchorHref on an (incorrectly statically typed) object
|
||||
* of type HTMLLinkElement can result in a security vulnerability.
|
||||
* Assertions of the correct run-time type help prevent such incorrect use.
|
||||
*
|
||||
* In some cases, code using the DOM API is tested using mock objects (e.g., a
|
||||
* plain object such as {'href': url} instead of an actual Location object).
|
||||
* To allow such mocking, the assertions permit objects of types that are not
|
||||
* relevant DOM API objects at all (for instance, not Element or Location).
|
||||
*
|
||||
* Note that instanceof checks don't work straightforwardly in older versions of
|
||||
* IE, or across frames (see,
|
||||
* http://stackoverflow.com/questions/384286/javascript-isdom-how-do-you-check-if-a-javascript-object-is-a-dom-object,
|
||||
* http://stackoverflow.com/questions/26248599/instanceof-htmlelement-in-iframe-is-not-element-or-object).
|
||||
*
|
||||
* Hence, these assertions may pass vacuously in such scenarios. The resulting
|
||||
* risk of security bugs is limited by the following factors:
|
||||
* - A bug can only arise in scenarios involving incorrect static typing (the
|
||||
* wrapper methods are statically typed to demand objects of the appropriate,
|
||||
* precise type).
|
||||
* - Typically, code is tested and exercised in multiple browsers.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Asserts that a given object is a Location.
|
||||
*
|
||||
* To permit this assertion to pass in the context of tests where DOM APIs might
|
||||
* be mocked, also accepts any other type except for subtypes of {!Element}.
|
||||
* This is to ensure that, for instance, HTMLLinkElement is not being used in
|
||||
* place of a Location, since this could result in security bugs due to stronger
|
||||
* contracts required for assignments to the href property of the latter.
|
||||
*
|
||||
* @param {?Object} o The object whose type to assert.
|
||||
* @return {!Location}
|
||||
*/
|
||||
goog.dom.asserts.assertIsLocation = function(o) {
|
||||
if (goog.asserts.ENABLE_ASSERTS) {
|
||||
var win = goog.dom.asserts.getWindow_(o);
|
||||
if (typeof win.Location != 'undefined' &&
|
||||
typeof win.Element != 'undefined') {
|
||||
goog.asserts.assert(
|
||||
o && (o instanceof win.Location || !(o instanceof win.Element)),
|
||||
'Argument is not a Location (or a non-Element mock); got: %s',
|
||||
goog.dom.asserts.debugStringForType_(o));
|
||||
}
|
||||
}
|
||||
return /** @type {!Location} */ (o);
|
||||
};
|
||||
|
||||
/**
|
||||
* Asserts that a given object is a HTMLAnchorElement.
|
||||
*
|
||||
* To permit this assertion to pass in the context of tests where elements might
|
||||
* be mocked, also accepts objects that are not of type Location nor a subtype
|
||||
* of Element.
|
||||
*
|
||||
* @param {?Object} o The object whose type to assert.
|
||||
* @return {!HTMLAnchorElement}
|
||||
*/
|
||||
goog.dom.asserts.assertIsHTMLAnchorElement = function(o) {
|
||||
if (goog.asserts.ENABLE_ASSERTS) {
|
||||
var win = goog.dom.asserts.getWindow_(o);
|
||||
if (typeof win.HTMLAnchorElement != 'undefined' &&
|
||||
typeof win.Location != 'undefined' &&
|
||||
typeof win.Element != 'undefined') {
|
||||
goog.asserts.assert(
|
||||
o &&
|
||||
(o instanceof win.HTMLAnchorElement ||
|
||||
!((o instanceof win.Location) || (o instanceof win.Element))),
|
||||
'Argument is not a HTMLAnchorElement (or a non-Element mock); ' +
|
||||
'got: %s',
|
||||
goog.dom.asserts.debugStringForType_(o));
|
||||
}
|
||||
}
|
||||
return /** @type {!HTMLAnchorElement} */ (o);
|
||||
};
|
||||
|
||||
/**
|
||||
* Asserts that a given object is a HTMLLinkElement.
|
||||
*
|
||||
* To permit this assertion to pass in the context of tests where elements might
|
||||
* be mocked, also accepts objects that are not a subtype of Element.
|
||||
*
|
||||
* @param {?Object} o The object whose type to assert.
|
||||
* @return {!HTMLLinkElement}
|
||||
*/
|
||||
goog.dom.asserts.assertIsHTMLLinkElement = function(o) {
|
||||
if (goog.asserts.ENABLE_ASSERTS) {
|
||||
var win = goog.dom.asserts.getWindow_(o);
|
||||
if (typeof win.HTMLLinkElement != 'undefined' &&
|
||||
typeof win.Location != 'undefined' &&
|
||||
typeof win.Element != 'undefined') {
|
||||
goog.asserts.assert(
|
||||
o &&
|
||||
(o instanceof win.HTMLLinkElement ||
|
||||
!((o instanceof win.Location) || (o instanceof win.Element))),
|
||||
'Argument is not a HTMLLinkElement (or a non-Element mock); got: %s',
|
||||
goog.dom.asserts.debugStringForType_(o));
|
||||
}
|
||||
}
|
||||
return /** @type {!HTMLLinkElement} */ (o);
|
||||
};
|
||||
|
||||
/**
|
||||
* Asserts that a given object is a HTMLImageElement.
|
||||
*
|
||||
* To permit this assertion to pass in the context of tests where elements might
|
||||
* be mocked, also accepts objects that are not a subtype of Element.
|
||||
*
|
||||
* @param {?Object} o The object whose type to assert.
|
||||
* @return {!HTMLImageElement}
|
||||
*/
|
||||
goog.dom.asserts.assertIsHTMLImageElement = function(o) {
|
||||
if (goog.asserts.ENABLE_ASSERTS) {
|
||||
var win = goog.dom.asserts.getWindow_(o);
|
||||
if (typeof win.HTMLImageElement != 'undefined' &&
|
||||
typeof win.Element != 'undefined') {
|
||||
goog.asserts.assert(
|
||||
o &&
|
||||
(o instanceof win.HTMLImageElement ||
|
||||
!(o instanceof win.Element)),
|
||||
'Argument is not a HTMLImageElement (or a non-Element mock); got: %s',
|
||||
goog.dom.asserts.debugStringForType_(o));
|
||||
}
|
||||
}
|
||||
return /** @type {!HTMLImageElement} */ (o);
|
||||
};
|
||||
|
||||
/**
|
||||
* Asserts that a given object is a HTMLEmbedElement.
|
||||
*
|
||||
* To permit this assertion to pass in the context of tests where elements might
|
||||
* be mocked, also accepts objects that are not a subtype of Element.
|
||||
*
|
||||
* @param {?Object} o The object whose type to assert.
|
||||
* @return {!HTMLEmbedElement}
|
||||
*/
|
||||
goog.dom.asserts.assertIsHTMLEmbedElement = function(o) {
|
||||
if (goog.asserts.ENABLE_ASSERTS) {
|
||||
var win = goog.dom.asserts.getWindow_(o);
|
||||
if (typeof win.HTMLEmbedElement != 'undefined' &&
|
||||
typeof win.Element != 'undefined') {
|
||||
goog.asserts.assert(
|
||||
o &&
|
||||
(o instanceof win.HTMLEmbedElement ||
|
||||
!(o instanceof win.Element)),
|
||||
'Argument is not a HTMLEmbedElement (or a non-Element mock); got: %s',
|
||||
goog.dom.asserts.debugStringForType_(o));
|
||||
}
|
||||
}
|
||||
return /** @type {!HTMLEmbedElement} */ (o);
|
||||
};
|
||||
|
||||
/**
|
||||
* Asserts that a given object is a HTMLFrameElement.
|
||||
*
|
||||
* To permit this assertion to pass in the context of tests where elements might
|
||||
* be mocked, also accepts objects that are not a subtype of Element.
|
||||
*
|
||||
* @param {?Object} o The object whose type to assert.
|
||||
* @return {!HTMLFrameElement}
|
||||
*/
|
||||
goog.dom.asserts.assertIsHTMLFrameElement = function(o) {
|
||||
if (goog.asserts.ENABLE_ASSERTS) {
|
||||
var win = goog.dom.asserts.getWindow_(o);
|
||||
if (typeof win.HTMLFrameElement != 'undefined' &&
|
||||
typeof win.Element != 'undefined') {
|
||||
goog.asserts.assert(
|
||||
o &&
|
||||
(o instanceof win.HTMLFrameElement ||
|
||||
!(o instanceof win.Element)),
|
||||
'Argument is not a HTMLFrameElement (or a non-Element mock); got: %s',
|
||||
goog.dom.asserts.debugStringForType_(o));
|
||||
}
|
||||
}
|
||||
return /** @type {!HTMLFrameElement} */ (o);
|
||||
};
|
||||
|
||||
/**
|
||||
* Asserts that a given object is a HTMLIFrameElement.
|
||||
*
|
||||
* To permit this assertion to pass in the context of tests where elements might
|
||||
* be mocked, also accepts objects that are not a subtype of Element.
|
||||
*
|
||||
* @param {?Object} o The object whose type to assert.
|
||||
* @return {!HTMLIFrameElement}
|
||||
*/
|
||||
goog.dom.asserts.assertIsHTMLIFrameElement = function(o) {
|
||||
if (goog.asserts.ENABLE_ASSERTS) {
|
||||
var win = goog.dom.asserts.getWindow_(o);
|
||||
if (typeof win.HTMLIFrameElement != 'undefined' &&
|
||||
typeof win.Element != 'undefined') {
|
||||
goog.asserts.assert(
|
||||
o &&
|
||||
(o instanceof win.HTMLIFrameElement ||
|
||||
!(o instanceof win.Element)),
|
||||
'Argument is not a HTMLIFrameElement (or a non-Element mock); ' +
|
||||
'got: %s',
|
||||
goog.dom.asserts.debugStringForType_(o));
|
||||
}
|
||||
}
|
||||
return /** @type {!HTMLIFrameElement} */ (o);
|
||||
};
|
||||
|
||||
/**
|
||||
* Asserts that a given object is a HTMLObjectElement.
|
||||
*
|
||||
* To permit this assertion to pass in the context of tests where elements might
|
||||
* be mocked, also accepts objects that are not a subtype of Element.
|
||||
*
|
||||
* @param {?Object} o The object whose type to assert.
|
||||
* @return {!HTMLObjectElement}
|
||||
*/
|
||||
goog.dom.asserts.assertIsHTMLObjectElement = function(o) {
|
||||
if (goog.asserts.ENABLE_ASSERTS) {
|
||||
var win = goog.dom.asserts.getWindow_(o);
|
||||
if (typeof win.HTMLObjectElement != 'undefined' &&
|
||||
typeof win.Element != 'undefined') {
|
||||
goog.asserts.assert(
|
||||
o &&
|
||||
(o instanceof win.HTMLObjectElement ||
|
||||
!(o instanceof win.Element)),
|
||||
'Argument is not a HTMLObjectElement (or a non-Element mock); ' +
|
||||
'got: %s',
|
||||
goog.dom.asserts.debugStringForType_(o));
|
||||
}
|
||||
}
|
||||
return /** @type {!HTMLObjectElement} */ (o);
|
||||
};
|
||||
|
||||
/**
|
||||
* Asserts that a given object is a HTMLScriptElement.
|
||||
*
|
||||
* To permit this assertion to pass in the context of tests where elements might
|
||||
* be mocked, also accepts objects that are not a subtype of Element.
|
||||
*
|
||||
* @param {?Object} o The object whose type to assert.
|
||||
* @return {!HTMLScriptElement}
|
||||
*/
|
||||
goog.dom.asserts.assertIsHTMLScriptElement = function(o) {
|
||||
if (goog.asserts.ENABLE_ASSERTS) {
|
||||
var win = goog.dom.asserts.getWindow_(o);
|
||||
if (typeof win.HTMLScriptElement != 'undefined' &&
|
||||
typeof win.Element != 'undefined') {
|
||||
goog.asserts.assert(
|
||||
o &&
|
||||
(o instanceof win.HTMLScriptElement ||
|
||||
!(o instanceof win.Element)),
|
||||
'Argument is not a HTMLScriptElement (or a non-Element mock); ' +
|
||||
'got: %s',
|
||||
goog.dom.asserts.debugStringForType_(o));
|
||||
}
|
||||
}
|
||||
return /** @type {!HTMLScriptElement} */ (o);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a string representation of a value's type.
|
||||
*
|
||||
* @param {*} value An object, or primitive.
|
||||
* @return {string} The best display name for the value.
|
||||
* @private
|
||||
*/
|
||||
goog.dom.asserts.debugStringForType_ = function(value) {
|
||||
if (goog.isObject(value)) {
|
||||
return value.constructor.displayName || value.constructor.name ||
|
||||
Object.prototype.toString.call(value);
|
||||
} else {
|
||||
return value === undefined ? 'undefined' :
|
||||
value === null ? 'null' : typeof value;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets window of element.
|
||||
* @param {?Object} o
|
||||
* @return {!Window}
|
||||
* @private
|
||||
*/
|
||||
goog.dom.asserts.getWindow_ = function(o) {
|
||||
var doc = o && o.ownerDocument;
|
||||
var win = doc && /** @type {?Window} */ (doc.defaultView || doc.parentWindow);
|
||||
return win || /** @type {!Window} */ (goog.global);
|
||||
};
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
// Copyright 2010 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 Browser capability checks for the dom package.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.dom.BrowserFeature');
|
||||
|
||||
goog.require('goog.userAgent');
|
||||
|
||||
|
||||
/**
|
||||
* Enum of browser capabilities.
|
||||
* @enum {boolean}
|
||||
*/
|
||||
goog.dom.BrowserFeature = {
|
||||
/**
|
||||
* Whether attributes 'name' and 'type' can be added to an element after it's
|
||||
* created. False in Internet Explorer prior to version 9.
|
||||
*/
|
||||
CAN_ADD_NAME_OR_TYPE_ATTRIBUTES:
|
||||
!goog.userAgent.IE || goog.userAgent.isDocumentModeOrHigher(9),
|
||||
|
||||
/**
|
||||
* Whether we can use element.children to access an element's Element
|
||||
* children. Available since Gecko 1.9.1, IE 9. (IE<9 also includes comment
|
||||
* nodes in the collection.)
|
||||
*/
|
||||
CAN_USE_CHILDREN_ATTRIBUTE: !goog.userAgent.GECKO && !goog.userAgent.IE ||
|
||||
goog.userAgent.IE && goog.userAgent.isDocumentModeOrHigher(9) ||
|
||||
goog.userAgent.GECKO && goog.userAgent.isVersionOrHigher('1.9.1'),
|
||||
|
||||
/**
|
||||
* Opera, Safari 3, and Internet Explorer 9 all support innerText but they
|
||||
* include text nodes in script and style tags. Not document-mode-dependent.
|
||||
*/
|
||||
CAN_USE_INNER_TEXT:
|
||||
(goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('9')),
|
||||
|
||||
/**
|
||||
* MSIE, Opera, and Safari>=4 support element.parentElement to access an
|
||||
* element's parent if it is an Element.
|
||||
*/
|
||||
CAN_USE_PARENT_ELEMENT_PROPERTY:
|
||||
goog.userAgent.IE || goog.userAgent.OPERA || goog.userAgent.WEBKIT,
|
||||
|
||||
/**
|
||||
* Whether NoScope elements need a scoped element written before them in
|
||||
* innerHTML.
|
||||
* MSDN: http://msdn.microsoft.com/en-us/library/ms533897(VS.85).aspx#1
|
||||
*/
|
||||
INNER_HTML_NEEDS_SCOPED_ELEMENT: goog.userAgent.IE,
|
||||
|
||||
/**
|
||||
* Whether we use legacy IE range API.
|
||||
*/
|
||||
LEGACY_IE_RANGES:
|
||||
goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9)
|
||||
};
|
||||
3233
resources/public/target/cljsbuild-compiler-1/goog/dom/dom.js
Normal file
3233
resources/public/target/cljsbuild-compiler-1/goog/dom/dom.js
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright 2017 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.
|
||||
|
||||
goog.provide('goog.dom.HtmlElement');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This subclass of HTMLElement is used when only a HTMLElement is possible and
|
||||
* not any of its subclasses. Normally, a type can refer to an instance of
|
||||
* itself or an instance of any subtype. More concretely, if HTMLElement is used
|
||||
* then the compiler must assume that it might still be e.g. HTMLScriptElement.
|
||||
* With this, the type check knows that it couldn't be any special element.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {HTMLElement}
|
||||
*/
|
||||
goog.dom.HtmlElement = function() {};
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
// Copyright 2006 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 Definition of goog.dom.NodeType.
|
||||
*/
|
||||
|
||||
goog.provide('goog.dom.NodeType');
|
||||
|
||||
|
||||
/**
|
||||
* Constants for the nodeType attribute in the Node interface.
|
||||
*
|
||||
* These constants match those specified in the Node interface. These are
|
||||
* usually present on the Node object in recent browsers, but not in older
|
||||
* browsers (specifically, early IEs) and thus are given here.
|
||||
*
|
||||
* In some browsers (early IEs), these are not defined on the Node object,
|
||||
* so they are provided here.
|
||||
*
|
||||
* See http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-1950641247
|
||||
* @enum {number}
|
||||
*/
|
||||
goog.dom.NodeType = {
|
||||
ELEMENT: 1,
|
||||
ATTRIBUTE: 2,
|
||||
TEXT: 3,
|
||||
CDATA_SECTION: 4,
|
||||
ENTITY_REFERENCE: 5,
|
||||
ENTITY: 6,
|
||||
PROCESSING_INSTRUCTION: 7,
|
||||
COMMENT: 8,
|
||||
DOCUMENT: 9,
|
||||
DOCUMENT_TYPE: 10,
|
||||
DOCUMENT_FRAGMENT: 11,
|
||||
NOTATION: 12
|
||||
};
|
||||
458
resources/public/target/cljsbuild-compiler-1/goog/dom/safe.js
Normal file
458
resources/public/target/cljsbuild-compiler-1/goog/dom/safe.js
Normal file
|
|
@ -0,0 +1,458 @@
|
|||
// Copyright 2013 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 Type-safe wrappers for unsafe DOM APIs.
|
||||
*
|
||||
* This file provides type-safe wrappers for DOM APIs that can result in
|
||||
* cross-site scripting (XSS) vulnerabilities, if the API is supplied with
|
||||
* untrusted (attacker-controlled) input. Instead of plain strings, the type
|
||||
* safe wrappers consume values of types from the goog.html package whose
|
||||
* contract promises that values are safe to use in the corresponding context.
|
||||
*
|
||||
* Hence, a program that exclusively uses the wrappers in this file (i.e., whose
|
||||
* only reference to security-sensitive raw DOM APIs are in this file) is
|
||||
* guaranteed to be free of XSS due to incorrect use of such DOM APIs (modulo
|
||||
* correctness of code that produces values of the respective goog.html types,
|
||||
* and absent code that violates type safety).
|
||||
*
|
||||
* For example, assigning to an element's .innerHTML property a string that is
|
||||
* derived (even partially) from untrusted input typically results in an XSS
|
||||
* vulnerability. The type-safe wrapper goog.dom.safe.setInnerHtml consumes a
|
||||
* value of type goog.html.SafeHtml, whose contract states that using its values
|
||||
* in a HTML context will not result in XSS. Hence a program that is free of
|
||||
* direct assignments to any element's innerHTML property (with the exception of
|
||||
* the assignment to .innerHTML in this file) is guaranteed to be free of XSS
|
||||
* due to assignment of untrusted strings to the innerHTML property.
|
||||
*/
|
||||
|
||||
goog.provide('goog.dom.safe');
|
||||
goog.provide('goog.dom.safe.InsertAdjacentHtmlPosition');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.dom.asserts');
|
||||
goog.require('goog.html.SafeHtml');
|
||||
goog.require('goog.html.SafeScript');
|
||||
goog.require('goog.html.SafeStyle');
|
||||
goog.require('goog.html.SafeUrl');
|
||||
goog.require('goog.html.TrustedResourceUrl');
|
||||
goog.require('goog.string');
|
||||
goog.require('goog.string.Const');
|
||||
|
||||
|
||||
/** @enum {string} */
|
||||
goog.dom.safe.InsertAdjacentHtmlPosition = {
|
||||
AFTERBEGIN: 'afterbegin',
|
||||
AFTEREND: 'afterend',
|
||||
BEFOREBEGIN: 'beforebegin',
|
||||
BEFOREEND: 'beforeend'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Inserts known-safe HTML into a Node, at the specified position.
|
||||
* @param {!Node} node The node on which to call insertAdjacentHTML.
|
||||
* @param {!goog.dom.safe.InsertAdjacentHtmlPosition} position Position where
|
||||
* to insert the HTML.
|
||||
* @param {!goog.html.SafeHtml} html The known-safe HTML to insert.
|
||||
*/
|
||||
goog.dom.safe.insertAdjacentHtml = function(node, position, html) {
|
||||
node.insertAdjacentHTML(position, goog.html.SafeHtml.unwrap(html));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tags not allowed in goog.dom.safe.setInnerHtml.
|
||||
* @private @const {!Object<string, boolean>}
|
||||
*/
|
||||
goog.dom.safe.SET_INNER_HTML_DISALLOWED_TAGS_ = {
|
||||
'MATH': true,
|
||||
'SCRIPT': true,
|
||||
'STYLE': true,
|
||||
'SVG': true,
|
||||
'TEMPLATE': true
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Assigns known-safe HTML to an element's innerHTML property.
|
||||
* @param {!Element} elem The element whose innerHTML is to be assigned to.
|
||||
* @param {!goog.html.SafeHtml} html The known-safe HTML to assign.
|
||||
* @throws {Error} If called with one of these tags: math, script, style, svg,
|
||||
* template.
|
||||
*/
|
||||
goog.dom.safe.setInnerHtml = function(elem, html) {
|
||||
if (goog.asserts.ENABLE_ASSERTS) {
|
||||
var tagName = elem.tagName.toUpperCase();
|
||||
if (goog.dom.safe.SET_INNER_HTML_DISALLOWED_TAGS_[tagName]) {
|
||||
throw Error(
|
||||
'goog.dom.safe.setInnerHtml cannot be used to set content of ' +
|
||||
elem.tagName + '.');
|
||||
}
|
||||
}
|
||||
elem.innerHTML = goog.html.SafeHtml.unwrap(html);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Assigns known-safe HTML to an element's outerHTML property.
|
||||
* @param {!Element} elem The element whose outerHTML is to be assigned to.
|
||||
* @param {!goog.html.SafeHtml} html The known-safe HTML to assign.
|
||||
*/
|
||||
goog.dom.safe.setOuterHtml = function(elem, html) {
|
||||
elem.outerHTML = goog.html.SafeHtml.unwrap(html);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the given element's style property to the contents of the provided
|
||||
* SafeStyle object.
|
||||
* @param {!Element} elem
|
||||
* @param {!goog.html.SafeStyle} style
|
||||
*/
|
||||
goog.dom.safe.setStyle = function(elem, style) {
|
||||
elem.style.cssText = goog.html.SafeStyle.unwrap(style);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Writes known-safe HTML to a document.
|
||||
* @param {!Document} doc The document to be written to.
|
||||
* @param {!goog.html.SafeHtml} html The known-safe HTML to assign.
|
||||
*/
|
||||
goog.dom.safe.documentWrite = function(doc, html) {
|
||||
doc.write(goog.html.SafeHtml.unwrap(html));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Safely assigns a URL to an anchor element's href property.
|
||||
*
|
||||
* If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to
|
||||
* anchor's href property. If url is of type string however, it is first
|
||||
* sanitized using goog.html.SafeUrl.sanitize.
|
||||
*
|
||||
* Example usage:
|
||||
* goog.dom.safe.setAnchorHref(anchorEl, url);
|
||||
* which is a safe alternative to
|
||||
* anchorEl.href = url;
|
||||
* The latter can result in XSS vulnerabilities if url is a
|
||||
* user-/attacker-controlled value.
|
||||
*
|
||||
* @param {!HTMLAnchorElement} anchor The anchor element whose href property
|
||||
* is to be assigned to.
|
||||
* @param {string|!goog.html.SafeUrl} url The URL to assign.
|
||||
* @see goog.html.SafeUrl#sanitize
|
||||
*/
|
||||
goog.dom.safe.setAnchorHref = function(anchor, url) {
|
||||
goog.dom.asserts.assertIsHTMLAnchorElement(anchor);
|
||||
/** @type {!goog.html.SafeUrl} */
|
||||
var safeUrl;
|
||||
if (url instanceof goog.html.SafeUrl) {
|
||||
safeUrl = url;
|
||||
} else {
|
||||
safeUrl = goog.html.SafeUrl.sanitizeAssertUnchanged(url);
|
||||
}
|
||||
anchor.href = goog.html.SafeUrl.unwrap(safeUrl);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Safely assigns a URL to an image element's src property.
|
||||
*
|
||||
* If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to
|
||||
* image's src property. If url is of type string however, it is first
|
||||
* sanitized using goog.html.SafeUrl.sanitize.
|
||||
*
|
||||
* @param {!HTMLImageElement} imageElement The image element whose src property
|
||||
* is to be assigned to.
|
||||
* @param {string|!goog.html.SafeUrl} url The URL to assign.
|
||||
* @see goog.html.SafeUrl#sanitize
|
||||
*/
|
||||
goog.dom.safe.setImageSrc = function(imageElement, url) {
|
||||
goog.dom.asserts.assertIsHTMLImageElement(imageElement);
|
||||
/** @type {!goog.html.SafeUrl} */
|
||||
var safeUrl;
|
||||
if (url instanceof goog.html.SafeUrl) {
|
||||
safeUrl = url;
|
||||
} else {
|
||||
safeUrl = goog.html.SafeUrl.sanitizeAssertUnchanged(url);
|
||||
}
|
||||
imageElement.src = goog.html.SafeUrl.unwrap(safeUrl);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Safely assigns a URL to an embed element's src property.
|
||||
*
|
||||
* Example usage:
|
||||
* goog.dom.safe.setEmbedSrc(embedEl, url);
|
||||
* which is a safe alternative to
|
||||
* embedEl.src = url;
|
||||
* The latter can result in loading untrusted code unless it is ensured that
|
||||
* the URL refers to a trustworthy resource.
|
||||
*
|
||||
* @param {!HTMLEmbedElement} embed The embed element whose src property
|
||||
* is to be assigned to.
|
||||
* @param {!goog.html.TrustedResourceUrl} url The URL to assign.
|
||||
*/
|
||||
goog.dom.safe.setEmbedSrc = function(embed, url) {
|
||||
goog.dom.asserts.assertIsHTMLEmbedElement(embed);
|
||||
embed.src = goog.html.TrustedResourceUrl.unwrap(url);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Safely assigns a URL to a frame element's src property.
|
||||
*
|
||||
* Example usage:
|
||||
* goog.dom.safe.setFrameSrc(frameEl, url);
|
||||
* which is a safe alternative to
|
||||
* frameEl.src = url;
|
||||
* The latter can result in loading untrusted code unless it is ensured that
|
||||
* the URL refers to a trustworthy resource.
|
||||
*
|
||||
* @param {!HTMLFrameElement} frame The frame element whose src property
|
||||
* is to be assigned to.
|
||||
* @param {!goog.html.TrustedResourceUrl} url The URL to assign.
|
||||
*/
|
||||
goog.dom.safe.setFrameSrc = function(frame, url) {
|
||||
goog.dom.asserts.assertIsHTMLFrameElement(frame);
|
||||
frame.src = goog.html.TrustedResourceUrl.unwrap(url);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Safely assigns a URL to an iframe element's src property.
|
||||
*
|
||||
* Example usage:
|
||||
* goog.dom.safe.setIframeSrc(iframeEl, url);
|
||||
* which is a safe alternative to
|
||||
* iframeEl.src = url;
|
||||
* The latter can result in loading untrusted code unless it is ensured that
|
||||
* the URL refers to a trustworthy resource.
|
||||
*
|
||||
* @param {!HTMLIFrameElement} iframe The iframe element whose src property
|
||||
* is to be assigned to.
|
||||
* @param {!goog.html.TrustedResourceUrl} url The URL to assign.
|
||||
*/
|
||||
goog.dom.safe.setIframeSrc = function(iframe, url) {
|
||||
goog.dom.asserts.assertIsHTMLIFrameElement(iframe);
|
||||
iframe.src = goog.html.TrustedResourceUrl.unwrap(url);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Safely assigns HTML to an iframe element's srcdoc property.
|
||||
*
|
||||
* Example usage:
|
||||
* goog.dom.safe.setIframeSrcdoc(iframeEl, safeHtml);
|
||||
* which is a safe alternative to
|
||||
* iframeEl.srcdoc = html;
|
||||
* The latter can result in loading untrusted code.
|
||||
*
|
||||
* @param {!HTMLIFrameElement} iframe The iframe element whose srcdoc property
|
||||
* is to be assigned to.
|
||||
* @param {!goog.html.SafeHtml} html The HTML to assign.
|
||||
*/
|
||||
goog.dom.safe.setIframeSrcdoc = function(iframe, html) {
|
||||
goog.dom.asserts.assertIsHTMLIFrameElement(iframe);
|
||||
iframe.srcdoc = goog.html.SafeHtml.unwrap(html);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Safely sets a link element's href and rel properties. Whether or not
|
||||
* the URL assigned to href has to be a goog.html.TrustedResourceUrl
|
||||
* depends on the value of the rel property. If rel contains "stylesheet"
|
||||
* then a TrustedResourceUrl is required.
|
||||
*
|
||||
* Example usage:
|
||||
* goog.dom.safe.setLinkHrefAndRel(linkEl, url, 'stylesheet');
|
||||
* which is a safe alternative to
|
||||
* linkEl.rel = 'stylesheet';
|
||||
* linkEl.href = url;
|
||||
* The latter can result in loading untrusted code unless it is ensured that
|
||||
* the URL refers to a trustworthy resource.
|
||||
*
|
||||
* @param {!HTMLLinkElement} link The link element whose href property
|
||||
* is to be assigned to.
|
||||
* @param {string|!goog.html.SafeUrl|!goog.html.TrustedResourceUrl} url The URL
|
||||
* to assign to the href property. Must be a TrustedResourceUrl if the
|
||||
* value assigned to rel contains "stylesheet". A string value is
|
||||
* sanitized with goog.html.SafeUrl.sanitize.
|
||||
* @param {string} rel The value to assign to the rel property.
|
||||
* @throws {Error} if rel contains "stylesheet" and url is not a
|
||||
* TrustedResourceUrl
|
||||
* @see goog.html.SafeUrl#sanitize
|
||||
*/
|
||||
goog.dom.safe.setLinkHrefAndRel = function(link, url, rel) {
|
||||
goog.dom.asserts.assertIsHTMLLinkElement(link);
|
||||
link.rel = rel;
|
||||
if (goog.string.caseInsensitiveContains(rel, 'stylesheet')) {
|
||||
goog.asserts.assert(
|
||||
url instanceof goog.html.TrustedResourceUrl,
|
||||
'URL must be TrustedResourceUrl because "rel" contains "stylesheet"');
|
||||
link.href = goog.html.TrustedResourceUrl.unwrap(url);
|
||||
} else if (url instanceof goog.html.TrustedResourceUrl) {
|
||||
link.href = goog.html.TrustedResourceUrl.unwrap(url);
|
||||
} else if (url instanceof goog.html.SafeUrl) {
|
||||
link.href = goog.html.SafeUrl.unwrap(url);
|
||||
} else { // string
|
||||
// SafeUrl.sanitize must return legitimate SafeUrl when passed a string.
|
||||
link.href =
|
||||
goog.html.SafeUrl.sanitizeAssertUnchanged(url).getTypedStringValue();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Safely assigns a URL to an object element's data property.
|
||||
*
|
||||
* Example usage:
|
||||
* goog.dom.safe.setObjectData(objectEl, url);
|
||||
* which is a safe alternative to
|
||||
* objectEl.data = url;
|
||||
* The latter can result in loading untrusted code unless setit is ensured that
|
||||
* the URL refers to a trustworthy resource.
|
||||
*
|
||||
* @param {!HTMLObjectElement} object The object element whose data property
|
||||
* is to be assigned to.
|
||||
* @param {!goog.html.TrustedResourceUrl} url The URL to assign.
|
||||
*/
|
||||
goog.dom.safe.setObjectData = function(object, url) {
|
||||
goog.dom.asserts.assertIsHTMLObjectElement(object);
|
||||
object.data = goog.html.TrustedResourceUrl.unwrap(url);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Safely assigns a URL to a script element's src property.
|
||||
*
|
||||
* Example usage:
|
||||
* goog.dom.safe.setScriptSrc(scriptEl, url);
|
||||
* which is a safe alternative to
|
||||
* scriptEl.src = url;
|
||||
* The latter can result in loading untrusted code unless it is ensured that
|
||||
* the URL refers to a trustworthy resource.
|
||||
*
|
||||
* @param {!HTMLScriptElement} script The script element whose src property
|
||||
* is to be assigned to.
|
||||
* @param {!goog.html.TrustedResourceUrl} url The URL to assign.
|
||||
*/
|
||||
goog.dom.safe.setScriptSrc = function(script, url) {
|
||||
goog.dom.asserts.assertIsHTMLScriptElement(script);
|
||||
script.src = goog.html.TrustedResourceUrl.unwrap(url);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Safely assigns a value to a script element's content.
|
||||
*
|
||||
* Example usage:
|
||||
* goog.dom.safe.setScriptContent(scriptEl, content);
|
||||
* which is a safe alternative to
|
||||
* scriptEl.text = content;
|
||||
* The latter can result in executing untrusted code unless it is ensured that
|
||||
* the code is loaded from a trustworthy resource.
|
||||
*
|
||||
* @param {!HTMLScriptElement} script The script element whose content is being
|
||||
* set.
|
||||
* @param {!goog.html.SafeScript} content The content to assign.
|
||||
*/
|
||||
goog.dom.safe.setScriptContent = function(script, content) {
|
||||
goog.dom.asserts.assertIsHTMLScriptElement(script);
|
||||
script.text = goog.html.SafeScript.unwrap(content);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Safely assigns a URL to a Location object's href property.
|
||||
*
|
||||
* If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to
|
||||
* loc's href property. If url is of type string however, it is first sanitized
|
||||
* using goog.html.SafeUrl.sanitize.
|
||||
*
|
||||
* Example usage:
|
||||
* goog.dom.safe.setLocationHref(document.location, redirectUrl);
|
||||
* which is a safe alternative to
|
||||
* document.location.href = redirectUrl;
|
||||
* The latter can result in XSS vulnerabilities if redirectUrl is a
|
||||
* user-/attacker-controlled value.
|
||||
*
|
||||
* @param {!Location} loc The Location object whose href property is to be
|
||||
* assigned to.
|
||||
* @param {string|!goog.html.SafeUrl} url The URL to assign.
|
||||
* @see goog.html.SafeUrl#sanitize
|
||||
*/
|
||||
goog.dom.safe.setLocationHref = function(loc, url) {
|
||||
goog.dom.asserts.assertIsLocation(loc);
|
||||
/** @type {!goog.html.SafeUrl} */
|
||||
var safeUrl;
|
||||
if (url instanceof goog.html.SafeUrl) {
|
||||
safeUrl = url;
|
||||
} else {
|
||||
safeUrl = goog.html.SafeUrl.sanitizeAssertUnchanged(url);
|
||||
}
|
||||
loc.href = goog.html.SafeUrl.unwrap(safeUrl);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Safely opens a URL in a new window (via window.open).
|
||||
*
|
||||
* If url is of type goog.html.SafeUrl, its value is unwrapped and passed in to
|
||||
* window.open. If url is of type string however, it is first sanitized
|
||||
* using goog.html.SafeUrl.sanitize.
|
||||
*
|
||||
* Note that this function does not prevent leakages via the referer that is
|
||||
* sent by window.open. It is advised to only use this to open 1st party URLs.
|
||||
*
|
||||
* Example usage:
|
||||
* goog.dom.safe.openInWindow(url);
|
||||
* which is a safe alternative to
|
||||
* window.open(url);
|
||||
* The latter can result in XSS vulnerabilities if redirectUrl is a
|
||||
* user-/attacker-controlled value.
|
||||
*
|
||||
* @param {string|!goog.html.SafeUrl} url The URL to open.
|
||||
* @param {Window=} opt_openerWin Window of which to call the .open() method.
|
||||
* Defaults to the global window.
|
||||
* @param {!goog.string.Const=} opt_name Name of the window to open in. Can be
|
||||
* _top, etc as allowed by window.open().
|
||||
* @param {string=} opt_specs Comma-separated list of specifications, same as
|
||||
* in window.open().
|
||||
* @param {boolean=} opt_replace Whether to replace the current entry in browser
|
||||
* history, same as in window.open().
|
||||
* @return {Window} Window the url was opened in.
|
||||
*/
|
||||
goog.dom.safe.openInWindow = function(
|
||||
url, opt_openerWin, opt_name, opt_specs, opt_replace) {
|
||||
/** @type {!goog.html.SafeUrl} */
|
||||
var safeUrl;
|
||||
if (url instanceof goog.html.SafeUrl) {
|
||||
safeUrl = url;
|
||||
} else {
|
||||
safeUrl = goog.html.SafeUrl.sanitizeAssertUnchanged(url);
|
||||
}
|
||||
var win = opt_openerWin || window;
|
||||
return win.open(
|
||||
goog.html.SafeUrl.unwrap(safeUrl),
|
||||
// If opt_name is undefined, simply passing that in to open() causes IE to
|
||||
// reuse the current window instead of opening a new one. Thus we pass ''
|
||||
// in instead, which according to spec opens a new window. See
|
||||
// https://html.spec.whatwg.org/multipage/browsers.html#dom-open .
|
||||
opt_name ? goog.string.Const.unwrap(opt_name) : '', opt_specs,
|
||||
opt_replace);
|
||||
};
|
||||
562
resources/public/target/cljsbuild-compiler-1/goog/dom/tagname.js
Normal file
562
resources/public/target/cljsbuild-compiler-1/goog/dom/tagname.js
Normal file
|
|
@ -0,0 +1,562 @@
|
|||
// Copyright 2007 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 the goog.dom.TagName class. Its constants enumerate
|
||||
* all HTML tag names specified in either the the W3C HTML 4.01 index of
|
||||
* elements or the HTML5 draft specification.
|
||||
*
|
||||
* References:
|
||||
* http://www.w3.org/TR/html401/index/elements.html
|
||||
* http://dev.w3.org/html5/spec/section-index.html
|
||||
*/
|
||||
goog.provide('goog.dom.TagName');
|
||||
|
||||
goog.require('goog.dom.HtmlElement');
|
||||
|
||||
|
||||
/**
|
||||
* A tag name with the type of the element stored in the generic.
|
||||
* @param {string} tagName
|
||||
* @constructor
|
||||
* @template T
|
||||
*/
|
||||
goog.dom.TagName = function(tagName) {
|
||||
/** @private {string} */
|
||||
this.tagName_ = tagName;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the tag name.
|
||||
* @return {string}
|
||||
* @override
|
||||
*/
|
||||
goog.dom.TagName.prototype.toString = function() {
|
||||
return this.tagName_;
|
||||
};
|
||||
|
||||
|
||||
// Closure Compiler unconditionally converts the following constants to their
|
||||
// string value (goog.dom.TagName.A -> 'A'). These are the consequences:
|
||||
// 1. Don't add any members or static members to goog.dom.TagName as they
|
||||
// couldn't be accessed after this optimization.
|
||||
// 2. Keep the constant name and its string value the same:
|
||||
// goog.dom.TagName.X = new goog.dom.TagName('Y');
|
||||
// is converted to 'X', not 'Y'.
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLAnchorElement>} */
|
||||
goog.dom.TagName.A = new goog.dom.TagName('A');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.ABBR = new goog.dom.TagName('ABBR');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.ACRONYM = new goog.dom.TagName('ACRONYM');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.ADDRESS = new goog.dom.TagName('ADDRESS');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLAppletElement>} */
|
||||
goog.dom.TagName.APPLET = new goog.dom.TagName('APPLET');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLAreaElement>} */
|
||||
goog.dom.TagName.AREA = new goog.dom.TagName('AREA');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.ARTICLE = new goog.dom.TagName('ARTICLE');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.ASIDE = new goog.dom.TagName('ASIDE');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLAudioElement>} */
|
||||
goog.dom.TagName.AUDIO = new goog.dom.TagName('AUDIO');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.B = new goog.dom.TagName('B');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLBaseElement>} */
|
||||
goog.dom.TagName.BASE = new goog.dom.TagName('BASE');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLBaseFontElement>} */
|
||||
goog.dom.TagName.BASEFONT = new goog.dom.TagName('BASEFONT');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.BDI = new goog.dom.TagName('BDI');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.BDO = new goog.dom.TagName('BDO');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.BIG = new goog.dom.TagName('BIG');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLQuoteElement>} */
|
||||
goog.dom.TagName.BLOCKQUOTE = new goog.dom.TagName('BLOCKQUOTE');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLBodyElement>} */
|
||||
goog.dom.TagName.BODY = new goog.dom.TagName('BODY');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLBRElement>} */
|
||||
goog.dom.TagName.BR = new goog.dom.TagName('BR');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLButtonElement>} */
|
||||
goog.dom.TagName.BUTTON = new goog.dom.TagName('BUTTON');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLCanvasElement>} */
|
||||
goog.dom.TagName.CANVAS = new goog.dom.TagName('CANVAS');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLTableCaptionElement>} */
|
||||
goog.dom.TagName.CAPTION = new goog.dom.TagName('CAPTION');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.CENTER = new goog.dom.TagName('CENTER');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.CITE = new goog.dom.TagName('CITE');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.CODE = new goog.dom.TagName('CODE');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLTableColElement>} */
|
||||
goog.dom.TagName.COL = new goog.dom.TagName('COL');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLTableColElement>} */
|
||||
goog.dom.TagName.COLGROUP = new goog.dom.TagName('COLGROUP');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.COMMAND = new goog.dom.TagName('COMMAND');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.DATA = new goog.dom.TagName('DATA');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLDataListElement>} */
|
||||
goog.dom.TagName.DATALIST = new goog.dom.TagName('DATALIST');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.DD = new goog.dom.TagName('DD');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLModElement>} */
|
||||
goog.dom.TagName.DEL = new goog.dom.TagName('DEL');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLDetailsElement>} */
|
||||
goog.dom.TagName.DETAILS = new goog.dom.TagName('DETAILS');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.DFN = new goog.dom.TagName('DFN');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLDialogElement>} */
|
||||
goog.dom.TagName.DIALOG = new goog.dom.TagName('DIALOG');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLDirectoryElement>} */
|
||||
goog.dom.TagName.DIR = new goog.dom.TagName('DIR');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLDivElement>} */
|
||||
goog.dom.TagName.DIV = new goog.dom.TagName('DIV');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLDListElement>} */
|
||||
goog.dom.TagName.DL = new goog.dom.TagName('DL');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.DT = new goog.dom.TagName('DT');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.EM = new goog.dom.TagName('EM');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLEmbedElement>} */
|
||||
goog.dom.TagName.EMBED = new goog.dom.TagName('EMBED');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLFieldSetElement>} */
|
||||
goog.dom.TagName.FIELDSET = new goog.dom.TagName('FIELDSET');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.FIGCAPTION = new goog.dom.TagName('FIGCAPTION');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.FIGURE = new goog.dom.TagName('FIGURE');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLFontElement>} */
|
||||
goog.dom.TagName.FONT = new goog.dom.TagName('FONT');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.FOOTER = new goog.dom.TagName('FOOTER');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLFormElement>} */
|
||||
goog.dom.TagName.FORM = new goog.dom.TagName('FORM');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLFrameElement>} */
|
||||
goog.dom.TagName.FRAME = new goog.dom.TagName('FRAME');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLFrameSetElement>} */
|
||||
goog.dom.TagName.FRAMESET = new goog.dom.TagName('FRAMESET');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLHeadingElement>} */
|
||||
goog.dom.TagName.H1 = new goog.dom.TagName('H1');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLHeadingElement>} */
|
||||
goog.dom.TagName.H2 = new goog.dom.TagName('H2');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLHeadingElement>} */
|
||||
goog.dom.TagName.H3 = new goog.dom.TagName('H3');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLHeadingElement>} */
|
||||
goog.dom.TagName.H4 = new goog.dom.TagName('H4');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLHeadingElement>} */
|
||||
goog.dom.TagName.H5 = new goog.dom.TagName('H5');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLHeadingElement>} */
|
||||
goog.dom.TagName.H6 = new goog.dom.TagName('H6');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLHeadElement>} */
|
||||
goog.dom.TagName.HEAD = new goog.dom.TagName('HEAD');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.HEADER = new goog.dom.TagName('HEADER');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.HGROUP = new goog.dom.TagName('HGROUP');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLHRElement>} */
|
||||
goog.dom.TagName.HR = new goog.dom.TagName('HR');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLHtmlElement>} */
|
||||
goog.dom.TagName.HTML = new goog.dom.TagName('HTML');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.I = new goog.dom.TagName('I');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLIFrameElement>} */
|
||||
goog.dom.TagName.IFRAME = new goog.dom.TagName('IFRAME');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLImageElement>} */
|
||||
goog.dom.TagName.IMG = new goog.dom.TagName('IMG');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLInputElement>} */
|
||||
goog.dom.TagName.INPUT = new goog.dom.TagName('INPUT');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLModElement>} */
|
||||
goog.dom.TagName.INS = new goog.dom.TagName('INS');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLIsIndexElement>} */
|
||||
goog.dom.TagName.ISINDEX = new goog.dom.TagName('ISINDEX');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.KBD = new goog.dom.TagName('KBD');
|
||||
|
||||
|
||||
// HTMLKeygenElement is deprecated.
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.KEYGEN = new goog.dom.TagName('KEYGEN');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLLabelElement>} */
|
||||
goog.dom.TagName.LABEL = new goog.dom.TagName('LABEL');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLLegendElement>} */
|
||||
goog.dom.TagName.LEGEND = new goog.dom.TagName('LEGEND');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLLIElement>} */
|
||||
goog.dom.TagName.LI = new goog.dom.TagName('LI');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLLinkElement>} */
|
||||
goog.dom.TagName.LINK = new goog.dom.TagName('LINK');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLMapElement>} */
|
||||
goog.dom.TagName.MAP = new goog.dom.TagName('MAP');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.MARK = new goog.dom.TagName('MARK');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.MATH = new goog.dom.TagName('MATH');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLMenuElement>} */
|
||||
goog.dom.TagName.MENU = new goog.dom.TagName('MENU');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLMetaElement>} */
|
||||
goog.dom.TagName.META = new goog.dom.TagName('META');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLMeterElement>} */
|
||||
goog.dom.TagName.METER = new goog.dom.TagName('METER');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.NAV = new goog.dom.TagName('NAV');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.NOFRAMES = new goog.dom.TagName('NOFRAMES');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.NOSCRIPT = new goog.dom.TagName('NOSCRIPT');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLObjectElement>} */
|
||||
goog.dom.TagName.OBJECT = new goog.dom.TagName('OBJECT');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLOListElement>} */
|
||||
goog.dom.TagName.OL = new goog.dom.TagName('OL');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLOptGroupElement>} */
|
||||
goog.dom.TagName.OPTGROUP = new goog.dom.TagName('OPTGROUP');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLOptionElement>} */
|
||||
goog.dom.TagName.OPTION = new goog.dom.TagName('OPTION');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLOutputElement>} */
|
||||
goog.dom.TagName.OUTPUT = new goog.dom.TagName('OUTPUT');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLParagraphElement>} */
|
||||
goog.dom.TagName.P = new goog.dom.TagName('P');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLParamElement>} */
|
||||
goog.dom.TagName.PARAM = new goog.dom.TagName('PARAM');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLPreElement>} */
|
||||
goog.dom.TagName.PRE = new goog.dom.TagName('PRE');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLProgressElement>} */
|
||||
goog.dom.TagName.PROGRESS = new goog.dom.TagName('PROGRESS');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLQuoteElement>} */
|
||||
goog.dom.TagName.Q = new goog.dom.TagName('Q');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.RP = new goog.dom.TagName('RP');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.RT = new goog.dom.TagName('RT');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.RUBY = new goog.dom.TagName('RUBY');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.S = new goog.dom.TagName('S');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.SAMP = new goog.dom.TagName('SAMP');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLScriptElement>} */
|
||||
goog.dom.TagName.SCRIPT = new goog.dom.TagName('SCRIPT');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.SECTION = new goog.dom.TagName('SECTION');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLSelectElement>} */
|
||||
goog.dom.TagName.SELECT = new goog.dom.TagName('SELECT');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.SMALL = new goog.dom.TagName('SMALL');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLSourceElement>} */
|
||||
goog.dom.TagName.SOURCE = new goog.dom.TagName('SOURCE');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLSpanElement>} */
|
||||
goog.dom.TagName.SPAN = new goog.dom.TagName('SPAN');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.STRIKE = new goog.dom.TagName('STRIKE');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.STRONG = new goog.dom.TagName('STRONG');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLStyleElement>} */
|
||||
goog.dom.TagName.STYLE = new goog.dom.TagName('STYLE');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.SUB = new goog.dom.TagName('SUB');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.SUMMARY = new goog.dom.TagName('SUMMARY');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.SUP = new goog.dom.TagName('SUP');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.SVG = new goog.dom.TagName('SVG');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLTableElement>} */
|
||||
goog.dom.TagName.TABLE = new goog.dom.TagName('TABLE');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLTableSectionElement>} */
|
||||
goog.dom.TagName.TBODY = new goog.dom.TagName('TBODY');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLTableCellElement>} */
|
||||
goog.dom.TagName.TD = new goog.dom.TagName('TD');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLTemplateElement>} */
|
||||
goog.dom.TagName.TEMPLATE = new goog.dom.TagName('TEMPLATE');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLTextAreaElement>} */
|
||||
goog.dom.TagName.TEXTAREA = new goog.dom.TagName('TEXTAREA');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLTableSectionElement>} */
|
||||
goog.dom.TagName.TFOOT = new goog.dom.TagName('TFOOT');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLTableCellElement>} */
|
||||
goog.dom.TagName.TH = new goog.dom.TagName('TH');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLTableSectionElement>} */
|
||||
goog.dom.TagName.THEAD = new goog.dom.TagName('THEAD');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.TIME = new goog.dom.TagName('TIME');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLTitleElement>} */
|
||||
goog.dom.TagName.TITLE = new goog.dom.TagName('TITLE');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLTableRowElement>} */
|
||||
goog.dom.TagName.TR = new goog.dom.TagName('TR');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLTrackElement>} */
|
||||
goog.dom.TagName.TRACK = new goog.dom.TagName('TRACK');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.TT = new goog.dom.TagName('TT');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.U = new goog.dom.TagName('U');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLUListElement>} */
|
||||
goog.dom.TagName.UL = new goog.dom.TagName('UL');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.VAR = new goog.dom.TagName('VAR');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!HTMLVideoElement>} */
|
||||
goog.dom.TagName.VIDEO = new goog.dom.TagName('VIDEO');
|
||||
|
||||
|
||||
/** @type {!goog.dom.TagName<!goog.dom.HtmlElement>} */
|
||||
goog.dom.TagName.WBR = new goog.dom.TagName('WBR');
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright 2014 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 Utilities for HTML element tag names.
|
||||
*/
|
||||
goog.provide('goog.dom.tags');
|
||||
|
||||
goog.require('goog.object');
|
||||
|
||||
|
||||
/**
|
||||
* The void elements specified by
|
||||
* http://www.w3.org/TR/html-markup/syntax.html#void-elements.
|
||||
* @const @private {!Object<string, boolean>}
|
||||
*/
|
||||
goog.dom.tags.VOID_TAGS_ = goog.object.createSet(
|
||||
'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input',
|
||||
'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr');
|
||||
|
||||
|
||||
/**
|
||||
* Checks whether the tag is void (with no contents allowed and no legal end
|
||||
* tag), for example 'br'.
|
||||
* @param {string} tagName The tag name in lower case.
|
||||
* @return {boolean}
|
||||
*/
|
||||
goog.dom.tags.isVoidTag = function(tagName) {
|
||||
return goog.dom.tags.VOID_TAGS_[tagName] === true;
|
||||
};
|
||||
|
|
@ -0,0 +1,409 @@
|
|||
// Copyright 2005 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 A patched, standardized event object for browser events.
|
||||
*
|
||||
* <pre>
|
||||
* The patched event object contains the following members:
|
||||
* - type {string} Event type, e.g. 'click'
|
||||
* - target {Object} The element that actually triggered the event
|
||||
* - currentTarget {Object} The element the listener is attached to
|
||||
* - relatedTarget {Object} For mouseover and mouseout, the previous object
|
||||
* - offsetX {number} X-coordinate relative to target
|
||||
* - offsetY {number} Y-coordinate relative to target
|
||||
* - clientX {number} X-coordinate relative to viewport
|
||||
* - clientY {number} Y-coordinate relative to viewport
|
||||
* - screenX {number} X-coordinate relative to the edge of the screen
|
||||
* - screenY {number} Y-coordinate relative to the edge of the screen
|
||||
* - button {number} Mouse button. Use isButton() to test.
|
||||
* - keyCode {number} Key-code
|
||||
* - ctrlKey {boolean} Was ctrl key depressed
|
||||
* - altKey {boolean} Was alt key depressed
|
||||
* - shiftKey {boolean} Was shift key depressed
|
||||
* - metaKey {boolean} Was meta key depressed
|
||||
* - defaultPrevented {boolean} Whether the default action has been prevented
|
||||
* - state {Object} History state object
|
||||
*
|
||||
* NOTE: The keyCode member contains the raw browser keyCode. For normalized
|
||||
* key and character code use {@link goog.events.KeyHandler}.
|
||||
* </pre>
|
||||
*
|
||||
* @author arv@google.com (Erik Arvidsson)
|
||||
*/
|
||||
|
||||
goog.provide('goog.events.BrowserEvent');
|
||||
goog.provide('goog.events.BrowserEvent.MouseButton');
|
||||
|
||||
goog.require('goog.events.BrowserFeature');
|
||||
goog.require('goog.events.Event');
|
||||
goog.require('goog.events.EventType');
|
||||
goog.require('goog.reflect');
|
||||
goog.require('goog.userAgent');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Accepts a browser event object and creates a patched, cross browser event
|
||||
* object.
|
||||
* The content of this object will not be initialized if no event object is
|
||||
* provided. If this is the case, init() needs to be invoked separately.
|
||||
* @param {Event=} opt_e Browser event object.
|
||||
* @param {EventTarget=} opt_currentTarget Current target for event.
|
||||
* @constructor
|
||||
* @extends {goog.events.Event}
|
||||
*/
|
||||
goog.events.BrowserEvent = function(opt_e, opt_currentTarget) {
|
||||
goog.events.BrowserEvent.base(this, 'constructor', opt_e ? opt_e.type : '');
|
||||
|
||||
/**
|
||||
* Target that fired the event.
|
||||
* @override
|
||||
* @type {Node}
|
||||
*/
|
||||
this.target = null;
|
||||
|
||||
/**
|
||||
* Node that had the listener attached.
|
||||
* @override
|
||||
* @type {Node|undefined}
|
||||
*/
|
||||
this.currentTarget = null;
|
||||
|
||||
/**
|
||||
* For mouseover and mouseout events, the related object for the event.
|
||||
* @type {Node}
|
||||
*/
|
||||
this.relatedTarget = null;
|
||||
|
||||
/**
|
||||
* X-coordinate relative to target.
|
||||
* @type {number}
|
||||
*/
|
||||
this.offsetX = 0;
|
||||
|
||||
/**
|
||||
* Y-coordinate relative to target.
|
||||
* @type {number}
|
||||
*/
|
||||
this.offsetY = 0;
|
||||
|
||||
/**
|
||||
* X-coordinate relative to the window.
|
||||
* @type {number}
|
||||
*/
|
||||
this.clientX = 0;
|
||||
|
||||
/**
|
||||
* Y-coordinate relative to the window.
|
||||
* @type {number}
|
||||
*/
|
||||
this.clientY = 0;
|
||||
|
||||
/**
|
||||
* X-coordinate relative to the monitor.
|
||||
* @type {number}
|
||||
*/
|
||||
this.screenX = 0;
|
||||
|
||||
/**
|
||||
* Y-coordinate relative to the monitor.
|
||||
* @type {number}
|
||||
*/
|
||||
this.screenY = 0;
|
||||
|
||||
/**
|
||||
* Which mouse button was pressed.
|
||||
* @type {number}
|
||||
*/
|
||||
this.button = 0;
|
||||
|
||||
/**
|
||||
* Key of key press.
|
||||
* @type {string}
|
||||
*/
|
||||
this.key = '';
|
||||
|
||||
/**
|
||||
* Keycode of key press.
|
||||
* @type {number}
|
||||
*/
|
||||
this.keyCode = 0;
|
||||
|
||||
/**
|
||||
* Keycode of key press.
|
||||
* @type {number}
|
||||
*/
|
||||
this.charCode = 0;
|
||||
|
||||
/**
|
||||
* Whether control was pressed at time of event.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.ctrlKey = false;
|
||||
|
||||
/**
|
||||
* Whether alt was pressed at time of event.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.altKey = false;
|
||||
|
||||
/**
|
||||
* Whether shift was pressed at time of event.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.shiftKey = false;
|
||||
|
||||
/**
|
||||
* Whether the meta key was pressed at time of event.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.metaKey = false;
|
||||
|
||||
/**
|
||||
* History state object, only set for PopState events where it's a copy of the
|
||||
* state object provided to pushState or replaceState.
|
||||
* @type {Object}
|
||||
*/
|
||||
this.state = null;
|
||||
|
||||
/**
|
||||
* Whether the default platform modifier key was pressed at time of event.
|
||||
* (This is control for all platforms except Mac, where it's Meta.)
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.platformModifierKey = false;
|
||||
|
||||
/**
|
||||
* The browser event object.
|
||||
* @private {Event}
|
||||
*/
|
||||
this.event_ = null;
|
||||
|
||||
if (opt_e) {
|
||||
this.init(opt_e, opt_currentTarget);
|
||||
}
|
||||
};
|
||||
goog.inherits(goog.events.BrowserEvent, goog.events.Event);
|
||||
|
||||
|
||||
/**
|
||||
* Normalized button constants for the mouse.
|
||||
* @enum {number}
|
||||
*/
|
||||
goog.events.BrowserEvent.MouseButton = {
|
||||
LEFT: 0,
|
||||
MIDDLE: 1,
|
||||
RIGHT: 2
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Static data for mapping mouse buttons.
|
||||
* @type {!Array<number>}
|
||||
*/
|
||||
goog.events.BrowserEvent.IEButtonMap = [
|
||||
1, // LEFT
|
||||
4, // MIDDLE
|
||||
2 // RIGHT
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Accepts a browser event object and creates a patched, cross browser event
|
||||
* object.
|
||||
* @param {Event} e Browser event object.
|
||||
* @param {EventTarget=} opt_currentTarget Current target for event.
|
||||
*/
|
||||
goog.events.BrowserEvent.prototype.init = function(e, opt_currentTarget) {
|
||||
var type = this.type = e.type;
|
||||
|
||||
/**
|
||||
* On touch devices use the first "changed touch" as the relevant touch.
|
||||
* @type {Touch}
|
||||
*/
|
||||
var relevantTouch = e.changedTouches ? e.changedTouches[0] : null;
|
||||
|
||||
// TODO(nicksantos): Change this.target to type EventTarget.
|
||||
this.target = /** @type {Node} */ (e.target) || e.srcElement;
|
||||
|
||||
// TODO(nicksantos): Change this.currentTarget to type EventTarget.
|
||||
this.currentTarget = /** @type {Node} */ (opt_currentTarget);
|
||||
|
||||
var relatedTarget = /** @type {Node} */ (e.relatedTarget);
|
||||
if (relatedTarget) {
|
||||
// There's a bug in FireFox where sometimes, relatedTarget will be a
|
||||
// chrome element, and accessing any property of it will get a permission
|
||||
// denied exception. See:
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=497780
|
||||
if (goog.userAgent.GECKO) {
|
||||
if (!goog.reflect.canAccessProperty(relatedTarget, 'nodeName')) {
|
||||
relatedTarget = null;
|
||||
}
|
||||
}
|
||||
// TODO(arv): Use goog.events.EventType when it has been refactored into its
|
||||
// own file.
|
||||
} else if (type == goog.events.EventType.MOUSEOVER) {
|
||||
relatedTarget = e.fromElement;
|
||||
} else if (type == goog.events.EventType.MOUSEOUT) {
|
||||
relatedTarget = e.toElement;
|
||||
}
|
||||
|
||||
this.relatedTarget = relatedTarget;
|
||||
|
||||
if (!goog.isNull(relevantTouch)) {
|
||||
this.clientX = relevantTouch.clientX !== undefined ? relevantTouch.clientX :
|
||||
relevantTouch.pageX;
|
||||
this.clientY = relevantTouch.clientY !== undefined ? relevantTouch.clientY :
|
||||
relevantTouch.pageY;
|
||||
this.screenX = relevantTouch.screenX || 0;
|
||||
this.screenY = relevantTouch.screenY || 0;
|
||||
} else {
|
||||
// Webkit emits a lame warning whenever layerX/layerY is accessed.
|
||||
// http://code.google.com/p/chromium/issues/detail?id=101733
|
||||
this.offsetX = (goog.userAgent.WEBKIT || e.offsetX !== undefined) ?
|
||||
e.offsetX :
|
||||
e.layerX;
|
||||
this.offsetY = (goog.userAgent.WEBKIT || e.offsetY !== undefined) ?
|
||||
e.offsetY :
|
||||
e.layerY;
|
||||
this.clientX = e.clientX !== undefined ? e.clientX : e.pageX;
|
||||
this.clientY = e.clientY !== undefined ? e.clientY : e.pageY;
|
||||
this.screenX = e.screenX || 0;
|
||||
this.screenY = e.screenY || 0;
|
||||
}
|
||||
|
||||
this.button = e.button;
|
||||
|
||||
this.keyCode = e.keyCode || 0;
|
||||
this.key = e.key || '';
|
||||
this.charCode = e.charCode || (type == 'keypress' ? e.keyCode : 0);
|
||||
this.ctrlKey = e.ctrlKey;
|
||||
this.altKey = e.altKey;
|
||||
this.shiftKey = e.shiftKey;
|
||||
this.metaKey = e.metaKey;
|
||||
this.platformModifierKey = goog.userAgent.MAC ? e.metaKey : e.ctrlKey;
|
||||
this.state = e.state;
|
||||
this.event_ = e;
|
||||
if (e.defaultPrevented) {
|
||||
this.preventDefault();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tests to see which button was pressed during the event. This is really only
|
||||
* useful in IE and Gecko browsers. And in IE, it's only useful for
|
||||
* mousedown/mouseup events, because click only fires for the left mouse button.
|
||||
*
|
||||
* Safari 2 only reports the left button being clicked, and uses the value '1'
|
||||
* instead of 0. Opera only reports a mousedown event for the middle button, and
|
||||
* no mouse events for the right button. Opera has default behavior for left and
|
||||
* middle click that can only be overridden via a configuration setting.
|
||||
*
|
||||
* There's a nice table of this mess at http://www.unixpapa.com/js/mouse.html.
|
||||
*
|
||||
* @param {goog.events.BrowserEvent.MouseButton} button The button
|
||||
* to test for.
|
||||
* @return {boolean} True if button was pressed.
|
||||
*/
|
||||
goog.events.BrowserEvent.prototype.isButton = function(button) {
|
||||
if (!goog.events.BrowserFeature.HAS_W3C_BUTTON) {
|
||||
if (this.type == 'click') {
|
||||
return button == goog.events.BrowserEvent.MouseButton.LEFT;
|
||||
} else {
|
||||
return !!(
|
||||
this.event_.button & goog.events.BrowserEvent.IEButtonMap[button]);
|
||||
}
|
||||
} else {
|
||||
return this.event_.button == button;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether this has an "action"-producing mouse button.
|
||||
*
|
||||
* By definition, this includes left-click on windows/linux, and left-click
|
||||
* without the ctrl key on Macs.
|
||||
*
|
||||
* @return {boolean} The result.
|
||||
*/
|
||||
goog.events.BrowserEvent.prototype.isMouseActionButton = function() {
|
||||
// Webkit does not ctrl+click to be a right-click, so we
|
||||
// normalize it to behave like Gecko and Opera.
|
||||
return this.isButton(goog.events.BrowserEvent.MouseButton.LEFT) &&
|
||||
!(goog.userAgent.WEBKIT && goog.userAgent.MAC && this.ctrlKey);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
goog.events.BrowserEvent.prototype.stopPropagation = function() {
|
||||
goog.events.BrowserEvent.superClass_.stopPropagation.call(this);
|
||||
if (this.event_.stopPropagation) {
|
||||
this.event_.stopPropagation();
|
||||
} else {
|
||||
this.event_.cancelBubble = true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
goog.events.BrowserEvent.prototype.preventDefault = function() {
|
||||
goog.events.BrowserEvent.superClass_.preventDefault.call(this);
|
||||
var be = this.event_;
|
||||
if (!be.preventDefault) {
|
||||
be.returnValue = false;
|
||||
if (goog.events.BrowserFeature.SET_KEY_CODE_TO_PREVENT_DEFAULT) {
|
||||
|
||||
try {
|
||||
// Most keys can be prevented using returnValue. Some special keys
|
||||
// require setting the keyCode to -1 as well:
|
||||
//
|
||||
// In IE7:
|
||||
// F3, F5, F10, F11, Ctrl+P, Crtl+O, Ctrl+F (these are taken from IE6)
|
||||
//
|
||||
// In IE8:
|
||||
// Ctrl+P, Crtl+O, Ctrl+F (F1-F12 cannot be stopped through the event)
|
||||
//
|
||||
// We therefore do this for all function keys as well as when Ctrl key
|
||||
// is pressed.
|
||||
var VK_F1 = 112;
|
||||
var VK_F12 = 123;
|
||||
if (be.ctrlKey || be.keyCode >= VK_F1 && be.keyCode <= VK_F12) {
|
||||
be.keyCode = -1;
|
||||
}
|
||||
} catch (ex) {
|
||||
// IE throws an 'access denied' exception when trying to change
|
||||
// keyCode in some situations (e.g. srcElement is input[type=file],
|
||||
// or srcElement is an anchor tag rewritten by parent's innerHTML).
|
||||
// Do nothing in this case.
|
||||
}
|
||||
}
|
||||
} else {
|
||||
be.preventDefault();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Event} The underlying browser event object.
|
||||
*/
|
||||
goog.events.BrowserEvent.prototype.getBrowserEvent = function() {
|
||||
return this.event_;
|
||||
};
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
// Copyright 2010 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 Browser capability checks for the events package.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.events.BrowserFeature');
|
||||
|
||||
goog.require('goog.userAgent');
|
||||
goog.scope(function() {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Enum of browser capabilities.
|
||||
* @enum {boolean}
|
||||
*/
|
||||
goog.events.BrowserFeature = {
|
||||
/**
|
||||
* Whether the button attribute of the event is W3C compliant. False in
|
||||
* Internet Explorer prior to version 9; document-version dependent.
|
||||
*/
|
||||
HAS_W3C_BUTTON:
|
||||
!goog.userAgent.IE || goog.userAgent.isDocumentModeOrHigher(9),
|
||||
|
||||
/**
|
||||
* Whether the browser supports full W3C event model.
|
||||
*/
|
||||
HAS_W3C_EVENT_SUPPORT:
|
||||
!goog.userAgent.IE || goog.userAgent.isDocumentModeOrHigher(9),
|
||||
|
||||
/**
|
||||
* To prevent default in IE7-8 for certain keydown events we need set the
|
||||
* keyCode to -1.
|
||||
*/
|
||||
SET_KEY_CODE_TO_PREVENT_DEFAULT:
|
||||
goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('9'),
|
||||
|
||||
/**
|
||||
* Whether the {@code navigator.onLine} property is supported.
|
||||
*/
|
||||
HAS_NAVIGATOR_ONLINE_PROPERTY:
|
||||
!goog.userAgent.WEBKIT || goog.userAgent.isVersionOrHigher('528'),
|
||||
|
||||
/**
|
||||
* Whether HTML5 network online/offline events are supported.
|
||||
*/
|
||||
HAS_HTML5_NETWORK_EVENT_SUPPORT:
|
||||
goog.userAgent.GECKO && goog.userAgent.isVersionOrHigher('1.9b') ||
|
||||
goog.userAgent.IE && goog.userAgent.isVersionOrHigher('8') ||
|
||||
goog.userAgent.OPERA && goog.userAgent.isVersionOrHigher('9.5') ||
|
||||
goog.userAgent.WEBKIT && goog.userAgent.isVersionOrHigher('528'),
|
||||
|
||||
/**
|
||||
* Whether HTML5 network events fire on document.body, or otherwise the
|
||||
* window.
|
||||
*/
|
||||
HTML5_NETWORK_EVENTS_FIRE_ON_BODY:
|
||||
goog.userAgent.GECKO && !goog.userAgent.isVersionOrHigher('8') ||
|
||||
goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('9'),
|
||||
|
||||
/**
|
||||
* Whether touch is enabled in the browser.
|
||||
*/
|
||||
TOUCH_ENABLED:
|
||||
('ontouchstart' in goog.global ||
|
||||
!!(goog.global['document'] && document.documentElement &&
|
||||
'ontouchstart' in document.documentElement) ||
|
||||
// IE10 uses non-standard touch events, so it has a different check.
|
||||
!!(goog.global['navigator'] &&
|
||||
goog.global['navigator']['msMaxTouchPoints'])),
|
||||
|
||||
/**
|
||||
* Whether addEventListener supports {passive: true}.
|
||||
* https://developers.google.com/web/updates/2016/06/passive-event-listeners
|
||||
*/
|
||||
PASSIVE_EVENTS: purify(function() {
|
||||
// If we're in a web worker or other custom environment, we can't tell.
|
||||
if (!goog.global.addEventListener || !Object.defineProperty) { // IE 8
|
||||
return false;
|
||||
}
|
||||
|
||||
var passive = false;
|
||||
var options = Object.defineProperty({}, 'passive', {
|
||||
get: function() {
|
||||
passive = true;
|
||||
}
|
||||
});
|
||||
goog.global.addEventListener('test', goog.nullFunction, options);
|
||||
goog.global.removeEventListener('test', goog.nullFunction, options);
|
||||
|
||||
return passive;
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tricks Closure Compiler into believing that a function is pure. The compiler
|
||||
* assumes that any `valueOf` function is pure, without analyzing its contents.
|
||||
*
|
||||
* @param {function(): T} fn
|
||||
* @return {T}
|
||||
* @template T
|
||||
*/
|
||||
function purify(fn) {
|
||||
return ({valueOf: fn}).valueOf();
|
||||
}
|
||||
}); // goog.scope
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
// Copyright 2005 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 A base class for event objects.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.events.Event');
|
||||
goog.provide('goog.events.EventLike');
|
||||
|
||||
/**
|
||||
* goog.events.Event no longer depends on goog.Disposable. Keep requiring
|
||||
* goog.Disposable here to not break projects which assume this dependency.
|
||||
* @suppress {extraRequire}
|
||||
*/
|
||||
goog.require('goog.Disposable');
|
||||
goog.require('goog.events.EventId');
|
||||
|
||||
|
||||
/**
|
||||
* A typedef for event like objects that are dispatchable via the
|
||||
* goog.events.dispatchEvent function. strings are treated as the type for a
|
||||
* goog.events.Event. Objects are treated as an extension of a new
|
||||
* goog.events.Event with the type property of the object being used as the type
|
||||
* of the Event.
|
||||
* @typedef {string|Object|goog.events.Event|goog.events.EventId}
|
||||
*/
|
||||
goog.events.EventLike;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A base class for event objects, so that they can support preventDefault and
|
||||
* stopPropagation.
|
||||
*
|
||||
* @suppress {underscore} Several properties on this class are technically
|
||||
* public, but referencing these properties outside this package is strongly
|
||||
* discouraged.
|
||||
*
|
||||
* @param {string|!goog.events.EventId} type Event Type.
|
||||
* @param {Object=} opt_target Reference to the object that is the target of
|
||||
* this event. It has to implement the {@code EventTarget} interface
|
||||
* declared at {@link http://developer.mozilla.org/en/DOM/EventTarget}.
|
||||
* @constructor
|
||||
*/
|
||||
goog.events.Event = function(type, opt_target) {
|
||||
/**
|
||||
* Event type.
|
||||
* @type {string}
|
||||
*/
|
||||
this.type = type instanceof goog.events.EventId ? String(type) : type;
|
||||
|
||||
/**
|
||||
* TODO(tbreisacher): The type should probably be
|
||||
* EventTarget|goog.events.EventTarget.
|
||||
*
|
||||
* Target of the event.
|
||||
* @type {Object|undefined}
|
||||
*/
|
||||
this.target = opt_target;
|
||||
|
||||
/**
|
||||
* Object that had the listener attached.
|
||||
* @type {Object|undefined}
|
||||
*/
|
||||
this.currentTarget = this.target;
|
||||
|
||||
/**
|
||||
* Whether to cancel the event in internal capture/bubble processing for IE.
|
||||
* @type {boolean}
|
||||
* @public
|
||||
*/
|
||||
this.propagationStopped_ = false;
|
||||
|
||||
/**
|
||||
* Whether the default action has been prevented.
|
||||
* This is a property to match the W3C specification at
|
||||
* {@link http://www.w3.org/TR/DOM-Level-3-Events/
|
||||
* #events-event-type-defaultPrevented}.
|
||||
* Must be treated as read-only outside the class.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.defaultPrevented = false;
|
||||
|
||||
/**
|
||||
* Return value for in internal capture/bubble processing for IE.
|
||||
* @type {boolean}
|
||||
* @public
|
||||
*/
|
||||
this.returnValue_ = true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Stops event propagation.
|
||||
*/
|
||||
goog.events.Event.prototype.stopPropagation = function() {
|
||||
this.propagationStopped_ = true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Prevents the default action, for example a link redirecting to a url.
|
||||
*/
|
||||
goog.events.Event.prototype.preventDefault = function() {
|
||||
this.defaultPrevented = true;
|
||||
this.returnValue_ = false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Stops the propagation of the event. It is equivalent to
|
||||
* {@code e.stopPropagation()}, but can be used as the callback argument of
|
||||
* {@link goog.events.listen} without declaring another function.
|
||||
* @param {!goog.events.Event} e An event.
|
||||
*/
|
||||
goog.events.Event.stopPropagation = function(e) {
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Prevents the default action. It is equivalent to
|
||||
* {@code e.preventDefault()}, but can be used as the callback argument of
|
||||
* {@link goog.events.listen} without declaring another function.
|
||||
* @param {!goog.events.Event} e An event.
|
||||
*/
|
||||
goog.events.Event.preventDefault = function(e) {
|
||||
e.preventDefault();
|
||||
};
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
// Copyright 2013 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.
|
||||
|
||||
goog.provide('goog.events.EventId');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A templated class that is used when registering for events. Typical usage:
|
||||
*
|
||||
* /** @type {goog.events.EventId<MyEventObj>} *\
|
||||
* var myEventId = new goog.events.EventId(
|
||||
* goog.events.getUniqueId(('someEvent'));
|
||||
*
|
||||
* // No need to cast or declare here since the compiler knows the
|
||||
* // correct type of 'evt' (MyEventObj).
|
||||
* something.listen(myEventId, function(evt) {});
|
||||
*
|
||||
* @param {string} eventId
|
||||
* @template T
|
||||
* @constructor
|
||||
* @struct
|
||||
* @final
|
||||
*/
|
||||
goog.events.EventId = function(eventId) {
|
||||
/** @const */ this.id = eventId;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
goog.events.EventId.prototype.toString = function() {
|
||||
return this.id;
|
||||
};
|
||||
1003
resources/public/target/cljsbuild-compiler-1/goog/events/events.js
Normal file
1003
resources/public/target/cljsbuild-compiler-1/goog/events/events.js
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,394 @@
|
|||
// Copyright 2005 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 A disposable implementation of a custom
|
||||
* listenable/event target. See also: documentation for
|
||||
* {@code goog.events.Listenable}.
|
||||
*
|
||||
* @author arv@google.com (Erik Arvidsson) [Original implementation]
|
||||
* @see ../demos/eventtarget.html
|
||||
* @see goog.events.Listenable
|
||||
*/
|
||||
|
||||
goog.provide('goog.events.EventTarget');
|
||||
|
||||
goog.require('goog.Disposable');
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.events.Event');
|
||||
goog.require('goog.events.Listenable');
|
||||
goog.require('goog.events.ListenerMap');
|
||||
goog.require('goog.object');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* An implementation of {@code goog.events.Listenable} with full W3C
|
||||
* EventTarget-like support (capture/bubble mechanism, stopping event
|
||||
* propagation, preventing default actions).
|
||||
*
|
||||
* You may subclass this class to turn your class into a Listenable.
|
||||
*
|
||||
* Unless propagation is stopped, an event dispatched by an
|
||||
* EventTarget will bubble to the parent returned by
|
||||
* {@code getParentEventTarget}. To set the parent, call
|
||||
* {@code setParentEventTarget}. Subclasses that don't support
|
||||
* changing the parent can override the setter to throw an error.
|
||||
*
|
||||
* Example usage:
|
||||
* <pre>
|
||||
* var source = new goog.events.EventTarget();
|
||||
* function handleEvent(e) {
|
||||
* alert('Type: ' + e.type + '; Target: ' + e.target);
|
||||
* }
|
||||
* source.listen('foo', handleEvent);
|
||||
* // Or: goog.events.listen(source, 'foo', handleEvent);
|
||||
* ...
|
||||
* source.dispatchEvent('foo'); // will call handleEvent
|
||||
* ...
|
||||
* source.unlisten('foo', handleEvent);
|
||||
* // Or: goog.events.unlisten(source, 'foo', handleEvent);
|
||||
* </pre>
|
||||
*
|
||||
* @constructor
|
||||
* @extends {goog.Disposable}
|
||||
* @implements {goog.events.Listenable}
|
||||
*/
|
||||
goog.events.EventTarget = function() {
|
||||
goog.Disposable.call(this);
|
||||
|
||||
/**
|
||||
* Maps of event type to an array of listeners.
|
||||
* @private {!goog.events.ListenerMap}
|
||||
*/
|
||||
this.eventTargetListeners_ = new goog.events.ListenerMap(this);
|
||||
|
||||
/**
|
||||
* The object to use for event.target. Useful when mixing in an
|
||||
* EventTarget to another object.
|
||||
* @private {!Object}
|
||||
*/
|
||||
this.actualEventTarget_ = this;
|
||||
|
||||
/**
|
||||
* Parent event target, used during event bubbling.
|
||||
*
|
||||
* TODO(chrishenry): Change this to goog.events.Listenable. This
|
||||
* currently breaks people who expect getParentEventTarget to return
|
||||
* goog.events.EventTarget.
|
||||
*
|
||||
* @private {goog.events.EventTarget}
|
||||
*/
|
||||
this.parentEventTarget_ = null;
|
||||
};
|
||||
goog.inherits(goog.events.EventTarget, goog.Disposable);
|
||||
goog.events.Listenable.addImplementation(goog.events.EventTarget);
|
||||
|
||||
|
||||
/**
|
||||
* An artificial cap on the number of ancestors you can have. This is mainly
|
||||
* for loop detection.
|
||||
* @const {number}
|
||||
* @private
|
||||
*/
|
||||
goog.events.EventTarget.MAX_ANCESTORS_ = 1000;
|
||||
|
||||
|
||||
/**
|
||||
* Returns the parent of this event target to use for bubbling.
|
||||
*
|
||||
* @return {goog.events.EventTarget} The parent EventTarget or null if
|
||||
* there is no parent.
|
||||
* @override
|
||||
*/
|
||||
goog.events.EventTarget.prototype.getParentEventTarget = function() {
|
||||
return this.parentEventTarget_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the parent of this event target to use for capture/bubble
|
||||
* mechanism.
|
||||
* @param {goog.events.EventTarget} parent Parent listenable (null if none).
|
||||
*/
|
||||
goog.events.EventTarget.prototype.setParentEventTarget = function(parent) {
|
||||
this.parentEventTarget_ = parent;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds an event listener to the event target. The same handler can only be
|
||||
* added once per the type. Even if you add the same handler multiple times
|
||||
* using the same type then it will only be called once when the event is
|
||||
* dispatched.
|
||||
*
|
||||
* @param {string|!goog.events.EventId} type The type of the event to listen for
|
||||
* @param {function(?):?|{handleEvent:function(?):?}|null} handler The function
|
||||
* to handle the event. The handler can also be an object that implements
|
||||
* the handleEvent method which takes the event object as argument.
|
||||
* @param {boolean=} opt_capture In DOM-compliant browsers, this determines
|
||||
* whether the listener is fired during the capture or bubble phase
|
||||
* of the event.
|
||||
* @param {Object=} opt_handlerScope Object in whose scope to call
|
||||
* the listener.
|
||||
* @deprecated Use {@code #listen} instead, when possible. Otherwise, use
|
||||
* {@code goog.events.listen} if you are passing Object
|
||||
* (instead of Function) as handler.
|
||||
*/
|
||||
goog.events.EventTarget.prototype.addEventListener = function(
|
||||
type, handler, opt_capture, opt_handlerScope) {
|
||||
goog.events.listen(this, type, handler, opt_capture, opt_handlerScope);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes an event listener from the event target. The handler must be the
|
||||
* same object as the one added. If the handler has not been added then
|
||||
* nothing is done.
|
||||
*
|
||||
* @param {string} type The type of the event to listen for.
|
||||
* @param {function(?):?|{handleEvent:function(?):?}|null} handler The function
|
||||
* to handle the event. The handler can also be an object that implements
|
||||
* the handleEvent method which takes the event object as argument.
|
||||
* @param {boolean=} opt_capture In DOM-compliant browsers, this determines
|
||||
* whether the listener is fired during the capture or bubble phase
|
||||
* of the event.
|
||||
* @param {Object=} opt_handlerScope Object in whose scope to call
|
||||
* the listener.
|
||||
* @deprecated Use {@code #unlisten} instead, when possible. Otherwise, use
|
||||
* {@code goog.events.unlisten} if you are passing Object
|
||||
* (instead of Function) as handler.
|
||||
*/
|
||||
goog.events.EventTarget.prototype.removeEventListener = function(
|
||||
type, handler, opt_capture, opt_handlerScope) {
|
||||
goog.events.unlisten(this, type, handler, opt_capture, opt_handlerScope);
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.events.EventTarget.prototype.dispatchEvent = function(e) {
|
||||
this.assertInitialized_();
|
||||
|
||||
var ancestorsTree, ancestor = this.getParentEventTarget();
|
||||
if (ancestor) {
|
||||
ancestorsTree = [];
|
||||
var ancestorCount = 1;
|
||||
for (; ancestor; ancestor = ancestor.getParentEventTarget()) {
|
||||
ancestorsTree.push(ancestor);
|
||||
goog.asserts.assert(
|
||||
(++ancestorCount < goog.events.EventTarget.MAX_ANCESTORS_),
|
||||
'infinite loop');
|
||||
}
|
||||
}
|
||||
|
||||
return goog.events.EventTarget.dispatchEventInternal_(
|
||||
this.actualEventTarget_, e, ancestorsTree);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes listeners from this object. Classes that extend EventTarget may
|
||||
* need to override this method in order to remove references to DOM Elements
|
||||
* and additional listeners.
|
||||
* @override
|
||||
*/
|
||||
goog.events.EventTarget.prototype.disposeInternal = function() {
|
||||
goog.events.EventTarget.superClass_.disposeInternal.call(this);
|
||||
|
||||
this.removeAllListeners();
|
||||
this.parentEventTarget_ = null;
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.events.EventTarget.prototype.listen = function(
|
||||
type, listener, opt_useCapture, opt_listenerScope) {
|
||||
this.assertInitialized_();
|
||||
return this.eventTargetListeners_.add(
|
||||
String(type), listener, false /* callOnce */, opt_useCapture,
|
||||
opt_listenerScope);
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.events.EventTarget.prototype.listenOnce = function(
|
||||
type, listener, opt_useCapture, opt_listenerScope) {
|
||||
return this.eventTargetListeners_.add(
|
||||
String(type), listener, true /* callOnce */, opt_useCapture,
|
||||
opt_listenerScope);
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.events.EventTarget.prototype.unlisten = function(
|
||||
type, listener, opt_useCapture, opt_listenerScope) {
|
||||
return this.eventTargetListeners_.remove(
|
||||
String(type), listener, opt_useCapture, opt_listenerScope);
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.events.EventTarget.prototype.unlistenByKey = function(key) {
|
||||
return this.eventTargetListeners_.removeByKey(key);
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.events.EventTarget.prototype.removeAllListeners = function(opt_type) {
|
||||
// TODO(chrishenry): Previously, removeAllListeners can be called on
|
||||
// uninitialized EventTarget, so we preserve that behavior. We
|
||||
// should remove this when usages that rely on that fact are purged.
|
||||
if (!this.eventTargetListeners_) {
|
||||
return 0;
|
||||
}
|
||||
return this.eventTargetListeners_.removeAll(opt_type);
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.events.EventTarget.prototype.fireListeners = function(
|
||||
type, capture, eventObject) {
|
||||
// TODO(chrishenry): Original code avoids array creation when there
|
||||
// is no listener, so we do the same. If this optimization turns
|
||||
// out to be not required, we can replace this with
|
||||
// getListeners(type, capture) instead, which is simpler.
|
||||
var listenerArray = this.eventTargetListeners_.listeners[String(type)];
|
||||
if (!listenerArray) {
|
||||
return true;
|
||||
}
|
||||
listenerArray = listenerArray.concat();
|
||||
|
||||
var rv = true;
|
||||
for (var i = 0; i < listenerArray.length; ++i) {
|
||||
var listener = listenerArray[i];
|
||||
// We might not have a listener if the listener was removed.
|
||||
if (listener && !listener.removed && listener.capture == capture) {
|
||||
var listenerFn = listener.listener;
|
||||
var listenerHandler = listener.handler || listener.src;
|
||||
|
||||
if (listener.callOnce) {
|
||||
this.unlistenByKey(listener);
|
||||
}
|
||||
rv = listenerFn.call(listenerHandler, eventObject) !== false && rv;
|
||||
}
|
||||
}
|
||||
|
||||
return rv && eventObject.returnValue_ != false;
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.events.EventTarget.prototype.getListeners = function(type, capture) {
|
||||
return this.eventTargetListeners_.getListeners(String(type), capture);
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.events.EventTarget.prototype.getListener = function(
|
||||
type, listener, capture, opt_listenerScope) {
|
||||
return this.eventTargetListeners_.getListener(
|
||||
String(type), listener, capture, opt_listenerScope);
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.events.EventTarget.prototype.hasListener = function(
|
||||
opt_type, opt_capture) {
|
||||
var id = goog.isDef(opt_type) ? String(opt_type) : undefined;
|
||||
return this.eventTargetListeners_.hasListener(id, opt_capture);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the target to be used for {@code event.target} when firing
|
||||
* event. Mainly used for testing. For example, see
|
||||
* {@code goog.testing.events.mixinListenable}.
|
||||
* @param {!Object} target The target.
|
||||
*/
|
||||
goog.events.EventTarget.prototype.setTargetForTesting = function(target) {
|
||||
this.actualEventTarget_ = target;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Asserts that the event target instance is initialized properly.
|
||||
* @private
|
||||
*/
|
||||
goog.events.EventTarget.prototype.assertInitialized_ = function() {
|
||||
goog.asserts.assert(
|
||||
this.eventTargetListeners_,
|
||||
'Event target is not initialized. Did you call the superclass ' +
|
||||
'(goog.events.EventTarget) constructor?');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Dispatches the given event on the ancestorsTree.
|
||||
*
|
||||
* @param {!Object} target The target to dispatch on.
|
||||
* @param {goog.events.Event|Object|string} e The event object.
|
||||
* @param {Array<goog.events.Listenable>=} opt_ancestorsTree The ancestors
|
||||
* tree of the target, in reverse order from the closest ancestor
|
||||
* to the root event target. May be null if the target has no ancestor.
|
||||
* @return {boolean} If anyone called preventDefault on the event object (or
|
||||
* if any of the listeners returns false) this will also return false.
|
||||
* @private
|
||||
*/
|
||||
goog.events.EventTarget.dispatchEventInternal_ = function(
|
||||
target, e, opt_ancestorsTree) {
|
||||
var type = e.type || /** @type {string} */ (e);
|
||||
|
||||
// If accepting a string or object, create a custom event object so that
|
||||
// preventDefault and stopPropagation work with the event.
|
||||
if (goog.isString(e)) {
|
||||
e = new goog.events.Event(e, target);
|
||||
} else if (!(e instanceof goog.events.Event)) {
|
||||
var oldEvent = e;
|
||||
e = new goog.events.Event(type, target);
|
||||
goog.object.extend(e, oldEvent);
|
||||
} else {
|
||||
e.target = e.target || target;
|
||||
}
|
||||
|
||||
var rv = true, currentTarget;
|
||||
|
||||
// Executes all capture listeners on the ancestors, if any.
|
||||
if (opt_ancestorsTree) {
|
||||
for (var i = opt_ancestorsTree.length - 1; !e.propagationStopped_ && i >= 0;
|
||||
i--) {
|
||||
currentTarget = e.currentTarget = opt_ancestorsTree[i];
|
||||
rv = currentTarget.fireListeners(type, true, e) && rv;
|
||||
}
|
||||
}
|
||||
|
||||
// Executes capture and bubble listeners on the target.
|
||||
if (!e.propagationStopped_) {
|
||||
currentTarget = /** @type {?} */ (e.currentTarget = target);
|
||||
rv = currentTarget.fireListeners(type, true, e) && rv;
|
||||
if (!e.propagationStopped_) {
|
||||
rv = currentTarget.fireListeners(type, false, e) && rv;
|
||||
}
|
||||
}
|
||||
|
||||
// Executes all bubble listeners on the ancestors, if any.
|
||||
if (opt_ancestorsTree) {
|
||||
for (i = 0; !e.propagationStopped_ && i < opt_ancestorsTree.length; i++) {
|
||||
currentTarget = e.currentTarget = opt_ancestorsTree[i];
|
||||
rv = currentTarget.fireListeners(type, false, e) && rv;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
};
|
||||
|
|
@ -0,0 +1,295 @@
|
|||
// Copyright 2010 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 Event Types.
|
||||
*
|
||||
* @author arv@google.com (Erik Arvidsson)
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.events.EventType');
|
||||
|
||||
goog.require('goog.userAgent');
|
||||
|
||||
|
||||
/**
|
||||
* Returns a prefixed event name for the current browser.
|
||||
* @param {string} eventName The name of the event.
|
||||
* @return {string} The prefixed event name.
|
||||
* @suppress {missingRequire|missingProvide}
|
||||
* @private
|
||||
*/
|
||||
goog.events.getVendorPrefixedName_ = function(eventName) {
|
||||
return goog.userAgent.WEBKIT ?
|
||||
'webkit' + eventName :
|
||||
(goog.userAgent.OPERA ? 'o' + eventName.toLowerCase() :
|
||||
eventName.toLowerCase());
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Constants for event names.
|
||||
* @enum {string}
|
||||
*/
|
||||
goog.events.EventType = {
|
||||
// Mouse events
|
||||
CLICK: 'click',
|
||||
RIGHTCLICK: 'rightclick',
|
||||
DBLCLICK: 'dblclick',
|
||||
MOUSEDOWN: 'mousedown',
|
||||
MOUSEUP: 'mouseup',
|
||||
MOUSEOVER: 'mouseover',
|
||||
MOUSEOUT: 'mouseout',
|
||||
MOUSEMOVE: 'mousemove',
|
||||
MOUSEENTER: 'mouseenter',
|
||||
MOUSELEAVE: 'mouseleave',
|
||||
|
||||
// Selection events.
|
||||
// https://www.w3.org/TR/selection-api/
|
||||
SELECTIONCHANGE: 'selectionchange',
|
||||
SELECTSTART: 'selectstart', // IE, Safari, Chrome
|
||||
|
||||
// Wheel events
|
||||
// http://www.w3.org/TR/DOM-Level-3-Events/#events-wheelevents
|
||||
WHEEL: 'wheel',
|
||||
|
||||
// Key events
|
||||
KEYPRESS: 'keypress',
|
||||
KEYDOWN: 'keydown',
|
||||
KEYUP: 'keyup',
|
||||
|
||||
// Focus
|
||||
BLUR: 'blur',
|
||||
FOCUS: 'focus',
|
||||
DEACTIVATE: 'deactivate', // IE only
|
||||
// NOTE: The following two events are not stable in cross-browser usage.
|
||||
// WebKit and Opera implement DOMFocusIn/Out.
|
||||
// IE implements focusin/out.
|
||||
// Gecko implements neither see bug at
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=396927.
|
||||
// The DOM Events Level 3 Draft deprecates DOMFocusIn in favor of focusin:
|
||||
// http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html
|
||||
// You can use FOCUS in Capture phase until implementations converge.
|
||||
FOCUSIN: goog.userAgent.IE ? 'focusin' : 'DOMFocusIn',
|
||||
FOCUSOUT: goog.userAgent.IE ? 'focusout' : 'DOMFocusOut',
|
||||
|
||||
// Forms
|
||||
CHANGE: 'change',
|
||||
RESET: 'reset',
|
||||
SELECT: 'select',
|
||||
SUBMIT: 'submit',
|
||||
INPUT: 'input',
|
||||
PROPERTYCHANGE: 'propertychange', // IE only
|
||||
|
||||
// Drag and drop
|
||||
DRAGSTART: 'dragstart',
|
||||
DRAG: 'drag',
|
||||
DRAGENTER: 'dragenter',
|
||||
DRAGOVER: 'dragover',
|
||||
DRAGLEAVE: 'dragleave',
|
||||
DROP: 'drop',
|
||||
DRAGEND: 'dragend',
|
||||
|
||||
// Touch events
|
||||
// Note that other touch events exist, but we should follow the W3C list here.
|
||||
// http://www.w3.org/TR/touch-events/#list-of-touchevent-types
|
||||
TOUCHSTART: 'touchstart',
|
||||
TOUCHMOVE: 'touchmove',
|
||||
TOUCHEND: 'touchend',
|
||||
TOUCHCANCEL: 'touchcancel',
|
||||
|
||||
// Misc
|
||||
BEFOREUNLOAD: 'beforeunload',
|
||||
CONSOLEMESSAGE: 'consolemessage',
|
||||
CONTEXTMENU: 'contextmenu',
|
||||
DEVICEMOTION: 'devicemotion',
|
||||
DEVICEORIENTATION: 'deviceorientation',
|
||||
DOMCONTENTLOADED: 'DOMContentLoaded',
|
||||
ERROR: 'error',
|
||||
HELP: 'help',
|
||||
LOAD: 'load',
|
||||
LOSECAPTURE: 'losecapture',
|
||||
ORIENTATIONCHANGE: 'orientationchange',
|
||||
READYSTATECHANGE: 'readystatechange',
|
||||
RESIZE: 'resize',
|
||||
SCROLL: 'scroll',
|
||||
UNLOAD: 'unload',
|
||||
|
||||
// Media events
|
||||
CANPLAY: 'canplay',
|
||||
CANPLAYTHROUGH: 'canplaythrough',
|
||||
DURATIONCHANGE: 'durationchange',
|
||||
EMPTIED: 'emptied',
|
||||
ENDED: 'ended',
|
||||
LOADEDDATA: 'loadeddata',
|
||||
LOADEDMETADATA: 'loadedmetadata',
|
||||
PAUSE: 'pause',
|
||||
PLAY: 'play',
|
||||
PLAYING: 'playing',
|
||||
RATECHANGE: 'ratechange',
|
||||
SEEKED: 'seeked',
|
||||
SEEKING: 'seeking',
|
||||
STALLED: 'stalled',
|
||||
SUSPEND: 'suspend',
|
||||
TIMEUPDATE: 'timeupdate',
|
||||
VOLUMECHANGE: 'volumechange',
|
||||
WAITING: 'waiting',
|
||||
|
||||
// Media Source Extensions events
|
||||
// https://www.w3.org/TR/media-source/#mediasource-events
|
||||
SOURCEOPEN: 'sourceopen',
|
||||
SOURCEENDED: 'sourceended',
|
||||
SOURCECLOSED: 'sourceclosed',
|
||||
// https://www.w3.org/TR/media-source/#sourcebuffer-events
|
||||
ABORT: 'abort',
|
||||
UPDATE: 'update',
|
||||
UPDATESTART: 'updatestart',
|
||||
UPDATEEND: 'updateend',
|
||||
|
||||
// HTML 5 History events
|
||||
// See http://www.w3.org/TR/html5/browsers.html#event-definitions-0
|
||||
HASHCHANGE: 'hashchange',
|
||||
PAGEHIDE: 'pagehide',
|
||||
PAGESHOW: 'pageshow',
|
||||
POPSTATE: 'popstate',
|
||||
|
||||
// Copy and Paste
|
||||
// Support is limited. Make sure it works on your favorite browser
|
||||
// before using.
|
||||
// http://www.quirksmode.org/dom/events/cutcopypaste.html
|
||||
COPY: 'copy',
|
||||
PASTE: 'paste',
|
||||
CUT: 'cut',
|
||||
BEFORECOPY: 'beforecopy',
|
||||
BEFORECUT: 'beforecut',
|
||||
BEFOREPASTE: 'beforepaste',
|
||||
|
||||
// HTML5 online/offline events.
|
||||
// http://www.w3.org/TR/offline-webapps/#related
|
||||
ONLINE: 'online',
|
||||
OFFLINE: 'offline',
|
||||
|
||||
// HTML 5 worker events
|
||||
MESSAGE: 'message',
|
||||
CONNECT: 'connect',
|
||||
|
||||
// Service Worker Events - ServiceWorkerGlobalScope context
|
||||
// See https://w3c.github.io/ServiceWorker/#execution-context-events
|
||||
// Note: message event defined in worker events section
|
||||
INSTALL: 'install',
|
||||
ACTIVATE: 'activate',
|
||||
FETCH: 'fetch',
|
||||
FOREIGNFETCH: 'foreignfetch',
|
||||
MESSAGEERROR: 'messageerror',
|
||||
|
||||
// Service Worker Events - Document context
|
||||
// See https://w3c.github.io/ServiceWorker/#document-context-events
|
||||
STATECHANGE: 'statechange',
|
||||
UPDATEFOUND: 'updatefound',
|
||||
CONTROLLERCHANGE: 'controllerchange',
|
||||
|
||||
// CSS animation events.
|
||||
/** @suppress {missingRequire} */
|
||||
ANIMATIONSTART: goog.events.getVendorPrefixedName_('AnimationStart'),
|
||||
/** @suppress {missingRequire} */
|
||||
ANIMATIONEND: goog.events.getVendorPrefixedName_('AnimationEnd'),
|
||||
/** @suppress {missingRequire} */
|
||||
ANIMATIONITERATION: goog.events.getVendorPrefixedName_('AnimationIteration'),
|
||||
|
||||
// CSS transition events. Based on the browser support described at:
|
||||
// https://developer.mozilla.org/en/css/css_transitions#Browser_compatibility
|
||||
/** @suppress {missingRequire} */
|
||||
TRANSITIONEND: goog.events.getVendorPrefixedName_('TransitionEnd'),
|
||||
|
||||
// W3C Pointer Events
|
||||
// http://www.w3.org/TR/pointerevents/
|
||||
POINTERDOWN: 'pointerdown',
|
||||
POINTERUP: 'pointerup',
|
||||
POINTERCANCEL: 'pointercancel',
|
||||
POINTERMOVE: 'pointermove',
|
||||
POINTEROVER: 'pointerover',
|
||||
POINTEROUT: 'pointerout',
|
||||
POINTERENTER: 'pointerenter',
|
||||
POINTERLEAVE: 'pointerleave',
|
||||
GOTPOINTERCAPTURE: 'gotpointercapture',
|
||||
LOSTPOINTERCAPTURE: 'lostpointercapture',
|
||||
|
||||
// IE specific events.
|
||||
// See http://msdn.microsoft.com/en-us/library/ie/hh772103(v=vs.85).aspx
|
||||
// Note: these events will be supplanted in IE11.
|
||||
MSGESTURECHANGE: 'MSGestureChange',
|
||||
MSGESTUREEND: 'MSGestureEnd',
|
||||
MSGESTUREHOLD: 'MSGestureHold',
|
||||
MSGESTURESTART: 'MSGestureStart',
|
||||
MSGESTURETAP: 'MSGestureTap',
|
||||
MSGOTPOINTERCAPTURE: 'MSGotPointerCapture',
|
||||
MSINERTIASTART: 'MSInertiaStart',
|
||||
MSLOSTPOINTERCAPTURE: 'MSLostPointerCapture',
|
||||
MSPOINTERCANCEL: 'MSPointerCancel',
|
||||
MSPOINTERDOWN: 'MSPointerDown',
|
||||
MSPOINTERENTER: 'MSPointerEnter',
|
||||
MSPOINTERHOVER: 'MSPointerHover',
|
||||
MSPOINTERLEAVE: 'MSPointerLeave',
|
||||
MSPOINTERMOVE: 'MSPointerMove',
|
||||
MSPOINTEROUT: 'MSPointerOut',
|
||||
MSPOINTEROVER: 'MSPointerOver',
|
||||
MSPOINTERUP: 'MSPointerUp',
|
||||
|
||||
// Native IMEs/input tools events.
|
||||
TEXT: 'text',
|
||||
// The textInput event is supported in IE9+, but only in lower case. All other
|
||||
// browsers use the camel-case event name.
|
||||
TEXTINPUT: goog.userAgent.IE ? 'textinput' : 'textInput',
|
||||
COMPOSITIONSTART: 'compositionstart',
|
||||
COMPOSITIONUPDATE: 'compositionupdate',
|
||||
COMPOSITIONEND: 'compositionend',
|
||||
|
||||
// The beforeinput event is initially only supported in Safari. See
|
||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=342670 for Chrome
|
||||
// implementation tracking.
|
||||
BEFOREINPUT: 'beforeinput',
|
||||
|
||||
// Webview tag events
|
||||
// See http://developer.chrome.com/dev/apps/webview_tag.html
|
||||
EXIT: 'exit',
|
||||
LOADABORT: 'loadabort',
|
||||
LOADCOMMIT: 'loadcommit',
|
||||
LOADREDIRECT: 'loadredirect',
|
||||
LOADSTART: 'loadstart',
|
||||
LOADSTOP: 'loadstop',
|
||||
RESPONSIVE: 'responsive',
|
||||
SIZECHANGED: 'sizechanged',
|
||||
UNRESPONSIVE: 'unresponsive',
|
||||
|
||||
// HTML5 Page Visibility API. See details at
|
||||
// {@code goog.labs.dom.PageVisibilityMonitor}.
|
||||
VISIBILITYCHANGE: 'visibilitychange',
|
||||
|
||||
// LocalStorage event.
|
||||
STORAGE: 'storage',
|
||||
|
||||
// DOM Level 2 mutation events (deprecated).
|
||||
DOMSUBTREEMODIFIED: 'DOMSubtreeModified',
|
||||
DOMNODEINSERTED: 'DOMNodeInserted',
|
||||
DOMNODEREMOVED: 'DOMNodeRemoved',
|
||||
DOMNODEREMOVEDFROMDOCUMENT: 'DOMNodeRemovedFromDocument',
|
||||
DOMNODEINSERTEDINTODOCUMENT: 'DOMNodeInsertedIntoDocument',
|
||||
DOMATTRMODIFIED: 'DOMAttrModified',
|
||||
DOMCHARACTERDATAMODIFIED: 'DOMCharacterDataModified',
|
||||
|
||||
// Print events.
|
||||
BEFOREPRINT: 'beforeprint',
|
||||
AFTERPRINT: 'afterprint'
|
||||
};
|
||||
|
|
@ -0,0 +1,338 @@
|
|||
// 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 An interface for a listenable JavaScript object.
|
||||
* @author chrishenry@google.com (Chris Henry)
|
||||
*/
|
||||
|
||||
goog.provide('goog.events.Listenable');
|
||||
goog.provide('goog.events.ListenableKey');
|
||||
|
||||
/** @suppress {extraRequire} */
|
||||
goog.require('goog.events.EventId');
|
||||
|
||||
goog.forwardDeclare('goog.events.EventLike');
|
||||
goog.forwardDeclare('goog.events.EventTarget');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A listenable interface. A listenable is an object with the ability
|
||||
* to dispatch/broadcast events to "event listeners" registered via
|
||||
* listen/listenOnce.
|
||||
*
|
||||
* The interface allows for an event propagation mechanism similar
|
||||
* to one offered by native browser event targets, such as
|
||||
* capture/bubble mechanism, stopping propagation, and preventing
|
||||
* default actions. Capture/bubble mechanism depends on the ancestor
|
||||
* tree constructed via {@code #getParentEventTarget}; this tree
|
||||
* must be directed acyclic graph. The meaning of default action(s)
|
||||
* in preventDefault is specific to a particular use case.
|
||||
*
|
||||
* Implementations that do not support capture/bubble or can not have
|
||||
* a parent listenable can simply not implement any ability to set the
|
||||
* parent listenable (and have {@code #getParentEventTarget} return
|
||||
* null).
|
||||
*
|
||||
* Implementation of this class can be used with or independently from
|
||||
* goog.events.
|
||||
*
|
||||
* Implementation must call {@code #addImplementation(implClass)}.
|
||||
*
|
||||
* @interface
|
||||
* @see goog.events
|
||||
* @see http://www.w3.org/TR/DOM-Level-2-Events/events.html
|
||||
*/
|
||||
goog.events.Listenable = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* An expando property to indicate that an object implements
|
||||
* goog.events.Listenable.
|
||||
*
|
||||
* See addImplementation/isImplementedBy.
|
||||
*
|
||||
* @type {string}
|
||||
* @const
|
||||
*/
|
||||
goog.events.Listenable.IMPLEMENTED_BY_PROP =
|
||||
'closure_listenable_' + ((Math.random() * 1e6) | 0);
|
||||
|
||||
|
||||
/**
|
||||
* Marks a given class (constructor) as an implementation of
|
||||
* Listenable, do that we can query that fact at runtime. The class
|
||||
* must have already implemented the interface.
|
||||
* @param {!function(new:goog.events.Listenable,...)} cls The class constructor.
|
||||
* The corresponding class must have already implemented the interface.
|
||||
*/
|
||||
goog.events.Listenable.addImplementation = function(cls) {
|
||||
cls.prototype[goog.events.Listenable.IMPLEMENTED_BY_PROP] = true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Object} obj The object to check.
|
||||
* @return {boolean} Whether a given instance implements Listenable. The
|
||||
* class/superclass of the instance must call addImplementation.
|
||||
*/
|
||||
goog.events.Listenable.isImplementedBy = function(obj) {
|
||||
return !!(obj && obj[goog.events.Listenable.IMPLEMENTED_BY_PROP]);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds an event listener. A listener can only be added once to an
|
||||
* object and if it is added again the key for the listener is
|
||||
* returned. Note that if the existing listener is a one-off listener
|
||||
* (registered via listenOnce), it will no longer be a one-off
|
||||
* listener after a call to listen().
|
||||
*
|
||||
* @param {string|!goog.events.EventId<EVENTOBJ>} type The event type id.
|
||||
* @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback
|
||||
* method.
|
||||
* @param {boolean=} opt_useCapture Whether to fire in capture phase
|
||||
* (defaults to false).
|
||||
* @param {SCOPE=} opt_listenerScope Object in whose scope to call the
|
||||
* listener.
|
||||
* @return {!goog.events.ListenableKey} Unique key for the listener.
|
||||
* @template SCOPE,EVENTOBJ
|
||||
*/
|
||||
goog.events.Listenable.prototype.listen;
|
||||
|
||||
|
||||
/**
|
||||
* Adds an event listener that is removed automatically after the
|
||||
* listener fired once.
|
||||
*
|
||||
* If an existing listener already exists, listenOnce will do
|
||||
* nothing. In particular, if the listener was previously registered
|
||||
* via listen(), listenOnce() will not turn the listener into a
|
||||
* one-off listener. Similarly, if there is already an existing
|
||||
* one-off listener, listenOnce does not modify the listeners (it is
|
||||
* still a once listener).
|
||||
*
|
||||
* @param {string|!goog.events.EventId<EVENTOBJ>} type The event type id.
|
||||
* @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback
|
||||
* method.
|
||||
* @param {boolean=} opt_useCapture Whether to fire in capture phase
|
||||
* (defaults to false).
|
||||
* @param {SCOPE=} opt_listenerScope Object in whose scope to call the
|
||||
* listener.
|
||||
* @return {!goog.events.ListenableKey} Unique key for the listener.
|
||||
* @template SCOPE,EVENTOBJ
|
||||
*/
|
||||
goog.events.Listenable.prototype.listenOnce;
|
||||
|
||||
|
||||
/**
|
||||
* Removes an event listener which was added with listen() or listenOnce().
|
||||
*
|
||||
* @param {string|!goog.events.EventId<EVENTOBJ>} type The event type id.
|
||||
* @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback
|
||||
* method.
|
||||
* @param {boolean=} opt_useCapture Whether to fire in capture phase
|
||||
* (defaults to false).
|
||||
* @param {SCOPE=} opt_listenerScope Object in whose scope to call
|
||||
* the listener.
|
||||
* @return {boolean} Whether any listener was removed.
|
||||
* @template SCOPE,EVENTOBJ
|
||||
*/
|
||||
goog.events.Listenable.prototype.unlisten;
|
||||
|
||||
|
||||
/**
|
||||
* Removes an event listener which was added with listen() by the key
|
||||
* returned by listen().
|
||||
*
|
||||
* @param {!goog.events.ListenableKey} key The key returned by
|
||||
* listen() or listenOnce().
|
||||
* @return {boolean} Whether any listener was removed.
|
||||
*/
|
||||
goog.events.Listenable.prototype.unlistenByKey;
|
||||
|
||||
|
||||
/**
|
||||
* Dispatches an event (or event like object) and calls all listeners
|
||||
* listening for events of this type. The type of the event is decided by the
|
||||
* type property on the event object.
|
||||
*
|
||||
* If any of the listeners returns false OR calls preventDefault then this
|
||||
* function will return false. If one of the capture listeners calls
|
||||
* stopPropagation, then the bubble listeners won't fire.
|
||||
*
|
||||
* @param {goog.events.EventLike} e Event object.
|
||||
* @return {boolean} If anyone called preventDefault on the event object (or
|
||||
* if any of the listeners returns false) this will also return false.
|
||||
*/
|
||||
goog.events.Listenable.prototype.dispatchEvent;
|
||||
|
||||
|
||||
/**
|
||||
* Removes all listeners from this listenable. If type is specified,
|
||||
* it will only remove listeners of the particular type. otherwise all
|
||||
* registered listeners will be removed.
|
||||
*
|
||||
* @param {string=} opt_type Type of event to remove, default is to
|
||||
* remove all types.
|
||||
* @return {number} Number of listeners removed.
|
||||
*/
|
||||
goog.events.Listenable.prototype.removeAllListeners;
|
||||
|
||||
|
||||
/**
|
||||
* Returns the parent of this event target to use for capture/bubble
|
||||
* mechanism.
|
||||
*
|
||||
* NOTE(chrishenry): The name reflects the original implementation of
|
||||
* custom event target ({@code goog.events.EventTarget}). We decided
|
||||
* that changing the name is not worth it.
|
||||
*
|
||||
* @return {goog.events.Listenable} The parent EventTarget or null if
|
||||
* there is no parent.
|
||||
*/
|
||||
goog.events.Listenable.prototype.getParentEventTarget;
|
||||
|
||||
|
||||
/**
|
||||
* Fires all registered listeners in this listenable for the given
|
||||
* type and capture mode, passing them the given eventObject. This
|
||||
* does not perform actual capture/bubble. Only implementors of the
|
||||
* interface should be using this.
|
||||
*
|
||||
* @param {string|!goog.events.EventId<EVENTOBJ>} type The type of the
|
||||
* listeners to fire.
|
||||
* @param {boolean} capture The capture mode of the listeners to fire.
|
||||
* @param {EVENTOBJ} eventObject The event object to fire.
|
||||
* @return {boolean} Whether all listeners succeeded without
|
||||
* attempting to prevent default behavior. If any listener returns
|
||||
* false or called goog.events.Event#preventDefault, this returns
|
||||
* false.
|
||||
* @template EVENTOBJ
|
||||
*/
|
||||
goog.events.Listenable.prototype.fireListeners;
|
||||
|
||||
|
||||
/**
|
||||
* Gets all listeners in this listenable for the given type and
|
||||
* capture mode.
|
||||
*
|
||||
* @param {string|!goog.events.EventId} type The type of the listeners to fire.
|
||||
* @param {boolean} capture The capture mode of the listeners to fire.
|
||||
* @return {!Array<!goog.events.ListenableKey>} An array of registered
|
||||
* listeners.
|
||||
* @template EVENTOBJ
|
||||
*/
|
||||
goog.events.Listenable.prototype.getListeners;
|
||||
|
||||
|
||||
/**
|
||||
* Gets the goog.events.ListenableKey for the event or null if no such
|
||||
* listener is in use.
|
||||
*
|
||||
* @param {string|!goog.events.EventId<EVENTOBJ>} type The name of the event
|
||||
* without the 'on' prefix.
|
||||
* @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener The
|
||||
* listener function to get.
|
||||
* @param {boolean} capture Whether the listener is a capturing listener.
|
||||
* @param {SCOPE=} opt_listenerScope Object in whose scope to call the
|
||||
* listener.
|
||||
* @return {goog.events.ListenableKey} the found listener or null if not found.
|
||||
* @template SCOPE,EVENTOBJ
|
||||
*/
|
||||
goog.events.Listenable.prototype.getListener;
|
||||
|
||||
|
||||
/**
|
||||
* Whether there is any active listeners matching the specified
|
||||
* signature. If either the type or capture parameters are
|
||||
* unspecified, the function will match on the remaining criteria.
|
||||
*
|
||||
* @param {string|!goog.events.EventId<EVENTOBJ>=} opt_type Event type.
|
||||
* @param {boolean=} opt_capture Whether to check for capture or bubble
|
||||
* listeners.
|
||||
* @return {boolean} Whether there is any active listeners matching
|
||||
* the requested type and/or capture phase.
|
||||
* @template EVENTOBJ
|
||||
*/
|
||||
goog.events.Listenable.prototype.hasListener;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* An interface that describes a single registered listener.
|
||||
* @interface
|
||||
*/
|
||||
goog.events.ListenableKey = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Counter used to create a unique key
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
goog.events.ListenableKey.counter_ = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Reserves a key to be used for ListenableKey#key field.
|
||||
* @return {number} A number to be used to fill ListenableKey#key
|
||||
* field.
|
||||
*/
|
||||
goog.events.ListenableKey.reserveKey = function() {
|
||||
return ++goog.events.ListenableKey.counter_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The source event target.
|
||||
* @type {Object|goog.events.Listenable|goog.events.EventTarget}
|
||||
*/
|
||||
goog.events.ListenableKey.prototype.src;
|
||||
|
||||
|
||||
/**
|
||||
* The event type the listener is listening to.
|
||||
* @type {string}
|
||||
*/
|
||||
goog.events.ListenableKey.prototype.type;
|
||||
|
||||
|
||||
/**
|
||||
* The listener function.
|
||||
* @type {function(?):?|{handleEvent:function(?):?}|null}
|
||||
*/
|
||||
goog.events.ListenableKey.prototype.listener;
|
||||
|
||||
|
||||
/**
|
||||
* Whether the listener works on capture phase.
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.events.ListenableKey.prototype.capture;
|
||||
|
||||
|
||||
/**
|
||||
* The 'this' object for the listener function's scope.
|
||||
* @type {Object|undefined}
|
||||
*/
|
||||
goog.events.ListenableKey.prototype.handler;
|
||||
|
||||
|
||||
/**
|
||||
* A globally unique number to identify the key.
|
||||
* @type {number}
|
||||
*/
|
||||
goog.events.ListenableKey.prototype.key;
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
// Copyright 2005 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 Listener object.
|
||||
* @see ../demos/events.html
|
||||
*/
|
||||
|
||||
goog.provide('goog.events.Listener');
|
||||
|
||||
goog.require('goog.events.ListenableKey');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Simple class that stores information about a listener
|
||||
* @param {function(?):?} listener Callback function.
|
||||
* @param {Function} proxy Wrapper for the listener that patches the event.
|
||||
* @param {EventTarget|goog.events.Listenable} src Source object for
|
||||
* the event.
|
||||
* @param {string} type Event type.
|
||||
* @param {boolean} capture Whether in capture or bubble phase.
|
||||
* @param {Object=} opt_handler Object in whose context to execute the callback.
|
||||
* @implements {goog.events.ListenableKey}
|
||||
* @constructor
|
||||
*/
|
||||
goog.events.Listener = function(
|
||||
listener, proxy, src, type, capture, opt_handler) {
|
||||
if (goog.events.Listener.ENABLE_MONITORING) {
|
||||
this.creationStack = new Error().stack;
|
||||
}
|
||||
|
||||
/** @override */
|
||||
this.listener = listener;
|
||||
|
||||
/**
|
||||
* A wrapper over the original listener. This is used solely to
|
||||
* handle native browser events (it is used to simulate the capture
|
||||
* phase and to patch the event object).
|
||||
* @type {Function}
|
||||
*/
|
||||
this.proxy = proxy;
|
||||
|
||||
/**
|
||||
* Object or node that callback is listening to
|
||||
* @type {EventTarget|goog.events.Listenable}
|
||||
*/
|
||||
this.src = src;
|
||||
|
||||
/**
|
||||
* The event type.
|
||||
* @const {string}
|
||||
*/
|
||||
this.type = type;
|
||||
|
||||
/**
|
||||
* Whether the listener is being called in the capture or bubble phase
|
||||
* @const {boolean}
|
||||
*/
|
||||
this.capture = !!capture;
|
||||
|
||||
/**
|
||||
* Optional object whose context to execute the listener in
|
||||
* @type {Object|undefined}
|
||||
*/
|
||||
this.handler = opt_handler;
|
||||
|
||||
/**
|
||||
* The key of the listener.
|
||||
* @const {number}
|
||||
* @override
|
||||
*/
|
||||
this.key = goog.events.ListenableKey.reserveKey();
|
||||
|
||||
/**
|
||||
* Whether to remove the listener after it has been called.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.callOnce = false;
|
||||
|
||||
/**
|
||||
* Whether the listener has been removed.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.removed = false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Whether to enable the monitoring of the
|
||||
* goog.events.Listener instances. Switching on the monitoring is only
|
||||
* recommended for debugging because it has a significant impact on
|
||||
* performance and memory usage. If switched off, the monitoring code
|
||||
* compiles down to 0 bytes.
|
||||
*/
|
||||
goog.define('goog.events.Listener.ENABLE_MONITORING', false);
|
||||
|
||||
|
||||
/**
|
||||
* If monitoring the goog.events.Listener instances is enabled, stores the
|
||||
* creation stack trace of the Disposable instance.
|
||||
* @type {string}
|
||||
*/
|
||||
goog.events.Listener.prototype.creationStack;
|
||||
|
||||
|
||||
/**
|
||||
* Marks this listener as removed. This also remove references held by
|
||||
* this listener object (such as listener and event source).
|
||||
*/
|
||||
goog.events.Listener.prototype.markAsRemoved = function() {
|
||||
this.removed = true;
|
||||
this.listener = null;
|
||||
this.proxy = null;
|
||||
this.src = null;
|
||||
this.handler = null;
|
||||
};
|
||||
|
|
@ -0,0 +1,307 @@
|
|||
// Copyright 2013 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 A map of listeners that provides utility functions to
|
||||
* deal with listeners on an event target. Used by
|
||||
* {@code goog.events.EventTarget}.
|
||||
*
|
||||
* WARNING: Do not use this class from outside goog.events package.
|
||||
*
|
||||
* @visibility {//closure/goog/bin/sizetests:__pkg__}
|
||||
* @visibility {//closure/goog:__pkg__}
|
||||
* @visibility {//closure/goog/events:__pkg__}
|
||||
* @visibility {//closure/goog/labs/events:__pkg__}
|
||||
*/
|
||||
|
||||
goog.provide('goog.events.ListenerMap');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.events.Listener');
|
||||
goog.require('goog.object');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new listener map.
|
||||
* @param {EventTarget|goog.events.Listenable} src The src object.
|
||||
* @constructor
|
||||
* @final
|
||||
*/
|
||||
goog.events.ListenerMap = function(src) {
|
||||
/** @type {EventTarget|goog.events.Listenable} */
|
||||
this.src = src;
|
||||
|
||||
/**
|
||||
* Maps of event type to an array of listeners.
|
||||
* @type {!Object<string, !Array<!goog.events.Listener>>}
|
||||
*/
|
||||
this.listeners = {};
|
||||
|
||||
/**
|
||||
* The count of types in this map that have registered listeners.
|
||||
* @private {number}
|
||||
*/
|
||||
this.typeCount_ = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} The count of event types in this map that actually
|
||||
* have registered listeners.
|
||||
*/
|
||||
goog.events.ListenerMap.prototype.getTypeCount = function() {
|
||||
return this.typeCount_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} Total number of registered listeners.
|
||||
*/
|
||||
goog.events.ListenerMap.prototype.getListenerCount = function() {
|
||||
var count = 0;
|
||||
for (var type in this.listeners) {
|
||||
count += this.listeners[type].length;
|
||||
}
|
||||
return count;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds an event listener. A listener can only be added once to an
|
||||
* object and if it is added again the key for the listener is
|
||||
* returned.
|
||||
*
|
||||
* Note that a one-off listener will not change an existing listener,
|
||||
* if any. On the other hand a normal listener will change existing
|
||||
* one-off listener to become a normal listener.
|
||||
*
|
||||
* @param {string|!goog.events.EventId} type The listener event type.
|
||||
* @param {!Function} listener This listener callback method.
|
||||
* @param {boolean} callOnce Whether the listener is a one-off
|
||||
* listener.
|
||||
* @param {boolean=} opt_useCapture The capture mode of the listener.
|
||||
* @param {Object=} opt_listenerScope Object in whose scope to call the
|
||||
* listener.
|
||||
* @return {!goog.events.ListenableKey} Unique key for the listener.
|
||||
*/
|
||||
goog.events.ListenerMap.prototype.add = function(
|
||||
type, listener, callOnce, opt_useCapture, opt_listenerScope) {
|
||||
var typeStr = type.toString();
|
||||
var listenerArray = this.listeners[typeStr];
|
||||
if (!listenerArray) {
|
||||
listenerArray = this.listeners[typeStr] = [];
|
||||
this.typeCount_++;
|
||||
}
|
||||
|
||||
var listenerObj;
|
||||
var index = goog.events.ListenerMap.findListenerIndex_(
|
||||
listenerArray, listener, opt_useCapture, opt_listenerScope);
|
||||
if (index > -1) {
|
||||
listenerObj = listenerArray[index];
|
||||
if (!callOnce) {
|
||||
// Ensure that, if there is an existing callOnce listener, it is no
|
||||
// longer a callOnce listener.
|
||||
listenerObj.callOnce = false;
|
||||
}
|
||||
} else {
|
||||
listenerObj = new goog.events.Listener(
|
||||
listener, null, this.src, typeStr, !!opt_useCapture, opt_listenerScope);
|
||||
listenerObj.callOnce = callOnce;
|
||||
listenerArray.push(listenerObj);
|
||||
}
|
||||
return listenerObj;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes a matching listener.
|
||||
* @param {string|!goog.events.EventId} type The listener event type.
|
||||
* @param {!Function} listener This listener callback method.
|
||||
* @param {boolean=} opt_useCapture The capture mode of the listener.
|
||||
* @param {Object=} opt_listenerScope Object in whose scope to call the
|
||||
* listener.
|
||||
* @return {boolean} Whether any listener was removed.
|
||||
*/
|
||||
goog.events.ListenerMap.prototype.remove = function(
|
||||
type, listener, opt_useCapture, opt_listenerScope) {
|
||||
var typeStr = type.toString();
|
||||
if (!(typeStr in this.listeners)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var listenerArray = this.listeners[typeStr];
|
||||
var index = goog.events.ListenerMap.findListenerIndex_(
|
||||
listenerArray, listener, opt_useCapture, opt_listenerScope);
|
||||
if (index > -1) {
|
||||
var listenerObj = listenerArray[index];
|
||||
listenerObj.markAsRemoved();
|
||||
goog.array.removeAt(listenerArray, index);
|
||||
if (listenerArray.length == 0) {
|
||||
delete this.listeners[typeStr];
|
||||
this.typeCount_--;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes the given listener object.
|
||||
* @param {!goog.events.ListenableKey} listener The listener to remove.
|
||||
* @return {boolean} Whether the listener is removed.
|
||||
*/
|
||||
goog.events.ListenerMap.prototype.removeByKey = function(listener) {
|
||||
var type = listener.type;
|
||||
if (!(type in this.listeners)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var removed = goog.array.remove(this.listeners[type], listener);
|
||||
if (removed) {
|
||||
/** @type {!goog.events.Listener} */ (listener).markAsRemoved();
|
||||
if (this.listeners[type].length == 0) {
|
||||
delete this.listeners[type];
|
||||
this.typeCount_--;
|
||||
}
|
||||
}
|
||||
return removed;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes all listeners from this map. If opt_type is provided, only
|
||||
* listeners that match the given type are removed.
|
||||
* @param {string|!goog.events.EventId=} opt_type Type of event to remove.
|
||||
* @return {number} Number of listeners removed.
|
||||
*/
|
||||
goog.events.ListenerMap.prototype.removeAll = function(opt_type) {
|
||||
var typeStr = opt_type && opt_type.toString();
|
||||
var count = 0;
|
||||
for (var type in this.listeners) {
|
||||
if (!typeStr || type == typeStr) {
|
||||
var listenerArray = this.listeners[type];
|
||||
for (var i = 0; i < listenerArray.length; i++) {
|
||||
++count;
|
||||
listenerArray[i].markAsRemoved();
|
||||
}
|
||||
delete this.listeners[type];
|
||||
this.typeCount_--;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets all listeners that match the given type and capture mode. The
|
||||
* returned array is a copy (but the listener objects are not).
|
||||
* @param {string|!goog.events.EventId} type The type of the listeners
|
||||
* to retrieve.
|
||||
* @param {boolean} capture The capture mode of the listeners to retrieve.
|
||||
* @return {!Array<!goog.events.ListenableKey>} An array of matching
|
||||
* listeners.
|
||||
*/
|
||||
goog.events.ListenerMap.prototype.getListeners = function(type, capture) {
|
||||
var listenerArray = this.listeners[type.toString()];
|
||||
var rv = [];
|
||||
if (listenerArray) {
|
||||
for (var i = 0; i < listenerArray.length; ++i) {
|
||||
var listenerObj = listenerArray[i];
|
||||
if (listenerObj.capture == capture) {
|
||||
rv.push(listenerObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the goog.events.ListenableKey for the event or null if no such
|
||||
* listener is in use.
|
||||
*
|
||||
* @param {string|!goog.events.EventId} type The type of the listener
|
||||
* to retrieve.
|
||||
* @param {!Function} listener The listener function to get.
|
||||
* @param {boolean} capture Whether the listener is a capturing listener.
|
||||
* @param {Object=} opt_listenerScope Object in whose scope to call the
|
||||
* listener.
|
||||
* @return {goog.events.ListenableKey} the found listener or null if not found.
|
||||
*/
|
||||
goog.events.ListenerMap.prototype.getListener = function(
|
||||
type, listener, capture, opt_listenerScope) {
|
||||
var listenerArray = this.listeners[type.toString()];
|
||||
var i = -1;
|
||||
if (listenerArray) {
|
||||
i = goog.events.ListenerMap.findListenerIndex_(
|
||||
listenerArray, listener, capture, opt_listenerScope);
|
||||
}
|
||||
return i > -1 ? listenerArray[i] : null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether there is a matching listener. If either the type or capture
|
||||
* parameters are unspecified, the function will match on the
|
||||
* remaining criteria.
|
||||
*
|
||||
* @param {string|!goog.events.EventId=} opt_type The type of the listener.
|
||||
* @param {boolean=} opt_capture The capture mode of the listener.
|
||||
* @return {boolean} Whether there is an active listener matching
|
||||
* the requested type and/or capture phase.
|
||||
*/
|
||||
goog.events.ListenerMap.prototype.hasListener = function(
|
||||
opt_type, opt_capture) {
|
||||
var hasType = goog.isDef(opt_type);
|
||||
var typeStr = hasType ? opt_type.toString() : '';
|
||||
var hasCapture = goog.isDef(opt_capture);
|
||||
|
||||
return goog.object.some(this.listeners, function(listenerArray, type) {
|
||||
for (var i = 0; i < listenerArray.length; ++i) {
|
||||
if ((!hasType || listenerArray[i].type == typeStr) &&
|
||||
(!hasCapture || listenerArray[i].capture == opt_capture)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Finds the index of a matching goog.events.Listener in the given
|
||||
* listenerArray.
|
||||
* @param {!Array<!goog.events.Listener>} listenerArray Array of listener.
|
||||
* @param {!Function} listener The listener function.
|
||||
* @param {boolean=} opt_useCapture The capture flag for the listener.
|
||||
* @param {Object=} opt_listenerScope The listener scope.
|
||||
* @return {number} The index of the matching listener within the
|
||||
* listenerArray.
|
||||
* @private
|
||||
*/
|
||||
goog.events.ListenerMap.findListenerIndex_ = function(
|
||||
listenerArray, listener, opt_useCapture, opt_listenerScope) {
|
||||
for (var i = 0; i < listenerArray.length; ++i) {
|
||||
var listenerObj = listenerArray[i];
|
||||
if (!listenerObj.removed && listenerObj.listener == listener &&
|
||||
listenerObj.capture == !!opt_useCapture &&
|
||||
listenerObj.handler == opt_listenerScope) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
106
resources/public/target/cljsbuild-compiler-1/goog/fs/url.js
Normal file
106
resources/public/target/cljsbuild-compiler-1/goog/fs/url.js
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
// Copyright 2015 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 Wrapper for URL and its createObjectUrl and revokeObjectUrl
|
||||
* methods that are part of the HTML5 File API.
|
||||
*/
|
||||
|
||||
goog.provide('goog.fs.url');
|
||||
|
||||
|
||||
/**
|
||||
* Creates a blob URL for a blob object.
|
||||
* Throws an error if the browser does not support Object Urls.
|
||||
*
|
||||
* @param {!Blob} blob The object for which to create the URL.
|
||||
* @return {string} The URL for the object.
|
||||
*/
|
||||
goog.fs.url.createObjectUrl = function(blob) {
|
||||
return goog.fs.url.getUrlObject_().createObjectURL(blob);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Revokes a URL created by {@link goog.fs.url.createObjectUrl}.
|
||||
* Throws an error if the browser does not support Object Urls.
|
||||
*
|
||||
* @param {string} url The URL to revoke.
|
||||
*/
|
||||
goog.fs.url.revokeObjectUrl = function(url) {
|
||||
goog.fs.url.getUrlObject_().revokeObjectURL(url);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {{createObjectURL: (function(!Blob): string),
|
||||
* revokeObjectURL: function(string): void}}
|
||||
*/
|
||||
goog.fs.url.UrlObject_;
|
||||
|
||||
|
||||
/**
|
||||
* Get the object that has the createObjectURL and revokeObjectURL functions for
|
||||
* this browser.
|
||||
*
|
||||
* @return {goog.fs.url.UrlObject_} The object for this browser.
|
||||
* @private
|
||||
*/
|
||||
goog.fs.url.getUrlObject_ = function() {
|
||||
var urlObject = goog.fs.url.findUrlObject_();
|
||||
if (urlObject != null) {
|
||||
return urlObject;
|
||||
} else {
|
||||
throw Error('This browser doesn\'t seem to support blob URLs');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Finds the object that has the createObjectURL and revokeObjectURL functions
|
||||
* for this browser.
|
||||
*
|
||||
* @return {?goog.fs.url.UrlObject_} The object for this browser or null if the
|
||||
* browser does not support Object Urls.
|
||||
* @private
|
||||
*/
|
||||
goog.fs.url.findUrlObject_ = function() {
|
||||
// This is what the spec says to do
|
||||
// http://dev.w3.org/2006/webapi/FileAPI/#dfn-createObjectURL
|
||||
if (goog.isDef(goog.global.URL) &&
|
||||
goog.isDef(goog.global.URL.createObjectURL)) {
|
||||
return /** @type {goog.fs.url.UrlObject_} */ (goog.global.URL);
|
||||
// This is what Chrome does (as of 10.0.648.6 dev)
|
||||
} else if (
|
||||
goog.isDef(goog.global.webkitURL) &&
|
||||
goog.isDef(goog.global.webkitURL.createObjectURL)) {
|
||||
return /** @type {goog.fs.url.UrlObject_} */ (goog.global.webkitURL);
|
||||
// This is what the spec used to say to do
|
||||
} else if (goog.isDef(goog.global.createObjectURL)) {
|
||||
return /** @type {goog.fs.url.UrlObject_} */ (goog.global);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Checks whether this browser supports Object Urls. If not, calls to
|
||||
* createObjectUrl and revokeObjectUrl will result in an error.
|
||||
*
|
||||
* @return {boolean} True if this browser supports Object Urls.
|
||||
*/
|
||||
goog.fs.url.browserSupportsObjectUrls = function() {
|
||||
return goog.fs.url.findUrlObject_() != null;
|
||||
};
|
||||
|
|
@ -0,0 +1,483 @@
|
|||
// Copyright 2008 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 Utilities for creating functions. Loosely inspired by the
|
||||
* java classes: http://goo.gl/GM0Hmu and http://goo.gl/6k7nI8.
|
||||
*
|
||||
* @author nicksantos@google.com (Nick Santos)
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.functions');
|
||||
|
||||
|
||||
/**
|
||||
* Creates a function that always returns the same value.
|
||||
* @param {T} retValue The value to return.
|
||||
* @return {function():T} The new function.
|
||||
* @template T
|
||||
*/
|
||||
goog.functions.constant = function(retValue) {
|
||||
return function() { return retValue; };
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Always returns false.
|
||||
* @type {function(...): boolean}
|
||||
*/
|
||||
goog.functions.FALSE = goog.functions.constant(false);
|
||||
|
||||
|
||||
/**
|
||||
* Always returns true.
|
||||
* @type {function(...): boolean}
|
||||
*/
|
||||
goog.functions.TRUE = goog.functions.constant(true);
|
||||
|
||||
|
||||
/**
|
||||
* Always returns NULL.
|
||||
* @type {function(...): null}
|
||||
*/
|
||||
goog.functions.NULL = goog.functions.constant(null);
|
||||
|
||||
|
||||
/**
|
||||
* A simple function that returns the first argument of whatever is passed
|
||||
* into it.
|
||||
* @param {T=} opt_returnValue The single value that will be returned.
|
||||
* @param {...*} var_args Optional trailing arguments. These are ignored.
|
||||
* @return {T} The first argument passed in, or undefined if nothing was passed.
|
||||
* @template T
|
||||
*/
|
||||
goog.functions.identity = function(opt_returnValue, var_args) {
|
||||
return opt_returnValue;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a function that always throws an error with the given message.
|
||||
* @param {string} message The error message.
|
||||
* @return {!Function} The error-throwing function.
|
||||
*/
|
||||
goog.functions.error = function(message) {
|
||||
return function() { throw Error(message); };
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a function that throws the given object.
|
||||
* @param {*} err An object to be thrown.
|
||||
* @return {!Function} The error-throwing function.
|
||||
*/
|
||||
goog.functions.fail = function(err) {
|
||||
return function() { throw err; };
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Given a function, create a function that keeps opt_numArgs arguments and
|
||||
* silently discards all additional arguments.
|
||||
* @param {Function} f The original function.
|
||||
* @param {number=} opt_numArgs The number of arguments to keep. Defaults to 0.
|
||||
* @return {!Function} A version of f that only keeps the first opt_numArgs
|
||||
* arguments.
|
||||
*/
|
||||
goog.functions.lock = function(f, opt_numArgs) {
|
||||
opt_numArgs = opt_numArgs || 0;
|
||||
return function() {
|
||||
return f.apply(this, Array.prototype.slice.call(arguments, 0, opt_numArgs));
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a function that returns its nth argument.
|
||||
* @param {number} n The position of the return argument.
|
||||
* @return {!Function} A new function.
|
||||
*/
|
||||
goog.functions.nth = function(n) {
|
||||
return function() { return arguments[n]; };
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Like goog.partial(), except that arguments are added after arguments to the
|
||||
* returned function.
|
||||
*
|
||||
* Usage:
|
||||
* function f(arg1, arg2, arg3, arg4) { ... }
|
||||
* var g = goog.functions.partialRight(f, arg3, arg4);
|
||||
* g(arg1, arg2);
|
||||
*
|
||||
* @param {!Function} fn A function to partially apply.
|
||||
* @param {...*} var_args Additional arguments that are partially applied to fn
|
||||
* at the end.
|
||||
* @return {!Function} A partially-applied form of the function goog.partial()
|
||||
* was invoked as a method of.
|
||||
*/
|
||||
goog.functions.partialRight = function(fn, var_args) {
|
||||
var rightArgs = Array.prototype.slice.call(arguments, 1);
|
||||
return function() {
|
||||
var newArgs = Array.prototype.slice.call(arguments);
|
||||
newArgs.push.apply(newArgs, rightArgs);
|
||||
return fn.apply(this, newArgs);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Given a function, create a new function that swallows its return value
|
||||
* and replaces it with a new one.
|
||||
* @param {Function} f A function.
|
||||
* @param {T} retValue A new return value.
|
||||
* @return {function(...?):T} A new function.
|
||||
* @template T
|
||||
*/
|
||||
goog.functions.withReturnValue = function(f, retValue) {
|
||||
return goog.functions.sequence(f, goog.functions.constant(retValue));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a function that returns whether its argument equals the given value.
|
||||
*
|
||||
* Example:
|
||||
* var key = goog.object.findKey(obj, goog.functions.equalTo('needle'));
|
||||
*
|
||||
* @param {*} value The value to compare to.
|
||||
* @param {boolean=} opt_useLooseComparison Whether to use a loose (==)
|
||||
* comparison rather than a strict (===) one. Defaults to false.
|
||||
* @return {function(*):boolean} The new function.
|
||||
*/
|
||||
goog.functions.equalTo = function(value, opt_useLooseComparison) {
|
||||
return function(other) {
|
||||
return opt_useLooseComparison ? (value == other) : (value === other);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates the composition of the functions passed in.
|
||||
* For example, (goog.functions.compose(f, g))(a) is equivalent to f(g(a)).
|
||||
* @param {function(...?):T} fn The final function.
|
||||
* @param {...Function} var_args A list of functions.
|
||||
* @return {function(...?):T} The composition of all inputs.
|
||||
* @template T
|
||||
*/
|
||||
goog.functions.compose = function(fn, var_args) {
|
||||
var functions = arguments;
|
||||
var length = functions.length;
|
||||
return function() {
|
||||
var result;
|
||||
if (length) {
|
||||
result = functions[length - 1].apply(this, arguments);
|
||||
}
|
||||
|
||||
for (var i = length - 2; i >= 0; i--) {
|
||||
result = functions[i].call(this, result);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a function that calls the functions passed in in sequence, and
|
||||
* returns the value of the last function. For example,
|
||||
* (goog.functions.sequence(f, g))(x) is equivalent to f(x),g(x).
|
||||
* @param {...Function} var_args A list of functions.
|
||||
* @return {!Function} A function that calls all inputs in sequence.
|
||||
*/
|
||||
goog.functions.sequence = function(var_args) {
|
||||
var functions = arguments;
|
||||
var length = functions.length;
|
||||
return function() {
|
||||
var result;
|
||||
for (var i = 0; i < length; i++) {
|
||||
result = functions[i].apply(this, arguments);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a function that returns true if each of its components evaluates
|
||||
* to true. The components are evaluated in order, and the evaluation will be
|
||||
* short-circuited as soon as a function returns false.
|
||||
* For example, (goog.functions.and(f, g))(x) is equivalent to f(x) && g(x).
|
||||
* @param {...Function} var_args A list of functions.
|
||||
* @return {function(...?):boolean} A function that ANDs its component
|
||||
* functions.
|
||||
*/
|
||||
goog.functions.and = function(var_args) {
|
||||
var functions = arguments;
|
||||
var length = functions.length;
|
||||
return function() {
|
||||
for (var i = 0; i < length; i++) {
|
||||
if (!functions[i].apply(this, arguments)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a function that returns true if any of its components evaluates
|
||||
* to true. The components are evaluated in order, and the evaluation will be
|
||||
* short-circuited as soon as a function returns true.
|
||||
* For example, (goog.functions.or(f, g))(x) is equivalent to f(x) || g(x).
|
||||
* @param {...Function} var_args A list of functions.
|
||||
* @return {function(...?):boolean} A function that ORs its component
|
||||
* functions.
|
||||
*/
|
||||
goog.functions.or = function(var_args) {
|
||||
var functions = arguments;
|
||||
var length = functions.length;
|
||||
return function() {
|
||||
for (var i = 0; i < length; i++) {
|
||||
if (functions[i].apply(this, arguments)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a function that returns the Boolean opposite of a provided function.
|
||||
* For example, (goog.functions.not(f))(x) is equivalent to !f(x).
|
||||
* @param {!Function} f The original function.
|
||||
* @return {function(...?):boolean} A function that delegates to f and returns
|
||||
* opposite.
|
||||
*/
|
||||
goog.functions.not = function(f) {
|
||||
return function() { return !f.apply(this, arguments); };
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Generic factory function to construct an object given the constructor
|
||||
* and the arguments. Intended to be bound to create object factories.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* var factory = goog.partial(goog.functions.create, Class);
|
||||
*
|
||||
* @param {function(new:T, ...)} constructor The constructor for the Object.
|
||||
* @param {...*} var_args The arguments to be passed to the constructor.
|
||||
* @return {T} A new instance of the class given in {@code constructor}.
|
||||
* @template T
|
||||
*/
|
||||
goog.functions.create = function(constructor, var_args) {
|
||||
/**
|
||||
* @constructor
|
||||
* @final
|
||||
*/
|
||||
var temp = function() {};
|
||||
temp.prototype = constructor.prototype;
|
||||
|
||||
// obj will have constructor's prototype in its chain and
|
||||
// 'obj instanceof constructor' will be true.
|
||||
var obj = new temp();
|
||||
|
||||
// obj is initialized by constructor.
|
||||
// arguments is only array-like so lacks shift(), but can be used with
|
||||
// the Array prototype function.
|
||||
constructor.apply(obj, Array.prototype.slice.call(arguments, 1));
|
||||
return obj;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Whether the return value cache should be used.
|
||||
* This should only be used to disable caches when testing.
|
||||
*/
|
||||
goog.define('goog.functions.CACHE_RETURN_VALUE', true);
|
||||
|
||||
|
||||
/**
|
||||
* Gives a wrapper function that caches the return value of a parameterless
|
||||
* function when first called.
|
||||
*
|
||||
* When called for the first time, the given function is called and its
|
||||
* return value is cached (thus this is only appropriate for idempotent
|
||||
* functions). Subsequent calls will return the cached return value. This
|
||||
* allows the evaluation of expensive functions to be delayed until first used.
|
||||
*
|
||||
* To cache the return values of functions with parameters, see goog.memoize.
|
||||
*
|
||||
* @param {function():T} fn A function to lazily evaluate.
|
||||
* @return {function():T} A wrapped version the function.
|
||||
* @template T
|
||||
*/
|
||||
goog.functions.cacheReturnValue = function(fn) {
|
||||
var called = false;
|
||||
var value;
|
||||
|
||||
return function() {
|
||||
if (!goog.functions.CACHE_RETURN_VALUE) {
|
||||
return fn();
|
||||
}
|
||||
|
||||
if (!called) {
|
||||
value = fn();
|
||||
called = true;
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Wraps a function to allow it to be called, at most, once. All
|
||||
* additional calls are no-ops.
|
||||
*
|
||||
* This is particularly useful for initialization functions
|
||||
* that should be called, at most, once.
|
||||
*
|
||||
* @param {function():*} f Function to call.
|
||||
* @return {function():undefined} Wrapped function.
|
||||
*/
|
||||
goog.functions.once = function(f) {
|
||||
// Keep a reference to the function that we null out when we're done with
|
||||
// it -- that way, the function can be GC'd when we're done with it.
|
||||
var inner = f;
|
||||
return function() {
|
||||
if (inner) {
|
||||
var tmp = inner;
|
||||
inner = null;
|
||||
tmp();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Wraps a function to allow it to be called, at most, once per interval
|
||||
* (specified in milliseconds). If the wrapper function is called N times within
|
||||
* that interval, only the Nth call will go through.
|
||||
*
|
||||
* This is particularly useful for batching up repeated actions where the
|
||||
* last action should win. This can be used, for example, for refreshing an
|
||||
* autocomplete pop-up every so often rather than updating with every keystroke,
|
||||
* since the final text typed by the user is the one that should produce the
|
||||
* final autocomplete results. For more stateful debouncing with support for
|
||||
* pausing, resuming, and canceling debounced actions, use {@code
|
||||
* goog.async.Debouncer}.
|
||||
*
|
||||
* @param {function(this:SCOPE, ...?)} f Function to call.
|
||||
* @param {number} interval Interval over which to debounce. The function will
|
||||
* only be called after the full interval has elapsed since the last call.
|
||||
* @param {SCOPE=} opt_scope Object in whose scope to call the function.
|
||||
* @return {function(...?): undefined} Wrapped function.
|
||||
* @template SCOPE
|
||||
*/
|
||||
goog.functions.debounce = function(f, interval, opt_scope) {
|
||||
var timeout = 0;
|
||||
return /** @type {function(...?)} */ (function(var_args) {
|
||||
goog.global.clearTimeout(timeout);
|
||||
var args = arguments;
|
||||
timeout = goog.global.setTimeout(function() {
|
||||
f.apply(opt_scope, args);
|
||||
}, interval);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Wraps a function to allow it to be called, at most, once per interval
|
||||
* (specified in milliseconds). If the wrapper function is called N times in
|
||||
* that interval, both the 1st and the Nth calls will go through.
|
||||
*
|
||||
* This is particularly useful for limiting repeated user requests where the
|
||||
* the last action should win, but you also don't want to wait until the end of
|
||||
* the interval before sending a request out, as it leads to a perception of
|
||||
* slowness for the user.
|
||||
*
|
||||
* @param {function(this:SCOPE, ...?)} f Function to call.
|
||||
* @param {number} interval Interval over which to throttle. The function can
|
||||
* only be called once per interval.
|
||||
* @param {SCOPE=} opt_scope Object in whose scope to call the function.
|
||||
* @return {function(...?): undefined} Wrapped function.
|
||||
* @template SCOPE
|
||||
*/
|
||||
goog.functions.throttle = function(f, interval, opt_scope) {
|
||||
var timeout = 0;
|
||||
var shouldFire = false;
|
||||
var args = [];
|
||||
|
||||
var handleTimeout = function() {
|
||||
timeout = 0;
|
||||
if (shouldFire) {
|
||||
shouldFire = false;
|
||||
fire();
|
||||
}
|
||||
};
|
||||
|
||||
var fire = function() {
|
||||
timeout = goog.global.setTimeout(handleTimeout, interval);
|
||||
f.apply(opt_scope, args);
|
||||
};
|
||||
|
||||
return /** @type {function(...?)} */ (function(var_args) {
|
||||
args = arguments;
|
||||
if (!timeout) {
|
||||
fire();
|
||||
} else {
|
||||
shouldFire = true;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Wraps a function to allow it to be called, at most, once per interval
|
||||
* (specified in milliseconds). If the wrapper function is called N times within
|
||||
* that interval, only the 1st call will go through.
|
||||
*
|
||||
* This is particularly useful for limiting repeated user requests where the
|
||||
* first request is guaranteed to have all the data required to perform the
|
||||
* final action, so there's no need to wait until the end of the interval before
|
||||
* sending the request out.
|
||||
*
|
||||
* @param {function(this:SCOPE, ...?)} f Function to call.
|
||||
* @param {number} interval Interval over which to rate-limit. The function will
|
||||
* only be called once per interval, and ignored for the remainer of the
|
||||
* interval.
|
||||
* @param {SCOPE=} opt_scope Object in whose scope to call the function.
|
||||
* @return {function(...?): undefined} Wrapped function.
|
||||
* @template SCOPE
|
||||
*/
|
||||
goog.functions.rateLimit = function(f, interval, opt_scope) {
|
||||
var timeout = 0;
|
||||
|
||||
var handleTimeout = function() {
|
||||
timeout = 0;
|
||||
};
|
||||
|
||||
return /** @type {function(...?)} */ (function(var_args) {
|
||||
if (!timeout) {
|
||||
timeout = goog.global.setTimeout(handleTimeout, interval);
|
||||
f.apply(opt_scope, arguments);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
@ -0,0 +1,195 @@
|
|||
// Copyright 2013 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 Transitional utilities to unsafely trust random strings as
|
||||
* goog.html types. Intended for temporary use when upgrading a library that
|
||||
* used to accept plain strings to use safe types, but where it's not
|
||||
* practical to transitively update callers.
|
||||
*
|
||||
* IMPORTANT: No new code should use the conversion functions in this file,
|
||||
* they are intended for refactoring old code to use goog.html types. New code
|
||||
* should construct goog.html types via their APIs, template systems or
|
||||
* sanitizers. If that’s not possible it should use
|
||||
* goog.html.uncheckedconversions and undergo security review.
|
||||
|
||||
*
|
||||
* The semantics of the conversions in goog.html.legacyconversions are very
|
||||
* different from the ones provided by goog.html.uncheckedconversions. The
|
||||
* latter are for use in code where it has been established through manual
|
||||
* security review that the value produced by a piece of code will always
|
||||
* satisfy the SafeHtml contract (e.g., the output of a secure HTML sanitizer).
|
||||
* In uses of goog.html.legacyconversions, this guarantee is not given -- the
|
||||
* value in question originates in unreviewed legacy code and there is no
|
||||
* guarantee that it satisfies the SafeHtml contract.
|
||||
*
|
||||
* There are only three valid uses of legacyconversions:
|
||||
*
|
||||
* 1. Introducing a goog.html version of a function which currently consumes
|
||||
* string and passes that string to a DOM API which can execute script - and
|
||||
* hence cause XSS - like innerHTML. For example, Dialog might expose a
|
||||
* setContent method which takes a string and sets the innerHTML property of
|
||||
* an element with it. In this case a setSafeHtmlContent function could be
|
||||
* added, consuming goog.html.SafeHtml instead of string, and using
|
||||
* goog.dom.safe.setInnerHtml instead of directly setting innerHTML.
|
||||
* setContent could then internally use legacyconversions to create a SafeHtml
|
||||
* from string and pass the SafeHtml to setSafeHtmlContent. In this scenario
|
||||
* remember to document the use of legacyconversions in the modified setContent
|
||||
* and consider deprecating it as well.
|
||||
*
|
||||
* 2. Automated refactoring of application code which handles HTML as string
|
||||
* but needs to call a function which only takes goog.html types. For example,
|
||||
* in the Dialog scenario from (1) an alternative option would be to refactor
|
||||
* setContent to accept goog.html.SafeHtml instead of string and then refactor
|
||||
* all current callers to use legacyconversions to pass SafeHtml. This is
|
||||
* generally preferable to (1) because it keeps the library clean of
|
||||
* legacyconversions, and makes code sites in application code that are
|
||||
* potentially vulnerable to XSS more apparent.
|
||||
*
|
||||
* 3. Old code which needs to call APIs which consume goog.html types and for
|
||||
* which it is prohibitively expensive to refactor to use goog.html types.
|
||||
* Generally, this is code where safety from XSS is either hopeless or
|
||||
* unimportant.
|
||||
*
|
||||
* @visibility {//closure/goog/html:approved_for_legacy_conversion}
|
||||
* @visibility {//closure/goog/bin/sizetests:__pkg__}
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.html.legacyconversions');
|
||||
|
||||
goog.require('goog.html.SafeHtml');
|
||||
goog.require('goog.html.SafeScript');
|
||||
goog.require('goog.html.SafeStyle');
|
||||
goog.require('goog.html.SafeStyleSheet');
|
||||
goog.require('goog.html.SafeUrl');
|
||||
goog.require('goog.html.TrustedResourceUrl');
|
||||
|
||||
|
||||
/**
|
||||
* Performs an "unchecked conversion" from string to SafeHtml for legacy API
|
||||
* purposes.
|
||||
*
|
||||
* Please read fileoverview documentation before using.
|
||||
*
|
||||
* @param {string} html A string to be converted to SafeHtml.
|
||||
* @return {!goog.html.SafeHtml} The value of html, wrapped in a SafeHtml
|
||||
* object.
|
||||
*/
|
||||
goog.html.legacyconversions.safeHtmlFromString = function(html) {
|
||||
goog.html.legacyconversions.reportCallback_();
|
||||
return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse(
|
||||
html, null /* dir */);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Performs an "unchecked conversion" from string to SafeScript for legacy API
|
||||
* purposes.
|
||||
*
|
||||
* Please read fileoverview documentation before using.
|
||||
*
|
||||
* @param {string} script A string to be converted to SafeScript.
|
||||
* @return {!goog.html.SafeScript} The value of script, wrapped in a SafeScript
|
||||
* object.
|
||||
*/
|
||||
goog.html.legacyconversions.safeScriptFromString = function(script) {
|
||||
goog.html.legacyconversions.reportCallback_();
|
||||
return goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse(
|
||||
script);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Performs an "unchecked conversion" from string to SafeStyle for legacy API
|
||||
* purposes.
|
||||
*
|
||||
* Please read fileoverview documentation before using.
|
||||
*
|
||||
* @param {string} style A string to be converted to SafeStyle.
|
||||
* @return {!goog.html.SafeStyle} The value of style, wrapped in a SafeStyle
|
||||
* object.
|
||||
*/
|
||||
goog.html.legacyconversions.safeStyleFromString = function(style) {
|
||||
goog.html.legacyconversions.reportCallback_();
|
||||
return goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse(
|
||||
style);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Performs an "unchecked conversion" from string to SafeStyleSheet for legacy
|
||||
* API purposes.
|
||||
*
|
||||
* Please read fileoverview documentation before using.
|
||||
*
|
||||
* @param {string} styleSheet A string to be converted to SafeStyleSheet.
|
||||
* @return {!goog.html.SafeStyleSheet} The value of style sheet, wrapped in
|
||||
* a SafeStyleSheet object.
|
||||
*/
|
||||
goog.html.legacyconversions.safeStyleSheetFromString = function(styleSheet) {
|
||||
goog.html.legacyconversions.reportCallback_();
|
||||
return goog.html.SafeStyleSheet
|
||||
.createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(styleSheet);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Performs an "unchecked conversion" from string to SafeUrl for legacy API
|
||||
* purposes.
|
||||
*
|
||||
* Please read fileoverview documentation before using.
|
||||
*
|
||||
* @param {string} url A string to be converted to SafeUrl.
|
||||
* @return {!goog.html.SafeUrl} The value of url, wrapped in a SafeUrl
|
||||
* object.
|
||||
*/
|
||||
goog.html.legacyconversions.safeUrlFromString = function(url) {
|
||||
goog.html.legacyconversions.reportCallback_();
|
||||
return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(url);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Performs an "unchecked conversion" from string to TrustedResourceUrl for
|
||||
* legacy API purposes.
|
||||
*
|
||||
* Please read fileoverview documentation before using.
|
||||
*
|
||||
* @param {string} url A string to be converted to TrustedResourceUrl.
|
||||
* @return {!goog.html.TrustedResourceUrl} The value of url, wrapped in a
|
||||
* TrustedResourceUrl object.
|
||||
*/
|
||||
goog.html.legacyconversions.trustedResourceUrlFromString = function(url) {
|
||||
goog.html.legacyconversions.reportCallback_();
|
||||
return goog.html.TrustedResourceUrl
|
||||
.createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse(url);
|
||||
};
|
||||
|
||||
/**
|
||||
* @private {function(): undefined}
|
||||
*/
|
||||
goog.html.legacyconversions.reportCallback_ = goog.nullFunction;
|
||||
|
||||
|
||||
/**
|
||||
* Sets a function that will be called every time a legacy conversion is
|
||||
* performed. The function is called with no parameters but it can use
|
||||
* goog.debug.getStacktrace to get a stacktrace.
|
||||
*
|
||||
* @param {function(): undefined} callback Error callback as defined above.
|
||||
*/
|
||||
goog.html.legacyconversions.setReportCallback = function(callback) {
|
||||
goog.html.legacyconversions.reportCallback_ = callback;
|
||||
};
|
||||
|
|
@ -0,0 +1,994 @@
|
|||
// Copyright 2013 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 The SafeHtml type and its builders.
|
||||
*
|
||||
* TODO(xtof): Link to document stating type contract.
|
||||
*/
|
||||
|
||||
goog.provide('goog.html.SafeHtml');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.dom.TagName');
|
||||
goog.require('goog.dom.tags');
|
||||
goog.require('goog.html.SafeScript');
|
||||
goog.require('goog.html.SafeStyle');
|
||||
goog.require('goog.html.SafeStyleSheet');
|
||||
goog.require('goog.html.SafeUrl');
|
||||
goog.require('goog.html.TrustedResourceUrl');
|
||||
goog.require('goog.i18n.bidi.Dir');
|
||||
goog.require('goog.i18n.bidi.DirectionalString');
|
||||
goog.require('goog.labs.userAgent.browser');
|
||||
goog.require('goog.object');
|
||||
goog.require('goog.string');
|
||||
goog.require('goog.string.Const');
|
||||
goog.require('goog.string.TypedString');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A string that is safe to use in HTML context in DOM APIs and HTML documents.
|
||||
*
|
||||
* A SafeHtml is a string-like object that carries the security type contract
|
||||
* that its value as a string will not cause untrusted script execution when
|
||||
* evaluated as HTML in a browser.
|
||||
*
|
||||
* Values of this type are guaranteed to be safe to use in HTML contexts,
|
||||
* such as, assignment to the innerHTML DOM property, or interpolation into
|
||||
* a HTML template in HTML PC_DATA context, in the sense that the use will not
|
||||
* result in a Cross-Site-Scripting vulnerability.
|
||||
*
|
||||
* Instances of this type must be created via the factory methods
|
||||
* ({@code goog.html.SafeHtml.create}, {@code goog.html.SafeHtml.htmlEscape}),
|
||||
* etc and not by invoking its constructor. The constructor intentionally
|
||||
* takes no parameters and the type is immutable; hence only a default instance
|
||||
* corresponding to the empty string can be obtained via constructor invocation.
|
||||
*
|
||||
* @see goog.html.SafeHtml#create
|
||||
* @see goog.html.SafeHtml#htmlEscape
|
||||
* @constructor
|
||||
* @final
|
||||
* @struct
|
||||
* @implements {goog.i18n.bidi.DirectionalString}
|
||||
* @implements {goog.string.TypedString}
|
||||
*/
|
||||
goog.html.SafeHtml = function() {
|
||||
/**
|
||||
* The contained value of this SafeHtml. The field has a purposely ugly
|
||||
* name to make (non-compiled) code that attempts to directly access this
|
||||
* field stand out.
|
||||
* @private {string}
|
||||
*/
|
||||
this.privateDoNotAccessOrElseSafeHtmlWrappedValue_ = '';
|
||||
|
||||
/**
|
||||
* A type marker used to implement additional run-time type checking.
|
||||
* @see goog.html.SafeHtml#unwrap
|
||||
* @const {!Object}
|
||||
* @private
|
||||
*/
|
||||
this.SAFE_HTML_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ =
|
||||
goog.html.SafeHtml.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_;
|
||||
|
||||
/**
|
||||
* This SafeHtml's directionality, or null if unknown.
|
||||
* @private {?goog.i18n.bidi.Dir}
|
||||
*/
|
||||
this.dir_ = null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @const
|
||||
*/
|
||||
goog.html.SafeHtml.prototype.implementsGoogI18nBidiDirectionalString = true;
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.html.SafeHtml.prototype.getDirection = function() {
|
||||
return this.dir_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @const
|
||||
*/
|
||||
goog.html.SafeHtml.prototype.implementsGoogStringTypedString = true;
|
||||
|
||||
|
||||
/**
|
||||
* Returns this SafeHtml's value as string.
|
||||
*
|
||||
* IMPORTANT: In code where it is security relevant that an object's type is
|
||||
* indeed {@code SafeHtml}, use {@code goog.html.SafeHtml.unwrap} instead of
|
||||
* this method. If in doubt, assume that it's security relevant. In particular,
|
||||
* note that goog.html functions which return a goog.html type do not guarantee
|
||||
* that the returned instance is of the right type. For example:
|
||||
*
|
||||
* <pre>
|
||||
* var fakeSafeHtml = new String('fake');
|
||||
* fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype;
|
||||
* var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml);
|
||||
* // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by
|
||||
* // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml
|
||||
* // instanceof goog.html.SafeHtml.
|
||||
* </pre>
|
||||
*
|
||||
* @see goog.html.SafeHtml#unwrap
|
||||
* @override
|
||||
*/
|
||||
goog.html.SafeHtml.prototype.getTypedStringValue = function() {
|
||||
return this.privateDoNotAccessOrElseSafeHtmlWrappedValue_;
|
||||
};
|
||||
|
||||
|
||||
if (goog.DEBUG) {
|
||||
/**
|
||||
* Returns a debug string-representation of this value.
|
||||
*
|
||||
* To obtain the actual string value wrapped in a SafeHtml, use
|
||||
* {@code goog.html.SafeHtml.unwrap}.
|
||||
*
|
||||
* @see goog.html.SafeHtml#unwrap
|
||||
* @override
|
||||
*/
|
||||
goog.html.SafeHtml.prototype.toString = function() {
|
||||
return 'SafeHtml{' + this.privateDoNotAccessOrElseSafeHtmlWrappedValue_ +
|
||||
'}';
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Performs a runtime check that the provided object is indeed a SafeHtml
|
||||
* object, and returns its value.
|
||||
* @param {!goog.html.SafeHtml} safeHtml The object to extract from.
|
||||
* @return {string} The SafeHtml object's contained string, unless the run-time
|
||||
* type check fails. In that case, {@code unwrap} returns an innocuous
|
||||
* string, or, if assertions are enabled, throws
|
||||
* {@code goog.asserts.AssertionError}.
|
||||
*/
|
||||
goog.html.SafeHtml.unwrap = function(safeHtml) {
|
||||
// Perform additional run-time type-checking to ensure that safeHtml is indeed
|
||||
// an instance of the expected type. This provides some additional protection
|
||||
// against security bugs due to application code that disables type checks.
|
||||
// Specifically, the following checks are performed:
|
||||
// 1. The object is an instance of the expected type.
|
||||
// 2. The object is not an instance of a subclass.
|
||||
// 3. The object carries a type marker for the expected type. "Faking" an
|
||||
// object requires a reference to the type marker, which has names intended
|
||||
// to stand out in code reviews.
|
||||
if (safeHtml instanceof goog.html.SafeHtml &&
|
||||
safeHtml.constructor === goog.html.SafeHtml &&
|
||||
safeHtml.SAFE_HTML_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ ===
|
||||
goog.html.SafeHtml.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) {
|
||||
return safeHtml.privateDoNotAccessOrElseSafeHtmlWrappedValue_;
|
||||
} else {
|
||||
goog.asserts.fail('expected object of type SafeHtml, got \'' +
|
||||
safeHtml + '\' of type ' + goog.typeOf(safeHtml));
|
||||
return 'type_error:SafeHtml';
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Shorthand for union of types that can sensibly be converted to strings
|
||||
* or might already be SafeHtml (as SafeHtml is a goog.string.TypedString).
|
||||
* @private
|
||||
* @typedef {string|number|boolean|!goog.string.TypedString|
|
||||
* !goog.i18n.bidi.DirectionalString}
|
||||
*/
|
||||
goog.html.SafeHtml.TextOrHtml_;
|
||||
|
||||
|
||||
/**
|
||||
* Returns HTML-escaped text as a SafeHtml object.
|
||||
*
|
||||
* If text is of a type that implements
|
||||
* {@code goog.i18n.bidi.DirectionalString}, the directionality of the new
|
||||
* {@code SafeHtml} object is set to {@code text}'s directionality, if known.
|
||||
* Otherwise, the directionality of the resulting SafeHtml is unknown (i.e.,
|
||||
* {@code null}).
|
||||
*
|
||||
* @param {!goog.html.SafeHtml.TextOrHtml_} textOrHtml The text to escape. If
|
||||
* the parameter is of type SafeHtml it is returned directly (no escaping
|
||||
* is done).
|
||||
* @return {!goog.html.SafeHtml} The escaped text, wrapped as a SafeHtml.
|
||||
*/
|
||||
goog.html.SafeHtml.htmlEscape = function(textOrHtml) {
|
||||
if (textOrHtml instanceof goog.html.SafeHtml) {
|
||||
return textOrHtml;
|
||||
}
|
||||
var dir = null;
|
||||
if (textOrHtml.implementsGoogI18nBidiDirectionalString) {
|
||||
dir = textOrHtml.getDirection();
|
||||
}
|
||||
var textAsString;
|
||||
if (textOrHtml.implementsGoogStringTypedString) {
|
||||
textAsString = textOrHtml.getTypedStringValue();
|
||||
} else {
|
||||
textAsString = String(textOrHtml);
|
||||
}
|
||||
return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse(
|
||||
goog.string.htmlEscape(textAsString), dir);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns HTML-escaped text as a SafeHtml object, with newlines changed to
|
||||
* <br>.
|
||||
* @param {!goog.html.SafeHtml.TextOrHtml_} textOrHtml The text to escape. If
|
||||
* the parameter is of type SafeHtml it is returned directly (no escaping
|
||||
* is done).
|
||||
* @return {!goog.html.SafeHtml} The escaped text, wrapped as a SafeHtml.
|
||||
*/
|
||||
goog.html.SafeHtml.htmlEscapePreservingNewlines = function(textOrHtml) {
|
||||
if (textOrHtml instanceof goog.html.SafeHtml) {
|
||||
return textOrHtml;
|
||||
}
|
||||
var html = goog.html.SafeHtml.htmlEscape(textOrHtml);
|
||||
return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse(
|
||||
goog.string.newLineToBr(goog.html.SafeHtml.unwrap(html)),
|
||||
html.getDirection());
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns HTML-escaped text as a SafeHtml object, with newlines changed to
|
||||
* <br> and escaping whitespace to preserve spatial formatting. Character
|
||||
* entity #160 is used to make it safer for XML.
|
||||
* @param {!goog.html.SafeHtml.TextOrHtml_} textOrHtml The text to escape. If
|
||||
* the parameter is of type SafeHtml it is returned directly (no escaping
|
||||
* is done).
|
||||
* @return {!goog.html.SafeHtml} The escaped text, wrapped as a SafeHtml.
|
||||
*/
|
||||
goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces = function(
|
||||
textOrHtml) {
|
||||
if (textOrHtml instanceof goog.html.SafeHtml) {
|
||||
return textOrHtml;
|
||||
}
|
||||
var html = goog.html.SafeHtml.htmlEscape(textOrHtml);
|
||||
return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse(
|
||||
goog.string.whitespaceEscape(goog.html.SafeHtml.unwrap(html)),
|
||||
html.getDirection());
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Coerces an arbitrary object into a SafeHtml object.
|
||||
*
|
||||
* If {@code textOrHtml} is already of type {@code goog.html.SafeHtml}, the same
|
||||
* object is returned. Otherwise, {@code textOrHtml} is coerced to string, and
|
||||
* HTML-escaped. If {@code textOrHtml} is of a type that implements
|
||||
* {@code goog.i18n.bidi.DirectionalString}, its directionality, if known, is
|
||||
* preserved.
|
||||
*
|
||||
* @param {!goog.html.SafeHtml.TextOrHtml_} textOrHtml The text or SafeHtml to
|
||||
* coerce.
|
||||
* @return {!goog.html.SafeHtml} The resulting SafeHtml object.
|
||||
* @deprecated Use goog.html.SafeHtml.htmlEscape.
|
||||
*/
|
||||
goog.html.SafeHtml.from = goog.html.SafeHtml.htmlEscape;
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @private
|
||||
*/
|
||||
goog.html.SafeHtml.VALID_NAMES_IN_TAG_ = /^[a-zA-Z0-9-]+$/;
|
||||
|
||||
|
||||
/**
|
||||
* Set of attributes containing URL as defined at
|
||||
* http://www.w3.org/TR/html5/index.html#attributes-1.
|
||||
* @private @const {!Object<string,boolean>}
|
||||
*/
|
||||
goog.html.SafeHtml.URL_ATTRIBUTES_ = goog.object.createSet(
|
||||
'action', 'cite', 'data', 'formaction', 'href', 'manifest', 'poster',
|
||||
'src');
|
||||
|
||||
|
||||
/**
|
||||
* Tags which are unsupported via create(). They might be supported via a
|
||||
* tag-specific create method. These are tags which might require a
|
||||
* TrustedResourceUrl in one of their attributes or a restricted type for
|
||||
* their content.
|
||||
* @private @const {!Object<string,boolean>}
|
||||
*/
|
||||
goog.html.SafeHtml.NOT_ALLOWED_TAG_NAMES_ = goog.object.createSet(
|
||||
goog.dom.TagName.APPLET, goog.dom.TagName.BASE, goog.dom.TagName.EMBED,
|
||||
goog.dom.TagName.IFRAME, goog.dom.TagName.LINK, goog.dom.TagName.MATH,
|
||||
goog.dom.TagName.META, goog.dom.TagName.OBJECT, goog.dom.TagName.SCRIPT,
|
||||
goog.dom.TagName.STYLE, goog.dom.TagName.SVG, goog.dom.TagName.TEMPLATE);
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {string|number|goog.string.TypedString|
|
||||
* goog.html.SafeStyle.PropertyMap|undefined}
|
||||
*/
|
||||
goog.html.SafeHtml.AttributeValue;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a SafeHtml content consisting of a tag with optional attributes and
|
||||
* optional content.
|
||||
*
|
||||
* For convenience tag names and attribute names are accepted as regular
|
||||
* strings, instead of goog.string.Const. Nevertheless, you should not pass
|
||||
* user-controlled values to these parameters. Note that these parameters are
|
||||
* syntactically validated at runtime, and invalid values will result in
|
||||
* an exception.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* goog.html.SafeHtml.create('br');
|
||||
* goog.html.SafeHtml.create('div', {'class': 'a'});
|
||||
* goog.html.SafeHtml.create('p', {}, 'a');
|
||||
* goog.html.SafeHtml.create('p', {}, goog.html.SafeHtml.create('br'));
|
||||
*
|
||||
* goog.html.SafeHtml.create('span', {
|
||||
* 'style': {'margin': '0'}
|
||||
* });
|
||||
*
|
||||
* To guarantee SafeHtml's type contract is upheld there are restrictions on
|
||||
* attribute values and tag names.
|
||||
*
|
||||
* - For attributes which contain script code (on*), a goog.string.Const is
|
||||
* required.
|
||||
* - For attributes which contain style (style), a goog.html.SafeStyle or a
|
||||
* goog.html.SafeStyle.PropertyMap is required.
|
||||
* - For attributes which are interpreted as URLs (e.g. src, href) a
|
||||
* goog.html.SafeUrl, goog.string.Const or string is required. If a string
|
||||
* is passed, it will be sanitized with SafeUrl.sanitize().
|
||||
* - For tags which can load code or set security relevant page metadata,
|
||||
* more specific goog.html.SafeHtml.create*() functions must be used. Tags
|
||||
* which are not supported by this function are applet, base, embed, iframe,
|
||||
* link, math, object, script, style, svg, and template.
|
||||
*
|
||||
* @param {!goog.dom.TagName|string} tagName The name of the tag. Only tag names
|
||||
* consisting of [a-zA-Z0-9-] are allowed. Tag names documented above are
|
||||
* disallowed.
|
||||
* @param {?Object<string, ?goog.html.SafeHtml.AttributeValue>=} opt_attributes
|
||||
* Mapping from attribute names to their values. Only attribute names
|
||||
* consisting of [a-zA-Z0-9-] are allowed. Value of null or undefined causes
|
||||
* the attribute to be omitted.
|
||||
* @param {!goog.html.SafeHtml.TextOrHtml_|
|
||||
* !Array<!goog.html.SafeHtml.TextOrHtml_>=} opt_content Content to
|
||||
* HTML-escape and put inside the tag. This must be empty for void tags
|
||||
* like <br>. Array elements are concatenated.
|
||||
* @return {!goog.html.SafeHtml} The SafeHtml content with the tag.
|
||||
* @throws {Error} If invalid tag name, attribute name, or attribute value is
|
||||
* provided.
|
||||
* @throws {goog.asserts.AssertionError} If content for void tag is provided.
|
||||
*/
|
||||
goog.html.SafeHtml.create = function(tagName, opt_attributes, opt_content) {
|
||||
goog.html.SafeHtml.verifyTagName(String(tagName));
|
||||
return goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse(
|
||||
String(tagName), opt_attributes, opt_content);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Verifies if the tag name is valid and if it doesn't change the context.
|
||||
* E.g. STRONG is fine but SCRIPT throws because it changes context. See
|
||||
* goog.html.SafeHtml.create for an explanation of allowed tags.
|
||||
* @param {string} tagName
|
||||
* @throws {Error} If invalid tag name is provided.
|
||||
* @package
|
||||
*/
|
||||
goog.html.SafeHtml.verifyTagName = function(tagName) {
|
||||
if (!goog.html.SafeHtml.VALID_NAMES_IN_TAG_.test(tagName)) {
|
||||
throw Error('Invalid tag name <' + tagName + '>.');
|
||||
}
|
||||
if (tagName.toUpperCase() in goog.html.SafeHtml.NOT_ALLOWED_TAG_NAMES_) {
|
||||
throw Error('Tag name <' + tagName + '> is not allowed for SafeHtml.');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a SafeHtml representing an iframe tag.
|
||||
*
|
||||
* This by default restricts the iframe as much as possible by setting the
|
||||
* sandbox attribute to the empty string. If the iframe requires less
|
||||
* restrictions, set the sandbox attribute as tight as possible, but do not rely
|
||||
* on the sandbox as a security feature because it is not supported by older
|
||||
* browsers. If a sandbox is essential to security (e.g. for third-party
|
||||
* frames), use createSandboxIframe which checks for browser support.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en/docs/Web/HTML/Element/iframe#attr-sandbox
|
||||
*
|
||||
* @param {?goog.html.TrustedResourceUrl=} opt_src The value of the src
|
||||
* attribute. If null or undefined src will not be set.
|
||||
* @param {?goog.html.SafeHtml=} opt_srcdoc The value of the srcdoc attribute.
|
||||
* If null or undefined srcdoc will not be set.
|
||||
* @param {?Object<string, ?goog.html.SafeHtml.AttributeValue>=} opt_attributes
|
||||
* Mapping from attribute names to their values. Only attribute names
|
||||
* consisting of [a-zA-Z0-9-] are allowed. Value of null or undefined causes
|
||||
* the attribute to be omitted.
|
||||
* @param {!goog.html.SafeHtml.TextOrHtml_|
|
||||
* !Array<!goog.html.SafeHtml.TextOrHtml_>=} opt_content Content to
|
||||
* HTML-escape and put inside the tag. Array elements are concatenated.
|
||||
* @return {!goog.html.SafeHtml} The SafeHtml content with the tag.
|
||||
* @throws {Error} If invalid tag name, attribute name, or attribute value is
|
||||
* provided. If opt_attributes contains the src or srcdoc attributes.
|
||||
*/
|
||||
goog.html.SafeHtml.createIframe = function(
|
||||
opt_src, opt_srcdoc, opt_attributes, opt_content) {
|
||||
if (opt_src) {
|
||||
// Check whether this is really TrustedResourceUrl.
|
||||
goog.html.TrustedResourceUrl.unwrap(opt_src);
|
||||
}
|
||||
|
||||
var fixedAttributes = {};
|
||||
fixedAttributes['src'] = opt_src || null;
|
||||
fixedAttributes['srcdoc'] =
|
||||
opt_srcdoc && goog.html.SafeHtml.unwrap(opt_srcdoc);
|
||||
var defaultAttributes = {'sandbox': ''};
|
||||
var attributes = goog.html.SafeHtml.combineAttributes(
|
||||
fixedAttributes, defaultAttributes, opt_attributes);
|
||||
return goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse(
|
||||
'iframe', attributes, opt_content);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a SafeHtml representing a sandboxed iframe tag.
|
||||
*
|
||||
* The sandbox attribute is enforced in its most restrictive mode, an empty
|
||||
* string. Consequently, the security requirements for the src and srcdoc
|
||||
* attributes are relaxed compared to SafeHtml.createIframe. This function
|
||||
* will throw on browsers that do not support the sandbox attribute, as
|
||||
* determined by SafeHtml.canUseSandboxIframe.
|
||||
*
|
||||
* The SafeHtml returned by this function can trigger downloads with no
|
||||
* user interaction on Chrome (though only a few, further attempts are blocked).
|
||||
* Firefox and IE will block all downloads from the sandbox.
|
||||
*
|
||||
* @see https://developer.mozilla.org/en/docs/Web/HTML/Element/iframe#attr-sandbox
|
||||
* @see https://lists.w3.org/Archives/Public/public-whatwg-archive/2013Feb/0112.html
|
||||
*
|
||||
* @param {string|!goog.html.SafeUrl=} opt_src The value of the src
|
||||
* attribute. If null or undefined src will not be set.
|
||||
* @param {string=} opt_srcdoc The value of the srcdoc attribute.
|
||||
* If null or undefined srcdoc will not be set. Will not be sanitized.
|
||||
* @param {!Object<string, ?goog.html.SafeHtml.AttributeValue>=} opt_attributes
|
||||
* Mapping from attribute names to their values. Only attribute names
|
||||
* consisting of [a-zA-Z0-9-] are allowed. Value of null or undefined causes
|
||||
* the attribute to be omitted.
|
||||
* @param {!goog.html.SafeHtml.TextOrHtml_|
|
||||
* !Array<!goog.html.SafeHtml.TextOrHtml_>=} opt_content Content to
|
||||
* HTML-escape and put inside the tag. Array elements are concatenated.
|
||||
* @return {!goog.html.SafeHtml} The SafeHtml content with the tag.
|
||||
* @throws {Error} If invalid tag name, attribute name, or attribute value is
|
||||
* provided. If opt_attributes contains the src, srcdoc or sandbox
|
||||
* attributes. If browser does not support the sandbox attribute on iframe.
|
||||
*/
|
||||
goog.html.SafeHtml.createSandboxIframe = function(
|
||||
opt_src, opt_srcdoc, opt_attributes, opt_content) {
|
||||
if (!goog.html.SafeHtml.canUseSandboxIframe()) {
|
||||
throw new Error('The browser does not support sandboxed iframes.');
|
||||
}
|
||||
|
||||
var fixedAttributes = {};
|
||||
if (opt_src) {
|
||||
// Note that sanitize is a no-op on SafeUrl.
|
||||
fixedAttributes['src'] =
|
||||
goog.html.SafeUrl.unwrap(goog.html.SafeUrl.sanitize(opt_src));
|
||||
} else {
|
||||
fixedAttributes['src'] = null;
|
||||
}
|
||||
fixedAttributes['srcdoc'] = opt_srcdoc || null;
|
||||
fixedAttributes['sandbox'] = '';
|
||||
var attributes =
|
||||
goog.html.SafeHtml.combineAttributes(fixedAttributes, {}, opt_attributes);
|
||||
return goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse(
|
||||
'iframe', attributes, opt_content);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the user agent supports sandboxed iframes.
|
||||
* @return {boolean}
|
||||
*/
|
||||
goog.html.SafeHtml.canUseSandboxIframe = function() {
|
||||
return goog.global['HTMLIFrameElement'] &&
|
||||
('sandbox' in goog.global['HTMLIFrameElement'].prototype);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a SafeHtml representing a script tag with the src attribute.
|
||||
* @param {!goog.html.TrustedResourceUrl} src The value of the src
|
||||
* attribute.
|
||||
* @param {?Object<string, ?goog.html.SafeHtml.AttributeValue>=}
|
||||
* opt_attributes
|
||||
* Mapping from attribute names to their values. Only attribute names
|
||||
* consisting of [a-zA-Z0-9-] are allowed. Value of null or undefined
|
||||
* causes the attribute to be omitted.
|
||||
* @return {!goog.html.SafeHtml} The SafeHtml content with the tag.
|
||||
* @throws {Error} If invalid attribute name or value is provided. If
|
||||
* opt_attributes contains the src attribute.
|
||||
*/
|
||||
goog.html.SafeHtml.createScriptSrc = function(src, opt_attributes) {
|
||||
// TODO(mlourenco): The charset attribute should probably be blocked. If
|
||||
// its value is attacker controlled, the script contains attacker controlled
|
||||
// sub-strings (even if properly escaped) and the server does not set charset
|
||||
// then XSS is likely possible.
|
||||
// https://html.spec.whatwg.org/multipage/scripting.html#dom-script-charset
|
||||
|
||||
// Check whether this is really TrustedResourceUrl.
|
||||
goog.html.TrustedResourceUrl.unwrap(src);
|
||||
|
||||
var fixedAttributes = {'src': src};
|
||||
var defaultAttributes = {};
|
||||
var attributes = goog.html.SafeHtml.combineAttributes(
|
||||
fixedAttributes, defaultAttributes, opt_attributes);
|
||||
return goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse(
|
||||
'script', attributes);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a SafeHtml representing a script tag. Does not allow the language,
|
||||
* src, text or type attributes to be set.
|
||||
* @param {!goog.html.SafeScript|!Array<!goog.html.SafeScript>}
|
||||
* script Content to put inside the tag. Array elements are
|
||||
* concatenated.
|
||||
* @param {?Object<string, ?goog.html.SafeHtml.AttributeValue>=} opt_attributes
|
||||
* Mapping from attribute names to their values. Only attribute names
|
||||
* consisting of [a-zA-Z0-9-] are allowed. Value of null or undefined causes
|
||||
* the attribute to be omitted.
|
||||
* @return {!goog.html.SafeHtml} The SafeHtml content with the tag.
|
||||
* @throws {Error} If invalid attribute name or attribute value is provided. If
|
||||
* opt_attributes contains the language, src, text or type attribute.
|
||||
*/
|
||||
goog.html.SafeHtml.createScript = function(script, opt_attributes) {
|
||||
for (var attr in opt_attributes) {
|
||||
var attrLower = attr.toLowerCase();
|
||||
if (attrLower == 'language' || attrLower == 'src' || attrLower == 'text' ||
|
||||
attrLower == 'type') {
|
||||
throw Error('Cannot set "' + attrLower + '" attribute');
|
||||
}
|
||||
}
|
||||
|
||||
var content = '';
|
||||
script = goog.array.concat(script);
|
||||
for (var i = 0; i < script.length; i++) {
|
||||
content += goog.html.SafeScript.unwrap(script[i]);
|
||||
}
|
||||
// Convert to SafeHtml so that it's not HTML-escaped. This is safe because
|
||||
// as part of its contract, SafeScript should have no dangerous '<'.
|
||||
var htmlContent =
|
||||
goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse(
|
||||
content, goog.i18n.bidi.Dir.NEUTRAL);
|
||||
return goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse(
|
||||
'script', opt_attributes, htmlContent);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a SafeHtml representing a style tag. The type attribute is set
|
||||
* to "text/css".
|
||||
* @param {!goog.html.SafeStyleSheet|!Array<!goog.html.SafeStyleSheet>}
|
||||
* styleSheet Content to put inside the tag. Array elements are
|
||||
* concatenated.
|
||||
* @param {?Object<string, ?goog.html.SafeHtml.AttributeValue>=} opt_attributes
|
||||
* Mapping from attribute names to their values. Only attribute names
|
||||
* consisting of [a-zA-Z0-9-] are allowed. Value of null or undefined causes
|
||||
* the attribute to be omitted.
|
||||
* @return {!goog.html.SafeHtml} The SafeHtml content with the tag.
|
||||
* @throws {Error} If invalid attribute name or attribute value is provided. If
|
||||
* opt_attributes contains the type attribute.
|
||||
*/
|
||||
goog.html.SafeHtml.createStyle = function(styleSheet, opt_attributes) {
|
||||
var fixedAttributes = {'type': 'text/css'};
|
||||
var defaultAttributes = {};
|
||||
var attributes = goog.html.SafeHtml.combineAttributes(
|
||||
fixedAttributes, defaultAttributes, opt_attributes);
|
||||
|
||||
var content = '';
|
||||
styleSheet = goog.array.concat(styleSheet);
|
||||
for (var i = 0; i < styleSheet.length; i++) {
|
||||
content += goog.html.SafeStyleSheet.unwrap(styleSheet[i]);
|
||||
}
|
||||
// Convert to SafeHtml so that it's not HTML-escaped. This is safe because
|
||||
// as part of its contract, SafeStyleSheet should have no dangerous '<'.
|
||||
var htmlContent =
|
||||
goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse(
|
||||
content, goog.i18n.bidi.Dir.NEUTRAL);
|
||||
return goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse(
|
||||
'style', attributes, htmlContent);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a SafeHtml representing a meta refresh tag.
|
||||
* @param {!goog.html.SafeUrl|string} url Where to redirect. If a string is
|
||||
* passed, it will be sanitized with SafeUrl.sanitize().
|
||||
* @param {number=} opt_secs Number of seconds until the page should be
|
||||
* reloaded. Will be set to 0 if unspecified.
|
||||
* @return {!goog.html.SafeHtml} The SafeHtml content with the tag.
|
||||
*/
|
||||
goog.html.SafeHtml.createMetaRefresh = function(url, opt_secs) {
|
||||
|
||||
// Note that sanitize is a no-op on SafeUrl.
|
||||
var unwrappedUrl = goog.html.SafeUrl.unwrap(goog.html.SafeUrl.sanitize(url));
|
||||
|
||||
if (goog.labs.userAgent.browser.isIE() ||
|
||||
goog.labs.userAgent.browser.isEdge()) {
|
||||
// IE/EDGE can't parse the content attribute if the url contains a
|
||||
// semicolon. We can fix this by adding quotes around the url, but then we
|
||||
// can't parse quotes in the URL correctly. Also, it seems that IE/EDGE
|
||||
// did not unescape semicolons in these URLs at some point in the past. We
|
||||
// take a best-effort approach.
|
||||
//
|
||||
// If the URL has semicolons (which may happen in some cases, see
|
||||
// http://www.w3.org/TR/1999/REC-html401-19991224/appendix/notes.html#h-B.2
|
||||
// for instance), wrap it in single quotes to protect the semicolons.
|
||||
// If the URL has semicolons and single quotes, url-encode the single quotes
|
||||
// as well.
|
||||
//
|
||||
// This is imperfect. Notice that both ' and ; are reserved characters in
|
||||
// URIs, so this could do the wrong thing, but at least it will do the wrong
|
||||
// thing in only rare cases.
|
||||
if (goog.string.contains(unwrappedUrl, ';')) {
|
||||
unwrappedUrl = "'" + unwrappedUrl.replace(/'/g, '%27') + "'";
|
||||
}
|
||||
}
|
||||
var attributes = {
|
||||
'http-equiv': 'refresh',
|
||||
'content': (opt_secs || 0) + '; url=' + unwrappedUrl
|
||||
};
|
||||
|
||||
// This function will handle the HTML escaping for attributes.
|
||||
return goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse(
|
||||
'meta', attributes);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} tagName The tag name.
|
||||
* @param {string} name The attribute name.
|
||||
* @param {!goog.html.SafeHtml.AttributeValue} value The attribute value.
|
||||
* @return {string} A "name=value" string.
|
||||
* @throws {Error} If attribute value is unsafe for the given tag and attribute.
|
||||
* @private
|
||||
*/
|
||||
goog.html.SafeHtml.getAttrNameAndValue_ = function(tagName, name, value) {
|
||||
// If it's goog.string.Const, allow any valid attribute name.
|
||||
if (value instanceof goog.string.Const) {
|
||||
value = goog.string.Const.unwrap(value);
|
||||
} else if (name.toLowerCase() == 'style') {
|
||||
value = goog.html.SafeHtml.getStyleValue_(value);
|
||||
} else if (/^on/i.test(name)) {
|
||||
// TODO(jakubvrana): Disallow more attributes with a special meaning.
|
||||
throw Error(
|
||||
'Attribute "' + name + '" requires goog.string.Const value, "' + value +
|
||||
'" given.');
|
||||
// URL attributes handled differently according to tag.
|
||||
} else if (name.toLowerCase() in goog.html.SafeHtml.URL_ATTRIBUTES_) {
|
||||
if (value instanceof goog.html.TrustedResourceUrl) {
|
||||
value = goog.html.TrustedResourceUrl.unwrap(value);
|
||||
} else if (value instanceof goog.html.SafeUrl) {
|
||||
value = goog.html.SafeUrl.unwrap(value);
|
||||
} else if (goog.isString(value)) {
|
||||
value = goog.html.SafeUrl.sanitize(value).getTypedStringValue();
|
||||
} else {
|
||||
throw Error(
|
||||
'Attribute "' + name + '" on tag "' + tagName +
|
||||
'" requires goog.html.SafeUrl, goog.string.Const, or string,' +
|
||||
' value "' + value + '" given.');
|
||||
}
|
||||
}
|
||||
|
||||
// Accept SafeUrl, TrustedResourceUrl, etc. for attributes which only require
|
||||
// HTML-escaping.
|
||||
if (value.implementsGoogStringTypedString) {
|
||||
// Ok to call getTypedStringValue() since there's no reliance on the type
|
||||
// contract for security here.
|
||||
value = value.getTypedStringValue();
|
||||
}
|
||||
|
||||
goog.asserts.assert(
|
||||
goog.isString(value) || goog.isNumber(value),
|
||||
'String or number value expected, got ' + (typeof value) +
|
||||
' with value: ' + value);
|
||||
return name + '="' + goog.string.htmlEscape(String(value)) + '"';
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets value allowed in "style" attribute.
|
||||
* @param {!goog.html.SafeHtml.AttributeValue} value It could be SafeStyle or a
|
||||
* map which will be passed to goog.html.SafeStyle.create.
|
||||
* @return {string} Unwrapped value.
|
||||
* @throws {Error} If string value is given.
|
||||
* @private
|
||||
*/
|
||||
goog.html.SafeHtml.getStyleValue_ = function(value) {
|
||||
if (!goog.isObject(value)) {
|
||||
throw Error(
|
||||
'The "style" attribute requires goog.html.SafeStyle or map ' +
|
||||
'of style properties, ' + (typeof value) + ' given: ' + value);
|
||||
}
|
||||
if (!(value instanceof goog.html.SafeStyle)) {
|
||||
// Process the property bag into a style object.
|
||||
value = goog.html.SafeStyle.create(value);
|
||||
}
|
||||
return goog.html.SafeStyle.unwrap(value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a SafeHtml content with known directionality consisting of a tag with
|
||||
* optional attributes and optional content.
|
||||
* @param {!goog.i18n.bidi.Dir} dir Directionality.
|
||||
* @param {string} tagName
|
||||
* @param {?Object<string, ?goog.html.SafeHtml.AttributeValue>=} opt_attributes
|
||||
* @param {!goog.html.SafeHtml.TextOrHtml_|
|
||||
* !Array<!goog.html.SafeHtml.TextOrHtml_>=} opt_content
|
||||
* @return {!goog.html.SafeHtml} The SafeHtml content with the tag.
|
||||
*/
|
||||
goog.html.SafeHtml.createWithDir = function(
|
||||
dir, tagName, opt_attributes, opt_content) {
|
||||
var html = goog.html.SafeHtml.create(tagName, opt_attributes, opt_content);
|
||||
html.dir_ = dir;
|
||||
return html;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new SafeHtml object by concatenating values.
|
||||
* @param {...(!goog.html.SafeHtml.TextOrHtml_|
|
||||
* !Array<!goog.html.SafeHtml.TextOrHtml_>)} var_args Values to concatenate.
|
||||
* @return {!goog.html.SafeHtml}
|
||||
*/
|
||||
goog.html.SafeHtml.concat = function(var_args) {
|
||||
var dir = goog.i18n.bidi.Dir.NEUTRAL;
|
||||
var content = '';
|
||||
|
||||
/**
|
||||
* @param {!goog.html.SafeHtml.TextOrHtml_|
|
||||
* !Array<!goog.html.SafeHtml.TextOrHtml_>} argument
|
||||
*/
|
||||
var addArgument = function(argument) {
|
||||
if (goog.isArray(argument)) {
|
||||
goog.array.forEach(argument, addArgument);
|
||||
} else {
|
||||
var html = goog.html.SafeHtml.htmlEscape(argument);
|
||||
content += goog.html.SafeHtml.unwrap(html);
|
||||
var htmlDir = html.getDirection();
|
||||
if (dir == goog.i18n.bidi.Dir.NEUTRAL) {
|
||||
dir = htmlDir;
|
||||
} else if (htmlDir != goog.i18n.bidi.Dir.NEUTRAL && dir != htmlDir) {
|
||||
dir = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
goog.array.forEach(arguments, addArgument);
|
||||
return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse(
|
||||
content, dir);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new SafeHtml object with known directionality by concatenating the
|
||||
* values.
|
||||
* @param {!goog.i18n.bidi.Dir} dir Directionality.
|
||||
* @param {...(!goog.html.SafeHtml.TextOrHtml_|
|
||||
* !Array<!goog.html.SafeHtml.TextOrHtml_>)} var_args Elements of array
|
||||
* arguments would be processed recursively.
|
||||
* @return {!goog.html.SafeHtml}
|
||||
*/
|
||||
goog.html.SafeHtml.concatWithDir = function(dir, var_args) {
|
||||
var html = goog.html.SafeHtml.concat(goog.array.slice(arguments, 1));
|
||||
html.dir_ = dir;
|
||||
return html;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Type marker for the SafeHtml type, used to implement additional run-time
|
||||
* type checking.
|
||||
* @const {!Object}
|
||||
* @private
|
||||
*/
|
||||
goog.html.SafeHtml.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {};
|
||||
|
||||
|
||||
/**
|
||||
* Package-internal utility method to create SafeHtml instances.
|
||||
*
|
||||
* @param {string} html The string to initialize the SafeHtml object with.
|
||||
* @param {?goog.i18n.bidi.Dir} dir The directionality of the SafeHtml to be
|
||||
* constructed, or null if unknown.
|
||||
* @return {!goog.html.SafeHtml} The initialized SafeHtml object.
|
||||
* @package
|
||||
*/
|
||||
goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse = function(
|
||||
html, dir) {
|
||||
return new goog.html.SafeHtml().initSecurityPrivateDoNotAccessOrElse_(
|
||||
html, dir);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Called from createSafeHtmlSecurityPrivateDoNotAccessOrElse(). This
|
||||
* method exists only so that the compiler can dead code eliminate static
|
||||
* fields (like EMPTY) when they're not accessed.
|
||||
* @param {string} html
|
||||
* @param {?goog.i18n.bidi.Dir} dir
|
||||
* @return {!goog.html.SafeHtml}
|
||||
* @private
|
||||
*/
|
||||
goog.html.SafeHtml.prototype.initSecurityPrivateDoNotAccessOrElse_ = function(
|
||||
html, dir) {
|
||||
this.privateDoNotAccessOrElseSafeHtmlWrappedValue_ = html;
|
||||
this.dir_ = dir;
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Like create() but does not restrict which tags can be constructed.
|
||||
*
|
||||
* @param {string} tagName Tag name. Set or validated by caller.
|
||||
* @param {?Object<string, ?goog.html.SafeHtml.AttributeValue>=} opt_attributes
|
||||
* @param {(!goog.html.SafeHtml.TextOrHtml_|
|
||||
* !Array<!goog.html.SafeHtml.TextOrHtml_>)=} opt_content
|
||||
* @return {!goog.html.SafeHtml}
|
||||
* @throws {Error} If invalid or unsafe attribute name or value is provided.
|
||||
* @throws {goog.asserts.AssertionError} If content for void tag is provided.
|
||||
* @package
|
||||
*/
|
||||
goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse = function(
|
||||
tagName, opt_attributes, opt_content) {
|
||||
var dir = null;
|
||||
var result = '<' + tagName;
|
||||
result += goog.html.SafeHtml.stringifyAttributes(tagName, opt_attributes);
|
||||
|
||||
var content = opt_content;
|
||||
if (!goog.isDefAndNotNull(content)) {
|
||||
content = [];
|
||||
} else if (!goog.isArray(content)) {
|
||||
content = [content];
|
||||
}
|
||||
|
||||
if (goog.dom.tags.isVoidTag(tagName.toLowerCase())) {
|
||||
goog.asserts.assert(
|
||||
!content.length, 'Void tag <' + tagName + '> does not allow content.');
|
||||
result += '>';
|
||||
} else {
|
||||
var html = goog.html.SafeHtml.concat(content);
|
||||
result += '>' + goog.html.SafeHtml.unwrap(html) + '</' + tagName + '>';
|
||||
dir = html.getDirection();
|
||||
}
|
||||
|
||||
var dirAttribute = opt_attributes && opt_attributes['dir'];
|
||||
if (dirAttribute) {
|
||||
if (/^(ltr|rtl|auto)$/i.test(dirAttribute)) {
|
||||
// If the tag has the "dir" attribute specified then its direction is
|
||||
// neutral because it can be safely used in any context.
|
||||
dir = goog.i18n.bidi.Dir.NEUTRAL;
|
||||
} else {
|
||||
dir = null;
|
||||
}
|
||||
}
|
||||
|
||||
return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse(
|
||||
result, dir);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a string with attributes to insert after tagName.
|
||||
* @param {string} tagName
|
||||
* @param {?Object<string, ?goog.html.SafeHtml.AttributeValue>=} opt_attributes
|
||||
* @return {string} Returns an empty string if there are no attributes, returns
|
||||
* a string starting with a space otherwise.
|
||||
* @throws {Error} If attribute value is unsafe for the given tag and attribute.
|
||||
* @package
|
||||
*/
|
||||
goog.html.SafeHtml.stringifyAttributes = function(tagName, opt_attributes) {
|
||||
var result = '';
|
||||
if (opt_attributes) {
|
||||
for (var name in opt_attributes) {
|
||||
if (!goog.html.SafeHtml.VALID_NAMES_IN_TAG_.test(name)) {
|
||||
throw Error('Invalid attribute name "' + name + '".');
|
||||
}
|
||||
var value = opt_attributes[name];
|
||||
if (!goog.isDefAndNotNull(value)) {
|
||||
continue;
|
||||
}
|
||||
result +=
|
||||
' ' + goog.html.SafeHtml.getAttrNameAndValue_(tagName, name, value);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {!Object<string, ?goog.html.SafeHtml.AttributeValue>} fixedAttributes
|
||||
* @param {!Object<string, string>} defaultAttributes
|
||||
* @param {?Object<string, ?goog.html.SafeHtml.AttributeValue>=} opt_attributes
|
||||
* Optional attributes passed to create*().
|
||||
* @return {!Object<string, ?goog.html.SafeHtml.AttributeValue>}
|
||||
* @throws {Error} If opt_attributes contains an attribute with the same name
|
||||
* as an attribute in fixedAttributes.
|
||||
* @package
|
||||
*/
|
||||
goog.html.SafeHtml.combineAttributes = function(
|
||||
fixedAttributes, defaultAttributes, opt_attributes) {
|
||||
var combinedAttributes = {};
|
||||
var name;
|
||||
|
||||
for (name in fixedAttributes) {
|
||||
goog.asserts.assert(name.toLowerCase() == name, 'Must be lower case');
|
||||
combinedAttributes[name] = fixedAttributes[name];
|
||||
}
|
||||
for (name in defaultAttributes) {
|
||||
goog.asserts.assert(name.toLowerCase() == name, 'Must be lower case');
|
||||
combinedAttributes[name] = defaultAttributes[name];
|
||||
}
|
||||
|
||||
for (name in opt_attributes) {
|
||||
var nameLower = name.toLowerCase();
|
||||
if (nameLower in fixedAttributes) {
|
||||
throw Error(
|
||||
'Cannot override "' + nameLower + '" attribute, got "' + name +
|
||||
'" with value "' + opt_attributes[name] + '"');
|
||||
}
|
||||
if (nameLower in defaultAttributes) {
|
||||
delete combinedAttributes[nameLower];
|
||||
}
|
||||
combinedAttributes[name] = opt_attributes[name];
|
||||
}
|
||||
|
||||
return combinedAttributes;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A SafeHtml instance corresponding to the HTML doctype: "<!DOCTYPE html>".
|
||||
* @const {!goog.html.SafeHtml}
|
||||
*/
|
||||
goog.html.SafeHtml.DOCTYPE_HTML =
|
||||
goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse(
|
||||
'<!DOCTYPE html>', goog.i18n.bidi.Dir.NEUTRAL);
|
||||
|
||||
|
||||
/**
|
||||
* A SafeHtml instance corresponding to the empty string.
|
||||
* @const {!goog.html.SafeHtml}
|
||||
*/
|
||||
goog.html.SafeHtml.EMPTY =
|
||||
goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse(
|
||||
'', goog.i18n.bidi.Dir.NEUTRAL);
|
||||
|
||||
|
||||
/**
|
||||
* A SafeHtml instance corresponding to the <br> tag.
|
||||
* @const {!goog.html.SafeHtml}
|
||||
*/
|
||||
goog.html.SafeHtml.BR =
|
||||
goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse(
|
||||
'<br>', goog.i18n.bidi.Dir.NEUTRAL);
|
||||
|
|
@ -0,0 +1,234 @@
|
|||
// Copyright 2014 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 The SafeScript type and its builders.
|
||||
*
|
||||
* TODO(xtof): Link to document stating type contract.
|
||||
*/
|
||||
|
||||
goog.provide('goog.html.SafeScript');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.string.Const');
|
||||
goog.require('goog.string.TypedString');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A string-like object which represents JavaScript code and that carries the
|
||||
* security type contract that its value, as a string, will not cause execution
|
||||
* of unconstrained attacker controlled code (XSS) when evaluated as JavaScript
|
||||
* in a browser.
|
||||
*
|
||||
* Instances of this type must be created via the factory method
|
||||
* {@code goog.html.SafeScript.fromConstant} and not by invoking its
|
||||
* constructor. The constructor intentionally takes no parameters and the type
|
||||
* is immutable; hence only a default instance corresponding to the empty string
|
||||
* can be obtained via constructor invocation.
|
||||
*
|
||||
* A SafeScript's string representation can safely be interpolated as the
|
||||
* content of a script element within HTML. The SafeScript string should not be
|
||||
* escaped before interpolation.
|
||||
*
|
||||
* Note that the SafeScript might contain text that is attacker-controlled but
|
||||
* that text should have been interpolated with appropriate escaping,
|
||||
* sanitization and/or validation into the right location in the script, such
|
||||
* that it is highly constrained in its effect (for example, it had to match a
|
||||
* set of whitelisted words).
|
||||
*
|
||||
* A SafeScript can be constructed via security-reviewed unchecked
|
||||
* conversions. In this case producers of SafeScript must ensure themselves that
|
||||
* the SafeScript does not contain unsafe script. Note in particular that
|
||||
* {@code <} is dangerous, even when inside JavaScript strings, and so should
|
||||
* always be forbidden or JavaScript escaped in user controlled input. For
|
||||
* example, if {@code </script><script>evil</script>"} were
|
||||
* interpolated inside a JavaScript string, it would break out of the context
|
||||
* of the original script element and {@code evil} would execute. Also note
|
||||
* that within an HTML script (raw text) element, HTML character references,
|
||||
* such as "<" are not allowed. See
|
||||
* http://www.w3.org/TR/html5/scripting-1.html#restrictions-for-contents-of-script-elements.
|
||||
*
|
||||
* @see goog.html.SafeScript#fromConstant
|
||||
* @constructor
|
||||
* @final
|
||||
* @struct
|
||||
* @implements {goog.string.TypedString}
|
||||
*/
|
||||
goog.html.SafeScript = function() {
|
||||
/**
|
||||
* The contained value of this SafeScript. The field has a purposely
|
||||
* ugly name to make (non-compiled) code that attempts to directly access this
|
||||
* field stand out.
|
||||
* @private {string}
|
||||
*/
|
||||
this.privateDoNotAccessOrElseSafeScriptWrappedValue_ = '';
|
||||
|
||||
/**
|
||||
* A type marker used to implement additional run-time type checking.
|
||||
* @see goog.html.SafeScript#unwrap
|
||||
* @const {!Object}
|
||||
* @private
|
||||
*/
|
||||
this.SAFE_SCRIPT_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ =
|
||||
goog.html.SafeScript.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @const
|
||||
*/
|
||||
goog.html.SafeScript.prototype.implementsGoogStringTypedString = true;
|
||||
|
||||
|
||||
/**
|
||||
* Type marker for the SafeScript type, used to implement additional
|
||||
* run-time type checking.
|
||||
* @const {!Object}
|
||||
* @private
|
||||
*/
|
||||
goog.html.SafeScript.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a SafeScript object from a compile-time constant string.
|
||||
*
|
||||
* @param {!goog.string.Const} script A compile-time-constant string from which
|
||||
* to create a SafeScript.
|
||||
* @return {!goog.html.SafeScript} A SafeScript object initialized to
|
||||
* {@code script}.
|
||||
*/
|
||||
goog.html.SafeScript.fromConstant = function(script) {
|
||||
var scriptString = goog.string.Const.unwrap(script);
|
||||
if (scriptString.length === 0) {
|
||||
return goog.html.SafeScript.EMPTY;
|
||||
}
|
||||
return goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse(
|
||||
scriptString);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns this SafeScript's value as a string.
|
||||
*
|
||||
* IMPORTANT: In code where it is security relevant that an object's type is
|
||||
* indeed {@code SafeScript}, use {@code goog.html.SafeScript.unwrap} instead of
|
||||
* this method. If in doubt, assume that it's security relevant. In particular,
|
||||
* note that goog.html functions which return a goog.html type do not guarantee
|
||||
* the returned instance is of the right type. For example:
|
||||
*
|
||||
* <pre>
|
||||
* var fakeSafeHtml = new String('fake');
|
||||
* fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype;
|
||||
* var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml);
|
||||
* // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by
|
||||
* // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml
|
||||
* // instanceof goog.html.SafeHtml.
|
||||
* </pre>
|
||||
*
|
||||
* @see goog.html.SafeScript#unwrap
|
||||
* @override
|
||||
*/
|
||||
goog.html.SafeScript.prototype.getTypedStringValue = function() {
|
||||
return this.privateDoNotAccessOrElseSafeScriptWrappedValue_;
|
||||
};
|
||||
|
||||
|
||||
if (goog.DEBUG) {
|
||||
/**
|
||||
* Returns a debug string-representation of this value.
|
||||
*
|
||||
* To obtain the actual string value wrapped in a SafeScript, use
|
||||
* {@code goog.html.SafeScript.unwrap}.
|
||||
*
|
||||
* @see goog.html.SafeScript#unwrap
|
||||
* @override
|
||||
*/
|
||||
goog.html.SafeScript.prototype.toString = function() {
|
||||
return 'SafeScript{' +
|
||||
this.privateDoNotAccessOrElseSafeScriptWrappedValue_ + '}';
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Performs a runtime check that the provided object is indeed a
|
||||
* SafeScript object, and returns its value.
|
||||
*
|
||||
* @param {!goog.html.SafeScript} safeScript The object to extract from.
|
||||
* @return {string} The safeScript object's contained string, unless
|
||||
* the run-time type check fails. In that case, {@code unwrap} returns an
|
||||
* innocuous string, or, if assertions are enabled, throws
|
||||
* {@code goog.asserts.AssertionError}.
|
||||
*/
|
||||
goog.html.SafeScript.unwrap = function(safeScript) {
|
||||
// Perform additional Run-time type-checking to ensure that
|
||||
// safeScript is indeed an instance of the expected type. This
|
||||
// provides some additional protection against security bugs due to
|
||||
// application code that disables type checks.
|
||||
// Specifically, the following checks are performed:
|
||||
// 1. The object is an instance of the expected type.
|
||||
// 2. The object is not an instance of a subclass.
|
||||
// 3. The object carries a type marker for the expected type. "Faking" an
|
||||
// object requires a reference to the type marker, which has names intended
|
||||
// to stand out in code reviews.
|
||||
if (safeScript instanceof goog.html.SafeScript &&
|
||||
safeScript.constructor === goog.html.SafeScript &&
|
||||
safeScript.SAFE_SCRIPT_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ ===
|
||||
goog.html.SafeScript.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) {
|
||||
return safeScript.privateDoNotAccessOrElseSafeScriptWrappedValue_;
|
||||
} else {
|
||||
goog.asserts.fail('expected object of type SafeScript, got \'' +
|
||||
safeScript + '\' of type ' + goog.typeOf(safeScript));
|
||||
return 'type_error:SafeScript';
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Package-internal utility method to create SafeScript instances.
|
||||
*
|
||||
* @param {string} script The string to initialize the SafeScript object with.
|
||||
* @return {!goog.html.SafeScript} The initialized SafeScript object.
|
||||
* @package
|
||||
*/
|
||||
goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse =
|
||||
function(script) {
|
||||
return new goog.html.SafeScript().initSecurityPrivateDoNotAccessOrElse_(
|
||||
script);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Called from createSafeScriptSecurityPrivateDoNotAccessOrElse(). This
|
||||
* method exists only so that the compiler can dead code eliminate static
|
||||
* fields (like EMPTY) when they're not accessed.
|
||||
* @param {string} script
|
||||
* @return {!goog.html.SafeScript}
|
||||
* @private
|
||||
*/
|
||||
goog.html.SafeScript.prototype.initSecurityPrivateDoNotAccessOrElse_ = function(
|
||||
script) {
|
||||
this.privateDoNotAccessOrElseSafeScriptWrappedValue_ = script;
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A SafeScript instance corresponding to the empty string.
|
||||
* @const {!goog.html.SafeScript}
|
||||
*/
|
||||
goog.html.SafeScript.EMPTY =
|
||||
goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse('');
|
||||
|
|
@ -0,0 +1,560 @@
|
|||
// Copyright 2014 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 The SafeStyle type and its builders.
|
||||
*
|
||||
* TODO(xtof): Link to document stating type contract.
|
||||
*/
|
||||
|
||||
goog.provide('goog.html.SafeStyle');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.html.SafeUrl');
|
||||
goog.require('goog.string');
|
||||
goog.require('goog.string.Const');
|
||||
goog.require('goog.string.TypedString');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A string-like object which represents a sequence of CSS declarations
|
||||
* ({@code propertyName1: propertyvalue1; propertyName2: propertyValue2; ...})
|
||||
* and that carries the security type contract that its value, as a string,
|
||||
* will not cause untrusted script execution (XSS) when evaluated as CSS in a
|
||||
* browser.
|
||||
*
|
||||
* Instances of this type must be created via the factory methods
|
||||
* ({@code goog.html.SafeStyle.create} or
|
||||
* {@code goog.html.SafeStyle.fromConstant}) and not by invoking its
|
||||
* constructor. The constructor intentionally takes no parameters and the type
|
||||
* is immutable; hence only a default instance corresponding to the empty string
|
||||
* can be obtained via constructor invocation.
|
||||
*
|
||||
* SafeStyle's string representation can safely be:
|
||||
* <ul>
|
||||
* <li>Interpolated as the content of a *quoted* HTML style attribute.
|
||||
* However, the SafeStyle string *must be HTML-attribute-escaped* before
|
||||
* interpolation.
|
||||
* <li>Interpolated as the content of a {}-wrapped block within a stylesheet.
|
||||
* '<' characters in the SafeStyle string *must be CSS-escaped* before
|
||||
* interpolation. The SafeStyle string is also guaranteed not to be able
|
||||
* to introduce new properties or elide existing ones.
|
||||
* <li>Interpolated as the content of a {}-wrapped block within an HTML
|
||||
* <style> element. '<' characters in the SafeStyle string
|
||||
* *must be CSS-escaped* before interpolation.
|
||||
* <li>Assigned to the style property of a DOM node. The SafeStyle string
|
||||
* should not be escaped before being assigned to the property.
|
||||
* </ul>
|
||||
*
|
||||
* A SafeStyle may never contain literal angle brackets. Otherwise, it could
|
||||
* be unsafe to place a SafeStyle into a <style> tag (where it can't
|
||||
* be HTML escaped). For example, if the SafeStyle containing
|
||||
* "{@code font: 'foo <style/><script>evil</script>'}" were
|
||||
* interpolated within a <style> tag, this would then break out of the
|
||||
* style context into HTML.
|
||||
*
|
||||
* A SafeStyle may contain literal single or double quotes, and as such the
|
||||
* entire style string must be escaped when used in a style attribute (if
|
||||
* this were not the case, the string could contain a matching quote that
|
||||
* would escape from the style attribute).
|
||||
*
|
||||
* Values of this type must be composable, i.e. for any two values
|
||||
* {@code style1} and {@code style2} of this type,
|
||||
* {@code goog.html.SafeStyle.unwrap(style1) +
|
||||
* goog.html.SafeStyle.unwrap(style2)} must itself be a value that satisfies
|
||||
* the SafeStyle type constraint. This requirement implies that for any value
|
||||
* {@code style} of this type, {@code goog.html.SafeStyle.unwrap(style)} must
|
||||
* not end in a "property value" or "property name" context. For example,
|
||||
* a value of {@code background:url("} or {@code font-} would not satisfy the
|
||||
* SafeStyle contract. This is because concatenating such strings with a
|
||||
* second value that itself does not contain unsafe CSS can result in an
|
||||
* overall string that does. For example, if {@code javascript:evil())"} is
|
||||
* appended to {@code background:url("}, the resulting string may result in
|
||||
* the execution of a malicious script.
|
||||
*
|
||||
* TODO(mlourenco): Consider whether we should implement UTF-8 interchange
|
||||
* validity checks and blacklisting of newlines (including Unicode ones) and
|
||||
* other whitespace characters (\t, \f). Document here if so and also update
|
||||
* SafeStyle.fromConstant().
|
||||
*
|
||||
* The following example values comply with this type's contract:
|
||||
* <ul>
|
||||
* <li><pre>width: 1em;</pre>
|
||||
* <li><pre>height:1em;</pre>
|
||||
* <li><pre>width: 1em;height: 1em;</pre>
|
||||
* <li><pre>background:url('http://url');</pre>
|
||||
* </ul>
|
||||
* In addition, the empty string is safe for use in a CSS attribute.
|
||||
*
|
||||
* The following example values do NOT comply with this type's contract:
|
||||
* <ul>
|
||||
* <li><pre>background: red</pre> (missing a trailing semi-colon)
|
||||
* <li><pre>background:</pre> (missing a value and a trailing semi-colon)
|
||||
* <li><pre>1em</pre> (missing an attribute name, which provides context for
|
||||
* the value)
|
||||
* </ul>
|
||||
*
|
||||
* @see goog.html.SafeStyle#create
|
||||
* @see goog.html.SafeStyle#fromConstant
|
||||
* @see http://www.w3.org/TR/css3-syntax/
|
||||
* @constructor
|
||||
* @final
|
||||
* @struct
|
||||
* @implements {goog.string.TypedString}
|
||||
*/
|
||||
goog.html.SafeStyle = function() {
|
||||
/**
|
||||
* The contained value of this SafeStyle. The field has a purposely
|
||||
* ugly name to make (non-compiled) code that attempts to directly access this
|
||||
* field stand out.
|
||||
* @private {string}
|
||||
*/
|
||||
this.privateDoNotAccessOrElseSafeStyleWrappedValue_ = '';
|
||||
|
||||
/**
|
||||
* A type marker used to implement additional run-time type checking.
|
||||
* @see goog.html.SafeStyle#unwrap
|
||||
* @const {!Object}
|
||||
* @private
|
||||
*/
|
||||
this.SAFE_STYLE_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ =
|
||||
goog.html.SafeStyle.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @const
|
||||
*/
|
||||
goog.html.SafeStyle.prototype.implementsGoogStringTypedString = true;
|
||||
|
||||
|
||||
/**
|
||||
* Type marker for the SafeStyle type, used to implement additional
|
||||
* run-time type checking.
|
||||
* @const {!Object}
|
||||
* @private
|
||||
*/
|
||||
goog.html.SafeStyle.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a SafeStyle object from a compile-time constant string.
|
||||
*
|
||||
* {@code style} should be in the format
|
||||
* {@code name: value; [name: value; ...]} and must not have any < or >
|
||||
* characters in it. This is so that SafeStyle's contract is preserved,
|
||||
* allowing the SafeStyle to correctly be interpreted as a sequence of CSS
|
||||
* declarations and without affecting the syntactic structure of any
|
||||
* surrounding CSS and HTML.
|
||||
*
|
||||
* This method performs basic sanity checks on the format of {@code style}
|
||||
* but does not constrain the format of {@code name} and {@code value}, except
|
||||
* for disallowing tag characters.
|
||||
*
|
||||
* @param {!goog.string.Const} style A compile-time-constant string from which
|
||||
* to create a SafeStyle.
|
||||
* @return {!goog.html.SafeStyle} A SafeStyle object initialized to
|
||||
* {@code style}.
|
||||
*/
|
||||
goog.html.SafeStyle.fromConstant = function(style) {
|
||||
var styleString = goog.string.Const.unwrap(style);
|
||||
if (styleString.length === 0) {
|
||||
return goog.html.SafeStyle.EMPTY;
|
||||
}
|
||||
goog.html.SafeStyle.checkStyle_(styleString);
|
||||
goog.asserts.assert(
|
||||
goog.string.endsWith(styleString, ';'),
|
||||
'Last character of style string is not \';\': ' + styleString);
|
||||
goog.asserts.assert(
|
||||
goog.string.contains(styleString, ':'),
|
||||
'Style string must contain at least one \':\', to ' +
|
||||
'specify a "name: value" pair: ' + styleString);
|
||||
return goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse(
|
||||
styleString);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the style definition is valid.
|
||||
* @param {string} style
|
||||
* @private
|
||||
*/
|
||||
goog.html.SafeStyle.checkStyle_ = function(style) {
|
||||
goog.asserts.assert(
|
||||
!/[<>]/.test(style), 'Forbidden characters in style string: ' + style);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns this SafeStyle's value as a string.
|
||||
*
|
||||
* IMPORTANT: In code where it is security relevant that an object's type is
|
||||
* indeed {@code SafeStyle}, use {@code goog.html.SafeStyle.unwrap} instead of
|
||||
* this method. If in doubt, assume that it's security relevant. In particular,
|
||||
* note that goog.html functions which return a goog.html type do not guarantee
|
||||
* the returned instance is of the right type. For example:
|
||||
*
|
||||
* <pre>
|
||||
* var fakeSafeHtml = new String('fake');
|
||||
* fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype;
|
||||
* var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml);
|
||||
* // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by
|
||||
* // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml
|
||||
* // instanceof goog.html.SafeHtml.
|
||||
* </pre>
|
||||
*
|
||||
* @see goog.html.SafeStyle#unwrap
|
||||
* @override
|
||||
*/
|
||||
goog.html.SafeStyle.prototype.getTypedStringValue = function() {
|
||||
return this.privateDoNotAccessOrElseSafeStyleWrappedValue_;
|
||||
};
|
||||
|
||||
|
||||
if (goog.DEBUG) {
|
||||
/**
|
||||
* Returns a debug string-representation of this value.
|
||||
*
|
||||
* To obtain the actual string value wrapped in a SafeStyle, use
|
||||
* {@code goog.html.SafeStyle.unwrap}.
|
||||
*
|
||||
* @see goog.html.SafeStyle#unwrap
|
||||
* @override
|
||||
*/
|
||||
goog.html.SafeStyle.prototype.toString = function() {
|
||||
return 'SafeStyle{' + this.privateDoNotAccessOrElseSafeStyleWrappedValue_ +
|
||||
'}';
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Performs a runtime check that the provided object is indeed a
|
||||
* SafeStyle object, and returns its value.
|
||||
*
|
||||
* @param {!goog.html.SafeStyle} safeStyle The object to extract from.
|
||||
* @return {string} The safeStyle object's contained string, unless
|
||||
* the run-time type check fails. In that case, {@code unwrap} returns an
|
||||
* innocuous string, or, if assertions are enabled, throws
|
||||
* {@code goog.asserts.AssertionError}.
|
||||
*/
|
||||
goog.html.SafeStyle.unwrap = function(safeStyle) {
|
||||
// Perform additional Run-time type-checking to ensure that
|
||||
// safeStyle is indeed an instance of the expected type. This
|
||||
// provides some additional protection against security bugs due to
|
||||
// application code that disables type checks.
|
||||
// Specifically, the following checks are performed:
|
||||
// 1. The object is an instance of the expected type.
|
||||
// 2. The object is not an instance of a subclass.
|
||||
// 3. The object carries a type marker for the expected type. "Faking" an
|
||||
// object requires a reference to the type marker, which has names intended
|
||||
// to stand out in code reviews.
|
||||
if (safeStyle instanceof goog.html.SafeStyle &&
|
||||
safeStyle.constructor === goog.html.SafeStyle &&
|
||||
safeStyle.SAFE_STYLE_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ ===
|
||||
goog.html.SafeStyle.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) {
|
||||
return safeStyle.privateDoNotAccessOrElseSafeStyleWrappedValue_;
|
||||
} else {
|
||||
goog.asserts.fail('expected object of type SafeStyle, got \'' +
|
||||
safeStyle + '\' of type ' + goog.typeOf(safeStyle));
|
||||
return 'type_error:SafeStyle';
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Package-internal utility method to create SafeStyle instances.
|
||||
*
|
||||
* @param {string} style The string to initialize the SafeStyle object with.
|
||||
* @return {!goog.html.SafeStyle} The initialized SafeStyle object.
|
||||
* @package
|
||||
*/
|
||||
goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse = function(
|
||||
style) {
|
||||
return new goog.html.SafeStyle().initSecurityPrivateDoNotAccessOrElse_(style);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Called from createSafeStyleSecurityPrivateDoNotAccessOrElse(). This
|
||||
* method exists only so that the compiler can dead code eliminate static
|
||||
* fields (like EMPTY) when they're not accessed.
|
||||
* @param {string} style
|
||||
* @return {!goog.html.SafeStyle}
|
||||
* @private
|
||||
*/
|
||||
goog.html.SafeStyle.prototype.initSecurityPrivateDoNotAccessOrElse_ = function(
|
||||
style) {
|
||||
this.privateDoNotAccessOrElseSafeStyleWrappedValue_ = style;
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A SafeStyle instance corresponding to the empty string.
|
||||
* @const {!goog.html.SafeStyle}
|
||||
*/
|
||||
goog.html.SafeStyle.EMPTY =
|
||||
goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse('');
|
||||
|
||||
|
||||
/**
|
||||
* The innocuous string generated by goog.html.SafeStyle.create when passed
|
||||
* an unsafe value.
|
||||
* @const {string}
|
||||
*/
|
||||
goog.html.SafeStyle.INNOCUOUS_STRING = 'zClosurez';
|
||||
|
||||
|
||||
/**
|
||||
* A single property value.
|
||||
* @typedef {string|!goog.string.Const|!goog.html.SafeUrl}
|
||||
*/
|
||||
goog.html.SafeStyle.PropertyValue;
|
||||
|
||||
|
||||
/**
|
||||
* Mapping of property names to their values.
|
||||
* We don't support numbers even though some values might be numbers (e.g.
|
||||
* line-height or 0 for any length). The reason is that most numeric values need
|
||||
* units (e.g. '1px') and allowing numbers could cause users forgetting about
|
||||
* them.
|
||||
* @typedef {!Object<string, ?goog.html.SafeStyle.PropertyValue|
|
||||
* ?Array<!goog.html.SafeStyle.PropertyValue>>}
|
||||
*/
|
||||
goog.html.SafeStyle.PropertyMap;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new SafeStyle object from the properties specified in the map.
|
||||
* @param {goog.html.SafeStyle.PropertyMap} map Mapping of property names to
|
||||
* their values, for example {'margin': '1px'}. Names must consist of
|
||||
* [-_a-zA-Z0-9]. Values might be strings consisting of
|
||||
* [-,.'"%_!# a-zA-Z0-9], where " and ' must be properly balanced. We also
|
||||
* allow simple functions like rgb() and url() which sanitizes its contents.
|
||||
* Other values must be wrapped in goog.string.Const. URLs might be passed
|
||||
* as goog.html.SafeUrl which will be wrapped into url(""). We also support
|
||||
* array whose elements are joined with ' '. Null value causes skipping the
|
||||
* property.
|
||||
* @return {!goog.html.SafeStyle}
|
||||
* @throws {Error} If invalid name is provided.
|
||||
* @throws {goog.asserts.AssertionError} If invalid value is provided. With
|
||||
* disabled assertions, invalid value is replaced by
|
||||
* goog.html.SafeStyle.INNOCUOUS_STRING.
|
||||
*/
|
||||
goog.html.SafeStyle.create = function(map) {
|
||||
var style = '';
|
||||
for (var name in map) {
|
||||
if (!/^[-_a-zA-Z0-9]+$/.test(name)) {
|
||||
throw Error('Name allows only [-_a-zA-Z0-9], got: ' + name);
|
||||
}
|
||||
var value = map[name];
|
||||
if (value == null) {
|
||||
continue;
|
||||
}
|
||||
if (goog.isArray(value)) {
|
||||
value = goog.array.map(value, goog.html.SafeStyle.sanitizePropertyValue_)
|
||||
.join(' ');
|
||||
} else {
|
||||
value = goog.html.SafeStyle.sanitizePropertyValue_(value);
|
||||
}
|
||||
style += name + ':' + value + ';';
|
||||
}
|
||||
if (!style) {
|
||||
return goog.html.SafeStyle.EMPTY;
|
||||
}
|
||||
goog.html.SafeStyle.checkStyle_(style);
|
||||
return goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse(
|
||||
style);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Checks and converts value to string.
|
||||
* @param {!goog.html.SafeStyle.PropertyValue} value
|
||||
* @return {string}
|
||||
* @private
|
||||
*/
|
||||
goog.html.SafeStyle.sanitizePropertyValue_ = function(value) {
|
||||
if (value instanceof goog.html.SafeUrl) {
|
||||
var url = goog.html.SafeUrl.unwrap(value);
|
||||
return 'url("' + url.replace(/</g, '%3c').replace(/[\\"]/g, '\\$&') + '")';
|
||||
}
|
||||
var result = value instanceof goog.string.Const ?
|
||||
goog.string.Const.unwrap(value) :
|
||||
goog.html.SafeStyle.sanitizePropertyValueString_(String(value));
|
||||
// These characters can be used to change context and we don't want that even
|
||||
// with const values.
|
||||
goog.asserts.assert(!/[{;}]/.test(result), 'Value does not allow [{;}].');
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Checks string value.
|
||||
* @param {string} value
|
||||
* @return {string}
|
||||
* @private
|
||||
*/
|
||||
goog.html.SafeStyle.sanitizePropertyValueString_ = function(value) {
|
||||
var valueWithoutFunctions =
|
||||
value.replace(goog.html.SafeUrl.FUNCTIONS_RE_, '$1')
|
||||
.replace(goog.html.SafeUrl.URL_RE_, 'url');
|
||||
if (!goog.html.SafeStyle.VALUE_RE_.test(valueWithoutFunctions)) {
|
||||
goog.asserts.fail(
|
||||
'String value allows only ' + goog.html.SafeStyle.VALUE_ALLOWED_CHARS_ +
|
||||
' and simple functions, got: ' + value);
|
||||
return goog.html.SafeStyle.INNOCUOUS_STRING;
|
||||
} else if (!goog.html.SafeStyle.hasBalancedQuotes_(value)) {
|
||||
goog.asserts.fail('String value requires balanced quotes, got: ' + value);
|
||||
return goog.html.SafeStyle.INNOCUOUS_STRING;
|
||||
}
|
||||
return goog.html.SafeStyle.sanitizeUrl_(value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Checks that quotes (" and ') are properly balanced inside a string. Assumes
|
||||
* that neither escape (\) nor any other character that could result in
|
||||
* breaking out of a string parsing context are allowed;
|
||||
* see http://www.w3.org/TR/css3-syntax/#string-token-diagram.
|
||||
* @param {string} value Untrusted CSS property value.
|
||||
* @return {boolean} True if property value is safe with respect to quote
|
||||
* balancedness.
|
||||
* @private
|
||||
*/
|
||||
goog.html.SafeStyle.hasBalancedQuotes_ = function(value) {
|
||||
var outsideSingle = true;
|
||||
var outsideDouble = true;
|
||||
for (var i = 0; i < value.length; i++) {
|
||||
var c = value.charAt(i);
|
||||
if (c == "'" && outsideDouble) {
|
||||
outsideSingle = !outsideSingle;
|
||||
} else if (c == '"' && outsideSingle) {
|
||||
outsideDouble = !outsideDouble;
|
||||
}
|
||||
}
|
||||
return outsideSingle && outsideDouble;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Characters allowed in goog.html.SafeStyle.VALUE_RE_.
|
||||
* @private {string}
|
||||
*/
|
||||
goog.html.SafeStyle.VALUE_ALLOWED_CHARS_ = '[-,."\'%_!# a-zA-Z0-9]';
|
||||
|
||||
|
||||
/**
|
||||
* Regular expression for safe values.
|
||||
*
|
||||
* Quotes (" and ') are allowed, but a check must be done elsewhere to ensure
|
||||
* they're balanced.
|
||||
*
|
||||
* ',' allows multiple values to be assigned to the same property
|
||||
* (e.g. background-attachment or font-family) and hence could allow
|
||||
* multiple values to get injected, but that should pose no risk of XSS.
|
||||
*
|
||||
* The expression checks only for XSS safety, not for CSS validity.
|
||||
* @const {!RegExp}
|
||||
* @private
|
||||
*/
|
||||
goog.html.SafeStyle.VALUE_RE_ =
|
||||
new RegExp('^' + goog.html.SafeStyle.VALUE_ALLOWED_CHARS_ + '+$');
|
||||
|
||||
|
||||
/**
|
||||
* Regular expression for url(). We support URLs allowed by
|
||||
* https://www.w3.org/TR/css-syntax-3/#url-token-diagram without using escape
|
||||
* sequences. Use percent-encoding if you need to use special characters like
|
||||
* backslash.
|
||||
* @private @const {!RegExp}
|
||||
*/
|
||||
goog.html.SafeUrl.URL_RE_ = new RegExp(
|
||||
'\\b(url\\([ \t\n]*)(' +
|
||||
'\'[ -&(-\\[\\]-~]*\'' + // Printable characters except ' and \.
|
||||
'|"[ !#-\\[\\]-~]*"' + // Printable characters except " and \.
|
||||
'|[!#-&*-\\[\\]-~]*' + // Printable characters except [ "'()\\].
|
||||
')([ \t\n]*\\))',
|
||||
'g');
|
||||
|
||||
|
||||
/**
|
||||
* Regular expression for simple functions.
|
||||
* @private @const {!RegExp}
|
||||
*/
|
||||
goog.html.SafeUrl.FUNCTIONS_RE_ = new RegExp(
|
||||
'\\b(hsl|hsla|rgb|rgba|(rotate|scale|translate)(X|Y|Z|3d)?)' +
|
||||
'\\([-0-9a-z.%, ]+\\)',
|
||||
'g');
|
||||
|
||||
|
||||
/**
|
||||
* Sanitize URLs inside url().
|
||||
*
|
||||
* NOTE: We could also consider using CSS.escape once that's available in the
|
||||
* browsers. However, loosely matching URL e.g. with url\(.*\) and then escaping
|
||||
* the contents would result in a slightly different language than CSS leading
|
||||
* to confusion of users. E.g. url(")") is valid in CSS but it would be invalid
|
||||
* as seen by our parser. On the other hand, url(\) is invalid in CSS but our
|
||||
* parser would be fine with it.
|
||||
*
|
||||
* @param {string} value Untrusted CSS property value.
|
||||
* @return {string}
|
||||
* @private
|
||||
*/
|
||||
goog.html.SafeStyle.sanitizeUrl_ = function(value) {
|
||||
return value.replace(
|
||||
goog.html.SafeUrl.URL_RE_, function(match, before, url, after) {
|
||||
var quote = '';
|
||||
url = url.replace(/^(['"])(.*)\1$/, function(match, start, inside) {
|
||||
quote = start;
|
||||
return inside;
|
||||
});
|
||||
var sanitized = goog.html.SafeUrl.sanitize(url).getTypedStringValue();
|
||||
return before + quote + sanitized + quote + after;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new SafeStyle object by concatenating the values.
|
||||
* @param {...(!goog.html.SafeStyle|!Array<!goog.html.SafeStyle>)} var_args
|
||||
* SafeStyles to concatenate.
|
||||
* @return {!goog.html.SafeStyle}
|
||||
*/
|
||||
goog.html.SafeStyle.concat = function(var_args) {
|
||||
var style = '';
|
||||
|
||||
/**
|
||||
* @param {!goog.html.SafeStyle|!Array<!goog.html.SafeStyle>} argument
|
||||
*/
|
||||
var addArgument = function(argument) {
|
||||
if (goog.isArray(argument)) {
|
||||
goog.array.forEach(argument, addArgument);
|
||||
} else {
|
||||
style += goog.html.SafeStyle.unwrap(argument);
|
||||
}
|
||||
};
|
||||
|
||||
goog.array.forEach(arguments, addArgument);
|
||||
if (!style) {
|
||||
return goog.html.SafeStyle.EMPTY;
|
||||
}
|
||||
return goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse(
|
||||
style);
|
||||
};
|
||||
|
|
@ -0,0 +1,344 @@
|
|||
// Copyright 2014 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 The SafeStyleSheet type and its builders.
|
||||
*
|
||||
* TODO(xtof): Link to document stating type contract.
|
||||
*/
|
||||
|
||||
goog.provide('goog.html.SafeStyleSheet');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.html.SafeStyle');
|
||||
goog.require('goog.object');
|
||||
goog.require('goog.string');
|
||||
goog.require('goog.string.Const');
|
||||
goog.require('goog.string.TypedString');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A string-like object which represents a CSS style sheet and that carries the
|
||||
* security type contract that its value, as a string, will not cause untrusted
|
||||
* script execution (XSS) when evaluated as CSS in a browser.
|
||||
*
|
||||
* Instances of this type must be created via the factory method
|
||||
* {@code goog.html.SafeStyleSheet.fromConstant} and not by invoking its
|
||||
* constructor. The constructor intentionally takes no parameters and the type
|
||||
* is immutable; hence only a default instance corresponding to the empty string
|
||||
* can be obtained via constructor invocation.
|
||||
*
|
||||
* A SafeStyleSheet's string representation can safely be interpolated as the
|
||||
* content of a style element within HTML. The SafeStyleSheet string should
|
||||
* not be escaped before interpolation.
|
||||
*
|
||||
* Values of this type must be composable, i.e. for any two values
|
||||
* {@code styleSheet1} and {@code styleSheet2} of this type,
|
||||
* {@code goog.html.SafeStyleSheet.unwrap(styleSheet1) +
|
||||
* goog.html.SafeStyleSheet.unwrap(styleSheet2)} must itself be a value that
|
||||
* satisfies the SafeStyleSheet type constraint. This requirement implies that
|
||||
* for any value {@code styleSheet} of this type,
|
||||
* {@code goog.html.SafeStyleSheet.unwrap(styleSheet1)} must end in
|
||||
* "beginning of rule" context.
|
||||
|
||||
* A SafeStyleSheet can be constructed via security-reviewed unchecked
|
||||
* conversions. In this case producers of SafeStyleSheet must ensure themselves
|
||||
* that the SafeStyleSheet does not contain unsafe script. Note in particular
|
||||
* that {@code <} is dangerous, even when inside CSS strings, and so should
|
||||
* always be forbidden or CSS-escaped in user controlled input. For example, if
|
||||
* {@code </style><script>evil</script>"} were interpolated
|
||||
* inside a CSS string, it would break out of the context of the original
|
||||
* style element and {@code evil} would execute. Also note that within an HTML
|
||||
* style (raw text) element, HTML character references, such as
|
||||
* {@code &lt;}, are not allowed. See
|
||||
*
|
||||
http://www.w3.org/TR/html5/scripting-1.html#restrictions-for-contents-of-script-elements
|
||||
* (similar considerations apply to the style element).
|
||||
*
|
||||
* @see goog.html.SafeStyleSheet#fromConstant
|
||||
* @constructor
|
||||
* @final
|
||||
* @struct
|
||||
* @implements {goog.string.TypedString}
|
||||
*/
|
||||
goog.html.SafeStyleSheet = function() {
|
||||
/**
|
||||
* The contained value of this SafeStyleSheet. The field has a purposely
|
||||
* ugly name to make (non-compiled) code that attempts to directly access this
|
||||
* field stand out.
|
||||
* @private {string}
|
||||
*/
|
||||
this.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_ = '';
|
||||
|
||||
/**
|
||||
* A type marker used to implement additional run-time type checking.
|
||||
* @see goog.html.SafeStyleSheet#unwrap
|
||||
* @const {!Object}
|
||||
* @private
|
||||
*/
|
||||
this.SAFE_STYLE_SHEET_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ =
|
||||
goog.html.SafeStyleSheet.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @const
|
||||
*/
|
||||
goog.html.SafeStyleSheet.prototype.implementsGoogStringTypedString = true;
|
||||
|
||||
|
||||
/**
|
||||
* Type marker for the SafeStyleSheet type, used to implement additional
|
||||
* run-time type checking.
|
||||
* @const {!Object}
|
||||
* @private
|
||||
*/
|
||||
goog.html.SafeStyleSheet.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a style sheet consisting of one selector and one style definition.
|
||||
* Use {@link goog.html.SafeStyleSheet.concat} to create longer style sheets.
|
||||
* This function doesn't support @import, @media and similar constructs.
|
||||
* @param {string} selector CSS selector, e.g. '#id' or 'tag .class, #id'. We
|
||||
* support CSS3 selectors: https://w3.org/TR/css3-selectors/#selectors.
|
||||
* @param {!goog.html.SafeStyle.PropertyMap|!goog.html.SafeStyle} style Style
|
||||
* definition associated with the selector.
|
||||
* @return {!goog.html.SafeStyleSheet}
|
||||
* @throws {Error} If invalid selector is provided.
|
||||
*/
|
||||
goog.html.SafeStyleSheet.createRule = function(selector, style) {
|
||||
if (goog.string.contains(selector, '<')) {
|
||||
throw Error('Selector does not allow \'<\', got: ' + selector);
|
||||
}
|
||||
|
||||
// Remove strings.
|
||||
var selectorToCheck =
|
||||
selector.replace(/('|")((?!\1)[^\r\n\f\\]|\\[\s\S])*\1/g, '');
|
||||
|
||||
// Check characters allowed in CSS3 selectors.
|
||||
if (!/^[-_a-zA-Z0-9#.:* ,>+~[\]()=^$|]+$/.test(selectorToCheck)) {
|
||||
throw Error(
|
||||
'Selector allows only [-_a-zA-Z0-9#.:* ,>+~[\\]()=^$|] and ' +
|
||||
'strings, got: ' + selector);
|
||||
}
|
||||
|
||||
// Check balanced () and [].
|
||||
if (!goog.html.SafeStyleSheet.hasBalancedBrackets_(selectorToCheck)) {
|
||||
throw Error('() and [] in selector must be balanced, got: ' + selector);
|
||||
}
|
||||
|
||||
if (!(style instanceof goog.html.SafeStyle)) {
|
||||
style = goog.html.SafeStyle.create(style);
|
||||
}
|
||||
var styleSheet = selector + '{' + goog.html.SafeStyle.unwrap(style) + '}';
|
||||
return goog.html.SafeStyleSheet
|
||||
.createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(styleSheet);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Checks if a string has balanced () and [] brackets.
|
||||
* @param {string} s String to check.
|
||||
* @return {boolean}
|
||||
* @private
|
||||
*/
|
||||
goog.html.SafeStyleSheet.hasBalancedBrackets_ = function(s) {
|
||||
var brackets = {'(': ')', '[': ']'};
|
||||
var expectedBrackets = [];
|
||||
for (var i = 0; i < s.length; i++) {
|
||||
var ch = s[i];
|
||||
if (brackets[ch]) {
|
||||
expectedBrackets.push(brackets[ch]);
|
||||
} else if (goog.object.contains(brackets, ch)) {
|
||||
if (expectedBrackets.pop() != ch) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return expectedBrackets.length == 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new SafeStyleSheet object by concatenating values.
|
||||
* @param {...(!goog.html.SafeStyleSheet|!Array<!goog.html.SafeStyleSheet>)}
|
||||
* var_args Values to concatenate.
|
||||
* @return {!goog.html.SafeStyleSheet}
|
||||
*/
|
||||
goog.html.SafeStyleSheet.concat = function(var_args) {
|
||||
var result = '';
|
||||
|
||||
/**
|
||||
* @param {!goog.html.SafeStyleSheet|!Array<!goog.html.SafeStyleSheet>}
|
||||
* argument
|
||||
*/
|
||||
var addArgument = function(argument) {
|
||||
if (goog.isArray(argument)) {
|
||||
goog.array.forEach(argument, addArgument);
|
||||
} else {
|
||||
result += goog.html.SafeStyleSheet.unwrap(argument);
|
||||
}
|
||||
};
|
||||
|
||||
goog.array.forEach(arguments, addArgument);
|
||||
return goog.html.SafeStyleSheet
|
||||
.createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(result);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a SafeStyleSheet object from a compile-time constant string.
|
||||
*
|
||||
* {@code styleSheet} must not have any < characters in it, so that
|
||||
* the syntactic structure of the surrounding HTML is not affected.
|
||||
*
|
||||
* @param {!goog.string.Const} styleSheet A compile-time-constant string from
|
||||
* which to create a SafeStyleSheet.
|
||||
* @return {!goog.html.SafeStyleSheet} A SafeStyleSheet object initialized to
|
||||
* {@code styleSheet}.
|
||||
*/
|
||||
goog.html.SafeStyleSheet.fromConstant = function(styleSheet) {
|
||||
var styleSheetString = goog.string.Const.unwrap(styleSheet);
|
||||
if (styleSheetString.length === 0) {
|
||||
return goog.html.SafeStyleSheet.EMPTY;
|
||||
}
|
||||
// > is a valid character in CSS selectors and there's no strict need to
|
||||
// block it if we already block <.
|
||||
goog.asserts.assert(
|
||||
!goog.string.contains(styleSheetString, '<'),
|
||||
"Forbidden '<' character in style sheet string: " + styleSheetString);
|
||||
return goog.html.SafeStyleSheet
|
||||
.createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(styleSheetString);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns this SafeStyleSheet's value as a string.
|
||||
*
|
||||
* IMPORTANT: In code where it is security relevant that an object's type is
|
||||
* indeed {@code SafeStyleSheet}, use {@code goog.html.SafeStyleSheet.unwrap}
|
||||
* instead of this method. If in doubt, assume that it's security relevant. In
|
||||
* particular, note that goog.html functions which return a goog.html type do
|
||||
* not guarantee the returned instance is of the right type. For example:
|
||||
*
|
||||
* <pre>
|
||||
* var fakeSafeHtml = new String('fake');
|
||||
* fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype;
|
||||
* var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml);
|
||||
* // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by
|
||||
* // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml
|
||||
* // instanceof goog.html.SafeHtml.
|
||||
* </pre>
|
||||
*
|
||||
* @see goog.html.SafeStyleSheet#unwrap
|
||||
* @override
|
||||
*/
|
||||
goog.html.SafeStyleSheet.prototype.getTypedStringValue = function() {
|
||||
return this.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_;
|
||||
};
|
||||
|
||||
|
||||
if (goog.DEBUG) {
|
||||
/**
|
||||
* Returns a debug string-representation of this value.
|
||||
*
|
||||
* To obtain the actual string value wrapped in a SafeStyleSheet, use
|
||||
* {@code goog.html.SafeStyleSheet.unwrap}.
|
||||
*
|
||||
* @see goog.html.SafeStyleSheet#unwrap
|
||||
* @override
|
||||
*/
|
||||
goog.html.SafeStyleSheet.prototype.toString = function() {
|
||||
return 'SafeStyleSheet{' +
|
||||
this.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_ + '}';
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Performs a runtime check that the provided object is indeed a
|
||||
* SafeStyleSheet object, and returns its value.
|
||||
*
|
||||
* @param {!goog.html.SafeStyleSheet} safeStyleSheet The object to extract from.
|
||||
* @return {string} The safeStyleSheet object's contained string, unless
|
||||
* the run-time type check fails. In that case, {@code unwrap} returns an
|
||||
* innocuous string, or, if assertions are enabled, throws
|
||||
* {@code goog.asserts.AssertionError}.
|
||||
*/
|
||||
goog.html.SafeStyleSheet.unwrap = function(safeStyleSheet) {
|
||||
// Perform additional Run-time type-checking to ensure that
|
||||
// safeStyleSheet is indeed an instance of the expected type. This
|
||||
// provides some additional protection against security bugs due to
|
||||
// application code that disables type checks.
|
||||
// Specifically, the following checks are performed:
|
||||
// 1. The object is an instance of the expected type.
|
||||
// 2. The object is not an instance of a subclass.
|
||||
// 3. The object carries a type marker for the expected type. "Faking" an
|
||||
// object requires a reference to the type marker, which has names intended
|
||||
// to stand out in code reviews.
|
||||
if (safeStyleSheet instanceof goog.html.SafeStyleSheet &&
|
||||
safeStyleSheet.constructor === goog.html.SafeStyleSheet &&
|
||||
safeStyleSheet
|
||||
.SAFE_STYLE_SHEET_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ ===
|
||||
goog.html.SafeStyleSheet.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) {
|
||||
return safeStyleSheet.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_;
|
||||
} else {
|
||||
goog.asserts.fail('expected object of type SafeStyleSheet, got \'' +
|
||||
safeStyleSheet + '\' of type ' + goog.typeOf(safeStyleSheet));
|
||||
return 'type_error:SafeStyleSheet';
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Package-internal utility method to create SafeStyleSheet instances.
|
||||
*
|
||||
* @param {string} styleSheet The string to initialize the SafeStyleSheet
|
||||
* object with.
|
||||
* @return {!goog.html.SafeStyleSheet} The initialized SafeStyleSheet object.
|
||||
* @package
|
||||
*/
|
||||
goog.html.SafeStyleSheet.createSafeStyleSheetSecurityPrivateDoNotAccessOrElse =
|
||||
function(styleSheet) {
|
||||
return new goog.html.SafeStyleSheet().initSecurityPrivateDoNotAccessOrElse_(
|
||||
styleSheet);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Called from createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(). This
|
||||
* method exists only so that the compiler can dead code eliminate static
|
||||
* fields (like EMPTY) when they're not accessed.
|
||||
* @param {string} styleSheet
|
||||
* @return {!goog.html.SafeStyleSheet}
|
||||
* @private
|
||||
*/
|
||||
goog.html.SafeStyleSheet.prototype.initSecurityPrivateDoNotAccessOrElse_ =
|
||||
function(styleSheet) {
|
||||
this.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_ = styleSheet;
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A SafeStyleSheet instance corresponding to the empty string.
|
||||
* @const {!goog.html.SafeStyleSheet}
|
||||
*/
|
||||
goog.html.SafeStyleSheet.EMPTY =
|
||||
goog.html.SafeStyleSheet
|
||||
.createSafeStyleSheetSecurityPrivateDoNotAccessOrElse('');
|
||||
|
|
@ -0,0 +1,454 @@
|
|||
// Copyright 2013 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 The SafeUrl type and its builders.
|
||||
*
|
||||
* TODO(xtof): Link to document stating type contract.
|
||||
*/
|
||||
|
||||
goog.provide('goog.html.SafeUrl');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.fs.url');
|
||||
goog.require('goog.html.TrustedResourceUrl');
|
||||
goog.require('goog.i18n.bidi.Dir');
|
||||
goog.require('goog.i18n.bidi.DirectionalString');
|
||||
goog.require('goog.string');
|
||||
goog.require('goog.string.Const');
|
||||
goog.require('goog.string.TypedString');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A string that is safe to use in URL context in DOM APIs and HTML documents.
|
||||
*
|
||||
* A SafeUrl is a string-like object that carries the security type contract
|
||||
* that its value as a string will not cause untrusted script execution
|
||||
* when evaluated as a hyperlink URL in a browser.
|
||||
*
|
||||
* Values of this type are guaranteed to be safe to use in URL/hyperlink
|
||||
* contexts, such as assignment to URL-valued DOM properties, in the sense that
|
||||
* the use will not result in a Cross-Site-Scripting vulnerability. Similarly,
|
||||
* SafeUrls can be interpolated into the URL context of an HTML template (e.g.,
|
||||
* inside a href attribute). However, appropriate HTML-escaping must still be
|
||||
* applied.
|
||||
*
|
||||
* Note that, as documented in {@code goog.html.SafeUrl.unwrap}, this type's
|
||||
* contract does not guarantee that instances are safe to interpolate into HTML
|
||||
* without appropriate escaping.
|
||||
*
|
||||
* Note also that this type's contract does not imply any guarantees regarding
|
||||
* the resource the URL refers to. In particular, SafeUrls are <b>not</b>
|
||||
* safe to use in a context where the referred-to resource is interpreted as
|
||||
* trusted code, e.g., as the src of a script tag.
|
||||
*
|
||||
* Instances of this type must be created via the factory methods
|
||||
* ({@code goog.html.SafeUrl.fromConstant}, {@code goog.html.SafeUrl.sanitize}),
|
||||
* etc and not by invoking its constructor. The constructor intentionally
|
||||
* takes no parameters and the type is immutable; hence only a default instance
|
||||
* corresponding to the empty string can be obtained via constructor invocation.
|
||||
*
|
||||
* @see goog.html.SafeUrl#fromConstant
|
||||
* @see goog.html.SafeUrl#from
|
||||
* @see goog.html.SafeUrl#sanitize
|
||||
* @constructor
|
||||
* @final
|
||||
* @struct
|
||||
* @implements {goog.i18n.bidi.DirectionalString}
|
||||
* @implements {goog.string.TypedString}
|
||||
*/
|
||||
goog.html.SafeUrl = function() {
|
||||
/**
|
||||
* The contained value of this SafeUrl. The field has a purposely ugly
|
||||
* name to make (non-compiled) code that attempts to directly access this
|
||||
* field stand out.
|
||||
* @private {string}
|
||||
*/
|
||||
this.privateDoNotAccessOrElseSafeHtmlWrappedValue_ = '';
|
||||
|
||||
/**
|
||||
* A type marker used to implement additional run-time type checking.
|
||||
* @see goog.html.SafeUrl#unwrap
|
||||
* @const {!Object}
|
||||
* @private
|
||||
*/
|
||||
this.SAFE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ =
|
||||
goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The innocuous string generated by goog.html.SafeUrl.sanitize when passed
|
||||
* an unsafe URL.
|
||||
*
|
||||
* about:invalid is registered in
|
||||
* http://www.w3.org/TR/css3-values/#about-invalid.
|
||||
* http://tools.ietf.org/html/rfc6694#section-2.2.1 permits about URLs to
|
||||
* contain a fragment, which is not to be considered when determining if an
|
||||
* about URL is well-known.
|
||||
*
|
||||
* Using about:invalid seems preferable to using a fixed data URL, since
|
||||
* browsers might choose to not report CSP violations on it, as legitimate
|
||||
* CSS function calls to attr() can result in this URL being produced. It is
|
||||
* also a standard URL which matches exactly the semantics we need:
|
||||
* "The about:invalid URI references a non-existent document with a generic
|
||||
* error condition. It can be used when a URI is necessary, but the default
|
||||
* value shouldn't be resolveable as any type of document".
|
||||
*
|
||||
* @const {string}
|
||||
*/
|
||||
goog.html.SafeUrl.INNOCUOUS_STRING = 'about:invalid#zClosurez';
|
||||
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @const
|
||||
*/
|
||||
goog.html.SafeUrl.prototype.implementsGoogStringTypedString = true;
|
||||
|
||||
|
||||
/**
|
||||
* Returns this SafeUrl's value a string.
|
||||
*
|
||||
* IMPORTANT: In code where it is security relevant that an object's type is
|
||||
* indeed {@code SafeUrl}, use {@code goog.html.SafeUrl.unwrap} instead of this
|
||||
* method. If in doubt, assume that it's security relevant. In particular, note
|
||||
* that goog.html functions which return a goog.html type do not guarantee that
|
||||
* the returned instance is of the right type. For example:
|
||||
*
|
||||
* <pre>
|
||||
* var fakeSafeHtml = new String('fake');
|
||||
* fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype;
|
||||
* var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml);
|
||||
* // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by
|
||||
* // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml instanceof
|
||||
* // goog.html.SafeHtml.
|
||||
* </pre>
|
||||
*
|
||||
* IMPORTANT: The guarantees of the SafeUrl type contract only extend to the
|
||||
* behavior of browsers when interpreting URLs. Values of SafeUrl objects MUST
|
||||
* be appropriately escaped before embedding in a HTML document. Note that the
|
||||
* required escaping is context-sensitive (e.g. a different escaping is
|
||||
* required for embedding a URL in a style property within a style
|
||||
* attribute, as opposed to embedding in a href attribute).
|
||||
*
|
||||
* @see goog.html.SafeUrl#unwrap
|
||||
* @override
|
||||
*/
|
||||
goog.html.SafeUrl.prototype.getTypedStringValue = function() {
|
||||
return this.privateDoNotAccessOrElseSafeHtmlWrappedValue_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @const
|
||||
*/
|
||||
goog.html.SafeUrl.prototype.implementsGoogI18nBidiDirectionalString = true;
|
||||
|
||||
|
||||
/**
|
||||
* Returns this URLs directionality, which is always {@code LTR}.
|
||||
* @override
|
||||
*/
|
||||
goog.html.SafeUrl.prototype.getDirection = function() {
|
||||
return goog.i18n.bidi.Dir.LTR;
|
||||
};
|
||||
|
||||
|
||||
if (goog.DEBUG) {
|
||||
/**
|
||||
* Returns a debug string-representation of this value.
|
||||
*
|
||||
* To obtain the actual string value wrapped in a SafeUrl, use
|
||||
* {@code goog.html.SafeUrl.unwrap}.
|
||||
*
|
||||
* @see goog.html.SafeUrl#unwrap
|
||||
* @override
|
||||
*/
|
||||
goog.html.SafeUrl.prototype.toString = function() {
|
||||
return 'SafeUrl{' + this.privateDoNotAccessOrElseSafeHtmlWrappedValue_ +
|
||||
'}';
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Performs a runtime check that the provided object is indeed a SafeUrl
|
||||
* object, and returns its value.
|
||||
*
|
||||
* IMPORTANT: The guarantees of the SafeUrl type contract only extend to the
|
||||
* behavior of browsers when interpreting URLs. Values of SafeUrl objects MUST
|
||||
* be appropriately escaped before embedding in a HTML document. Note that the
|
||||
* required escaping is context-sensitive (e.g. a different escaping is
|
||||
* required for embedding a URL in a style property within a style
|
||||
* attribute, as opposed to embedding in a href attribute).
|
||||
*
|
||||
* @param {!goog.html.SafeUrl} safeUrl The object to extract from.
|
||||
* @return {string} The SafeUrl object's contained string, unless the run-time
|
||||
* type check fails. In that case, {@code unwrap} returns an innocuous
|
||||
* string, or, if assertions are enabled, throws
|
||||
* {@code goog.asserts.AssertionError}.
|
||||
*/
|
||||
goog.html.SafeUrl.unwrap = function(safeUrl) {
|
||||
// Perform additional Run-time type-checking to ensure that safeUrl is indeed
|
||||
// an instance of the expected type. This provides some additional protection
|
||||
// against security bugs due to application code that disables type checks.
|
||||
// Specifically, the following checks are performed:
|
||||
// 1. The object is an instance of the expected type.
|
||||
// 2. The object is not an instance of a subclass.
|
||||
// 3. The object carries a type marker for the expected type. "Faking" an
|
||||
// object requires a reference to the type marker, which has names intended
|
||||
// to stand out in code reviews.
|
||||
if (safeUrl instanceof goog.html.SafeUrl &&
|
||||
safeUrl.constructor === goog.html.SafeUrl &&
|
||||
safeUrl.SAFE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ ===
|
||||
goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) {
|
||||
return safeUrl.privateDoNotAccessOrElseSafeHtmlWrappedValue_;
|
||||
} else {
|
||||
goog.asserts.fail('expected object of type SafeUrl, got \'' +
|
||||
safeUrl + '\' of type ' + goog.typeOf(safeUrl));
|
||||
return 'type_error:SafeUrl';
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a SafeUrl object from a compile-time constant string.
|
||||
*
|
||||
* Compile-time constant strings are inherently program-controlled and hence
|
||||
* trusted.
|
||||
*
|
||||
* @param {!goog.string.Const} url A compile-time-constant string from which to
|
||||
* create a SafeUrl.
|
||||
* @return {!goog.html.SafeUrl} A SafeUrl object initialized to {@code url}.
|
||||
*/
|
||||
goog.html.SafeUrl.fromConstant = function(url) {
|
||||
return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(
|
||||
goog.string.Const.unwrap(url));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A pattern that matches Blob or data types that can have SafeUrls created
|
||||
* from URL.createObjectURL(blob) or via a data: URI.
|
||||
* @const
|
||||
* @private
|
||||
*/
|
||||
goog.html.SAFE_MIME_TYPE_PATTERN_ = new RegExp(
|
||||
'^(?:audio/(?:3gpp|3gpp2|aac|midi|mp4|mpeg|ogg|x-m4a|x-wav|webm)|' +
|
||||
'image/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|' +
|
||||
'text/csv|' +
|
||||
'video/(?:mpeg|mp4|ogg|webm))$',
|
||||
'i');
|
||||
|
||||
|
||||
/**
|
||||
* Creates a SafeUrl wrapping a blob URL for the given {@code blob}.
|
||||
*
|
||||
* The blob URL is created with {@code URL.createObjectURL}. If the MIME type
|
||||
* for {@code blob} is not of a known safe audio, image or video MIME type,
|
||||
* then the SafeUrl will wrap {@link #INNOCUOUS_STRING}.
|
||||
*
|
||||
* @see http://www.w3.org/TR/FileAPI/#url
|
||||
* @param {!Blob} blob
|
||||
* @return {!goog.html.SafeUrl} The blob URL, or an innocuous string wrapped
|
||||
* as a SafeUrl.
|
||||
*/
|
||||
goog.html.SafeUrl.fromBlob = function(blob) {
|
||||
var url = goog.html.SAFE_MIME_TYPE_PATTERN_.test(blob.type) ?
|
||||
goog.fs.url.createObjectUrl(blob) :
|
||||
goog.html.SafeUrl.INNOCUOUS_STRING;
|
||||
return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(url);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Matches a base-64 data URL, with the first match group being the MIME type.
|
||||
* @const
|
||||
* @private
|
||||
*/
|
||||
goog.html.DATA_URL_PATTERN_ = /^data:([^;,]*);base64,[a-z0-9+\/]+=*$/i;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a SafeUrl wrapping a data: URL, after validating it matches a
|
||||
* known-safe audio, image or video MIME type.
|
||||
*
|
||||
* @param {string} dataUrl A valid base64 data URL with one of the whitelisted
|
||||
* audio, image or video MIME types.
|
||||
* @return {!goog.html.SafeUrl} A matching safe URL, or {@link INNOCUOUS_STRING}
|
||||
* wrapped as a SafeUrl if it does not pass.
|
||||
*/
|
||||
goog.html.SafeUrl.fromDataUrl = function(dataUrl) {
|
||||
// There's a slight risk here that a browser sniffs the content type if it
|
||||
// doesn't know the MIME type and executes HTML within the data: URL. For this
|
||||
// to cause XSS it would also have to execute the HTML in the same origin
|
||||
// of the page with the link. It seems unlikely that both of these will
|
||||
// happen, particularly in not really old IEs.
|
||||
var match = dataUrl.match(goog.html.DATA_URL_PATTERN_);
|
||||
var valid = match && goog.html.SAFE_MIME_TYPE_PATTERN_.test(match[1]);
|
||||
return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(
|
||||
valid ? dataUrl : goog.html.SafeUrl.INNOCUOUS_STRING);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a SafeUrl wrapping a tel: URL.
|
||||
*
|
||||
* @param {string} telUrl A tel URL.
|
||||
* @return {!goog.html.SafeUrl} A matching safe URL, or {@link INNOCUOUS_STRING}
|
||||
* wrapped as a SafeUrl if it does not pass.
|
||||
*/
|
||||
goog.html.SafeUrl.fromTelUrl = function(telUrl) {
|
||||
// There's a risk that a tel: URL could immediately place a call once
|
||||
// clicked, without requiring user confirmation. For that reason it is
|
||||
// handled in this separate function.
|
||||
if (!goog.string.caseInsensitiveStartsWith(telUrl, 'tel:')) {
|
||||
telUrl = goog.html.SafeUrl.INNOCUOUS_STRING;
|
||||
}
|
||||
return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(
|
||||
telUrl);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a SafeUrl from TrustedResourceUrl. This is safe because
|
||||
* TrustedResourceUrl is more tightly restricted than SafeUrl.
|
||||
*
|
||||
* @param {!goog.html.TrustedResourceUrl} trustedResourceUrl
|
||||
* @return {!goog.html.SafeUrl}
|
||||
*/
|
||||
goog.html.SafeUrl.fromTrustedResourceUrl = function(trustedResourceUrl) {
|
||||
return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(
|
||||
goog.html.TrustedResourceUrl.unwrap(trustedResourceUrl));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A pattern that recognizes a commonly useful subset of URLs that satisfy
|
||||
* the SafeUrl contract.
|
||||
*
|
||||
* This regular expression matches a subset of URLs that will not cause script
|
||||
* execution if used in URL context within a HTML document. Specifically, this
|
||||
* regular expression matches if (comment from here on and regex copied from
|
||||
* Soy's EscapingConventions):
|
||||
* (1) Either a protocol in a whitelist (http, https, mailto or ftp).
|
||||
* (2) or no protocol. A protocol must be followed by a colon. The below
|
||||
* allows that by allowing colons only after one of the characters [/?#].
|
||||
* A colon after a hash (#) must be in the fragment.
|
||||
* Otherwise, a colon after a (?) must be in a query.
|
||||
* Otherwise, a colon after a single solidus (/) must be in a path.
|
||||
* Otherwise, a colon after a double solidus (//) must be in the authority
|
||||
* (before port).
|
||||
*
|
||||
* @private
|
||||
* @const {!RegExp}
|
||||
*/
|
||||
goog.html.SAFE_URL_PATTERN_ =
|
||||
/^(?:(?:https?|mailto|ftp):|[^:/?#]*(?:[/?#]|$))/i;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a SafeUrl object from {@code url}. If {@code url} is a
|
||||
* goog.html.SafeUrl then it is simply returned. Otherwise the input string is
|
||||
* validated to match a pattern of commonly used safe URLs.
|
||||
*
|
||||
* {@code url} may be a URL with the http, https, mailto or ftp scheme,
|
||||
* or a relative URL (i.e., a URL without a scheme; specifically, a
|
||||
* scheme-relative, absolute-path-relative, or path-relative URL).
|
||||
*
|
||||
* @see http://url.spec.whatwg.org/#concept-relative-url
|
||||
* @param {string|!goog.string.TypedString} url The URL to validate.
|
||||
* @return {!goog.html.SafeUrl} The validated URL, wrapped as a SafeUrl.
|
||||
*/
|
||||
goog.html.SafeUrl.sanitize = function(url) {
|
||||
if (url instanceof goog.html.SafeUrl) {
|
||||
return url;
|
||||
} else if (url.implementsGoogStringTypedString) {
|
||||
url = url.getTypedStringValue();
|
||||
} else {
|
||||
url = String(url);
|
||||
}
|
||||
if (!goog.html.SAFE_URL_PATTERN_.test(url)) {
|
||||
url = goog.html.SafeUrl.INNOCUOUS_STRING;
|
||||
}
|
||||
return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(url);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a SafeUrl object from {@code url}. If {@code url} is a
|
||||
* goog.html.SafeUrl then it is simply returned. Otherwise the input string is
|
||||
* validated to match a pattern of commonly used safe URLs.
|
||||
*
|
||||
* {@code url} may be a URL with the http, https, mailto or ftp scheme,
|
||||
* or a relative URL (i.e., a URL without a scheme; specifically, a
|
||||
* scheme-relative, absolute-path-relative, or path-relative URL).
|
||||
*
|
||||
* This function asserts (using goog.asserts) that the URL matches this pattern.
|
||||
* If it does not, in addition to failing the assert, an innocous URL will be
|
||||
* returned.
|
||||
*
|
||||
* @see http://url.spec.whatwg.org/#concept-relative-url
|
||||
* @param {string|!goog.string.TypedString} url The URL to validate.
|
||||
* @return {!goog.html.SafeUrl} The validated URL, wrapped as a SafeUrl.
|
||||
*/
|
||||
goog.html.SafeUrl.sanitizeAssertUnchanged = function(url) {
|
||||
if (url instanceof goog.html.SafeUrl) {
|
||||
return url;
|
||||
} else if (url.implementsGoogStringTypedString) {
|
||||
url = url.getTypedStringValue();
|
||||
} else {
|
||||
url = String(url);
|
||||
}
|
||||
if (!goog.asserts.assert(goog.html.SAFE_URL_PATTERN_.test(url))) {
|
||||
url = goog.html.SafeUrl.INNOCUOUS_STRING;
|
||||
}
|
||||
return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(url);
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Type marker for the SafeUrl type, used to implement additional run-time
|
||||
* type checking.
|
||||
* @const {!Object}
|
||||
* @private
|
||||
*/
|
||||
goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {};
|
||||
|
||||
|
||||
/**
|
||||
* Package-internal utility method to create SafeUrl instances.
|
||||
*
|
||||
* @param {string} url The string to initialize the SafeUrl object with.
|
||||
* @return {!goog.html.SafeUrl} The initialized SafeUrl object.
|
||||
* @package
|
||||
*/
|
||||
goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse = function(
|
||||
url) {
|
||||
var safeUrl = new goog.html.SafeUrl();
|
||||
safeUrl.privateDoNotAccessOrElseSafeHtmlWrappedValue_ = url;
|
||||
return safeUrl;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A SafeUrl corresponding to the special about:blank url.
|
||||
* @const {!goog.html.SafeUrl}
|
||||
*/
|
||||
goog.html.SafeUrl.ABOUT_BLANK =
|
||||
goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(
|
||||
'about:blank');
|
||||
|
|
@ -0,0 +1,408 @@
|
|||
// Copyright 2013 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 The TrustedResourceUrl type and its builders.
|
||||
*
|
||||
* TODO(xtof): Link to document stating type contract.
|
||||
*/
|
||||
|
||||
goog.provide('goog.html.TrustedResourceUrl');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.i18n.bidi.Dir');
|
||||
goog.require('goog.i18n.bidi.DirectionalString');
|
||||
goog.require('goog.string.Const');
|
||||
goog.require('goog.string.TypedString');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A URL which is under application control and from which script, CSS, and
|
||||
* other resources that represent executable code, can be fetched.
|
||||
*
|
||||
* Given that the URL can only be constructed from strings under application
|
||||
* control and is used to load resources, bugs resulting in a malformed URL
|
||||
* should not have a security impact and are likely to be easily detectable
|
||||
* during testing. Given the wide number of non-RFC compliant URLs in use,
|
||||
* stricter validation could prevent some applications from being able to use
|
||||
* this type.
|
||||
*
|
||||
* Instances of this type must be created via the factory method,
|
||||
* ({@code fromConstant}, {@code fromConstants}, {@code format} or {@code
|
||||
* formatWithParams}), and not by invoking its constructor. The constructor
|
||||
* intentionally takes no parameters and the type is immutable; hence only a
|
||||
* default instance corresponding to the empty string can be obtained via
|
||||
* constructor invocation.
|
||||
*
|
||||
* @see goog.html.TrustedResourceUrl#fromConstant
|
||||
* @constructor
|
||||
* @final
|
||||
* @struct
|
||||
* @implements {goog.i18n.bidi.DirectionalString}
|
||||
* @implements {goog.string.TypedString}
|
||||
*/
|
||||
goog.html.TrustedResourceUrl = function() {
|
||||
/**
|
||||
* The contained value of this TrustedResourceUrl. The field has a purposely
|
||||
* ugly name to make (non-compiled) code that attempts to directly access this
|
||||
* field stand out.
|
||||
* @private {string}
|
||||
*/
|
||||
this.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_ = '';
|
||||
|
||||
/**
|
||||
* A type marker used to implement additional run-time type checking.
|
||||
* @see goog.html.TrustedResourceUrl#unwrap
|
||||
* @const {!Object}
|
||||
* @private
|
||||
*/
|
||||
this.TRUSTED_RESOURCE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ =
|
||||
goog.html.TrustedResourceUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @const
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.prototype.implementsGoogStringTypedString = true;
|
||||
|
||||
|
||||
/**
|
||||
* Returns this TrustedResourceUrl's value as a string.
|
||||
*
|
||||
* IMPORTANT: In code where it is security relevant that an object's type is
|
||||
* indeed {@code TrustedResourceUrl}, use
|
||||
* {@code goog.html.TrustedResourceUrl.unwrap} instead of this method. If in
|
||||
* doubt, assume that it's security relevant. In particular, note that
|
||||
* goog.html functions which return a goog.html type do not guarantee that
|
||||
* the returned instance is of the right type. For example:
|
||||
*
|
||||
* <pre>
|
||||
* var fakeSafeHtml = new String('fake');
|
||||
* fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype;
|
||||
* var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml);
|
||||
* // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by
|
||||
* // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml instanceof
|
||||
* // goog.html.SafeHtml.
|
||||
* </pre>
|
||||
*
|
||||
* @see goog.html.TrustedResourceUrl#unwrap
|
||||
* @override
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.prototype.getTypedStringValue = function() {
|
||||
return this.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @const
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.prototype.implementsGoogI18nBidiDirectionalString =
|
||||
true;
|
||||
|
||||
|
||||
/**
|
||||
* Returns this URLs directionality, which is always {@code LTR}.
|
||||
* @override
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.prototype.getDirection = function() {
|
||||
return goog.i18n.bidi.Dir.LTR;
|
||||
};
|
||||
|
||||
|
||||
if (goog.DEBUG) {
|
||||
/**
|
||||
* Returns a debug string-representation of this value.
|
||||
*
|
||||
* To obtain the actual string value wrapped in a TrustedResourceUrl, use
|
||||
* {@code goog.html.TrustedResourceUrl.unwrap}.
|
||||
*
|
||||
* @see goog.html.TrustedResourceUrl#unwrap
|
||||
* @override
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.prototype.toString = function() {
|
||||
return 'TrustedResourceUrl{' +
|
||||
this.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_ + '}';
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Performs a runtime check that the provided object is indeed a
|
||||
* TrustedResourceUrl object, and returns its value.
|
||||
*
|
||||
* @param {!goog.html.TrustedResourceUrl} trustedResourceUrl The object to
|
||||
* extract from.
|
||||
* @return {string} The trustedResourceUrl object's contained string, unless
|
||||
* the run-time type check fails. In that case, {@code unwrap} returns an
|
||||
* innocuous string, or, if assertions are enabled, throws
|
||||
* {@code goog.asserts.AssertionError}.
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.unwrap = function(trustedResourceUrl) {
|
||||
// Perform additional Run-time type-checking to ensure that
|
||||
// trustedResourceUrl is indeed an instance of the expected type. This
|
||||
// provides some additional protection against security bugs due to
|
||||
// application code that disables type checks.
|
||||
// Specifically, the following checks are performed:
|
||||
// 1. The object is an instance of the expected type.
|
||||
// 2. The object is not an instance of a subclass.
|
||||
// 3. The object carries a type marker for the expected type. "Faking" an
|
||||
// object requires a reference to the type marker, which has names intended
|
||||
// to stand out in code reviews.
|
||||
if (trustedResourceUrl instanceof goog.html.TrustedResourceUrl &&
|
||||
trustedResourceUrl.constructor === goog.html.TrustedResourceUrl &&
|
||||
trustedResourceUrl
|
||||
.TRUSTED_RESOURCE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ ===
|
||||
goog.html.TrustedResourceUrl
|
||||
.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) {
|
||||
return trustedResourceUrl
|
||||
.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_;
|
||||
} else {
|
||||
goog.asserts.fail('expected object of type TrustedResourceUrl, got \'' +
|
||||
trustedResourceUrl + '\' of type ' + goog.typeOf(trustedResourceUrl));
|
||||
return 'type_error:TrustedResourceUrl';
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a TrustedResourceUrl from a format string and arguments.
|
||||
*
|
||||
* The arguments for interpolation into the format string map labels to values.
|
||||
* Values of type `goog.string.Const` are interpolated without modifcation.
|
||||
* Values of other types are cast to string and encoded with
|
||||
* encodeURIComponent.
|
||||
*
|
||||
* `%{<label>}` markers are used in the format string to indicate locations
|
||||
* to be interpolated with the valued mapped to the given label. `<label>`
|
||||
* must contain only alphanumeric and `_` characters.
|
||||
*
|
||||
* The format string must start with one of the following:
|
||||
* - `https://<origin>/`
|
||||
* - `//<origin>/`
|
||||
* - `/<pathStart>`
|
||||
* - `about:blank`
|
||||
*
|
||||
* `<origin>` must contain only alphanumeric or any of the following: `-.:[]`.
|
||||
* `<pathStart>` is any character except `/` and `\`.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* var url = goog.html.TrustedResourceUrl.format(goog.string.Const.from(
|
||||
* 'https://www.google.com/search?q=%{query}), {'query': searchTerm});
|
||||
*
|
||||
* var url = goog.html.TrustedResourceUrl.format(goog.string.Const.from(
|
||||
* '//www.youtube.com/v/%{videoId}?hl=en&fs=1%{autoplay}'), {
|
||||
* 'videoId': videoId,
|
||||
* 'autoplay': opt_autoplay ?
|
||||
* goog.string.Const.EMPTY : goog.string.Const.from('&autoplay=1')
|
||||
* });
|
||||
*
|
||||
* While this function can be used to create a TrustedResourceUrl from only
|
||||
* constants, fromConstant() and fromConstants() are generally preferable for
|
||||
* that purpose.
|
||||
*
|
||||
* @param {!goog.string.Const} format The format string.
|
||||
* @param {!Object<string, (string|number|!goog.string.Const)>} args Mapping
|
||||
* of labels to values to be interpolated into the format string.
|
||||
* goog.string.Const values are interpolated without encoding.
|
||||
* @return {!goog.html.TrustedResourceUrl}
|
||||
* @throws {!Error} On an invalid format string or if a label used in the
|
||||
* the format string is not present in args.
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.format = function(format, args) {
|
||||
var result = goog.html.TrustedResourceUrl.format_(format, args);
|
||||
return goog.html.TrustedResourceUrl
|
||||
.createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse(result);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* String version of TrustedResourceUrl.format.
|
||||
* @param {!goog.string.Const} format
|
||||
* @param {!Object<string, (string|number|!goog.string.Const)>} args
|
||||
* @return {string}
|
||||
* @throws {!Error}
|
||||
* @private
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.format_ = function(format, args) {
|
||||
var formatStr = goog.string.Const.unwrap(format);
|
||||
if (!goog.html.TrustedResourceUrl.BASE_URL_.test(formatStr)) {
|
||||
throw new Error('Invalid TrustedResourceUrl format: ' + formatStr);
|
||||
}
|
||||
return formatStr.replace(
|
||||
goog.html.TrustedResourceUrl.FORMAT_MARKER_, function(match, id) {
|
||||
if (!Object.prototype.hasOwnProperty.call(args, id)) {
|
||||
throw new Error(
|
||||
'Found marker, "' + id + '", in format string, "' + formatStr +
|
||||
'", but no valid label mapping found ' +
|
||||
'in args: ' + JSON.stringify(args));
|
||||
}
|
||||
var arg = args[id];
|
||||
if (arg instanceof goog.string.Const) {
|
||||
return goog.string.Const.unwrap(arg);
|
||||
} else {
|
||||
return encodeURIComponent(String(arg));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private @const {!RegExp}
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.FORMAT_MARKER_ = /%{(\w+)}/g;
|
||||
|
||||
|
||||
/**
|
||||
* The URL must be absolute, scheme-relative or path-absolute. So it must
|
||||
* start with:
|
||||
* - https:// followed by allowed origin characters.
|
||||
* - // followed by allowed origin characters.
|
||||
* - / not followed by / or \. There will only be an absolute path.
|
||||
*
|
||||
* Based on
|
||||
* https://url.spec.whatwg.org/commit-snapshots/56b74ce7cca8883eab62e9a12666e2fac665d03d/#url-parsing
|
||||
* an initial / which is not followed by another / or \ will end up in the "path
|
||||
* state" and from there it can only go to "fragment state" and "query state".
|
||||
*
|
||||
* We don't enforce a well-formed domain name. So '.' or '1.2' are valid.
|
||||
* That's ok because the origin comes from a compile-time constant.
|
||||
*
|
||||
* A regular expression is used instead of goog.uri for several reasons:
|
||||
* - Strictness. E.g. we don't want any userinfo component and we don't
|
||||
* want '/./, nor \' in the first path component.
|
||||
* - Small trusted base. goog.uri is generic and might need to change,
|
||||
* reasoning about all the ways it can parse a URL now and in the future
|
||||
* is error-prone.
|
||||
* - Code size. We expect many calls to .format(), many of which might
|
||||
* not be using goog.uri.
|
||||
* - Simplicity. Using goog.uri would likely not result in simpler nor shorter
|
||||
* code.
|
||||
* @private @const {!RegExp}
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.BASE_URL_ =
|
||||
/^(?:https:)?\/\/[0-9a-z.:[\]-]+\/|^\/[^\/\\]|^about:blank(#|$)/i;
|
||||
|
||||
|
||||
/**
|
||||
* Formats the URL same as TrustedResourceUrl.format and then adds extra URL
|
||||
* parameters.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* // Creates '//www.youtube.com/v/abc?autoplay=1' for videoId='abc' and
|
||||
* // opt_autoplay=1. Creates '//www.youtube.com/v/abc' for videoId='abc'
|
||||
* // and opt_autoplay=undefined.
|
||||
* var url = goog.html.TrustedResourceUrl.formatWithParams(
|
||||
* goog.string.Const.from('//www.youtube.com/v/%{videoId}'),
|
||||
* {'videoId': videoId},
|
||||
* {'autoplay': opt_autoplay});
|
||||
*
|
||||
* @param {!goog.string.Const} format The format string.
|
||||
* @param {!Object<string, (string|number|!goog.string.Const)>} args Mapping
|
||||
* of labels to values to be interpolated into the format string.
|
||||
* goog.string.Const values are interpolated without encoding.
|
||||
* @param {!Object<string, *>} params Parameters to add to URL. Parameters with
|
||||
* value {@code null} or {@code undefined} are skipped. Both keys and values
|
||||
* are encoded. Note that JavaScript doesn't guarantee the order of values
|
||||
* in an object which might result in non-deterministic order of the
|
||||
* parameters. However, browsers currently preserve the order.
|
||||
* @return {!goog.html.TrustedResourceUrl}
|
||||
* @throws {!Error} On an invalid format string or if a label used in the
|
||||
* the format string is not present in args.
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.formatWithParams = function(format, args, params) {
|
||||
var url = goog.html.TrustedResourceUrl.format_(format, args);
|
||||
var separator = /\?/.test(url) ? '&' : '?';
|
||||
for (var key in params) {
|
||||
if (params[key] == null) {
|
||||
continue;
|
||||
}
|
||||
url += separator + encodeURIComponent(key) + '=' +
|
||||
encodeURIComponent(String(params[key]));
|
||||
separator = '&';
|
||||
}
|
||||
return goog.html.TrustedResourceUrl
|
||||
.createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse(url);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a TrustedResourceUrl object from a compile-time constant string.
|
||||
*
|
||||
* Compile-time constant strings are inherently program-controlled and hence
|
||||
* trusted.
|
||||
*
|
||||
* @param {!goog.string.Const} url A compile-time-constant string from which to
|
||||
* create a TrustedResourceUrl.
|
||||
* @return {!goog.html.TrustedResourceUrl} A TrustedResourceUrl object
|
||||
* initialized to {@code url}.
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.fromConstant = function(url) {
|
||||
return goog.html.TrustedResourceUrl
|
||||
.createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse(
|
||||
goog.string.Const.unwrap(url));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a TrustedResourceUrl object from a compile-time constant strings.
|
||||
*
|
||||
* Compile-time constant strings are inherently program-controlled and hence
|
||||
* trusted.
|
||||
*
|
||||
* @param {!Array<!goog.string.Const>} parts Compile-time-constant strings from
|
||||
* which to create a TrustedResourceUrl.
|
||||
* @return {!goog.html.TrustedResourceUrl} A TrustedResourceUrl object
|
||||
* initialized to concatenation of {@code parts}.
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.fromConstants = function(parts) {
|
||||
var unwrapped = '';
|
||||
for (var i = 0; i < parts.length; i++) {
|
||||
unwrapped += goog.string.Const.unwrap(parts[i]);
|
||||
}
|
||||
return goog.html.TrustedResourceUrl
|
||||
.createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse(unwrapped);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Type marker for the TrustedResourceUrl type, used to implement additional
|
||||
* run-time type checking.
|
||||
* @const {!Object}
|
||||
* @private
|
||||
*/
|
||||
goog.html.TrustedResourceUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {};
|
||||
|
||||
|
||||
/**
|
||||
* Package-internal utility method to create TrustedResourceUrl instances.
|
||||
*
|
||||
* @param {string} url The string to initialize the TrustedResourceUrl object
|
||||
* with.
|
||||
* @return {!goog.html.TrustedResourceUrl} The initialized TrustedResourceUrl
|
||||
* object.
|
||||
* @package
|
||||
*/
|
||||
goog.html.TrustedResourceUrl
|
||||
.createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse = function(url) {
|
||||
var trustedResourceUrl = new goog.html.TrustedResourceUrl();
|
||||
trustedResourceUrl.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_ =
|
||||
url;
|
||||
return trustedResourceUrl;
|
||||
};
|
||||
|
|
@ -0,0 +1,228 @@
|
|||
// Copyright 2013 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 Unchecked conversions to create values of goog.html types from
|
||||
* plain strings. Use of these functions could potentially result in instances
|
||||
* of goog.html types that violate their type contracts, and hence result in
|
||||
* security vulnerabilties.
|
||||
*
|
||||
* Therefore, all uses of the methods herein must be carefully security
|
||||
* reviewed. Avoid use of the methods in this file whenever possible; instead
|
||||
* prefer to create instances of goog.html types using inherently safe builders
|
||||
* or template systems.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @visibility {//closure/goog/html:approved_for_unchecked_conversion}
|
||||
* @visibility {//closure/goog/bin/sizetests:__pkg__}
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.html.uncheckedconversions');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.html.SafeHtml');
|
||||
goog.require('goog.html.SafeScript');
|
||||
goog.require('goog.html.SafeStyle');
|
||||
goog.require('goog.html.SafeStyleSheet');
|
||||
goog.require('goog.html.SafeUrl');
|
||||
goog.require('goog.html.TrustedResourceUrl');
|
||||
goog.require('goog.string');
|
||||
goog.require('goog.string.Const');
|
||||
|
||||
|
||||
/**
|
||||
* Performs an "unchecked conversion" to SafeHtml from a plain string that is
|
||||
* known to satisfy the SafeHtml type contract.
|
||||
*
|
||||
* IMPORTANT: Uses of this method must be carefully security-reviewed to ensure
|
||||
* that the value of {@code html} satisfies the SafeHtml type contract in all
|
||||
* possible program states.
|
||||
*
|
||||
*
|
||||
* @param {!goog.string.Const} justification A constant string explaining why
|
||||
* this use of this method is safe. May include a security review ticket
|
||||
* number.
|
||||
* @param {string} html A string that is claimed to adhere to the SafeHtml
|
||||
* contract.
|
||||
* @param {?goog.i18n.bidi.Dir=} opt_dir The optional directionality of the
|
||||
* SafeHtml to be constructed. A null or undefined value signifies an
|
||||
* unknown directionality.
|
||||
* @return {!goog.html.SafeHtml} The value of html, wrapped in a SafeHtml
|
||||
* object.
|
||||
*/
|
||||
goog.html.uncheckedconversions.safeHtmlFromStringKnownToSatisfyTypeContract =
|
||||
function(justification, html, opt_dir) {
|
||||
// unwrap() called inside an assert so that justification can be optimized
|
||||
// away in production code.
|
||||
goog.asserts.assertString(
|
||||
goog.string.Const.unwrap(justification), 'must provide justification');
|
||||
goog.asserts.assert(
|
||||
!goog.string.isEmptyOrWhitespace(goog.string.Const.unwrap(justification)),
|
||||
'must provide non-empty justification');
|
||||
return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse(
|
||||
html, opt_dir || null);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Performs an "unchecked conversion" to SafeScript from a plain string that is
|
||||
* known to satisfy the SafeScript type contract.
|
||||
*
|
||||
* IMPORTANT: Uses of this method must be carefully security-reviewed to ensure
|
||||
* that the value of {@code script} satisfies the SafeScript type contract in
|
||||
* all possible program states.
|
||||
*
|
||||
*
|
||||
* @param {!goog.string.Const} justification A constant string explaining why
|
||||
* this use of this method is safe. May include a security review ticket
|
||||
* number.
|
||||
* @param {string} script The string to wrap as a SafeScript.
|
||||
* @return {!goog.html.SafeScript} The value of {@code script}, wrapped in a
|
||||
* SafeScript object.
|
||||
*/
|
||||
goog.html.uncheckedconversions.safeScriptFromStringKnownToSatisfyTypeContract =
|
||||
function(justification, script) {
|
||||
// unwrap() called inside an assert so that justification can be optimized
|
||||
// away in production code.
|
||||
goog.asserts.assertString(
|
||||
goog.string.Const.unwrap(justification), 'must provide justification');
|
||||
goog.asserts.assert(
|
||||
!goog.string.isEmptyOrWhitespace(goog.string.Const.unwrap(justification)),
|
||||
'must provide non-empty justification');
|
||||
return goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse(
|
||||
script);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Performs an "unchecked conversion" to SafeStyle from a plain string that is
|
||||
* known to satisfy the SafeStyle type contract.
|
||||
*
|
||||
* IMPORTANT: Uses of this method must be carefully security-reviewed to ensure
|
||||
* that the value of {@code style} satisfies the SafeStyle type contract in all
|
||||
* possible program states.
|
||||
*
|
||||
*
|
||||
* @param {!goog.string.Const} justification A constant string explaining why
|
||||
* this use of this method is safe. May include a security review ticket
|
||||
* number.
|
||||
* @param {string} style The string to wrap as a SafeStyle.
|
||||
* @return {!goog.html.SafeStyle} The value of {@code style}, wrapped in a
|
||||
* SafeStyle object.
|
||||
*/
|
||||
goog.html.uncheckedconversions.safeStyleFromStringKnownToSatisfyTypeContract =
|
||||
function(justification, style) {
|
||||
// unwrap() called inside an assert so that justification can be optimized
|
||||
// away in production code.
|
||||
goog.asserts.assertString(
|
||||
goog.string.Const.unwrap(justification), 'must provide justification');
|
||||
goog.asserts.assert(
|
||||
!goog.string.isEmptyOrWhitespace(goog.string.Const.unwrap(justification)),
|
||||
'must provide non-empty justification');
|
||||
return goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse(
|
||||
style);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Performs an "unchecked conversion" to SafeStyleSheet from a plain string
|
||||
* that is known to satisfy the SafeStyleSheet type contract.
|
||||
*
|
||||
* IMPORTANT: Uses of this method must be carefully security-reviewed to ensure
|
||||
* that the value of {@code styleSheet} satisfies the SafeStyleSheet type
|
||||
* contract in all possible program states.
|
||||
*
|
||||
*
|
||||
* @param {!goog.string.Const} justification A constant string explaining why
|
||||
* this use of this method is safe. May include a security review ticket
|
||||
* number.
|
||||
* @param {string} styleSheet The string to wrap as a SafeStyleSheet.
|
||||
* @return {!goog.html.SafeStyleSheet} The value of {@code styleSheet}, wrapped
|
||||
* in a SafeStyleSheet object.
|
||||
*/
|
||||
goog.html.uncheckedconversions
|
||||
.safeStyleSheetFromStringKnownToSatisfyTypeContract = function(
|
||||
justification, styleSheet) {
|
||||
// unwrap() called inside an assert so that justification can be optimized
|
||||
// away in production code.
|
||||
goog.asserts.assertString(
|
||||
goog.string.Const.unwrap(justification), 'must provide justification');
|
||||
goog.asserts.assert(
|
||||
!goog.string.isEmptyOrWhitespace(goog.string.Const.unwrap(justification)),
|
||||
'must provide non-empty justification');
|
||||
return goog.html.SafeStyleSheet
|
||||
.createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(styleSheet);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Performs an "unchecked conversion" to SafeUrl from a plain string that is
|
||||
* known to satisfy the SafeUrl type contract.
|
||||
*
|
||||
* IMPORTANT: Uses of this method must be carefully security-reviewed to ensure
|
||||
* that the value of {@code url} satisfies the SafeUrl type contract in all
|
||||
* possible program states.
|
||||
*
|
||||
*
|
||||
* @param {!goog.string.Const} justification A constant string explaining why
|
||||
* this use of this method is safe. May include a security review ticket
|
||||
* number.
|
||||
* @param {string} url The string to wrap as a SafeUrl.
|
||||
* @return {!goog.html.SafeUrl} The value of {@code url}, wrapped in a SafeUrl
|
||||
* object.
|
||||
*/
|
||||
goog.html.uncheckedconversions.safeUrlFromStringKnownToSatisfyTypeContract =
|
||||
function(justification, url) {
|
||||
// unwrap() called inside an assert so that justification can be optimized
|
||||
// away in production code.
|
||||
goog.asserts.assertString(
|
||||
goog.string.Const.unwrap(justification), 'must provide justification');
|
||||
goog.asserts.assert(
|
||||
!goog.string.isEmptyOrWhitespace(goog.string.Const.unwrap(justification)),
|
||||
'must provide non-empty justification');
|
||||
return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(url);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Performs an "unchecked conversion" to TrustedResourceUrl from a plain string
|
||||
* that is known to satisfy the TrustedResourceUrl type contract.
|
||||
*
|
||||
* IMPORTANT: Uses of this method must be carefully security-reviewed to ensure
|
||||
* that the value of {@code url} satisfies the TrustedResourceUrl type contract
|
||||
* in all possible program states.
|
||||
*
|
||||
*
|
||||
* @param {!goog.string.Const} justification A constant string explaining why
|
||||
* this use of this method is safe. May include a security review ticket
|
||||
* number.
|
||||
* @param {string} url The string to wrap as a TrustedResourceUrl.
|
||||
* @return {!goog.html.TrustedResourceUrl} The value of {@code url}, wrapped in
|
||||
* a TrustedResourceUrl object.
|
||||
*/
|
||||
goog.html.uncheckedconversions
|
||||
.trustedResourceUrlFromStringKnownToSatisfyTypeContract = function(
|
||||
justification, url) {
|
||||
// unwrap() called inside an assert so that justification can be optimized
|
||||
// away in production code.
|
||||
goog.asserts.assertString(
|
||||
goog.string.Const.unwrap(justification), 'must provide justification');
|
||||
goog.asserts.assert(
|
||||
!goog.string.isEmptyOrWhitespace(goog.string.Const.unwrap(justification)),
|
||||
'must provide non-empty justification');
|
||||
return goog.html.TrustedResourceUrl
|
||||
.createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse(url);
|
||||
};
|
||||
876
resources/public/target/cljsbuild-compiler-1/goog/i18n/bidi.js
Normal file
876
resources/public/target/cljsbuild-compiler-1/goog/i18n/bidi.js
Normal file
|
|
@ -0,0 +1,876 @@
|
|||
// Copyright 2007 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 Utility functions for supporting Bidi issues.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Namespace for bidi supporting functions.
|
||||
*/
|
||||
goog.provide('goog.i18n.bidi');
|
||||
goog.provide('goog.i18n.bidi.Dir');
|
||||
goog.provide('goog.i18n.bidi.DirectionalString');
|
||||
goog.provide('goog.i18n.bidi.Format');
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} FORCE_RTL forces the {@link goog.i18n.bidi.IS_RTL} constant
|
||||
* to say that the current locale is a RTL locale. This should only be used
|
||||
* if you want to override the default behavior for deciding whether the
|
||||
* current locale is RTL or not.
|
||||
*
|
||||
* {@see goog.i18n.bidi.IS_RTL}
|
||||
*/
|
||||
goog.define('goog.i18n.bidi.FORCE_RTL', false);
|
||||
|
||||
|
||||
/**
|
||||
* Constant that defines whether or not the current locale is a RTL locale.
|
||||
* If {@link goog.i18n.bidi.FORCE_RTL} is not true, this constant will default
|
||||
* to check that {@link goog.LOCALE} is one of a few major RTL locales.
|
||||
*
|
||||
* <p>This is designed to be a maximally efficient compile-time constant. For
|
||||
* example, for the default goog.LOCALE, compiling
|
||||
* "if (goog.i18n.bidi.IS_RTL) alert('rtl') else {}" should produce no code. It
|
||||
* is this design consideration that limits the implementation to only
|
||||
* supporting a few major RTL locales, as opposed to the broader repertoire of
|
||||
* something like goog.i18n.bidi.isRtlLanguage.
|
||||
*
|
||||
* <p>Since this constant refers to the directionality of the locale, it is up
|
||||
* to the caller to determine if this constant should also be used for the
|
||||
* direction of the UI.
|
||||
*
|
||||
* {@see goog.LOCALE}
|
||||
*
|
||||
* @type {boolean}
|
||||
*
|
||||
* TODO(user): write a test that checks that this is a compile-time constant.
|
||||
*/
|
||||
goog.i18n.bidi.IS_RTL = goog.i18n.bidi.FORCE_RTL ||
|
||||
((goog.LOCALE.substring(0, 2).toLowerCase() == 'ar' ||
|
||||
goog.LOCALE.substring(0, 2).toLowerCase() == 'fa' ||
|
||||
goog.LOCALE.substring(0, 2).toLowerCase() == 'he' ||
|
||||
goog.LOCALE.substring(0, 2).toLowerCase() == 'iw' ||
|
||||
goog.LOCALE.substring(0, 2).toLowerCase() == 'ps' ||
|
||||
goog.LOCALE.substring(0, 2).toLowerCase() == 'sd' ||
|
||||
goog.LOCALE.substring(0, 2).toLowerCase() == 'ug' ||
|
||||
goog.LOCALE.substring(0, 2).toLowerCase() == 'ur' ||
|
||||
goog.LOCALE.substring(0, 2).toLowerCase() == 'yi') &&
|
||||
(goog.LOCALE.length == 2 || goog.LOCALE.substring(2, 3) == '-' ||
|
||||
goog.LOCALE.substring(2, 3) == '_')) ||
|
||||
(goog.LOCALE.length >= 3 &&
|
||||
goog.LOCALE.substring(0, 3).toLowerCase() == 'ckb' &&
|
||||
(goog.LOCALE.length == 3 || goog.LOCALE.substring(3, 4) == '-' ||
|
||||
goog.LOCALE.substring(3, 4) == '_'));
|
||||
|
||||
|
||||
/**
|
||||
* Unicode formatting characters and directionality string constants.
|
||||
* @enum {string}
|
||||
*/
|
||||
goog.i18n.bidi.Format = {
|
||||
/** Unicode "Left-To-Right Embedding" (LRE) character. */
|
||||
LRE: '\u202A',
|
||||
/** Unicode "Right-To-Left Embedding" (RLE) character. */
|
||||
RLE: '\u202B',
|
||||
/** Unicode "Pop Directional Formatting" (PDF) character. */
|
||||
PDF: '\u202C',
|
||||
/** Unicode "Left-To-Right Mark" (LRM) character. */
|
||||
LRM: '\u200E',
|
||||
/** Unicode "Right-To-Left Mark" (RLM) character. */
|
||||
RLM: '\u200F'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Directionality enum.
|
||||
* @enum {number}
|
||||
*/
|
||||
goog.i18n.bidi.Dir = {
|
||||
/**
|
||||
* Left-to-right.
|
||||
*/
|
||||
LTR: 1,
|
||||
|
||||
/**
|
||||
* Right-to-left.
|
||||
*/
|
||||
RTL: -1,
|
||||
|
||||
/**
|
||||
* Neither left-to-right nor right-to-left.
|
||||
*/
|
||||
NEUTRAL: 0
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 'right' string constant.
|
||||
* @type {string}
|
||||
*/
|
||||
goog.i18n.bidi.RIGHT = 'right';
|
||||
|
||||
|
||||
/**
|
||||
* 'left' string constant.
|
||||
* @type {string}
|
||||
*/
|
||||
goog.i18n.bidi.LEFT = 'left';
|
||||
|
||||
|
||||
/**
|
||||
* 'left' if locale is RTL, 'right' if not.
|
||||
* @type {string}
|
||||
*/
|
||||
goog.i18n.bidi.I18N_RIGHT =
|
||||
goog.i18n.bidi.IS_RTL ? goog.i18n.bidi.LEFT : goog.i18n.bidi.RIGHT;
|
||||
|
||||
|
||||
/**
|
||||
* 'right' if locale is RTL, 'left' if not.
|
||||
* @type {string}
|
||||
*/
|
||||
goog.i18n.bidi.I18N_LEFT =
|
||||
goog.i18n.bidi.IS_RTL ? goog.i18n.bidi.RIGHT : goog.i18n.bidi.LEFT;
|
||||
|
||||
|
||||
/**
|
||||
* Convert a directionality given in various formats to a goog.i18n.bidi.Dir
|
||||
* constant. Useful for interaction with different standards of directionality
|
||||
* representation.
|
||||
*
|
||||
* @param {goog.i18n.bidi.Dir|number|boolean|null} givenDir Directionality given
|
||||
* in one of the following formats:
|
||||
* 1. A goog.i18n.bidi.Dir constant.
|
||||
* 2. A number (positive = LTR, negative = RTL, 0 = neutral).
|
||||
* 3. A boolean (true = RTL, false = LTR).
|
||||
* 4. A null for unknown directionality.
|
||||
* @param {boolean=} opt_noNeutral Whether a givenDir of zero or
|
||||
* goog.i18n.bidi.Dir.NEUTRAL should be treated as null, i.e. unknown, in
|
||||
* order to preserve legacy behavior.
|
||||
* @return {?goog.i18n.bidi.Dir} A goog.i18n.bidi.Dir constant matching the
|
||||
* given directionality. If given null, returns null (i.e. unknown).
|
||||
*/
|
||||
goog.i18n.bidi.toDir = function(givenDir, opt_noNeutral) {
|
||||
if (typeof givenDir == 'number') {
|
||||
// This includes the non-null goog.i18n.bidi.Dir case.
|
||||
return givenDir > 0 ? goog.i18n.bidi.Dir.LTR : givenDir < 0 ?
|
||||
goog.i18n.bidi.Dir.RTL :
|
||||
opt_noNeutral ? null : goog.i18n.bidi.Dir.NEUTRAL;
|
||||
} else if (givenDir == null) {
|
||||
return null;
|
||||
} else {
|
||||
// Must be typeof givenDir == 'boolean'.
|
||||
return givenDir ? goog.i18n.bidi.Dir.RTL : goog.i18n.bidi.Dir.LTR;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A practical pattern to identify strong LTR characters. This pattern is not
|
||||
* theoretically correct according to the Unicode standard. It is simplified for
|
||||
* performance and small code size.
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.bidi.ltrChars_ =
|
||||
'A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02B8\u0300-\u0590\u0800-\u1FFF' +
|
||||
'\u200E\u2C00-\uFB1C\uFE00-\uFE6F\uFEFD-\uFFFF';
|
||||
|
||||
|
||||
/**
|
||||
* A practical pattern to identify strong RTL character. This pattern is not
|
||||
* theoretically correct according to the Unicode standard. It is simplified
|
||||
* for performance and small code size.
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.bidi.rtlChars_ =
|
||||
'\u0591-\u06EF\u06FA-\u07FF\u200F\uFB1D-\uFDFF\uFE70-\uFEFC';
|
||||
|
||||
|
||||
/**
|
||||
* Simplified regular expression for an HTML tag (opening or closing) or an HTML
|
||||
* escape. We might want to skip over such expressions when estimating the text
|
||||
* directionality.
|
||||
* @type {RegExp}
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.bidi.htmlSkipReg_ = /<[^>]*>|&[^;]+;/g;
|
||||
|
||||
|
||||
/**
|
||||
* Returns the input text with spaces instead of HTML tags or HTML escapes, if
|
||||
* opt_isStripNeeded is true. Else returns the input as is.
|
||||
* Useful for text directionality estimation.
|
||||
* Note: the function should not be used in other contexts; it is not 100%
|
||||
* correct, but rather a good-enough implementation for directionality
|
||||
* estimation purposes.
|
||||
* @param {string} str The given string.
|
||||
* @param {boolean=} opt_isStripNeeded Whether to perform the stripping.
|
||||
* Default: false (to retain consistency with calling functions).
|
||||
* @return {string} The given string cleaned of HTML tags / escapes.
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.bidi.stripHtmlIfNeeded_ = function(str, opt_isStripNeeded) {
|
||||
return opt_isStripNeeded ? str.replace(goog.i18n.bidi.htmlSkipReg_, '') : str;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Regular expression to check for RTL characters.
|
||||
* @type {RegExp}
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.bidi.rtlCharReg_ = new RegExp('[' + goog.i18n.bidi.rtlChars_ + ']');
|
||||
|
||||
|
||||
/**
|
||||
* Regular expression to check for LTR characters.
|
||||
* @type {RegExp}
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.bidi.ltrCharReg_ = new RegExp('[' + goog.i18n.bidi.ltrChars_ + ']');
|
||||
|
||||
|
||||
/**
|
||||
* Test whether the given string has any RTL characters in it.
|
||||
* @param {string} str The given string that need to be tested.
|
||||
* @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
|
||||
* Default: false.
|
||||
* @return {boolean} Whether the string contains RTL characters.
|
||||
*/
|
||||
goog.i18n.bidi.hasAnyRtl = function(str, opt_isHtml) {
|
||||
return goog.i18n.bidi.rtlCharReg_.test(
|
||||
goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Test whether the given string has any RTL characters in it.
|
||||
* @param {string} str The given string that need to be tested.
|
||||
* @return {boolean} Whether the string contains RTL characters.
|
||||
* @deprecated Use hasAnyRtl.
|
||||
*/
|
||||
goog.i18n.bidi.hasRtlChar = goog.i18n.bidi.hasAnyRtl;
|
||||
|
||||
|
||||
/**
|
||||
* Test whether the given string has any LTR characters in it.
|
||||
* @param {string} str The given string that need to be tested.
|
||||
* @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
|
||||
* Default: false.
|
||||
* @return {boolean} Whether the string contains LTR characters.
|
||||
*/
|
||||
goog.i18n.bidi.hasAnyLtr = function(str, opt_isHtml) {
|
||||
return goog.i18n.bidi.ltrCharReg_.test(
|
||||
goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Regular expression pattern to check if the first character in the string
|
||||
* is LTR.
|
||||
* @type {RegExp}
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.bidi.ltrRe_ = new RegExp('^[' + goog.i18n.bidi.ltrChars_ + ']');
|
||||
|
||||
|
||||
/**
|
||||
* Regular expression pattern to check if the first character in the string
|
||||
* is RTL.
|
||||
* @type {RegExp}
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.bidi.rtlRe_ = new RegExp('^[' + goog.i18n.bidi.rtlChars_ + ']');
|
||||
|
||||
|
||||
/**
|
||||
* Check if the first character in the string is RTL or not.
|
||||
* @param {string} str The given string that need to be tested.
|
||||
* @return {boolean} Whether the first character in str is an RTL char.
|
||||
*/
|
||||
goog.i18n.bidi.isRtlChar = function(str) {
|
||||
return goog.i18n.bidi.rtlRe_.test(str);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Check if the first character in the string is LTR or not.
|
||||
* @param {string} str The given string that need to be tested.
|
||||
* @return {boolean} Whether the first character in str is an LTR char.
|
||||
*/
|
||||
goog.i18n.bidi.isLtrChar = function(str) {
|
||||
return goog.i18n.bidi.ltrRe_.test(str);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Check if the first character in the string is neutral or not.
|
||||
* @param {string} str The given string that need to be tested.
|
||||
* @return {boolean} Whether the first character in str is a neutral char.
|
||||
*/
|
||||
goog.i18n.bidi.isNeutralChar = function(str) {
|
||||
return !goog.i18n.bidi.isLtrChar(str) && !goog.i18n.bidi.isRtlChar(str);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Regular expressions to check if a piece of text is of LTR directionality
|
||||
* on first character with strong directionality.
|
||||
* @type {RegExp}
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.bidi.ltrDirCheckRe_ = new RegExp(
|
||||
'^[^' + goog.i18n.bidi.rtlChars_ + ']*[' + goog.i18n.bidi.ltrChars_ + ']');
|
||||
|
||||
|
||||
/**
|
||||
* Regular expressions to check if a piece of text is of RTL directionality
|
||||
* on first character with strong directionality.
|
||||
* @type {RegExp}
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.bidi.rtlDirCheckRe_ = new RegExp(
|
||||
'^[^' + goog.i18n.bidi.ltrChars_ + ']*[' + goog.i18n.bidi.rtlChars_ + ']');
|
||||
|
||||
|
||||
/**
|
||||
* Check whether the first strongly directional character (if any) is RTL.
|
||||
* @param {string} str String being checked.
|
||||
* @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
|
||||
* Default: false.
|
||||
* @return {boolean} Whether RTL directionality is detected using the first
|
||||
* strongly-directional character method.
|
||||
*/
|
||||
goog.i18n.bidi.startsWithRtl = function(str, opt_isHtml) {
|
||||
return goog.i18n.bidi.rtlDirCheckRe_.test(
|
||||
goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Check whether the first strongly directional character (if any) is RTL.
|
||||
* @param {string} str String being checked.
|
||||
* @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
|
||||
* Default: false.
|
||||
* @return {boolean} Whether RTL directionality is detected using the first
|
||||
* strongly-directional character method.
|
||||
* @deprecated Use startsWithRtl.
|
||||
*/
|
||||
goog.i18n.bidi.isRtlText = goog.i18n.bidi.startsWithRtl;
|
||||
|
||||
|
||||
/**
|
||||
* Check whether the first strongly directional character (if any) is LTR.
|
||||
* @param {string} str String being checked.
|
||||
* @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
|
||||
* Default: false.
|
||||
* @return {boolean} Whether LTR directionality is detected using the first
|
||||
* strongly-directional character method.
|
||||
*/
|
||||
goog.i18n.bidi.startsWithLtr = function(str, opt_isHtml) {
|
||||
return goog.i18n.bidi.ltrDirCheckRe_.test(
|
||||
goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Check whether the first strongly directional character (if any) is LTR.
|
||||
* @param {string} str String being checked.
|
||||
* @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
|
||||
* Default: false.
|
||||
* @return {boolean} Whether LTR directionality is detected using the first
|
||||
* strongly-directional character method.
|
||||
* @deprecated Use startsWithLtr.
|
||||
*/
|
||||
goog.i18n.bidi.isLtrText = goog.i18n.bidi.startsWithLtr;
|
||||
|
||||
|
||||
/**
|
||||
* Regular expression to check if a string looks like something that must
|
||||
* always be LTR even in RTL text, e.g. a URL. When estimating the
|
||||
* directionality of text containing these, we treat these as weakly LTR,
|
||||
* like numbers.
|
||||
* @type {RegExp}
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.bidi.isRequiredLtrRe_ = /^http:\/\/.*/;
|
||||
|
||||
|
||||
/**
|
||||
* Check whether the input string either contains no strongly directional
|
||||
* characters or looks like a url.
|
||||
* @param {string} str String being checked.
|
||||
* @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
|
||||
* Default: false.
|
||||
* @return {boolean} Whether neutral directionality is detected.
|
||||
*/
|
||||
goog.i18n.bidi.isNeutralText = function(str, opt_isHtml) {
|
||||
str = goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml);
|
||||
return goog.i18n.bidi.isRequiredLtrRe_.test(str) ||
|
||||
!goog.i18n.bidi.hasAnyLtr(str) && !goog.i18n.bidi.hasAnyRtl(str);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Regular expressions to check if the last strongly-directional character in a
|
||||
* piece of text is LTR.
|
||||
* @type {RegExp}
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.bidi.ltrExitDirCheckRe_ = new RegExp(
|
||||
'[' + goog.i18n.bidi.ltrChars_ + '][^' + goog.i18n.bidi.rtlChars_ + ']*$');
|
||||
|
||||
|
||||
/**
|
||||
* Regular expressions to check if the last strongly-directional character in a
|
||||
* piece of text is RTL.
|
||||
* @type {RegExp}
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.bidi.rtlExitDirCheckRe_ = new RegExp(
|
||||
'[' + goog.i18n.bidi.rtlChars_ + '][^' + goog.i18n.bidi.ltrChars_ + ']*$');
|
||||
|
||||
|
||||
/**
|
||||
* Check if the exit directionality a piece of text is LTR, i.e. if the last
|
||||
* strongly-directional character in the string is LTR.
|
||||
* @param {string} str String being checked.
|
||||
* @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
|
||||
* Default: false.
|
||||
* @return {boolean} Whether LTR exit directionality was detected.
|
||||
*/
|
||||
goog.i18n.bidi.endsWithLtr = function(str, opt_isHtml) {
|
||||
return goog.i18n.bidi.ltrExitDirCheckRe_.test(
|
||||
goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Check if the exit directionality a piece of text is LTR, i.e. if the last
|
||||
* strongly-directional character in the string is LTR.
|
||||
* @param {string} str String being checked.
|
||||
* @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
|
||||
* Default: false.
|
||||
* @return {boolean} Whether LTR exit directionality was detected.
|
||||
* @deprecated Use endsWithLtr.
|
||||
*/
|
||||
goog.i18n.bidi.isLtrExitText = goog.i18n.bidi.endsWithLtr;
|
||||
|
||||
|
||||
/**
|
||||
* Check if the exit directionality a piece of text is RTL, i.e. if the last
|
||||
* strongly-directional character in the string is RTL.
|
||||
* @param {string} str String being checked.
|
||||
* @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
|
||||
* Default: false.
|
||||
* @return {boolean} Whether RTL exit directionality was detected.
|
||||
*/
|
||||
goog.i18n.bidi.endsWithRtl = function(str, opt_isHtml) {
|
||||
return goog.i18n.bidi.rtlExitDirCheckRe_.test(
|
||||
goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Check if the exit directionality a piece of text is RTL, i.e. if the last
|
||||
* strongly-directional character in the string is RTL.
|
||||
* @param {string} str String being checked.
|
||||
* @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
|
||||
* Default: false.
|
||||
* @return {boolean} Whether RTL exit directionality was detected.
|
||||
* @deprecated Use endsWithRtl.
|
||||
*/
|
||||
goog.i18n.bidi.isRtlExitText = goog.i18n.bidi.endsWithRtl;
|
||||
|
||||
|
||||
/**
|
||||
* A regular expression for matching right-to-left language codes.
|
||||
* See {@link #isRtlLanguage} for the design.
|
||||
* @type {RegExp}
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.bidi.rtlLocalesRe_ = new RegExp(
|
||||
'^(ar|ckb|dv|he|iw|fa|nqo|ps|sd|ug|ur|yi|' +
|
||||
'.*[-_](Arab|Hebr|Thaa|Nkoo|Tfng))' +
|
||||
'(?!.*[-_](Latn|Cyrl)($|-|_))($|-|_)',
|
||||
'i');
|
||||
|
||||
|
||||
/**
|
||||
* Check if a BCP 47 / III language code indicates an RTL language, i.e. either:
|
||||
* - a language code explicitly specifying one of the right-to-left scripts,
|
||||
* e.g. "az-Arab", or<p>
|
||||
* - a language code specifying one of the languages normally written in a
|
||||
* right-to-left script, e.g. "fa" (Farsi), except ones explicitly specifying
|
||||
* Latin or Cyrillic script (which are the usual LTR alternatives).<p>
|
||||
* The list of right-to-left scripts appears in the 100-199 range in
|
||||
* http://www.unicode.org/iso15924/iso15924-num.html, of which Arabic and
|
||||
* Hebrew are by far the most widely used. We also recognize Thaana, N'Ko, and
|
||||
* Tifinagh, which also have significant modern usage. The rest (Syriac,
|
||||
* Samaritan, Mandaic, etc.) seem to have extremely limited or no modern usage
|
||||
* and are not recognized to save on code size.
|
||||
* The languages usually written in a right-to-left script are taken as those
|
||||
* with Suppress-Script: Hebr|Arab|Thaa|Nkoo|Tfng in
|
||||
* http://www.iana.org/assignments/language-subtag-registry,
|
||||
* as well as Central (or Sorani) Kurdish (ckb), Sindhi (sd) and Uyghur (ug).
|
||||
* Other subtags of the language code, e.g. regions like EG (Egypt), are
|
||||
* ignored.
|
||||
* @param {string} lang BCP 47 (a.k.a III) language code.
|
||||
* @return {boolean} Whether the language code is an RTL language.
|
||||
*/
|
||||
goog.i18n.bidi.isRtlLanguage = function(lang) {
|
||||
return goog.i18n.bidi.rtlLocalesRe_.test(lang);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Regular expression for bracket guard replacement in text.
|
||||
* @type {RegExp}
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.bidi.bracketGuardTextRe_ =
|
||||
/(\(.*?\)+)|(\[.*?\]+)|(\{.*?\}+)|(<.*?>+)/g;
|
||||
|
||||
|
||||
/**
|
||||
* Apply bracket guard using LRM and RLM. This is to address the problem of
|
||||
* messy bracket display frequently happens in RTL layout.
|
||||
* This function works for plain text, not for HTML. In HTML, the opening
|
||||
* bracket might be in a different context than the closing bracket (such as
|
||||
* an attribute value).
|
||||
* @param {string} s The string that need to be processed.
|
||||
* @param {boolean=} opt_isRtlContext specifies default direction (usually
|
||||
* direction of the UI).
|
||||
* @return {string} The processed string, with all bracket guarded.
|
||||
*/
|
||||
goog.i18n.bidi.guardBracketInText = function(s, opt_isRtlContext) {
|
||||
var useRtl = opt_isRtlContext === undefined ? goog.i18n.bidi.hasAnyRtl(s) :
|
||||
opt_isRtlContext;
|
||||
var mark = useRtl ? goog.i18n.bidi.Format.RLM : goog.i18n.bidi.Format.LRM;
|
||||
return s.replace(goog.i18n.bidi.bracketGuardTextRe_, mark + '$&' + mark);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Enforce the html snippet in RTL directionality regardless overall context.
|
||||
* If the html piece was enclosed by tag, dir will be applied to existing
|
||||
* tag, otherwise a span tag will be added as wrapper. For this reason, if
|
||||
* html snippet start with with tag, this tag must enclose the whole piece. If
|
||||
* the tag already has a dir specified, this new one will override existing
|
||||
* one in behavior (tested on FF and IE).
|
||||
* @param {string} html The string that need to be processed.
|
||||
* @return {string} The processed string, with directionality enforced to RTL.
|
||||
*/
|
||||
goog.i18n.bidi.enforceRtlInHtml = function(html) {
|
||||
if (html.charAt(0) == '<') {
|
||||
return html.replace(/<\w+/, '$& dir=rtl');
|
||||
}
|
||||
// '\n' is important for FF so that it won't incorrectly merge span groups
|
||||
return '\n<span dir=rtl>' + html + '</span>';
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Enforce RTL on both end of the given text piece using unicode BiDi formatting
|
||||
* characters RLE and PDF.
|
||||
* @param {string} text The piece of text that need to be wrapped.
|
||||
* @return {string} The wrapped string after process.
|
||||
*/
|
||||
goog.i18n.bidi.enforceRtlInText = function(text) {
|
||||
return goog.i18n.bidi.Format.RLE + text + goog.i18n.bidi.Format.PDF;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Enforce the html snippet in RTL directionality regardless overall context.
|
||||
* If the html piece was enclosed by tag, dir will be applied to existing
|
||||
* tag, otherwise a span tag will be added as wrapper. For this reason, if
|
||||
* html snippet start with with tag, this tag must enclose the whole piece. If
|
||||
* the tag already has a dir specified, this new one will override existing
|
||||
* one in behavior (tested on FF and IE).
|
||||
* @param {string} html The string that need to be processed.
|
||||
* @return {string} The processed string, with directionality enforced to RTL.
|
||||
*/
|
||||
goog.i18n.bidi.enforceLtrInHtml = function(html) {
|
||||
if (html.charAt(0) == '<') {
|
||||
return html.replace(/<\w+/, '$& dir=ltr');
|
||||
}
|
||||
// '\n' is important for FF so that it won't incorrectly merge span groups
|
||||
return '\n<span dir=ltr>' + html + '</span>';
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Enforce LTR on both end of the given text piece using unicode BiDi formatting
|
||||
* characters LRE and PDF.
|
||||
* @param {string} text The piece of text that need to be wrapped.
|
||||
* @return {string} The wrapped string after process.
|
||||
*/
|
||||
goog.i18n.bidi.enforceLtrInText = function(text) {
|
||||
return goog.i18n.bidi.Format.LRE + text + goog.i18n.bidi.Format.PDF;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Regular expression to find dimensions such as "padding: .3 0.4ex 5px 6;"
|
||||
* @type {RegExp}
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.bidi.dimensionsRe_ =
|
||||
/:\s*([.\d][.\w]*)\s+([.\d][.\w]*)\s+([.\d][.\w]*)\s+([.\d][.\w]*)/g;
|
||||
|
||||
|
||||
/**
|
||||
* Regular expression for left.
|
||||
* @type {RegExp}
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.bidi.leftRe_ = /left/gi;
|
||||
|
||||
|
||||
/**
|
||||
* Regular expression for right.
|
||||
* @type {RegExp}
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.bidi.rightRe_ = /right/gi;
|
||||
|
||||
|
||||
/**
|
||||
* Placeholder regular expression for swapping.
|
||||
* @type {RegExp}
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.bidi.tempRe_ = /%%%%/g;
|
||||
|
||||
|
||||
/**
|
||||
* Swap location parameters and 'left'/'right' in CSS specification. The
|
||||
* processed string will be suited for RTL layout. Though this function can
|
||||
* cover most cases, there are always exceptions. It is suggested to put
|
||||
* those exceptions in separate group of CSS string.
|
||||
* @param {string} cssStr CSS spefication string.
|
||||
* @return {string} Processed CSS specification string.
|
||||
*/
|
||||
goog.i18n.bidi.mirrorCSS = function(cssStr) {
|
||||
return cssStr
|
||||
.
|
||||
// reverse dimensions
|
||||
replace(goog.i18n.bidi.dimensionsRe_, ':$1 $4 $3 $2')
|
||||
.replace(goog.i18n.bidi.leftRe_, '%%%%')
|
||||
. // swap left and right
|
||||
replace(goog.i18n.bidi.rightRe_, goog.i18n.bidi.LEFT)
|
||||
.replace(goog.i18n.bidi.tempRe_, goog.i18n.bidi.RIGHT);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Regular expression for hebrew double quote substitution, finding quote
|
||||
* directly after hebrew characters.
|
||||
* @type {RegExp}
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.bidi.doubleQuoteSubstituteRe_ = /([\u0591-\u05f2])"/g;
|
||||
|
||||
|
||||
/**
|
||||
* Regular expression for hebrew single quote substitution, finding quote
|
||||
* directly after hebrew characters.
|
||||
* @type {RegExp}
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.bidi.singleQuoteSubstituteRe_ = /([\u0591-\u05f2])'/g;
|
||||
|
||||
|
||||
/**
|
||||
* Replace the double and single quote directly after a Hebrew character with
|
||||
* GERESH and GERSHAYIM. In such case, most likely that's user intention.
|
||||
* @param {string} str String that need to be processed.
|
||||
* @return {string} Processed string with double/single quote replaced.
|
||||
*/
|
||||
goog.i18n.bidi.normalizeHebrewQuote = function(str) {
|
||||
return str.replace(goog.i18n.bidi.doubleQuoteSubstituteRe_, '$1\u05f4')
|
||||
.replace(goog.i18n.bidi.singleQuoteSubstituteRe_, '$1\u05f3');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Regular expression to split a string into "words" for directionality
|
||||
* estimation based on relative word counts.
|
||||
* @type {RegExp}
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.bidi.wordSeparatorRe_ = /\s+/;
|
||||
|
||||
|
||||
/**
|
||||
* Regular expression to check if a string contains any numerals. Used to
|
||||
* differentiate between completely neutral strings and those containing
|
||||
* numbers, which are weakly LTR.
|
||||
*
|
||||
* Native Arabic digits (\u0660 - \u0669) are not included because although they
|
||||
* do flow left-to-right inside a number, this is the case even if the overall
|
||||
* directionality is RTL, and a mathematical expression using these digits is
|
||||
* supposed to flow right-to-left overall, including unary plus and minus
|
||||
* appearing to the right of a number, and this does depend on the overall
|
||||
* directionality being RTL. The digits used in Farsi (\u06F0 - \u06F9), on the
|
||||
* other hand, are included, since Farsi math (including unary plus and minus)
|
||||
* does flow left-to-right.
|
||||
*
|
||||
* @type {RegExp}
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.bidi.hasNumeralsRe_ = /[\d\u06f0-\u06f9]/;
|
||||
|
||||
|
||||
/**
|
||||
* This constant controls threshold of RTL directionality.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
goog.i18n.bidi.rtlDetectionThreshold_ = 0.40;
|
||||
|
||||
|
||||
/**
|
||||
* Estimates the directionality of a string based on relative word counts.
|
||||
* If the number of RTL words is above a certain percentage of the total number
|
||||
* of strongly directional words, returns RTL.
|
||||
* Otherwise, if any words are strongly or weakly LTR, returns LTR.
|
||||
* Otherwise, returns UNKNOWN, which is used to mean "neutral".
|
||||
* Numbers are counted as weakly LTR.
|
||||
* @param {string} str The string to be checked.
|
||||
* @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
|
||||
* Default: false.
|
||||
* @return {goog.i18n.bidi.Dir} Estimated overall directionality of {@code str}.
|
||||
*/
|
||||
goog.i18n.bidi.estimateDirection = function(str, opt_isHtml) {
|
||||
var rtlCount = 0;
|
||||
var totalCount = 0;
|
||||
var hasWeaklyLtr = false;
|
||||
var tokens = goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml)
|
||||
.split(goog.i18n.bidi.wordSeparatorRe_);
|
||||
for (var i = 0; i < tokens.length; i++) {
|
||||
var token = tokens[i];
|
||||
if (goog.i18n.bidi.startsWithRtl(token)) {
|
||||
rtlCount++;
|
||||
totalCount++;
|
||||
} else if (goog.i18n.bidi.isRequiredLtrRe_.test(token)) {
|
||||
hasWeaklyLtr = true;
|
||||
} else if (goog.i18n.bidi.hasAnyLtr(token)) {
|
||||
totalCount++;
|
||||
} else if (goog.i18n.bidi.hasNumeralsRe_.test(token)) {
|
||||
hasWeaklyLtr = true;
|
||||
}
|
||||
}
|
||||
|
||||
return totalCount == 0 ?
|
||||
(hasWeaklyLtr ? goog.i18n.bidi.Dir.LTR : goog.i18n.bidi.Dir.NEUTRAL) :
|
||||
(rtlCount / totalCount > goog.i18n.bidi.rtlDetectionThreshold_ ?
|
||||
goog.i18n.bidi.Dir.RTL :
|
||||
goog.i18n.bidi.Dir.LTR);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Check the directionality of a piece of text, return true if the piece of
|
||||
* text should be laid out in RTL direction.
|
||||
* @param {string} str The piece of text that need to be detected.
|
||||
* @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
|
||||
* Default: false.
|
||||
* @return {boolean} Whether this piece of text should be laid out in RTL.
|
||||
*/
|
||||
goog.i18n.bidi.detectRtlDirectionality = function(str, opt_isHtml) {
|
||||
return goog.i18n.bidi.estimateDirection(str, opt_isHtml) ==
|
||||
goog.i18n.bidi.Dir.RTL;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets text input element's directionality and text alignment based on a
|
||||
* given directionality. Does nothing if the given directionality is unknown or
|
||||
* neutral.
|
||||
* @param {Element} element Input field element to set directionality to.
|
||||
* @param {goog.i18n.bidi.Dir|number|boolean|null} dir Desired directionality,
|
||||
* given in one of the following formats:
|
||||
* 1. A goog.i18n.bidi.Dir constant.
|
||||
* 2. A number (positive = LRT, negative = RTL, 0 = neutral).
|
||||
* 3. A boolean (true = RTL, false = LTR).
|
||||
* 4. A null for unknown directionality.
|
||||
*/
|
||||
goog.i18n.bidi.setElementDirAndAlign = function(element, dir) {
|
||||
if (element) {
|
||||
dir = goog.i18n.bidi.toDir(dir);
|
||||
if (dir) {
|
||||
element.style.textAlign = dir == goog.i18n.bidi.Dir.RTL ?
|
||||
goog.i18n.bidi.RIGHT :
|
||||
goog.i18n.bidi.LEFT;
|
||||
element.dir = dir == goog.i18n.bidi.Dir.RTL ? 'rtl' : 'ltr';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets element dir based on estimated directionality of the given text.
|
||||
* @param {!Element} element
|
||||
* @param {string} text
|
||||
*/
|
||||
goog.i18n.bidi.setElementDirByTextDirectionality = function(element, text) {
|
||||
switch (goog.i18n.bidi.estimateDirection(text)) {
|
||||
case (goog.i18n.bidi.Dir.LTR):
|
||||
element.dir = 'ltr';
|
||||
break;
|
||||
case (goog.i18n.bidi.Dir.RTL):
|
||||
element.dir = 'rtl';
|
||||
break;
|
||||
default:
|
||||
// Default for no direction, inherit from document.
|
||||
element.removeAttribute('dir');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Strings that have an (optional) known direction.
|
||||
*
|
||||
* Implementations of this interface are string-like objects that carry an
|
||||
* attached direction, if known.
|
||||
* @interface
|
||||
*/
|
||||
goog.i18n.bidi.DirectionalString = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Interface marker of the DirectionalString interface.
|
||||
*
|
||||
* This property can be used to determine at runtime whether or not an object
|
||||
* implements this interface. All implementations of this interface set this
|
||||
* property to {@code true}.
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.i18n.bidi.DirectionalString.prototype
|
||||
.implementsGoogI18nBidiDirectionalString;
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves this object's known direction (if any).
|
||||
* @return {?goog.i18n.bidi.Dir} The known direction. Null if unknown.
|
||||
*/
|
||||
goog.i18n.bidi.DirectionalString.prototype.getDirection;
|
||||
1284
resources/public/target/cljsbuild-compiler-1/goog/iter/iter.js
Normal file
1284
resources/public/target/cljsbuild-compiler-1/goog/iter/iter.js
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,90 @@
|
|||
// Copyright 2013 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 Utility to attempt native JSON processing, falling back to
|
||||
* goog.json if not available.
|
||||
*
|
||||
* This is intended as a drop-in for current users of goog.json who want
|
||||
* to take advantage of native JSON if present.
|
||||
*
|
||||
* @author nnaze@google.com (Nathan Naze)
|
||||
*/
|
||||
|
||||
goog.provide('goog.json.hybrid');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.json');
|
||||
|
||||
|
||||
/**
|
||||
* Attempts to serialize the JSON string natively, falling back to
|
||||
* {@code goog.json.serialize} if unsuccessful.
|
||||
* @param {!Object} obj JavaScript object to serialize to JSON.
|
||||
* @return {string} Resulting JSON string.
|
||||
*/
|
||||
goog.json.hybrid.stringify =
|
||||
goog.json.USE_NATIVE_JSON ? goog.global['JSON']['stringify'] : function(
|
||||
obj) {
|
||||
if (goog.global.JSON) {
|
||||
try {
|
||||
return goog.global.JSON.stringify(obj);
|
||||
} catch (e) {
|
||||
// Native serialization failed. Fall through to retry with
|
||||
// goog.json.serialize.
|
||||
}
|
||||
}
|
||||
|
||||
return goog.json.serialize(obj);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Attempts to parse the JSON string natively, falling back to
|
||||
* the supplied {@code fallbackParser} if unsuccessful.
|
||||
* @param {string} jsonString JSON string to parse.
|
||||
* @param {function(string):Object} fallbackParser Fallback JSON parser used
|
||||
* if native
|
||||
* @return {!Object} Resulting JSON object.
|
||||
* @private
|
||||
*/
|
||||
goog.json.hybrid.parse_ = function(jsonString, fallbackParser) {
|
||||
if (goog.global.JSON) {
|
||||
try {
|
||||
var obj = goog.global.JSON.parse(jsonString);
|
||||
goog.asserts.assertObject(obj);
|
||||
return obj;
|
||||
} catch (e) {
|
||||
// Native parse failed. Fall through to retry with goog.json.parse.
|
||||
}
|
||||
}
|
||||
|
||||
var obj = fallbackParser(jsonString);
|
||||
goog.asserts.assert(obj);
|
||||
return obj;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Attempts to parse the JSON string natively, falling back to
|
||||
* {@code goog.json.parse} if unsuccessful.
|
||||
* @param {string} jsonString JSON string to parse.
|
||||
* @return {!Object} Resulting JSON object.
|
||||
*/
|
||||
goog.json.hybrid.parse =
|
||||
goog.json.USE_NATIVE_JSON ? goog.global['JSON']['parse'] : function(
|
||||
jsonString) {
|
||||
return goog.json.hybrid.parse_(jsonString, goog.json.parse);
|
||||
};
|
||||
418
resources/public/target/cljsbuild-compiler-1/goog/json/json.js
Normal file
418
resources/public/target/cljsbuild-compiler-1/goog/json/json.js
Normal file
|
|
@ -0,0 +1,418 @@
|
|||
// Copyright 2006 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 JSON utility functions.
|
||||
* @author arv@google.com (Erik Arvidsson)
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.json');
|
||||
goog.provide('goog.json.Replacer');
|
||||
goog.provide('goog.json.Reviver');
|
||||
goog.provide('goog.json.Serializer');
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} If true, use the native JSON parsing API.
|
||||
* NOTE: The default {@code goog.json.parse} implementation is able to handle
|
||||
* invalid JSON. JSPB used to produce invalid JSON which is not the case
|
||||
* anymore so this is safe to enable for parsing JSPB. Using native JSON is
|
||||
* faster and safer than the default implementation using {@code eval}.
|
||||
*/
|
||||
goog.define('goog.json.USE_NATIVE_JSON', false);
|
||||
|
||||
/**
|
||||
* @define {boolean} If true, try the native JSON parsing API first. If it
|
||||
* fails, log an error and use {@code eval} instead. This is useful when
|
||||
* transitioning to {@code goog.json.USE_NATIVE_JSON}. The error logger needs to
|
||||
* be set by {@code goog.json.setErrorLogger}. If it is not set then the error
|
||||
* is ignored.
|
||||
*/
|
||||
goog.define('goog.json.TRY_NATIVE_JSON', false);
|
||||
|
||||
|
||||
/**
|
||||
* Tests if a string is an invalid JSON string. This only ensures that we are
|
||||
* not using any invalid characters
|
||||
* @param {string} s The string to test.
|
||||
* @return {boolean} True if the input is a valid JSON string.
|
||||
*/
|
||||
goog.json.isValid = function(s) {
|
||||
// All empty whitespace is not valid.
|
||||
if (/^\s*$/.test(s)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// This is taken from http://www.json.org/json2.js which is released to the
|
||||
// public domain.
|
||||
// Changes: We dissallow \u2028 Line separator and \u2029 Paragraph separator
|
||||
// inside strings. We also treat \u2028 and \u2029 as whitespace which they
|
||||
// are in the RFC but IE and Safari does not match \s to these so we need to
|
||||
// include them in the reg exps in all places where whitespace is allowed.
|
||||
// We allowed \x7f inside strings because some tools don't escape it,
|
||||
// e.g. http://www.json.org/java/org/json/JSONObject.java
|
||||
|
||||
// Parsing happens in three stages. In the first stage, we run the text
|
||||
// against regular expressions that look for non-JSON patterns. We are
|
||||
// especially concerned with '()' and 'new' because they can cause invocation,
|
||||
// and '=' because it can cause mutation. But just to be safe, we want to
|
||||
// reject all unexpected forms.
|
||||
|
||||
// We split the first stage into 4 regexp operations in order to work around
|
||||
// crippling inefficiencies in IE's and Safari's regexp engines. First we
|
||||
// replace all backslash pairs with '@' (a non-JSON character). Second, we
|
||||
// replace all simple value tokens with ']' characters, but only when followed
|
||||
// by a colon, comma, closing bracket or end of string. Third, we delete all
|
||||
// open brackets that follow a colon or comma or that begin the text. Finally,
|
||||
// we look to see that the remaining characters are only whitespace or ']' or
|
||||
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
|
||||
|
||||
// Don't make these static since they have the global flag.
|
||||
var backslashesRe = /\\["\\\/bfnrtu]/g;
|
||||
var simpleValuesRe =
|
||||
/(?:"[^"\\\n\r\u2028\u2029\x00-\x08\x0a-\x1f]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)[\s\u2028\u2029]*(?=:|,|]|}|$)/g;
|
||||
var openBracketsRe = /(?:^|:|,)(?:[\s\u2028\u2029]*\[)+/g;
|
||||
var remainderRe = /^[\],:{}\s\u2028\u2029]*$/;
|
||||
|
||||
return remainderRe.test(
|
||||
s.replace(backslashesRe, '@')
|
||||
.replace(simpleValuesRe, ']')
|
||||
.replace(openBracketsRe, ''));
|
||||
};
|
||||
|
||||
/**
|
||||
* Logs a parsing error in {@code JSON.parse} solvable by using {@code eval}
|
||||
* if {@code goog.json.TRY_NATIVE_JSON} is enabled.
|
||||
* @private {function(string, !Error)} The first parameter is the error message,
|
||||
* the second is the exception thrown by {@code JSON.parse}.
|
||||
*/
|
||||
goog.json.errorLogger_ = goog.nullFunction;
|
||||
|
||||
|
||||
/**
|
||||
* Sets an error logger to use if there's a recoverable parsing error and {@code
|
||||
* goog.json.TRY_NATIVE_JSON} is enabled.
|
||||
* @param {function(string, !Error)} errorLogger The first parameter is the
|
||||
* error message, the second is the exception thrown by {@code JSON.parse}.
|
||||
*/
|
||||
goog.json.setErrorLogger = function(errorLogger) {
|
||||
goog.json.errorLogger_ = errorLogger;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parses a JSON string and returns the result. This throws an exception if
|
||||
* the string is an invalid JSON string.
|
||||
*
|
||||
* Note that this is very slow on large strings. Use JSON.parse if possible.
|
||||
*
|
||||
* @param {*} s The JSON string to parse.
|
||||
* @throws Error if s is invalid JSON.
|
||||
* @return {Object} The object generated from the JSON string, or null.
|
||||
*/
|
||||
goog.json.parse = goog.json.USE_NATIVE_JSON ?
|
||||
/** @type {function(*):Object} */ (goog.global['JSON']['parse']) :
|
||||
function(s) {
|
||||
var error;
|
||||
if (goog.json.TRY_NATIVE_JSON) {
|
||||
try {
|
||||
return goog.global['JSON']['parse'](s);
|
||||
} catch (ex) {
|
||||
error = ex;
|
||||
}
|
||||
}
|
||||
var o = String(s);
|
||||
if (goog.json.isValid(o)) {
|
||||
|
||||
try {
|
||||
var result = /** @type {?Object} */ (eval('(' + o + ')'));
|
||||
if (error) {
|
||||
goog.json.errorLogger_('Invalid JSON: ' + o, error);
|
||||
}
|
||||
return result;
|
||||
} catch (ex) {
|
||||
}
|
||||
}
|
||||
throw Error('Invalid JSON string: ' + o);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parses a JSON string and returns the result. This uses eval so it is open
|
||||
* to security issues and it should only be used if you trust the source.
|
||||
*
|
||||
* @param {string} s The JSON string to parse.
|
||||
* @return {Object} The object generated from the JSON string.
|
||||
* @deprecated Use JSON.parse if possible or goog.json.parse.
|
||||
*/
|
||||
goog.json.unsafeParse = goog.json.USE_NATIVE_JSON ?
|
||||
/** @type {function(string):Object} */ (goog.global['JSON']['parse']) :
|
||||
function(s) {
|
||||
var error;
|
||||
if (goog.json.TRY_NATIVE_JSON) {
|
||||
try {
|
||||
return goog.global['JSON']['parse'](s);
|
||||
} catch (ex) {
|
||||
error = ex;
|
||||
}
|
||||
}
|
||||
var result = /** @type {?Object} */ (eval('(' + s + ')'));
|
||||
if (error) {
|
||||
goog.json.errorLogger_('Invalid JSON: ' + s, error);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* JSON replacer, as defined in Section 15.12.3 of the ES5 spec.
|
||||
* @see http://ecma-international.org/ecma-262/5.1/#sec-15.12.3
|
||||
*
|
||||
* TODO(nicksantos): Array should also be a valid replacer.
|
||||
*
|
||||
* @typedef {function(this:Object, string, *): *}
|
||||
*/
|
||||
goog.json.Replacer;
|
||||
|
||||
|
||||
/**
|
||||
* JSON reviver, as defined in Section 15.12.2 of the ES5 spec.
|
||||
* @see http://ecma-international.org/ecma-262/5.1/#sec-15.12.3
|
||||
*
|
||||
* @typedef {function(this:Object, string, *): *}
|
||||
*/
|
||||
goog.json.Reviver;
|
||||
|
||||
|
||||
/**
|
||||
* Serializes an object or a value to a JSON string.
|
||||
*
|
||||
* @param {*} object The object to serialize.
|
||||
* @param {?goog.json.Replacer=} opt_replacer A replacer function
|
||||
* called for each (key, value) pair that determines how the value
|
||||
* should be serialized. By defult, this just returns the value
|
||||
* and allows default serialization to kick in.
|
||||
* @throws Error if there are loops in the object graph.
|
||||
* @return {string} A JSON string representation of the input.
|
||||
*/
|
||||
goog.json.serialize = goog.json.USE_NATIVE_JSON ?
|
||||
/** @type {function(*, ?goog.json.Replacer=):string} */
|
||||
(goog.global['JSON']['stringify']) :
|
||||
function(object, opt_replacer) {
|
||||
// NOTE(nicksantos): Currently, we never use JSON.stringify.
|
||||
//
|
||||
// The last time I evaluated this, JSON.stringify had subtle bugs and
|
||||
// behavior differences on all browsers, and the performance win was not
|
||||
// large enough to justify all the issues. This may change in the future
|
||||
// as browser implementations get better.
|
||||
//
|
||||
// assertSerialize in json_test contains if branches for the cases
|
||||
// that fail.
|
||||
return new goog.json.Serializer(opt_replacer).serialize(object);
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Class that is used to serialize JSON objects to a string.
|
||||
* @param {?goog.json.Replacer=} opt_replacer Replacer.
|
||||
* @constructor
|
||||
*/
|
||||
goog.json.Serializer = function(opt_replacer) {
|
||||
/**
|
||||
* @type {goog.json.Replacer|null|undefined}
|
||||
* @private
|
||||
*/
|
||||
this.replacer_ = opt_replacer;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes an object or a value to a JSON string.
|
||||
*
|
||||
* @param {*} object The object to serialize.
|
||||
* @throws Error if there are loops in the object graph.
|
||||
* @return {string} A JSON string representation of the input.
|
||||
*/
|
||||
goog.json.Serializer.prototype.serialize = function(object) {
|
||||
var sb = [];
|
||||
this.serializeInternal(object, sb);
|
||||
return sb.join('');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes a generic value to a JSON string
|
||||
* @protected
|
||||
* @param {*} object The object to serialize.
|
||||
* @param {Array<string>} sb Array used as a string builder.
|
||||
* @throws Error if there are loops in the object graph.
|
||||
*/
|
||||
goog.json.Serializer.prototype.serializeInternal = function(object, sb) {
|
||||
if (object == null) {
|
||||
// undefined == null so this branch covers undefined as well as null
|
||||
sb.push('null');
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof object == 'object') {
|
||||
if (goog.isArray(object)) {
|
||||
this.serializeArray(object, sb);
|
||||
return;
|
||||
} else if (
|
||||
object instanceof String || object instanceof Number ||
|
||||
object instanceof Boolean) {
|
||||
object = object.valueOf();
|
||||
// Fall through to switch below.
|
||||
} else {
|
||||
this.serializeObject_(/** @type {!Object} */ (object), sb);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (typeof object) {
|
||||
case 'string':
|
||||
this.serializeString_(object, sb);
|
||||
break;
|
||||
case 'number':
|
||||
this.serializeNumber_(object, sb);
|
||||
break;
|
||||
case 'boolean':
|
||||
sb.push(String(object));
|
||||
break;
|
||||
case 'function':
|
||||
sb.push('null');
|
||||
break;
|
||||
default:
|
||||
throw Error('Unknown type: ' + typeof object);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Character mappings used internally for goog.string.quote
|
||||
* @private
|
||||
* @type {!Object}
|
||||
*/
|
||||
goog.json.Serializer.charToJsonCharCache_ = {
|
||||
'\"': '\\"',
|
||||
'\\': '\\\\',
|
||||
'/': '\\/',
|
||||
'\b': '\\b',
|
||||
'\f': '\\f',
|
||||
'\n': '\\n',
|
||||
'\r': '\\r',
|
||||
'\t': '\\t',
|
||||
|
||||
'\x0B': '\\u000b' // '\v' is not supported in JScript
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Regular expression used to match characters that need to be replaced.
|
||||
* The S60 browser has a bug where unicode characters are not matched by
|
||||
* regular expressions. The condition below detects such behaviour and
|
||||
* adjusts the regular expression accordingly.
|
||||
* @private
|
||||
* @type {!RegExp}
|
||||
*/
|
||||
goog.json.Serializer.charsToReplace_ = /\uffff/.test('\uffff') ?
|
||||
/[\\\"\x00-\x1f\x7f-\uffff]/g :
|
||||
/[\\\"\x00-\x1f\x7f-\xff]/g;
|
||||
|
||||
|
||||
/**
|
||||
* Serializes a string to a JSON string
|
||||
* @private
|
||||
* @param {string} s The string to serialize.
|
||||
* @param {Array<string>} sb Array used as a string builder.
|
||||
*/
|
||||
goog.json.Serializer.prototype.serializeString_ = function(s, sb) {
|
||||
// The official JSON implementation does not work with international
|
||||
// characters.
|
||||
sb.push('"', s.replace(goog.json.Serializer.charsToReplace_, function(c) {
|
||||
// caching the result improves performance by a factor 2-3
|
||||
var rv = goog.json.Serializer.charToJsonCharCache_[c];
|
||||
if (!rv) {
|
||||
rv = '\\u' + (c.charCodeAt(0) | 0x10000).toString(16).substr(1);
|
||||
goog.json.Serializer.charToJsonCharCache_[c] = rv;
|
||||
}
|
||||
return rv;
|
||||
}), '"');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes a number to a JSON string
|
||||
* @private
|
||||
* @param {number} n The number to serialize.
|
||||
* @param {Array<string>} sb Array used as a string builder.
|
||||
*/
|
||||
goog.json.Serializer.prototype.serializeNumber_ = function(n, sb) {
|
||||
sb.push(isFinite(n) && !isNaN(n) ? String(n) : 'null');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes an array to a JSON string
|
||||
* @param {Array<string>} arr The array to serialize.
|
||||
* @param {Array<string>} sb Array used as a string builder.
|
||||
* @protected
|
||||
*/
|
||||
goog.json.Serializer.prototype.serializeArray = function(arr, sb) {
|
||||
var l = arr.length;
|
||||
sb.push('[');
|
||||
var sep = '';
|
||||
for (var i = 0; i < l; i++) {
|
||||
sb.push(sep);
|
||||
|
||||
var value = arr[i];
|
||||
this.serializeInternal(
|
||||
this.replacer_ ? this.replacer_.call(arr, String(i), value) : value,
|
||||
sb);
|
||||
|
||||
sep = ',';
|
||||
}
|
||||
sb.push(']');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes an object to a JSON string
|
||||
* @private
|
||||
* @param {!Object} obj The object to serialize.
|
||||
* @param {Array<string>} sb Array used as a string builder.
|
||||
*/
|
||||
goog.json.Serializer.prototype.serializeObject_ = function(obj, sb) {
|
||||
sb.push('{');
|
||||
var sep = '';
|
||||
for (var key in obj) {
|
||||
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
||||
var value = obj[key];
|
||||
// Skip functions.
|
||||
if (typeof value != 'function') {
|
||||
sb.push(sep);
|
||||
this.serializeString_(key, sb);
|
||||
sb.push(':');
|
||||
|
||||
this.serializeInternal(
|
||||
this.replacer_ ? this.replacer_.call(obj, key, value) : value, sb);
|
||||
|
||||
sep = ',';
|
||||
}
|
||||
}
|
||||
}
|
||||
sb.push('}');
|
||||
};
|
||||
|
|
@ -0,0 +1,338 @@
|
|||
// Copyright 2013 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 Closure user agent detection (Browser).
|
||||
* @see <a href="http://www.useragentstring.com/">User agent strings</a>
|
||||
* For more information on rendering engine, platform, or device see the other
|
||||
* sub-namespaces in goog.labs.userAgent, goog.labs.userAgent.platform,
|
||||
* goog.labs.userAgent.device respectively.)
|
||||
*
|
||||
* @author martone@google.com (Andy Martone)
|
||||
*/
|
||||
|
||||
goog.provide('goog.labs.userAgent.browser');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.labs.userAgent.util');
|
||||
goog.require('goog.object');
|
||||
goog.require('goog.string');
|
||||
|
||||
|
||||
// TODO(nnaze): Refactor to remove excessive exclusion logic in matching
|
||||
// functions.
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the user's browser is Opera. Note: Chromium
|
||||
* based Opera (Opera 15+) is detected as Chrome to avoid unnecessary
|
||||
* special casing.
|
||||
* @private
|
||||
*/
|
||||
goog.labs.userAgent.browser.matchOpera_ = function() {
|
||||
return goog.labs.userAgent.util.matchUserAgent('Opera');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the user's browser is IE.
|
||||
* @private
|
||||
*/
|
||||
goog.labs.userAgent.browser.matchIE_ = function() {
|
||||
return goog.labs.userAgent.util.matchUserAgent('Trident') ||
|
||||
goog.labs.userAgent.util.matchUserAgent('MSIE');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the user's browser is Edge.
|
||||
* @private
|
||||
*/
|
||||
goog.labs.userAgent.browser.matchEdge_ = function() {
|
||||
return goog.labs.userAgent.util.matchUserAgent('Edge');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the user's browser is Firefox.
|
||||
* @private
|
||||
*/
|
||||
goog.labs.userAgent.browser.matchFirefox_ = function() {
|
||||
return goog.labs.userAgent.util.matchUserAgent('Firefox');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the user's browser is Safari.
|
||||
* @private
|
||||
*/
|
||||
goog.labs.userAgent.browser.matchSafari_ = function() {
|
||||
return goog.labs.userAgent.util.matchUserAgent('Safari') &&
|
||||
!(goog.labs.userAgent.browser.matchChrome_() ||
|
||||
goog.labs.userAgent.browser.matchCoast_() ||
|
||||
goog.labs.userAgent.browser.matchOpera_() ||
|
||||
goog.labs.userAgent.browser.matchEdge_() ||
|
||||
goog.labs.userAgent.browser.isSilk() ||
|
||||
goog.labs.userAgent.util.matchUserAgent('Android'));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the user's browser is Coast (Opera's Webkit-based
|
||||
* iOS browser).
|
||||
* @private
|
||||
*/
|
||||
goog.labs.userAgent.browser.matchCoast_ = function() {
|
||||
return goog.labs.userAgent.util.matchUserAgent('Coast');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the user's browser is iOS Webview.
|
||||
* @private
|
||||
*/
|
||||
goog.labs.userAgent.browser.matchIosWebview_ = function() {
|
||||
// iOS Webview does not show up as Chrome or Safari. Also check for Opera's
|
||||
// WebKit-based iOS browser, Coast.
|
||||
return (goog.labs.userAgent.util.matchUserAgent('iPad') ||
|
||||
goog.labs.userAgent.util.matchUserAgent('iPhone')) &&
|
||||
!goog.labs.userAgent.browser.matchSafari_() &&
|
||||
!goog.labs.userAgent.browser.matchChrome_() &&
|
||||
!goog.labs.userAgent.browser.matchCoast_() &&
|
||||
goog.labs.userAgent.util.matchUserAgent('AppleWebKit');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the user's browser is Chrome.
|
||||
* @private
|
||||
*/
|
||||
goog.labs.userAgent.browser.matchChrome_ = function() {
|
||||
return (goog.labs.userAgent.util.matchUserAgent('Chrome') ||
|
||||
goog.labs.userAgent.util.matchUserAgent('CriOS')) &&
|
||||
!goog.labs.userAgent.browser.matchEdge_();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the user's browser is the Android browser.
|
||||
* @private
|
||||
*/
|
||||
goog.labs.userAgent.browser.matchAndroidBrowser_ = function() {
|
||||
// Android can appear in the user agent string for Chrome on Android.
|
||||
// This is not the Android standalone browser if it does.
|
||||
return goog.labs.userAgent.util.matchUserAgent('Android') &&
|
||||
!(goog.labs.userAgent.browser.isChrome() ||
|
||||
goog.labs.userAgent.browser.isFirefox() ||
|
||||
goog.labs.userAgent.browser.isOpera() ||
|
||||
goog.labs.userAgent.browser.isSilk());
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the user's browser is Opera.
|
||||
*/
|
||||
goog.labs.userAgent.browser.isOpera = goog.labs.userAgent.browser.matchOpera_;
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the user's browser is IE.
|
||||
*/
|
||||
goog.labs.userAgent.browser.isIE = goog.labs.userAgent.browser.matchIE_;
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the user's browser is Edge.
|
||||
*/
|
||||
goog.labs.userAgent.browser.isEdge = goog.labs.userAgent.browser.matchEdge_;
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the user's browser is Firefox.
|
||||
*/
|
||||
goog.labs.userAgent.browser.isFirefox =
|
||||
goog.labs.userAgent.browser.matchFirefox_;
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the user's browser is Safari.
|
||||
*/
|
||||
goog.labs.userAgent.browser.isSafari = goog.labs.userAgent.browser.matchSafari_;
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the user's browser is Coast (Opera's Webkit-based
|
||||
* iOS browser).
|
||||
*/
|
||||
goog.labs.userAgent.browser.isCoast = goog.labs.userAgent.browser.matchCoast_;
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the user's browser is iOS Webview.
|
||||
*/
|
||||
goog.labs.userAgent.browser.isIosWebview =
|
||||
goog.labs.userAgent.browser.matchIosWebview_;
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the user's browser is Chrome.
|
||||
*/
|
||||
goog.labs.userAgent.browser.isChrome = goog.labs.userAgent.browser.matchChrome_;
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the user's browser is the Android browser.
|
||||
*/
|
||||
goog.labs.userAgent.browser.isAndroidBrowser =
|
||||
goog.labs.userAgent.browser.matchAndroidBrowser_;
|
||||
|
||||
|
||||
/**
|
||||
* For more information, see:
|
||||
* http://docs.aws.amazon.com/silk/latest/developerguide/user-agent.html
|
||||
* @return {boolean} Whether the user's browser is Silk.
|
||||
*/
|
||||
goog.labs.userAgent.browser.isSilk = function() {
|
||||
return goog.labs.userAgent.util.matchUserAgent('Silk');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {string} The browser version or empty string if version cannot be
|
||||
* determined. Note that for Internet Explorer, this returns the version of
|
||||
* the browser, not the version of the rendering engine. (IE 8 in
|
||||
* compatibility mode will return 8.0 rather than 7.0. To determine the
|
||||
* rendering engine version, look at document.documentMode instead. See
|
||||
* http://msdn.microsoft.com/en-us/library/cc196988(v=vs.85).aspx for more
|
||||
* details.)
|
||||
*/
|
||||
goog.labs.userAgent.browser.getVersion = function() {
|
||||
var userAgentString = goog.labs.userAgent.util.getUserAgent();
|
||||
// Special case IE since IE's version is inside the parenthesis and
|
||||
// without the '/'.
|
||||
if (goog.labs.userAgent.browser.isIE()) {
|
||||
return goog.labs.userAgent.browser.getIEVersion_(userAgentString);
|
||||
}
|
||||
|
||||
var versionTuples =
|
||||
goog.labs.userAgent.util.extractVersionTuples(userAgentString);
|
||||
|
||||
// Construct a map for easy lookup.
|
||||
var versionMap = {};
|
||||
goog.array.forEach(versionTuples, function(tuple) {
|
||||
// Note that the tuple is of length three, but we only care about the
|
||||
// first two.
|
||||
var key = tuple[0];
|
||||
var value = tuple[1];
|
||||
versionMap[key] = value;
|
||||
});
|
||||
|
||||
var versionMapHasKey = goog.partial(goog.object.containsKey, versionMap);
|
||||
|
||||
// Gives the value with the first key it finds, otherwise empty string.
|
||||
function lookUpValueWithKeys(keys) {
|
||||
var key = goog.array.find(keys, versionMapHasKey);
|
||||
return versionMap[key] || '';
|
||||
}
|
||||
|
||||
// Check Opera before Chrome since Opera 15+ has "Chrome" in the string.
|
||||
// See
|
||||
// http://my.opera.com/ODIN/blog/2013/07/15/opera-user-agent-strings-opera-15-and-beyond
|
||||
if (goog.labs.userAgent.browser.isOpera()) {
|
||||
// Opera 10 has Version/10.0 but Opera/9.8, so look for "Version" first.
|
||||
// Opera uses 'OPR' for more recent UAs.
|
||||
return lookUpValueWithKeys(['Version', 'Opera']);
|
||||
}
|
||||
|
||||
// Check Edge before Chrome since it has Chrome in the string.
|
||||
if (goog.labs.userAgent.browser.isEdge()) {
|
||||
return lookUpValueWithKeys(['Edge']);
|
||||
}
|
||||
|
||||
if (goog.labs.userAgent.browser.isChrome()) {
|
||||
return lookUpValueWithKeys(['Chrome', 'CriOS']);
|
||||
}
|
||||
|
||||
// Usually products browser versions are in the third tuple after "Mozilla"
|
||||
// and the engine.
|
||||
var tuple = versionTuples[2];
|
||||
return tuple && tuple[1] || '';
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string|number} version The version to check.
|
||||
* @return {boolean} Whether the browser version is higher or the same as the
|
||||
* given version.
|
||||
*/
|
||||
goog.labs.userAgent.browser.isVersionOrHigher = function(version) {
|
||||
return goog.string.compareVersions(
|
||||
goog.labs.userAgent.browser.getVersion(), version) >= 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Determines IE version. More information:
|
||||
* http://msdn.microsoft.com/en-us/library/ie/bg182625(v=vs.85).aspx#uaString
|
||||
* http://msdn.microsoft.com/en-us/library/hh869301(v=vs.85).aspx
|
||||
* http://blogs.msdn.com/b/ie/archive/2010/03/23/introducing-ie9-s-user-agent-string.aspx
|
||||
* http://blogs.msdn.com/b/ie/archive/2009/01/09/the-internet-explorer-8-user-agent-string-updated-edition.aspx
|
||||
*
|
||||
* @param {string} userAgent the User-Agent.
|
||||
* @return {string}
|
||||
* @private
|
||||
*/
|
||||
goog.labs.userAgent.browser.getIEVersion_ = function(userAgent) {
|
||||
// IE11 may identify itself as MSIE 9.0 or MSIE 10.0 due to an IE 11 upgrade
|
||||
// bug. Example UA:
|
||||
// Mozilla/5.0 (MSIE 9.0; Windows NT 6.1; WOW64; Trident/7.0; rv:11.0)
|
||||
// like Gecko.
|
||||
// See http://www.whatismybrowser.com/developers/unknown-user-agent-fragments.
|
||||
var rv = /rv: *([\d\.]*)/.exec(userAgent);
|
||||
if (rv && rv[1]) {
|
||||
return rv[1];
|
||||
}
|
||||
|
||||
var version = '';
|
||||
var msie = /MSIE +([\d\.]+)/.exec(userAgent);
|
||||
if (msie && msie[1]) {
|
||||
// IE in compatibility mode usually identifies itself as MSIE 7.0; in this
|
||||
// case, use the Trident version to determine the version of IE. For more
|
||||
// details, see the links above.
|
||||
var tridentVersion = /Trident\/(\d.\d)/.exec(userAgent);
|
||||
if (msie[1] == '7.0') {
|
||||
if (tridentVersion && tridentVersion[1]) {
|
||||
switch (tridentVersion[1]) {
|
||||
case '4.0':
|
||||
version = '8.0';
|
||||
break;
|
||||
case '5.0':
|
||||
version = '9.0';
|
||||
break;
|
||||
case '6.0':
|
||||
version = '10.0';
|
||||
break;
|
||||
case '7.0':
|
||||
version = '11.0';
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
version = '7.0';
|
||||
}
|
||||
} else {
|
||||
version = msie[1];
|
||||
}
|
||||
}
|
||||
return version;
|
||||
};
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
// Copyright 2013 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 Closure user agent detection.
|
||||
* @see http://en.wikipedia.org/wiki/User_agent
|
||||
* For more information on browser brand, platform, or device see the other
|
||||
* sub-namespaces in goog.labs.userAgent (browser, platform, and device).
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.labs.userAgent.engine');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.labs.userAgent.util');
|
||||
goog.require('goog.string');
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the rendering engine is Presto.
|
||||
*/
|
||||
goog.labs.userAgent.engine.isPresto = function() {
|
||||
return goog.labs.userAgent.util.matchUserAgent('Presto');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the rendering engine is Trident.
|
||||
*/
|
||||
goog.labs.userAgent.engine.isTrident = function() {
|
||||
// IE only started including the Trident token in IE8.
|
||||
return goog.labs.userAgent.util.matchUserAgent('Trident') ||
|
||||
goog.labs.userAgent.util.matchUserAgent('MSIE');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the rendering engine is Edge.
|
||||
*/
|
||||
goog.labs.userAgent.engine.isEdge = function() {
|
||||
return goog.labs.userAgent.util.matchUserAgent('Edge');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the rendering engine is WebKit.
|
||||
*/
|
||||
goog.labs.userAgent.engine.isWebKit = function() {
|
||||
return goog.labs.userAgent.util.matchUserAgentIgnoreCase('WebKit') &&
|
||||
!goog.labs.userAgent.engine.isEdge();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the rendering engine is Gecko.
|
||||
*/
|
||||
goog.labs.userAgent.engine.isGecko = function() {
|
||||
return goog.labs.userAgent.util.matchUserAgent('Gecko') &&
|
||||
!goog.labs.userAgent.engine.isWebKit() &&
|
||||
!goog.labs.userAgent.engine.isTrident() &&
|
||||
!goog.labs.userAgent.engine.isEdge();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {string} The rendering engine's version or empty string if version
|
||||
* can't be determined.
|
||||
*/
|
||||
goog.labs.userAgent.engine.getVersion = function() {
|
||||
var userAgentString = goog.labs.userAgent.util.getUserAgent();
|
||||
if (userAgentString) {
|
||||
var tuples = goog.labs.userAgent.util.extractVersionTuples(userAgentString);
|
||||
|
||||
var engineTuple = goog.labs.userAgent.engine.getEngineTuple_(tuples);
|
||||
if (engineTuple) {
|
||||
// In Gecko, the version string is either in the browser info or the
|
||||
// Firefox version. See Gecko user agent string reference:
|
||||
// http://goo.gl/mULqa
|
||||
if (engineTuple[0] == 'Gecko') {
|
||||
return goog.labs.userAgent.engine.getVersionForKey_(tuples, 'Firefox');
|
||||
}
|
||||
|
||||
return engineTuple[1];
|
||||
}
|
||||
|
||||
// MSIE has only one version identifier, and the Trident version is
|
||||
// specified in the parenthetical. IE Edge is covered in the engine tuple
|
||||
// detection.
|
||||
var browserTuple = tuples[0];
|
||||
var info;
|
||||
if (browserTuple && (info = browserTuple[2])) {
|
||||
var match = /Trident\/([^\s;]+)/.exec(info);
|
||||
if (match) {
|
||||
return match[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {!Array<!Array<string>>} tuples Extracted version tuples.
|
||||
* @return {!Array<string>|undefined} The engine tuple or undefined if not
|
||||
* found.
|
||||
* @private
|
||||
*/
|
||||
goog.labs.userAgent.engine.getEngineTuple_ = function(tuples) {
|
||||
if (!goog.labs.userAgent.engine.isEdge()) {
|
||||
return tuples[1];
|
||||
}
|
||||
for (var i = 0; i < tuples.length; i++) {
|
||||
var tuple = tuples[i];
|
||||
if (tuple[0] == 'Edge') {
|
||||
return tuple;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string|number} version The version to check.
|
||||
* @return {boolean} Whether the rendering engine version is higher or the same
|
||||
* as the given version.
|
||||
*/
|
||||
goog.labs.userAgent.engine.isVersionOrHigher = function(version) {
|
||||
return goog.string.compareVersions(
|
||||
goog.labs.userAgent.engine.getVersion(), version) >= 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {!Array<!Array<string>>} tuples Version tuples.
|
||||
* @param {string} key The key to look for.
|
||||
* @return {string} The version string of the given key, if present.
|
||||
* Otherwise, the empty string.
|
||||
* @private
|
||||
*/
|
||||
goog.labs.userAgent.engine.getVersionForKey_ = function(tuples, key) {
|
||||
// TODO(nnaze): Move to util if useful elsewhere.
|
||||
|
||||
var pair = goog.array.find(tuples, function(pair) { return key == pair[0]; });
|
||||
|
||||
return pair && pair[1] || '';
|
||||
};
|
||||
|
|
@ -0,0 +1,160 @@
|
|||
// Copyright 2013 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 Closure user agent platform detection.
|
||||
* @see <a href="http://www.useragentstring.com/">User agent strings</a>
|
||||
* For more information on browser brand, rendering engine, or device see the
|
||||
* other sub-namespaces in goog.labs.userAgent (browser, engine, and device
|
||||
* respectively).
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.labs.userAgent.platform');
|
||||
|
||||
goog.require('goog.labs.userAgent.util');
|
||||
goog.require('goog.string');
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the platform is Android.
|
||||
*/
|
||||
goog.labs.userAgent.platform.isAndroid = function() {
|
||||
return goog.labs.userAgent.util.matchUserAgent('Android');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the platform is iPod.
|
||||
*/
|
||||
goog.labs.userAgent.platform.isIpod = function() {
|
||||
return goog.labs.userAgent.util.matchUserAgent('iPod');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the platform is iPhone.
|
||||
*/
|
||||
goog.labs.userAgent.platform.isIphone = function() {
|
||||
return goog.labs.userAgent.util.matchUserAgent('iPhone') &&
|
||||
!goog.labs.userAgent.util.matchUserAgent('iPod') &&
|
||||
!goog.labs.userAgent.util.matchUserAgent('iPad');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the platform is iPad.
|
||||
*/
|
||||
goog.labs.userAgent.platform.isIpad = function() {
|
||||
return goog.labs.userAgent.util.matchUserAgent('iPad');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the platform is iOS.
|
||||
*/
|
||||
goog.labs.userAgent.platform.isIos = function() {
|
||||
return goog.labs.userAgent.platform.isIphone() ||
|
||||
goog.labs.userAgent.platform.isIpad() ||
|
||||
goog.labs.userAgent.platform.isIpod();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the platform is Mac.
|
||||
*/
|
||||
goog.labs.userAgent.platform.isMacintosh = function() {
|
||||
return goog.labs.userAgent.util.matchUserAgent('Macintosh');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Note: ChromeOS is not considered to be Linux as it does not report itself
|
||||
* as Linux in the user agent string.
|
||||
* @return {boolean} Whether the platform is Linux.
|
||||
*/
|
||||
goog.labs.userAgent.platform.isLinux = function() {
|
||||
return goog.labs.userAgent.util.matchUserAgent('Linux');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the platform is Windows.
|
||||
*/
|
||||
goog.labs.userAgent.platform.isWindows = function() {
|
||||
return goog.labs.userAgent.util.matchUserAgent('Windows');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the platform is ChromeOS.
|
||||
*/
|
||||
goog.labs.userAgent.platform.isChromeOS = function() {
|
||||
return goog.labs.userAgent.util.matchUserAgent('CrOS');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The version of the platform. We only determine the version for Windows,
|
||||
* Mac, and Chrome OS. It doesn't make much sense on Linux. For Windows, we only
|
||||
* look at the NT version. Non-NT-based versions (e.g. 95, 98, etc.) are given
|
||||
* version 0.0.
|
||||
*
|
||||
* @return {string} The platform version or empty string if version cannot be
|
||||
* determined.
|
||||
*/
|
||||
goog.labs.userAgent.platform.getVersion = function() {
|
||||
var userAgentString = goog.labs.userAgent.util.getUserAgent();
|
||||
var version = '', re;
|
||||
if (goog.labs.userAgent.platform.isWindows()) {
|
||||
re = /Windows (?:NT|Phone) ([0-9.]+)/;
|
||||
var match = re.exec(userAgentString);
|
||||
if (match) {
|
||||
version = match[1];
|
||||
} else {
|
||||
version = '0.0';
|
||||
}
|
||||
} else if (goog.labs.userAgent.platform.isIos()) {
|
||||
re = /(?:iPhone|iPod|iPad|CPU)\s+OS\s+(\S+)/;
|
||||
var match = re.exec(userAgentString);
|
||||
// Report the version as x.y.z and not x_y_z
|
||||
version = match && match[1].replace(/_/g, '.');
|
||||
} else if (goog.labs.userAgent.platform.isMacintosh()) {
|
||||
re = /Mac OS X ([0-9_.]+)/;
|
||||
var match = re.exec(userAgentString);
|
||||
// Note: some old versions of Camino do not report an OSX version.
|
||||
// Default to 10.
|
||||
version = match ? match[1].replace(/_/g, '.') : '10';
|
||||
} else if (goog.labs.userAgent.platform.isAndroid()) {
|
||||
re = /Android\s+([^\);]+)(\)|;)/;
|
||||
var match = re.exec(userAgentString);
|
||||
version = match && match[1];
|
||||
} else if (goog.labs.userAgent.platform.isChromeOS()) {
|
||||
re = /(?:CrOS\s+(?:i686|x86_64)\s+([0-9.]+))/;
|
||||
var match = re.exec(userAgentString);
|
||||
version = match && match[1];
|
||||
}
|
||||
return version || '';
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string|number} version The version to check.
|
||||
* @return {boolean} Whether the browser version is higher or the same as the
|
||||
* given version.
|
||||
*/
|
||||
goog.labs.userAgent.platform.isVersionOrHigher = function(version) {
|
||||
return goog.string.compareVersions(
|
||||
goog.labs.userAgent.platform.getVersion(), version) >= 0;
|
||||
};
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
// Copyright 2013 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 Utilities used by goog.labs.userAgent tools. These functions
|
||||
* should not be used outside of goog.labs.userAgent.*.
|
||||
*
|
||||
*
|
||||
* @author nnaze@google.com (Nathan Naze)
|
||||
*/
|
||||
|
||||
goog.provide('goog.labs.userAgent.util');
|
||||
|
||||
goog.require('goog.string');
|
||||
|
||||
|
||||
/**
|
||||
* Gets the native userAgent string from navigator if it exists.
|
||||
* If navigator or navigator.userAgent string is missing, returns an empty
|
||||
* string.
|
||||
* @return {string}
|
||||
* @private
|
||||
*/
|
||||
goog.labs.userAgent.util.getNativeUserAgentString_ = function() {
|
||||
var navigator = goog.labs.userAgent.util.getNavigator_();
|
||||
if (navigator) {
|
||||
var userAgent = navigator.userAgent;
|
||||
if (userAgent) {
|
||||
return userAgent;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Getter for the native navigator.
|
||||
* This is a separate function so it can be stubbed out in testing.
|
||||
* @return {Navigator}
|
||||
* @private
|
||||
*/
|
||||
goog.labs.userAgent.util.getNavigator_ = function() {
|
||||
return goog.global.navigator;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A possible override for applications which wish to not check
|
||||
* navigator.userAgent but use a specified value for detection instead.
|
||||
* @private {string}
|
||||
*/
|
||||
goog.labs.userAgent.util.userAgent_ =
|
||||
goog.labs.userAgent.util.getNativeUserAgentString_();
|
||||
|
||||
|
||||
/**
|
||||
* Applications may override browser detection on the built in
|
||||
* navigator.userAgent object by setting this string. Set to null to use the
|
||||
* browser object instead.
|
||||
* @param {?string=} opt_userAgent The User-Agent override.
|
||||
*/
|
||||
goog.labs.userAgent.util.setUserAgent = function(opt_userAgent) {
|
||||
goog.labs.userAgent.util.userAgent_ =
|
||||
opt_userAgent || goog.labs.userAgent.util.getNativeUserAgentString_();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {string} The user agent string.
|
||||
*/
|
||||
goog.labs.userAgent.util.getUserAgent = function() {
|
||||
return goog.labs.userAgent.util.userAgent_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} str
|
||||
* @return {boolean} Whether the user agent contains the given string.
|
||||
*/
|
||||
goog.labs.userAgent.util.matchUserAgent = function(str) {
|
||||
var userAgent = goog.labs.userAgent.util.getUserAgent();
|
||||
return goog.string.contains(userAgent, str);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} str
|
||||
* @return {boolean} Whether the user agent contains the given string, ignoring
|
||||
* case.
|
||||
*/
|
||||
goog.labs.userAgent.util.matchUserAgentIgnoreCase = function(str) {
|
||||
var userAgent = goog.labs.userAgent.util.getUserAgent();
|
||||
return goog.string.caseInsensitiveContains(userAgent, str);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parses the user agent into tuples for each section.
|
||||
* @param {string} userAgent
|
||||
* @return {!Array<!Array<string>>} Tuples of key, version, and the contents
|
||||
* of the parenthetical.
|
||||
*/
|
||||
goog.labs.userAgent.util.extractVersionTuples = function(userAgent) {
|
||||
// Matches each section of a user agent string.
|
||||
// Example UA:
|
||||
// Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us)
|
||||
// AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405
|
||||
// This has three version tuples: Mozilla, AppleWebKit, and Mobile.
|
||||
|
||||
var versionRegExp = new RegExp(
|
||||
// Key. Note that a key may have a space.
|
||||
// (i.e. 'Mobile Safari' in 'Mobile Safari/5.0')
|
||||
'(\\w[\\w ]+)' +
|
||||
|
||||
'/' + // slash
|
||||
'([^\\s]+)' + // version (i.e. '5.0b')
|
||||
'\\s*' + // whitespace
|
||||
'(?:\\((.*?)\\))?', // parenthetical info. parentheses not matched.
|
||||
'g');
|
||||
|
||||
var data = [];
|
||||
var match;
|
||||
|
||||
// Iterate and collect the version tuples. Each iteration will be the
|
||||
// next regex match.
|
||||
while (match = versionRegExp.exec(userAgent)) {
|
||||
data.push([
|
||||
match[1], // key
|
||||
match[2], // value
|
||||
// || undefined as this is not undefined in IE7 and IE8
|
||||
match[3] || undefined // info
|
||||
]);
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
197
resources/public/target/cljsbuild-compiler-1/goog/log/log.js
Normal file
197
resources/public/target/cljsbuild-compiler-1/goog/log/log.js
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
// Copyright 2013 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 Basic strippable logging definitions.
|
||||
* @see http://go/closurelogging
|
||||
*
|
||||
* @author johnlenz@google.com (John Lenz)
|
||||
*/
|
||||
|
||||
goog.provide('goog.log');
|
||||
goog.provide('goog.log.Level');
|
||||
goog.provide('goog.log.LogRecord');
|
||||
goog.provide('goog.log.Logger');
|
||||
|
||||
goog.require('goog.debug');
|
||||
goog.require('goog.debug.LogManager');
|
||||
goog.require('goog.debug.LogRecord');
|
||||
goog.require('goog.debug.Logger');
|
||||
|
||||
|
||||
/** @define {boolean} Whether logging is enabled. */
|
||||
goog.define('goog.log.ENABLED', goog.debug.LOGGING_ENABLED);
|
||||
|
||||
|
||||
/** @const {string} */
|
||||
goog.log.ROOT_LOGGER_NAME = goog.debug.Logger.ROOT_LOGGER_NAME;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @final
|
||||
*/
|
||||
goog.log.Logger = goog.debug.Logger;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @final
|
||||
*/
|
||||
goog.log.Level = goog.debug.Logger.Level;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @final
|
||||
*/
|
||||
goog.log.LogRecord = goog.debug.LogRecord;
|
||||
|
||||
|
||||
/**
|
||||
* Finds or creates a logger for a named subsystem. If a logger has already been
|
||||
* created with the given name it is returned. Otherwise a new logger is
|
||||
* created. If a new logger is created its log level will be configured based
|
||||
* on the goog.debug.LogManager configuration and it will configured to also
|
||||
* send logging output to its parent's handlers.
|
||||
* @see goog.debug.LogManager
|
||||
*
|
||||
* @param {string} name A name for the logger. This should be a dot-separated
|
||||
* name and should normally be based on the package name or class name of
|
||||
* the subsystem, such as goog.net.BrowserChannel.
|
||||
* @param {goog.log.Level=} opt_level If provided, override the
|
||||
* default logging level with the provided level.
|
||||
* @return {goog.log.Logger} The named logger or null if logging is disabled.
|
||||
*/
|
||||
goog.log.getLogger = function(name, opt_level) {
|
||||
if (goog.log.ENABLED) {
|
||||
var logger = goog.debug.LogManager.getLogger(name);
|
||||
if (opt_level && logger) {
|
||||
logger.setLevel(opt_level);
|
||||
}
|
||||
return logger;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// TODO(johnlenz): try to tighten the types to these functions.
|
||||
/**
|
||||
* Adds a handler to the logger. This doesn't use the event system because
|
||||
* we want to be able to add logging to the event system.
|
||||
* @param {goog.log.Logger} logger
|
||||
* @param {Function} handler Handler function to add.
|
||||
*/
|
||||
goog.log.addHandler = function(logger, handler) {
|
||||
if (goog.log.ENABLED && logger) {
|
||||
logger.addHandler(handler);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes a handler from the logger. This doesn't use the event system because
|
||||
* we want to be able to add logging to the event system.
|
||||
* @param {goog.log.Logger} logger
|
||||
* @param {Function} handler Handler function to remove.
|
||||
* @return {boolean} Whether the handler was removed.
|
||||
*/
|
||||
goog.log.removeHandler = function(logger, handler) {
|
||||
if (goog.log.ENABLED && logger) {
|
||||
return logger.removeHandler(handler);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Logs a message. If the logger is currently enabled for the
|
||||
* given message level then the given message is forwarded to all the
|
||||
* registered output Handler objects.
|
||||
* @param {goog.log.Logger} logger
|
||||
* @param {goog.log.Level} level One of the level identifiers.
|
||||
* @param {goog.debug.Loggable} msg The message to log.
|
||||
* @param {Error|Object=} opt_exception An exception associated with the
|
||||
* message.
|
||||
*/
|
||||
goog.log.log = function(logger, level, msg, opt_exception) {
|
||||
if (goog.log.ENABLED && logger) {
|
||||
logger.log(level, msg, opt_exception);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Logs a message at the Level.SEVERE level.
|
||||
* If the logger is currently enabled for the given message level then the
|
||||
* given message is forwarded to all the registered output Handler objects.
|
||||
* @param {goog.log.Logger} logger
|
||||
* @param {goog.debug.Loggable} msg The message to log.
|
||||
* @param {Error=} opt_exception An exception associated with the message.
|
||||
*/
|
||||
goog.log.error = function(logger, msg, opt_exception) {
|
||||
if (goog.log.ENABLED && logger) {
|
||||
logger.severe(msg, opt_exception);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Logs a message at the Level.WARNING level.
|
||||
* If the logger is currently enabled for the given message level then the
|
||||
* given message is forwarded to all the registered output Handler objects.
|
||||
* @param {goog.log.Logger} logger
|
||||
* @param {goog.debug.Loggable} msg The message to log.
|
||||
* @param {Error=} opt_exception An exception associated with the message.
|
||||
*/
|
||||
goog.log.warning = function(logger, msg, opt_exception) {
|
||||
if (goog.log.ENABLED && logger) {
|
||||
logger.warning(msg, opt_exception);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Logs a message at the Level.INFO level.
|
||||
* If the logger is currently enabled for the given message level then the
|
||||
* given message is forwarded to all the registered output Handler objects.
|
||||
* @param {goog.log.Logger} logger
|
||||
* @param {goog.debug.Loggable} msg The message to log.
|
||||
* @param {Error=} opt_exception An exception associated with the message.
|
||||
*/
|
||||
goog.log.info = function(logger, msg, opt_exception) {
|
||||
if (goog.log.ENABLED && logger) {
|
||||
logger.info(msg, opt_exception);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Logs a message at the Level.Fine level.
|
||||
* If the logger is currently enabled for the given message level then the
|
||||
* given message is forwarded to all the registered output Handler objects.
|
||||
* @param {goog.log.Logger} logger
|
||||
* @param {goog.debug.Loggable} msg The message to log.
|
||||
* @param {Error=} opt_exception An exception associated with the message.
|
||||
*/
|
||||
goog.log.fine = function(logger, msg, opt_exception) {
|
||||
if (goog.log.ENABLED && logger) {
|
||||
logger.fine(msg, opt_exception);
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,279 @@
|
|||
// Copyright 2006 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 A utility class for representing two-dimensional positions.
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.math.Coordinate');
|
||||
|
||||
goog.require('goog.math');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Class for representing coordinates and positions.
|
||||
* @param {number=} opt_x Left, defaults to 0.
|
||||
* @param {number=} opt_y Top, defaults to 0.
|
||||
* @struct
|
||||
* @constructor
|
||||
*/
|
||||
goog.math.Coordinate = function(opt_x, opt_y) {
|
||||
/**
|
||||
* X-value
|
||||
* @type {number}
|
||||
*/
|
||||
this.x = goog.isDef(opt_x) ? opt_x : 0;
|
||||
|
||||
/**
|
||||
* Y-value
|
||||
* @type {number}
|
||||
*/
|
||||
this.y = goog.isDef(opt_y) ? opt_y : 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns a new copy of the coordinate.
|
||||
* @return {!goog.math.Coordinate} A clone of this coordinate.
|
||||
*/
|
||||
goog.math.Coordinate.prototype.clone = function() {
|
||||
return new goog.math.Coordinate(this.x, this.y);
|
||||
};
|
||||
|
||||
|
||||
if (goog.DEBUG) {
|
||||
/**
|
||||
* Returns a nice string representing the coordinate.
|
||||
* @return {string} In the form (50, 73).
|
||||
* @override
|
||||
*/
|
||||
goog.math.Coordinate.prototype.toString = function() {
|
||||
return '(' + this.x + ', ' + this.y + ')';
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns whether the specified value is equal to this coordinate.
|
||||
* @param {*} other Some other value.
|
||||
* @return {boolean} Whether the specified value is equal to this coordinate.
|
||||
*/
|
||||
goog.math.Coordinate.prototype.equals = function(other) {
|
||||
return other instanceof goog.math.Coordinate &&
|
||||
goog.math.Coordinate.equals(this, other);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Compares coordinates for equality.
|
||||
* @param {goog.math.Coordinate} a A Coordinate.
|
||||
* @param {goog.math.Coordinate} b A Coordinate.
|
||||
* @return {boolean} True iff the coordinates are equal, or if both are null.
|
||||
*/
|
||||
goog.math.Coordinate.equals = function(a, b) {
|
||||
if (a == b) {
|
||||
return true;
|
||||
}
|
||||
if (!a || !b) {
|
||||
return false;
|
||||
}
|
||||
return a.x == b.x && a.y == b.y;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the distance between two coordinates.
|
||||
* @param {!goog.math.Coordinate} a A Coordinate.
|
||||
* @param {!goog.math.Coordinate} b A Coordinate.
|
||||
* @return {number} The distance between {@code a} and {@code b}.
|
||||
*/
|
||||
goog.math.Coordinate.distance = function(a, b) {
|
||||
var dx = a.x - b.x;
|
||||
var dy = a.y - b.y;
|
||||
return Math.sqrt(dx * dx + dy * dy);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the magnitude of a coordinate.
|
||||
* @param {!goog.math.Coordinate} a A Coordinate.
|
||||
* @return {number} The distance between the origin and {@code a}.
|
||||
*/
|
||||
goog.math.Coordinate.magnitude = function(a) {
|
||||
return Math.sqrt(a.x * a.x + a.y * a.y);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the angle from the origin to a coordinate.
|
||||
* @param {!goog.math.Coordinate} a A Coordinate.
|
||||
* @return {number} The angle, in degrees, clockwise from the positive X
|
||||
* axis to {@code a}.
|
||||
*/
|
||||
goog.math.Coordinate.azimuth = function(a) {
|
||||
return goog.math.angle(0, 0, a.x, a.y);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the squared distance between two coordinates. Squared distances can
|
||||
* be used for comparisons when the actual value is not required.
|
||||
*
|
||||
* Performance note: eliminating the square root is an optimization often used
|
||||
* in lower-level languages, but the speed difference is not nearly as
|
||||
* pronounced in JavaScript (only a few percent.)
|
||||
*
|
||||
* @param {!goog.math.Coordinate} a A Coordinate.
|
||||
* @param {!goog.math.Coordinate} b A Coordinate.
|
||||
* @return {number} The squared distance between {@code a} and {@code b}.
|
||||
*/
|
||||
goog.math.Coordinate.squaredDistance = function(a, b) {
|
||||
var dx = a.x - b.x;
|
||||
var dy = a.y - b.y;
|
||||
return dx * dx + dy * dy;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the difference between two coordinates as a new
|
||||
* goog.math.Coordinate.
|
||||
* @param {!goog.math.Coordinate} a A Coordinate.
|
||||
* @param {!goog.math.Coordinate} b A Coordinate.
|
||||
* @return {!goog.math.Coordinate} A Coordinate representing the difference
|
||||
* between {@code a} and {@code b}.
|
||||
*/
|
||||
goog.math.Coordinate.difference = function(a, b) {
|
||||
return new goog.math.Coordinate(a.x - b.x, a.y - b.y);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the sum of two coordinates as a new goog.math.Coordinate.
|
||||
* @param {!goog.math.Coordinate} a A Coordinate.
|
||||
* @param {!goog.math.Coordinate} b A Coordinate.
|
||||
* @return {!goog.math.Coordinate} A Coordinate representing the sum of the two
|
||||
* coordinates.
|
||||
*/
|
||||
goog.math.Coordinate.sum = function(a, b) {
|
||||
return new goog.math.Coordinate(a.x + b.x, a.y + b.y);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Rounds the x and y fields to the next larger integer values.
|
||||
* @return {!goog.math.Coordinate} This coordinate with ceil'd fields.
|
||||
*/
|
||||
goog.math.Coordinate.prototype.ceil = function() {
|
||||
this.x = Math.ceil(this.x);
|
||||
this.y = Math.ceil(this.y);
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Rounds the x and y fields to the next smaller integer values.
|
||||
* @return {!goog.math.Coordinate} This coordinate with floored fields.
|
||||
*/
|
||||
goog.math.Coordinate.prototype.floor = function() {
|
||||
this.x = Math.floor(this.x);
|
||||
this.y = Math.floor(this.y);
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Rounds the x and y fields to the nearest integer values.
|
||||
* @return {!goog.math.Coordinate} This coordinate with rounded fields.
|
||||
*/
|
||||
goog.math.Coordinate.prototype.round = function() {
|
||||
this.x = Math.round(this.x);
|
||||
this.y = Math.round(this.y);
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Translates this box by the given offsets. If a {@code goog.math.Coordinate}
|
||||
* is given, then the x and y values are translated by the coordinate's x and y.
|
||||
* Otherwise, x and y are translated by {@code tx} and {@code opt_ty}
|
||||
* respectively.
|
||||
* @param {number|goog.math.Coordinate} tx The value to translate x by or the
|
||||
* the coordinate to translate this coordinate by.
|
||||
* @param {number=} opt_ty The value to translate y by.
|
||||
* @return {!goog.math.Coordinate} This coordinate after translating.
|
||||
*/
|
||||
goog.math.Coordinate.prototype.translate = function(tx, opt_ty) {
|
||||
if (tx instanceof goog.math.Coordinate) {
|
||||
this.x += tx.x;
|
||||
this.y += tx.y;
|
||||
} else {
|
||||
this.x += Number(tx);
|
||||
if (goog.isNumber(opt_ty)) {
|
||||
this.y += opt_ty;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Scales this coordinate by the given scale factors. The x and y values are
|
||||
* scaled by {@code sx} and {@code opt_sy} respectively. If {@code opt_sy}
|
||||
* is not given, then {@code sx} is used for both x and y.
|
||||
* @param {number} sx The scale factor to use for the x dimension.
|
||||
* @param {number=} opt_sy The scale factor to use for the y dimension.
|
||||
* @return {!goog.math.Coordinate} This coordinate after scaling.
|
||||
*/
|
||||
goog.math.Coordinate.prototype.scale = function(sx, opt_sy) {
|
||||
var sy = goog.isNumber(opt_sy) ? opt_sy : sx;
|
||||
this.x *= sx;
|
||||
this.y *= sy;
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Rotates this coordinate clockwise about the origin (or, optionally, the given
|
||||
* center) by the given angle, in radians.
|
||||
* @param {number} radians The angle by which to rotate this coordinate
|
||||
* clockwise about the given center, in radians.
|
||||
* @param {!goog.math.Coordinate=} opt_center The center of rotation. Defaults
|
||||
* to (0, 0) if not given.
|
||||
*/
|
||||
goog.math.Coordinate.prototype.rotateRadians = function(radians, opt_center) {
|
||||
var center = opt_center || new goog.math.Coordinate(0, 0);
|
||||
|
||||
var x = this.x;
|
||||
var y = this.y;
|
||||
var cos = Math.cos(radians);
|
||||
var sin = Math.sin(radians);
|
||||
|
||||
this.x = (x - center.x) * cos - (y - center.y) * sin + center.x;
|
||||
this.y = (x - center.x) * sin + (y - center.y) * cos + center.y;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Rotates this coordinate clockwise about the origin (or, optionally, the given
|
||||
* center) by the given angle, in degrees.
|
||||
* @param {number} degrees The angle by which to rotate this coordinate
|
||||
* clockwise about the given center, in degrees.
|
||||
* @param {!goog.math.Coordinate=} opt_center The center of rotation. Defaults
|
||||
* to (0, 0) if not given.
|
||||
*/
|
||||
goog.math.Coordinate.prototype.rotateDegrees = function(degrees, opt_center) {
|
||||
this.rotateRadians(goog.math.toRadians(degrees), opt_center);
|
||||
};
|
||||
|
|
@ -0,0 +1,808 @@
|
|||
// Copyright 2009 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 an Integer class for representing (potentially)
|
||||
* infinite length two's-complement integer values.
|
||||
*
|
||||
* For the specific case of 64-bit integers, use goog.math.Long, which is more
|
||||
* efficient.
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.math.Integer');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a two's-complement integer an array containing bits of the
|
||||
* integer in 32-bit (signed) pieces, given in little-endian order (i.e.,
|
||||
* lowest-order bits in the first piece), and the sign of -1 or 0.
|
||||
*
|
||||
* See the from* functions below for other convenient ways of constructing
|
||||
* Integers.
|
||||
*
|
||||
* The internal representation of an integer is an array of 32-bit signed
|
||||
* pieces, along with a sign (0 or -1) that indicates the contents of all the
|
||||
* other 32-bit pieces out to infinity. We use 32-bit pieces because these are
|
||||
* the size of integers on which Javascript performs bit-operations. For
|
||||
* operations like addition and multiplication, we split each number into 16-bit
|
||||
* pieces, which can easily be multiplied within Javascript's floating-point
|
||||
* representation without overflow or change in sign.
|
||||
*
|
||||
* @struct
|
||||
* @constructor
|
||||
* @param {Array<number>} bits Array containing the bits of the number.
|
||||
* @param {number} sign The sign of the number: -1 for negative and 0 positive.
|
||||
* @final
|
||||
*/
|
||||
goog.math.Integer = function(bits, sign) {
|
||||
/**
|
||||
* @type {!Array<number>}
|
||||
* @private
|
||||
*/
|
||||
this.bits_ = [];
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.sign_ = sign;
|
||||
|
||||
// Copy the 32-bit signed integer values passed in. We prune out those at the
|
||||
// top that equal the sign since they are redundant.
|
||||
var top = true;
|
||||
for (var i = bits.length - 1; i >= 0; i--) {
|
||||
var val = bits[i] | 0;
|
||||
if (!top || val != sign) {
|
||||
this.bits_[i] = val;
|
||||
top = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// NOTE: Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the
|
||||
// from* methods on which they depend.
|
||||
|
||||
|
||||
/**
|
||||
* A cache of the Integer representations of small integer values.
|
||||
* @type {!Object}
|
||||
* @private
|
||||
*/
|
||||
goog.math.Integer.IntCache_ = {};
|
||||
|
||||
|
||||
/**
|
||||
* Returns an Integer representing the given (32-bit) integer value.
|
||||
* @param {number} value A 32-bit integer value.
|
||||
* @return {!goog.math.Integer} The corresponding Integer value.
|
||||
*/
|
||||
goog.math.Integer.fromInt = function(value) {
|
||||
if (-128 <= value && value < 128) {
|
||||
var cachedObj = goog.math.Integer.IntCache_[value];
|
||||
if (cachedObj) {
|
||||
return cachedObj;
|
||||
}
|
||||
}
|
||||
|
||||
var obj = new goog.math.Integer([value | 0], value < 0 ? -1 : 0);
|
||||
if (-128 <= value && value < 128) {
|
||||
goog.math.Integer.IntCache_[value] = obj;
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns an Integer representing the given value, provided that it is a finite
|
||||
* number. Otherwise, zero is returned.
|
||||
* @param {number} value The value in question.
|
||||
* @return {!goog.math.Integer} The corresponding Integer value.
|
||||
*/
|
||||
goog.math.Integer.fromNumber = function(value) {
|
||||
if (isNaN(value) || !isFinite(value)) {
|
||||
return goog.math.Integer.ZERO;
|
||||
} else if (value < 0) {
|
||||
return goog.math.Integer.fromNumber(-value).negate();
|
||||
} else {
|
||||
var bits = [];
|
||||
var pow = 1;
|
||||
for (var i = 0; value >= pow; i++) {
|
||||
bits[i] = (value / pow) | 0;
|
||||
pow *= goog.math.Integer.TWO_PWR_32_DBL_;
|
||||
}
|
||||
return new goog.math.Integer(bits, 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns a Integer representing the value that comes by concatenating the
|
||||
* given entries, each is assumed to be 32 signed bits, given in little-endian
|
||||
* order (lowest order bits in the lowest index), and sign-extending the highest
|
||||
* order 32-bit value.
|
||||
* @param {Array<number>} bits The bits of the number, in 32-bit signed pieces,
|
||||
* in little-endian order.
|
||||
* @return {!goog.math.Integer} The corresponding Integer value.
|
||||
*/
|
||||
goog.math.Integer.fromBits = function(bits) {
|
||||
var high = bits[bits.length - 1];
|
||||
return new goog.math.Integer(bits, high & (1 << 31) ? -1 : 0);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns an Integer representation of the given string, written using the
|
||||
* given radix.
|
||||
* @param {string} str The textual representation of the Integer.
|
||||
* @param {number=} opt_radix The radix in which the text is written.
|
||||
* @return {!goog.math.Integer} The corresponding Integer value.
|
||||
*/
|
||||
goog.math.Integer.fromString = function(str, opt_radix) {
|
||||
if (str.length == 0) {
|
||||
throw Error('number format error: empty string');
|
||||
}
|
||||
|
||||
var radix = opt_radix || 10;
|
||||
if (radix < 2 || 36 < radix) {
|
||||
throw Error('radix out of range: ' + radix);
|
||||
}
|
||||
|
||||
if (str.charAt(0) == '-') {
|
||||
return goog.math.Integer.fromString(str.substring(1), radix).negate();
|
||||
} else if (str.indexOf('-') >= 0) {
|
||||
throw Error('number format error: interior "-" character');
|
||||
}
|
||||
|
||||
// Do several (8) digits each time through the loop, so as to
|
||||
// minimize the calls to the very expensive emulated div.
|
||||
var radixToPower = goog.math.Integer.fromNumber(Math.pow(radix, 8));
|
||||
|
||||
var result = goog.math.Integer.ZERO;
|
||||
for (var i = 0; i < str.length; i += 8) {
|
||||
var size = Math.min(8, str.length - i);
|
||||
var value = parseInt(str.substring(i, i + size), radix);
|
||||
if (size < 8) {
|
||||
var power = goog.math.Integer.fromNumber(Math.pow(radix, size));
|
||||
result = result.multiply(power).add(goog.math.Integer.fromNumber(value));
|
||||
} else {
|
||||
result = result.multiply(radixToPower);
|
||||
result = result.add(goog.math.Integer.fromNumber(value));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A number used repeatedly in calculations. This must appear before the first
|
||||
* call to the from* functions below.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
goog.math.Integer.TWO_PWR_32_DBL_ = (1 << 16) * (1 << 16);
|
||||
|
||||
|
||||
/** @type {!goog.math.Integer} */
|
||||
goog.math.Integer.ZERO = goog.math.Integer.fromInt(0);
|
||||
|
||||
|
||||
/** @type {!goog.math.Integer} */
|
||||
goog.math.Integer.ONE = goog.math.Integer.fromInt(1);
|
||||
|
||||
|
||||
/**
|
||||
* @type {!goog.math.Integer}
|
||||
* @private
|
||||
*/
|
||||
goog.math.Integer.TWO_PWR_24_ = goog.math.Integer.fromInt(1 << 24);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the value, assuming it is a 32-bit integer.
|
||||
* @return {number} The corresponding int value.
|
||||
*/
|
||||
goog.math.Integer.prototype.toInt = function() {
|
||||
return this.bits_.length > 0 ? this.bits_[0] : this.sign_;
|
||||
};
|
||||
|
||||
|
||||
/** @return {number} The closest floating-point representation to this value. */
|
||||
goog.math.Integer.prototype.toNumber = function() {
|
||||
if (this.isNegative()) {
|
||||
return -this.negate().toNumber();
|
||||
} else {
|
||||
var val = 0;
|
||||
var pow = 1;
|
||||
for (var i = 0; i < this.bits_.length; i++) {
|
||||
val += this.getBitsUnsigned(i) * pow;
|
||||
pow *= goog.math.Integer.TWO_PWR_32_DBL_;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number=} opt_radix The radix in which the text should be written.
|
||||
* @return {string} The textual representation of this value.
|
||||
* @override
|
||||
*/
|
||||
goog.math.Integer.prototype.toString = function(opt_radix) {
|
||||
var radix = opt_radix || 10;
|
||||
if (radix < 2 || 36 < radix) {
|
||||
throw Error('radix out of range: ' + radix);
|
||||
}
|
||||
|
||||
if (this.isZero()) {
|
||||
return '0';
|
||||
} else if (this.isNegative()) {
|
||||
return '-' + this.negate().toString(radix);
|
||||
}
|
||||
|
||||
// Do several (6) digits each time through the loop, so as to
|
||||
// minimize the calls to the very expensive emulated div.
|
||||
var radixToPower = goog.math.Integer.fromNumber(Math.pow(radix, 6));
|
||||
|
||||
var rem = this;
|
||||
var result = '';
|
||||
while (true) {
|
||||
var remDiv = rem.divide(radixToPower);
|
||||
// The right shifting fixes negative values in the case when
|
||||
// intval >= 2^31; for more details see
|
||||
// https://github.com/google/closure-library/pull/498
|
||||
var intval = rem.subtract(remDiv.multiply(radixToPower)).toInt() >>> 0;
|
||||
var digits = intval.toString(radix);
|
||||
|
||||
rem = remDiv;
|
||||
if (rem.isZero()) {
|
||||
return digits + result;
|
||||
} else {
|
||||
while (digits.length < 6) {
|
||||
digits = '0' + digits;
|
||||
}
|
||||
result = '' + digits + result;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the index-th 32-bit (signed) piece of the Integer according to
|
||||
* little-endian order (i.e., index 0 contains the smallest bits).
|
||||
* @param {number} index The index in question.
|
||||
* @return {number} The requested 32-bits as a signed number.
|
||||
*/
|
||||
goog.math.Integer.prototype.getBits = function(index) {
|
||||
if (index < 0) {
|
||||
return 0; // Allowing this simplifies bit shifting operations below...
|
||||
} else if (index < this.bits_.length) {
|
||||
return this.bits_[index];
|
||||
} else {
|
||||
return this.sign_;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the index-th 32-bit piece as an unsigned number.
|
||||
* @param {number} index The index in question.
|
||||
* @return {number} The requested 32-bits as an unsigned number.
|
||||
*/
|
||||
goog.math.Integer.prototype.getBitsUnsigned = function(index) {
|
||||
var val = this.getBits(index);
|
||||
return val >= 0 ? val : goog.math.Integer.TWO_PWR_32_DBL_ + val;
|
||||
};
|
||||
|
||||
|
||||
/** @return {number} The sign bit of this number, -1 or 0. */
|
||||
goog.math.Integer.prototype.getSign = function() {
|
||||
return this.sign_;
|
||||
};
|
||||
|
||||
|
||||
/** @return {boolean} Whether this value is zero. */
|
||||
goog.math.Integer.prototype.isZero = function() {
|
||||
if (this.sign_ != 0) {
|
||||
return false;
|
||||
}
|
||||
for (var i = 0; i < this.bits_.length; i++) {
|
||||
if (this.bits_[i] != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/** @return {boolean} Whether this value is negative. */
|
||||
goog.math.Integer.prototype.isNegative = function() {
|
||||
return this.sign_ == -1;
|
||||
};
|
||||
|
||||
|
||||
/** @return {boolean} Whether this value is odd. */
|
||||
goog.math.Integer.prototype.isOdd = function() {
|
||||
return (this.bits_.length == 0) && (this.sign_ == -1) ||
|
||||
(this.bits_.length > 0) && ((this.bits_[0] & 1) != 0);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {goog.math.Integer} other Integer to compare against.
|
||||
* @return {boolean} Whether this Integer equals the other.
|
||||
*/
|
||||
goog.math.Integer.prototype.equals = function(other) {
|
||||
if (this.sign_ != other.sign_) {
|
||||
return false;
|
||||
}
|
||||
var len = Math.max(this.bits_.length, other.bits_.length);
|
||||
for (var i = 0; i < len; i++) {
|
||||
if (this.getBits(i) != other.getBits(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {goog.math.Integer} other Integer to compare against.
|
||||
* @return {boolean} Whether this Integer does not equal the other.
|
||||
*/
|
||||
goog.math.Integer.prototype.notEquals = function(other) {
|
||||
return !this.equals(other);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {goog.math.Integer} other Integer to compare against.
|
||||
* @return {boolean} Whether this Integer is greater than the other.
|
||||
*/
|
||||
goog.math.Integer.prototype.greaterThan = function(other) {
|
||||
return this.compare(other) > 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {goog.math.Integer} other Integer to compare against.
|
||||
* @return {boolean} Whether this Integer is greater than or equal to the other.
|
||||
*/
|
||||
goog.math.Integer.prototype.greaterThanOrEqual = function(other) {
|
||||
return this.compare(other) >= 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {goog.math.Integer} other Integer to compare against.
|
||||
* @return {boolean} Whether this Integer is less than the other.
|
||||
*/
|
||||
goog.math.Integer.prototype.lessThan = function(other) {
|
||||
return this.compare(other) < 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {goog.math.Integer} other Integer to compare against.
|
||||
* @return {boolean} Whether this Integer is less than or equal to the other.
|
||||
*/
|
||||
goog.math.Integer.prototype.lessThanOrEqual = function(other) {
|
||||
return this.compare(other) <= 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Compares this Integer with the given one.
|
||||
* @param {goog.math.Integer} other Integer to compare against.
|
||||
* @return {number} 0 if they are the same, 1 if the this is greater, and -1
|
||||
* if the given one is greater.
|
||||
*/
|
||||
goog.math.Integer.prototype.compare = function(other) {
|
||||
var diff = this.subtract(other);
|
||||
if (diff.isNegative()) {
|
||||
return -1;
|
||||
} else if (diff.isZero()) {
|
||||
return 0;
|
||||
} else {
|
||||
return +1;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns an integer with only the first numBits bits of this value, sign
|
||||
* extended from the final bit.
|
||||
* @param {number} numBits The number of bits by which to shift.
|
||||
* @return {!goog.math.Integer} The shorted integer value.
|
||||
*/
|
||||
goog.math.Integer.prototype.shorten = function(numBits) {
|
||||
var arr_index = (numBits - 1) >> 5;
|
||||
var bit_index = (numBits - 1) % 32;
|
||||
var bits = [];
|
||||
for (var i = 0; i < arr_index; i++) {
|
||||
bits[i] = this.getBits(i);
|
||||
}
|
||||
var sigBits = bit_index == 31 ? 0xFFFFFFFF : (1 << (bit_index + 1)) - 1;
|
||||
var val = this.getBits(arr_index) & sigBits;
|
||||
if (val & (1 << bit_index)) {
|
||||
val |= 0xFFFFFFFF - sigBits;
|
||||
bits[arr_index] = val;
|
||||
return new goog.math.Integer(bits, -1);
|
||||
} else {
|
||||
bits[arr_index] = val;
|
||||
return new goog.math.Integer(bits, 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** @return {!goog.math.Integer} The negation of this value. */
|
||||
goog.math.Integer.prototype.negate = function() {
|
||||
return this.not().add(goog.math.Integer.ONE);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the sum of this and the given Integer.
|
||||
* @param {goog.math.Integer} other The Integer to add to this.
|
||||
* @return {!goog.math.Integer} The Integer result.
|
||||
*/
|
||||
goog.math.Integer.prototype.add = function(other) {
|
||||
var len = Math.max(this.bits_.length, other.bits_.length);
|
||||
var arr = [];
|
||||
var carry = 0;
|
||||
|
||||
for (var i = 0; i <= len; i++) {
|
||||
var a1 = this.getBits(i) >>> 16;
|
||||
var a0 = this.getBits(i) & 0xFFFF;
|
||||
|
||||
var b1 = other.getBits(i) >>> 16;
|
||||
var b0 = other.getBits(i) & 0xFFFF;
|
||||
|
||||
var c0 = carry + a0 + b0;
|
||||
var c1 = (c0 >>> 16) + a1 + b1;
|
||||
carry = c1 >>> 16;
|
||||
c0 &= 0xFFFF;
|
||||
c1 &= 0xFFFF;
|
||||
arr[i] = (c1 << 16) | c0;
|
||||
}
|
||||
return goog.math.Integer.fromBits(arr);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the difference of this and the given Integer.
|
||||
* @param {goog.math.Integer} other The Integer to subtract from this.
|
||||
* @return {!goog.math.Integer} The Integer result.
|
||||
*/
|
||||
goog.math.Integer.prototype.subtract = function(other) {
|
||||
return this.add(other.negate());
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the product of this and the given Integer.
|
||||
* @param {goog.math.Integer} other The Integer to multiply against this.
|
||||
* @return {!goog.math.Integer} The product of this and the other.
|
||||
*/
|
||||
goog.math.Integer.prototype.multiply = function(other) {
|
||||
if (this.isZero()) {
|
||||
return goog.math.Integer.ZERO;
|
||||
} else if (other.isZero()) {
|
||||
return goog.math.Integer.ZERO;
|
||||
}
|
||||
|
||||
if (this.isNegative()) {
|
||||
if (other.isNegative()) {
|
||||
return this.negate().multiply(other.negate());
|
||||
} else {
|
||||
return this.negate().multiply(other).negate();
|
||||
}
|
||||
} else if (other.isNegative()) {
|
||||
return this.multiply(other.negate()).negate();
|
||||
}
|
||||
|
||||
// If both numbers are small, use float multiplication
|
||||
if (this.lessThan(goog.math.Integer.TWO_PWR_24_) &&
|
||||
other.lessThan(goog.math.Integer.TWO_PWR_24_)) {
|
||||
return goog.math.Integer.fromNumber(this.toNumber() * other.toNumber());
|
||||
}
|
||||
|
||||
// Fill in an array of 16-bit products.
|
||||
var len = this.bits_.length + other.bits_.length;
|
||||
var arr = [];
|
||||
for (var i = 0; i < 2 * len; i++) {
|
||||
arr[i] = 0;
|
||||
}
|
||||
for (var i = 0; i < this.bits_.length; i++) {
|
||||
for (var j = 0; j < other.bits_.length; j++) {
|
||||
var a1 = this.getBits(i) >>> 16;
|
||||
var a0 = this.getBits(i) & 0xFFFF;
|
||||
|
||||
var b1 = other.getBits(j) >>> 16;
|
||||
var b0 = other.getBits(j) & 0xFFFF;
|
||||
|
||||
arr[2 * i + 2 * j] += a0 * b0;
|
||||
goog.math.Integer.carry16_(arr, 2 * i + 2 * j);
|
||||
arr[2 * i + 2 * j + 1] += a1 * b0;
|
||||
goog.math.Integer.carry16_(arr, 2 * i + 2 * j + 1);
|
||||
arr[2 * i + 2 * j + 1] += a0 * b1;
|
||||
goog.math.Integer.carry16_(arr, 2 * i + 2 * j + 1);
|
||||
arr[2 * i + 2 * j + 2] += a1 * b1;
|
||||
goog.math.Integer.carry16_(arr, 2 * i + 2 * j + 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Combine the 16-bit values into 32-bit values.
|
||||
for (var i = 0; i < len; i++) {
|
||||
arr[i] = (arr[2 * i + 1] << 16) | arr[2 * i];
|
||||
}
|
||||
for (var i = len; i < 2 * len; i++) {
|
||||
arr[i] = 0;
|
||||
}
|
||||
return new goog.math.Integer(arr, 0);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Carries any overflow from the given index into later entries.
|
||||
* @param {Array<number>} bits Array of 16-bit values in little-endian order.
|
||||
* @param {number} index The index in question.
|
||||
* @private
|
||||
*/
|
||||
goog.math.Integer.carry16_ = function(bits, index) {
|
||||
while ((bits[index] & 0xFFFF) != bits[index]) {
|
||||
bits[index + 1] += bits[index] >>> 16;
|
||||
bits[index] &= 0xFFFF;
|
||||
index++;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns "this" Integer divided by the given one. Both "this" and the given
|
||||
* Integer MUST be positive.
|
||||
*
|
||||
* This method is only needed for very large numbers (>10^308),
|
||||
* for which the original division algorithm gets into an infinite
|
||||
* loop (see https://github.com/google/closure-library/issues/500).
|
||||
*
|
||||
* The algorithm has some possible performance enhancements (or
|
||||
* could be rewritten entirely), it's just an initial solution for
|
||||
* the issue linked above.
|
||||
*
|
||||
* @param {!goog.math.Integer} other The Integer to divide "this" by.
|
||||
* @return {!goog.math.Integer} "this" value divided by the given one.
|
||||
* @private
|
||||
*/
|
||||
goog.math.Integer.prototype.slowDivide_ = function(other) {
|
||||
if (this.isNegative() || other.isNegative()) {
|
||||
throw Error('slowDivide_ only works with positive integers.');
|
||||
}
|
||||
|
||||
var twoPower = goog.math.Integer.ONE;
|
||||
var multiple = other;
|
||||
|
||||
// First we have to figure out what the highest bit of the result
|
||||
// is, so we increase "twoPower" and "multiple" until "multiple"
|
||||
// exceeds "this".
|
||||
while (multiple.lessThanOrEqual(this)) {
|
||||
twoPower = twoPower.shiftLeft(1);
|
||||
multiple = multiple.shiftLeft(1);
|
||||
}
|
||||
|
||||
// Rewind by one power of two, giving us the highest bit of the
|
||||
// result.
|
||||
var res = twoPower.shiftRight(1);
|
||||
var total = multiple.shiftRight(1);
|
||||
|
||||
// Now we starting decreasing "multiple" and "twoPower" to find the
|
||||
// rest of the bits of the result.
|
||||
var total2;
|
||||
multiple = multiple.shiftRight(2);
|
||||
twoPower = twoPower.shiftRight(2);
|
||||
while (!multiple.isZero()) {
|
||||
// whenever we can add "multiple" to the total and not exceed
|
||||
// "this", that means we've found a 1 bit. Else we've found a 0
|
||||
// and don't need to add to the result.
|
||||
total2 = total.add(multiple);
|
||||
if (total2.lessThanOrEqual(this)) {
|
||||
res = res.add(twoPower);
|
||||
total = total2;
|
||||
}
|
||||
multiple = multiple.shiftRight(1);
|
||||
twoPower = twoPower.shiftRight(1);
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns this Integer divided by the given one.
|
||||
* @param {!goog.math.Integer} other The Integer to divide this by.
|
||||
* @return {!goog.math.Integer} This value divided by the given one.
|
||||
*/
|
||||
goog.math.Integer.prototype.divide = function(other) {
|
||||
if (other.isZero()) {
|
||||
throw Error('division by zero');
|
||||
} else if (this.isZero()) {
|
||||
return goog.math.Integer.ZERO;
|
||||
}
|
||||
|
||||
if (this.isNegative()) {
|
||||
if (other.isNegative()) {
|
||||
return this.negate().divide(other.negate());
|
||||
} else {
|
||||
return this.negate().divide(other).negate();
|
||||
}
|
||||
} else if (other.isNegative()) {
|
||||
return this.divide(other.negate()).negate();
|
||||
}
|
||||
|
||||
// Have to degrade to slowDivide for Very Large Numbers, because
|
||||
// they're out of range for the floating-point approximation
|
||||
// technique used below.
|
||||
if (this.bits_.length > 30) {
|
||||
return this.slowDivide_(other);
|
||||
}
|
||||
|
||||
// Repeat the following until the remainder is less than other: find a
|
||||
// floating-point that approximates remainder / other *from below*, add this
|
||||
// into the result, and subtract it from the remainder. It is critical that
|
||||
// the approximate value is less than or equal to the real value so that the
|
||||
// remainder never becomes negative.
|
||||
var res = goog.math.Integer.ZERO;
|
||||
var rem = this;
|
||||
while (rem.greaterThanOrEqual(other)) {
|
||||
// Approximate the result of division. This may be a little greater or
|
||||
// smaller than the actual value.
|
||||
var approx = Math.max(1, Math.floor(rem.toNumber() / other.toNumber()));
|
||||
|
||||
// We will tweak the approximate result by changing it in the 48-th digit or
|
||||
// the smallest non-fractional digit, whichever is larger.
|
||||
var log2 = Math.ceil(Math.log(approx) / Math.LN2);
|
||||
var delta = (log2 <= 48) ? 1 : Math.pow(2, log2 - 48);
|
||||
|
||||
// Decrease the approximation until it is smaller than the remainder. Note
|
||||
// that if it is too large, the product overflows and is negative.
|
||||
var approxRes = goog.math.Integer.fromNumber(approx);
|
||||
var approxRem = approxRes.multiply(other);
|
||||
while (approxRem.isNegative() || approxRem.greaterThan(rem)) {
|
||||
approx -= delta;
|
||||
approxRes = goog.math.Integer.fromNumber(approx);
|
||||
approxRem = approxRes.multiply(other);
|
||||
}
|
||||
|
||||
// We know the answer can't be zero... and actually, zero would cause
|
||||
// infinite recursion since we would make no progress.
|
||||
if (approxRes.isZero()) {
|
||||
approxRes = goog.math.Integer.ONE;
|
||||
}
|
||||
|
||||
res = res.add(approxRes);
|
||||
rem = rem.subtract(approxRem);
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns this Integer modulo the given one.
|
||||
* @param {!goog.math.Integer} other The Integer by which to mod.
|
||||
* @return {!goog.math.Integer} This value modulo the given one.
|
||||
*/
|
||||
goog.math.Integer.prototype.modulo = function(other) {
|
||||
return this.subtract(this.divide(other).multiply(other));
|
||||
};
|
||||
|
||||
|
||||
/** @return {!goog.math.Integer} The bitwise-NOT of this value. */
|
||||
goog.math.Integer.prototype.not = function() {
|
||||
var len = this.bits_.length;
|
||||
var arr = [];
|
||||
for (var i = 0; i < len; i++) {
|
||||
arr[i] = ~this.bits_[i];
|
||||
}
|
||||
return new goog.math.Integer(arr, ~this.sign_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the bitwise-AND of this Integer and the given one.
|
||||
* @param {goog.math.Integer} other The Integer to AND with this.
|
||||
* @return {!goog.math.Integer} The bitwise-AND of this and the other.
|
||||
*/
|
||||
goog.math.Integer.prototype.and = function(other) {
|
||||
var len = Math.max(this.bits_.length, other.bits_.length);
|
||||
var arr = [];
|
||||
for (var i = 0; i < len; i++) {
|
||||
arr[i] = this.getBits(i) & other.getBits(i);
|
||||
}
|
||||
return new goog.math.Integer(arr, this.sign_ & other.sign_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the bitwise-OR of this Integer and the given one.
|
||||
* @param {goog.math.Integer} other The Integer to OR with this.
|
||||
* @return {!goog.math.Integer} The bitwise-OR of this and the other.
|
||||
*/
|
||||
goog.math.Integer.prototype.or = function(other) {
|
||||
var len = Math.max(this.bits_.length, other.bits_.length);
|
||||
var arr = [];
|
||||
for (var i = 0; i < len; i++) {
|
||||
arr[i] = this.getBits(i) | other.getBits(i);
|
||||
}
|
||||
return new goog.math.Integer(arr, this.sign_ | other.sign_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the bitwise-XOR of this Integer and the given one.
|
||||
* @param {goog.math.Integer} other The Integer to XOR with this.
|
||||
* @return {!goog.math.Integer} The bitwise-XOR of this and the other.
|
||||
*/
|
||||
goog.math.Integer.prototype.xor = function(other) {
|
||||
var len = Math.max(this.bits_.length, other.bits_.length);
|
||||
var arr = [];
|
||||
for (var i = 0; i < len; i++) {
|
||||
arr[i] = this.getBits(i) ^ other.getBits(i);
|
||||
}
|
||||
return new goog.math.Integer(arr, this.sign_ ^ other.sign_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns this value with bits shifted to the left by the given amount.
|
||||
* @param {number} numBits The number of bits by which to shift.
|
||||
* @return {!goog.math.Integer} This shifted to the left by the given amount.
|
||||
*/
|
||||
goog.math.Integer.prototype.shiftLeft = function(numBits) {
|
||||
var arr_delta = numBits >> 5;
|
||||
var bit_delta = numBits % 32;
|
||||
var len = this.bits_.length + arr_delta + (bit_delta > 0 ? 1 : 0);
|
||||
var arr = [];
|
||||
for (var i = 0; i < len; i++) {
|
||||
if (bit_delta > 0) {
|
||||
arr[i] = (this.getBits(i - arr_delta) << bit_delta) |
|
||||
(this.getBits(i - arr_delta - 1) >>> (32 - bit_delta));
|
||||
} else {
|
||||
arr[i] = this.getBits(i - arr_delta);
|
||||
}
|
||||
}
|
||||
return new goog.math.Integer(arr, this.sign_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns this value with bits shifted to the right by the given amount.
|
||||
* @param {number} numBits The number of bits by which to shift.
|
||||
* @return {!goog.math.Integer} This shifted to the right by the given amount.
|
||||
*/
|
||||
goog.math.Integer.prototype.shiftRight = function(numBits) {
|
||||
var arr_delta = numBits >> 5;
|
||||
var bit_delta = numBits % 32;
|
||||
var len = this.bits_.length - arr_delta;
|
||||
var arr = [];
|
||||
for (var i = 0; i < len; i++) {
|
||||
if (bit_delta > 0) {
|
||||
arr[i] = (this.getBits(i + arr_delta) >>> bit_delta) |
|
||||
(this.getBits(i + arr_delta + 1) << (32 - bit_delta));
|
||||
} else {
|
||||
arr[i] = this.getBits(i + arr_delta);
|
||||
}
|
||||
}
|
||||
return new goog.math.Integer(arr, this.sign_);
|
||||
};
|
||||
965
resources/public/target/cljsbuild-compiler-1/goog/math/long.js
Normal file
965
resources/public/target/cljsbuild-compiler-1/goog/math/long.js
Normal file
|
|
@ -0,0 +1,965 @@
|
|||
// Copyright 2009 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 a Long class for representing a 64-bit two's-complement
|
||||
* integer value, which faithfully simulates the behavior of a Java "long". This
|
||||
* implementation is derived from LongLib in GWT.
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.math.Long');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.reflect');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a 64-bit two's-complement integer, given its low and high 32-bit
|
||||
* values as *signed* integers. See the from* functions below for more
|
||||
* convenient ways of constructing Longs.
|
||||
*
|
||||
* The internal representation of a long is the two given signed, 32-bit values.
|
||||
* We use 32-bit pieces because these are the size of integers on which
|
||||
* Javascript performs bit-operations. For operations like addition and
|
||||
* multiplication, we split each number into 16-bit pieces, which can easily be
|
||||
* multiplied within Javascript's floating-point representation without overflow
|
||||
* or change in sign.
|
||||
*
|
||||
* In the algorithms below, we frequently reduce the negative case to the
|
||||
* positive case by negating the input(s) and then post-processing the result.
|
||||
* Note that we must ALWAYS check specially whether those values are MIN_VALUE
|
||||
* (-2^63) because -MIN_VALUE == MIN_VALUE (since 2^63 cannot be represented as
|
||||
* a positive number, it overflows back into a negative). Not handling this
|
||||
* case would often result in infinite recursion.
|
||||
*
|
||||
* @param {number} low The low (signed) 32 bits of the long.
|
||||
* @param {number} high The high (signed) 32 bits of the long.
|
||||
* @struct
|
||||
* @constructor
|
||||
* @final
|
||||
*/
|
||||
goog.math.Long = function(low, high) {
|
||||
/**
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.low_ = low | 0; // force into 32 signed bits.
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.high_ = high | 0; // force into 32 signed bits.
|
||||
};
|
||||
|
||||
|
||||
// NOTE: Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the
|
||||
// from* methods on which they depend.
|
||||
|
||||
|
||||
/**
|
||||
* A cache of the Long representations of small integer values.
|
||||
* @type {!Object<number, !goog.math.Long>}
|
||||
* @private
|
||||
*/
|
||||
goog.math.Long.IntCache_ = {};
|
||||
|
||||
|
||||
/**
|
||||
* A cache of the Long representations of common values.
|
||||
* @type {!Object<goog.math.Long.ValueCacheId_, !goog.math.Long>}
|
||||
* @private
|
||||
*/
|
||||
goog.math.Long.valueCache_ = {};
|
||||
|
||||
/**
|
||||
* Returns a cached long number representing the given (32-bit) integer value.
|
||||
* @param {number} value The 32-bit integer in question.
|
||||
* @return {!goog.math.Long} The corresponding Long value.
|
||||
* @private
|
||||
*/
|
||||
goog.math.Long.getCachedIntValue_ = function(value) {
|
||||
return goog.reflect.cache(goog.math.Long.IntCache_, value, function(val) {
|
||||
return new goog.math.Long(val, val < 0 ? -1 : 0);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* The array of maximum values of a Long in string representation for a given
|
||||
* radix between 2 and 36, inclusive.
|
||||
* @private @const {!Array<string>}
|
||||
*/
|
||||
goog.math.Long.MAX_VALUE_FOR_RADIX_ = [
|
||||
'', '', // unused
|
||||
'111111111111111111111111111111111111111111111111111111111111111',
|
||||
// base 2
|
||||
'2021110011022210012102010021220101220221', // base 3
|
||||
'13333333333333333333333333333333', // base 4
|
||||
'1104332401304422434310311212', // base 5
|
||||
'1540241003031030222122211', // base 6
|
||||
'22341010611245052052300', // base 7
|
||||
'777777777777777777777', // base 8
|
||||
'67404283172107811827', // base 9
|
||||
'9223372036854775807', // base 10
|
||||
'1728002635214590697', // base 11
|
||||
'41a792678515120367', // base 12
|
||||
'10b269549075433c37', // base 13
|
||||
'4340724c6c71dc7a7', // base 14
|
||||
'160e2ad3246366807', // base 15
|
||||
'7fffffffffffffff', // base 16
|
||||
'33d3d8307b214008', // base 17
|
||||
'16agh595df825fa7', // base 18
|
||||
'ba643dci0ffeehh', // base 19
|
||||
'5cbfjia3fh26ja7', // base 20
|
||||
'2heiciiie82dh97', // base 21
|
||||
'1adaibb21dckfa7', // base 22
|
||||
'i6k448cf4192c2', // base 23
|
||||
'acd772jnc9l0l7', // base 24
|
||||
'64ie1focnn5g77', // base 25
|
||||
'3igoecjbmca687', // base 26
|
||||
'27c48l5b37oaop', // base 27
|
||||
'1bk39f3ah3dmq7', // base 28
|
||||
'q1se8f0m04isb', // base 29
|
||||
'hajppbc1fc207', // base 30
|
||||
'bm03i95hia437', // base 31
|
||||
'7vvvvvvvvvvvv', // base 32
|
||||
'5hg4ck9jd4u37', // base 33
|
||||
'3tdtk1v8j6tpp', // base 34
|
||||
'2pijmikexrxp7', // base 35
|
||||
'1y2p0ij32e8e7' // base 36
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* The array of minimum values of a Long in string representation for a given
|
||||
* radix between 2 and 36, inclusive.
|
||||
* @private @const {!Array<string>}
|
||||
*/
|
||||
goog.math.Long.MIN_VALUE_FOR_RADIX_ = [
|
||||
'', '', // unused
|
||||
'-1000000000000000000000000000000000000000000000000000000000000000',
|
||||
// base 2
|
||||
'-2021110011022210012102010021220101220222', // base 3
|
||||
'-20000000000000000000000000000000', // base 4
|
||||
'-1104332401304422434310311213', // base 5
|
||||
'-1540241003031030222122212', // base 6
|
||||
'-22341010611245052052301', // base 7
|
||||
'-1000000000000000000000', // base 8
|
||||
'-67404283172107811828', // base 9
|
||||
'-9223372036854775808', // base 10
|
||||
'-1728002635214590698', // base 11
|
||||
'-41a792678515120368', // base 12
|
||||
'-10b269549075433c38', // base 13
|
||||
'-4340724c6c71dc7a8', // base 14
|
||||
'-160e2ad3246366808', // base 15
|
||||
'-8000000000000000', // base 16
|
||||
'-33d3d8307b214009', // base 17
|
||||
'-16agh595df825fa8', // base 18
|
||||
'-ba643dci0ffeehi', // base 19
|
||||
'-5cbfjia3fh26ja8', // base 20
|
||||
'-2heiciiie82dh98', // base 21
|
||||
'-1adaibb21dckfa8', // base 22
|
||||
'-i6k448cf4192c3', // base 23
|
||||
'-acd772jnc9l0l8', // base 24
|
||||
'-64ie1focnn5g78', // base 25
|
||||
'-3igoecjbmca688', // base 26
|
||||
'-27c48l5b37oaoq', // base 27
|
||||
'-1bk39f3ah3dmq8', // base 28
|
||||
'-q1se8f0m04isc', // base 29
|
||||
'-hajppbc1fc208', // base 30
|
||||
'-bm03i95hia438', // base 31
|
||||
'-8000000000000', // base 32
|
||||
'-5hg4ck9jd4u38', // base 33
|
||||
'-3tdtk1v8j6tpq', // base 34
|
||||
'-2pijmikexrxp8', // base 35
|
||||
'-1y2p0ij32e8e8' // base 36
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Returns a Long representing the given (32-bit) integer value.
|
||||
* @param {number} value The 32-bit integer in question.
|
||||
* @return {!goog.math.Long} The corresponding Long value.
|
||||
*/
|
||||
goog.math.Long.fromInt = function(value) {
|
||||
var intValue = value | 0;
|
||||
goog.asserts.assert(value === intValue, 'value should be a 32-bit integer');
|
||||
|
||||
if (-128 <= intValue && intValue < 128) {
|
||||
return goog.math.Long.getCachedIntValue_(intValue);
|
||||
} else {
|
||||
return new goog.math.Long(intValue, intValue < 0 ? -1 : 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns a Long representing the given value.
|
||||
* NaN will be returned as zero. Infinity is converted to max value and
|
||||
* -Infinity to min value.
|
||||
* @param {number} value The number in question.
|
||||
* @return {!goog.math.Long} The corresponding Long value.
|
||||
*/
|
||||
goog.math.Long.fromNumber = function(value) {
|
||||
if (isNaN(value)) {
|
||||
return goog.math.Long.getZero();
|
||||
} else if (value <= -goog.math.Long.TWO_PWR_63_DBL_) {
|
||||
return goog.math.Long.getMinValue();
|
||||
} else if (value + 1 >= goog.math.Long.TWO_PWR_63_DBL_) {
|
||||
return goog.math.Long.getMaxValue();
|
||||
} else if (value < 0) {
|
||||
return goog.math.Long.fromNumber(-value).negate();
|
||||
} else {
|
||||
return new goog.math.Long(
|
||||
(value % goog.math.Long.TWO_PWR_32_DBL_) | 0,
|
||||
(value / goog.math.Long.TWO_PWR_32_DBL_) | 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns a Long representing the 64-bit integer that comes by concatenating
|
||||
* the given high and low bits. Each is assumed to use 32 bits.
|
||||
* @param {number} lowBits The low 32-bits.
|
||||
* @param {number} highBits The high 32-bits.
|
||||
* @return {!goog.math.Long} The corresponding Long value.
|
||||
*/
|
||||
goog.math.Long.fromBits = function(lowBits, highBits) {
|
||||
return new goog.math.Long(lowBits, highBits);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns a Long representation of the given string, written using the given
|
||||
* radix.
|
||||
* @param {string} str The textual representation of the Long.
|
||||
* @param {number=} opt_radix The radix in which the text is written.
|
||||
* @return {!goog.math.Long} The corresponding Long value.
|
||||
*/
|
||||
goog.math.Long.fromString = function(str, opt_radix) {
|
||||
if (str.length == 0) {
|
||||
throw Error('number format error: empty string');
|
||||
}
|
||||
|
||||
var radix = opt_radix || 10;
|
||||
if (radix < 2 || 36 < radix) {
|
||||
throw Error('radix out of range: ' + radix);
|
||||
}
|
||||
|
||||
if (str.charAt(0) == '-') {
|
||||
return goog.math.Long.fromString(str.substring(1), radix).negate();
|
||||
} else if (str.indexOf('-') >= 0) {
|
||||
throw Error('number format error: interior "-" character: ' + str);
|
||||
}
|
||||
|
||||
// Do several (8) digits each time through the loop, so as to
|
||||
// minimize the calls to the very expensive emulated div.
|
||||
var radixToPower = goog.math.Long.fromNumber(Math.pow(radix, 8));
|
||||
|
||||
var result = goog.math.Long.getZero();
|
||||
for (var i = 0; i < str.length; i += 8) {
|
||||
var size = Math.min(8, str.length - i);
|
||||
var value = parseInt(str.substring(i, i + size), radix);
|
||||
if (size < 8) {
|
||||
var power = goog.math.Long.fromNumber(Math.pow(radix, size));
|
||||
result = result.multiply(power).add(goog.math.Long.fromNumber(value));
|
||||
} else {
|
||||
result = result.multiply(radixToPower);
|
||||
result = result.add(goog.math.Long.fromNumber(value));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the boolean value of whether the input string is within a Long's
|
||||
* range. Assumes an input string containing only numeric characters with an
|
||||
* optional preceding '-'.
|
||||
* @param {string} str The textual representation of the Long.
|
||||
* @param {number=} opt_radix The radix in which the text is written.
|
||||
* @return {boolean} Whether the string is within the range of a Long.
|
||||
*/
|
||||
goog.math.Long.isStringInRange = function(str, opt_radix) {
|
||||
var radix = opt_radix || 10;
|
||||
if (radix < 2 || 36 < radix) {
|
||||
throw Error('radix out of range: ' + radix);
|
||||
}
|
||||
|
||||
var extremeValue = (str.charAt(0) == '-') ?
|
||||
goog.math.Long.MIN_VALUE_FOR_RADIX_[radix] :
|
||||
goog.math.Long.MAX_VALUE_FOR_RADIX_[radix];
|
||||
|
||||
if (str.length < extremeValue.length) {
|
||||
return true;
|
||||
} else if (str.length == extremeValue.length && str <= extremeValue) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// NOTE: the compiler should inline these constant values below and then remove
|
||||
// these variables, so there should be no runtime penalty for these.
|
||||
|
||||
|
||||
/**
|
||||
* Number used repeated below in calculations. This must appear before the
|
||||
* first call to any from* function below.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
goog.math.Long.TWO_PWR_16_DBL_ = 1 << 16;
|
||||
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
goog.math.Long.TWO_PWR_32_DBL_ =
|
||||
goog.math.Long.TWO_PWR_16_DBL_ * goog.math.Long.TWO_PWR_16_DBL_;
|
||||
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
goog.math.Long.TWO_PWR_64_DBL_ =
|
||||
goog.math.Long.TWO_PWR_32_DBL_ * goog.math.Long.TWO_PWR_32_DBL_;
|
||||
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
goog.math.Long.TWO_PWR_63_DBL_ = goog.math.Long.TWO_PWR_64_DBL_ / 2;
|
||||
|
||||
|
||||
/**
|
||||
* @return {!goog.math.Long}
|
||||
* @public
|
||||
*/
|
||||
goog.math.Long.getZero = function() {
|
||||
return goog.math.Long.getCachedIntValue_(0);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {!goog.math.Long}
|
||||
* @public
|
||||
*/
|
||||
goog.math.Long.getOne = function() {
|
||||
return goog.math.Long.getCachedIntValue_(1);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {!goog.math.Long}
|
||||
* @public
|
||||
*/
|
||||
goog.math.Long.getNegOne = function() {
|
||||
return goog.math.Long.getCachedIntValue_(-1);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {!goog.math.Long}
|
||||
* @public
|
||||
*/
|
||||
goog.math.Long.getMaxValue = function() {
|
||||
return goog.reflect.cache(
|
||||
goog.math.Long.valueCache_, goog.math.Long.ValueCacheId_.MAX_VALUE,
|
||||
function() {
|
||||
return goog.math.Long.fromBits(0xFFFFFFFF | 0, 0x7FFFFFFF | 0);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {!goog.math.Long}
|
||||
* @public
|
||||
*/
|
||||
goog.math.Long.getMinValue = function() {
|
||||
return goog.reflect.cache(
|
||||
goog.math.Long.valueCache_, goog.math.Long.ValueCacheId_.MIN_VALUE,
|
||||
function() { return goog.math.Long.fromBits(0, 0x80000000 | 0); });
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {!goog.math.Long}
|
||||
* @public
|
||||
*/
|
||||
goog.math.Long.getTwoPwr24 = function() {
|
||||
return goog.reflect.cache(
|
||||
goog.math.Long.valueCache_, goog.math.Long.ValueCacheId_.TWO_PWR_24,
|
||||
function() { return goog.math.Long.fromInt(1 << 24); });
|
||||
};
|
||||
|
||||
|
||||
/** @return {number} The value, assuming it is a 32-bit integer. */
|
||||
goog.math.Long.prototype.toInt = function() {
|
||||
return this.low_;
|
||||
};
|
||||
|
||||
|
||||
/** @return {number} The closest floating-point representation to this value. */
|
||||
goog.math.Long.prototype.toNumber = function() {
|
||||
return this.high_ * goog.math.Long.TWO_PWR_32_DBL_ +
|
||||
this.getLowBitsUnsigned();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number=} opt_radix The radix in which the text should be written.
|
||||
* @return {string} The textual representation of this value.
|
||||
* @override
|
||||
*/
|
||||
goog.math.Long.prototype.toString = function(opt_radix) {
|
||||
var radix = opt_radix || 10;
|
||||
if (radix < 2 || 36 < radix) {
|
||||
throw Error('radix out of range: ' + radix);
|
||||
}
|
||||
|
||||
if (this.isZero()) {
|
||||
return '0';
|
||||
}
|
||||
|
||||
if (this.isNegative()) {
|
||||
if (this.equals(goog.math.Long.getMinValue())) {
|
||||
// We need to change the Long value before it can be negated, so we remove
|
||||
// the bottom-most digit in this base and then recurse to do the rest.
|
||||
var radixLong = goog.math.Long.fromNumber(radix);
|
||||
var div = this.div(radixLong);
|
||||
var rem = div.multiply(radixLong).subtract(this);
|
||||
return div.toString(radix) + rem.toInt().toString(radix);
|
||||
} else {
|
||||
return '-' + this.negate().toString(radix);
|
||||
}
|
||||
}
|
||||
|
||||
// Do several (6) digits each time through the loop, so as to
|
||||
// minimize the calls to the very expensive emulated div.
|
||||
var radixToPower = goog.math.Long.fromNumber(Math.pow(radix, 6));
|
||||
|
||||
var rem = this;
|
||||
var result = '';
|
||||
while (true) {
|
||||
var remDiv = rem.div(radixToPower);
|
||||
// The right shifting fixes negative values in the case when
|
||||
// intval >= 2^31; for more details see
|
||||
// https://github.com/google/closure-library/pull/498
|
||||
var intval = rem.subtract(remDiv.multiply(radixToPower)).toInt() >>> 0;
|
||||
var digits = intval.toString(radix);
|
||||
|
||||
rem = remDiv;
|
||||
if (rem.isZero()) {
|
||||
return digits + result;
|
||||
} else {
|
||||
while (digits.length < 6) {
|
||||
digits = '0' + digits;
|
||||
}
|
||||
result = '' + digits + result;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** @return {number} The high 32-bits as a signed value. */
|
||||
goog.math.Long.prototype.getHighBits = function() {
|
||||
return this.high_;
|
||||
};
|
||||
|
||||
|
||||
/** @return {number} The low 32-bits as a signed value. */
|
||||
goog.math.Long.prototype.getLowBits = function() {
|
||||
return this.low_;
|
||||
};
|
||||
|
||||
|
||||
/** @return {number} The low 32-bits as an unsigned value. */
|
||||
goog.math.Long.prototype.getLowBitsUnsigned = function() {
|
||||
return (this.low_ >= 0) ? this.low_ :
|
||||
goog.math.Long.TWO_PWR_32_DBL_ + this.low_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} Returns the number of bits needed to represent the absolute
|
||||
* value of this Long.
|
||||
*/
|
||||
goog.math.Long.prototype.getNumBitsAbs = function() {
|
||||
if (this.isNegative()) {
|
||||
if (this.equals(goog.math.Long.getMinValue())) {
|
||||
return 64;
|
||||
} else {
|
||||
return this.negate().getNumBitsAbs();
|
||||
}
|
||||
} else {
|
||||
var val = this.high_ != 0 ? this.high_ : this.low_;
|
||||
for (var bit = 31; bit > 0; bit--) {
|
||||
if ((val & (1 << bit)) != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return this.high_ != 0 ? bit + 33 : bit + 1;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** @return {boolean} Whether this value is zero. */
|
||||
goog.math.Long.prototype.isZero = function() {
|
||||
return this.high_ == 0 && this.low_ == 0;
|
||||
};
|
||||
|
||||
|
||||
/** @return {boolean} Whether this value is negative. */
|
||||
goog.math.Long.prototype.isNegative = function() {
|
||||
return this.high_ < 0;
|
||||
};
|
||||
|
||||
|
||||
/** @return {boolean} Whether this value is odd. */
|
||||
goog.math.Long.prototype.isOdd = function() {
|
||||
return (this.low_ & 1) == 1;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {goog.math.Long} other Long to compare against.
|
||||
* @return {boolean} Whether this Long equals the other.
|
||||
*/
|
||||
goog.math.Long.prototype.equals = function(other) {
|
||||
return (this.high_ == other.high_) && (this.low_ == other.low_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {goog.math.Long} other Long to compare against.
|
||||
* @return {boolean} Whether this Long does not equal the other.
|
||||
*/
|
||||
goog.math.Long.prototype.notEquals = function(other) {
|
||||
return (this.high_ != other.high_) || (this.low_ != other.low_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {goog.math.Long} other Long to compare against.
|
||||
* @return {boolean} Whether this Long is less than the other.
|
||||
*/
|
||||
goog.math.Long.prototype.lessThan = function(other) {
|
||||
return this.compare(other) < 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {goog.math.Long} other Long to compare against.
|
||||
* @return {boolean} Whether this Long is less than or equal to the other.
|
||||
*/
|
||||
goog.math.Long.prototype.lessThanOrEqual = function(other) {
|
||||
return this.compare(other) <= 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {goog.math.Long} other Long to compare against.
|
||||
* @return {boolean} Whether this Long is greater than the other.
|
||||
*/
|
||||
goog.math.Long.prototype.greaterThan = function(other) {
|
||||
return this.compare(other) > 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {goog.math.Long} other Long to compare against.
|
||||
* @return {boolean} Whether this Long is greater than or equal to the other.
|
||||
*/
|
||||
goog.math.Long.prototype.greaterThanOrEqual = function(other) {
|
||||
return this.compare(other) >= 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Compares this Long with the given one.
|
||||
* @param {goog.math.Long} other Long to compare against.
|
||||
* @return {number} 0 if they are the same, 1 if the this is greater, and -1
|
||||
* if the given one is greater.
|
||||
*/
|
||||
goog.math.Long.prototype.compare = function(other) {
|
||||
if (this.equals(other)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
var thisNeg = this.isNegative();
|
||||
var otherNeg = other.isNegative();
|
||||
if (thisNeg && !otherNeg) {
|
||||
return -1;
|
||||
}
|
||||
if (!thisNeg && otherNeg) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// at this point, the signs are the same, so subtraction will not overflow
|
||||
if (this.subtract(other).isNegative()) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** @return {!goog.math.Long} The negation of this value. */
|
||||
goog.math.Long.prototype.negate = function() {
|
||||
if (this.equals(goog.math.Long.getMinValue())) {
|
||||
return goog.math.Long.getMinValue();
|
||||
} else {
|
||||
return this.not().add(goog.math.Long.getOne());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the sum of this and the given Long.
|
||||
* @param {goog.math.Long} other Long to add to this one.
|
||||
* @return {!goog.math.Long} The sum of this and the given Long.
|
||||
*/
|
||||
goog.math.Long.prototype.add = function(other) {
|
||||
// Divide each number into 4 chunks of 16 bits, and then sum the chunks.
|
||||
|
||||
var a48 = this.high_ >>> 16;
|
||||
var a32 = this.high_ & 0xFFFF;
|
||||
var a16 = this.low_ >>> 16;
|
||||
var a00 = this.low_ & 0xFFFF;
|
||||
|
||||
var b48 = other.high_ >>> 16;
|
||||
var b32 = other.high_ & 0xFFFF;
|
||||
var b16 = other.low_ >>> 16;
|
||||
var b00 = other.low_ & 0xFFFF;
|
||||
|
||||
var c48 = 0, c32 = 0, c16 = 0, c00 = 0;
|
||||
c00 += a00 + b00;
|
||||
c16 += c00 >>> 16;
|
||||
c00 &= 0xFFFF;
|
||||
c16 += a16 + b16;
|
||||
c32 += c16 >>> 16;
|
||||
c16 &= 0xFFFF;
|
||||
c32 += a32 + b32;
|
||||
c48 += c32 >>> 16;
|
||||
c32 &= 0xFFFF;
|
||||
c48 += a48 + b48;
|
||||
c48 &= 0xFFFF;
|
||||
return goog.math.Long.fromBits((c16 << 16) | c00, (c48 << 16) | c32);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the difference of this and the given Long.
|
||||
* @param {goog.math.Long} other Long to subtract from this.
|
||||
* @return {!goog.math.Long} The difference of this and the given Long.
|
||||
*/
|
||||
goog.math.Long.prototype.subtract = function(other) {
|
||||
return this.add(other.negate());
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the product of this and the given long.
|
||||
* @param {goog.math.Long} other Long to multiply with this.
|
||||
* @return {!goog.math.Long} The product of this and the other.
|
||||
*/
|
||||
goog.math.Long.prototype.multiply = function(other) {
|
||||
if (this.isZero()) {
|
||||
return goog.math.Long.getZero();
|
||||
} else if (other.isZero()) {
|
||||
return goog.math.Long.getZero();
|
||||
}
|
||||
|
||||
if (this.equals(goog.math.Long.getMinValue())) {
|
||||
return other.isOdd() ? goog.math.Long.getMinValue() :
|
||||
goog.math.Long.getZero();
|
||||
} else if (other.equals(goog.math.Long.getMinValue())) {
|
||||
return this.isOdd() ? goog.math.Long.getMinValue() :
|
||||
goog.math.Long.getZero();
|
||||
}
|
||||
|
||||
if (this.isNegative()) {
|
||||
if (other.isNegative()) {
|
||||
return this.negate().multiply(other.negate());
|
||||
} else {
|
||||
return this.negate().multiply(other).negate();
|
||||
}
|
||||
} else if (other.isNegative()) {
|
||||
return this.multiply(other.negate()).negate();
|
||||
}
|
||||
|
||||
// If both longs are small, use float multiplication
|
||||
if (this.lessThan(goog.math.Long.getTwoPwr24()) &&
|
||||
other.lessThan(goog.math.Long.getTwoPwr24())) {
|
||||
return goog.math.Long.fromNumber(this.toNumber() * other.toNumber());
|
||||
}
|
||||
|
||||
// Divide each long into 4 chunks of 16 bits, and then add up 4x4 products.
|
||||
// We can skip products that would overflow.
|
||||
|
||||
var a48 = this.high_ >>> 16;
|
||||
var a32 = this.high_ & 0xFFFF;
|
||||
var a16 = this.low_ >>> 16;
|
||||
var a00 = this.low_ & 0xFFFF;
|
||||
|
||||
var b48 = other.high_ >>> 16;
|
||||
var b32 = other.high_ & 0xFFFF;
|
||||
var b16 = other.low_ >>> 16;
|
||||
var b00 = other.low_ & 0xFFFF;
|
||||
|
||||
var c48 = 0, c32 = 0, c16 = 0, c00 = 0;
|
||||
c00 += a00 * b00;
|
||||
c16 += c00 >>> 16;
|
||||
c00 &= 0xFFFF;
|
||||
c16 += a16 * b00;
|
||||
c32 += c16 >>> 16;
|
||||
c16 &= 0xFFFF;
|
||||
c16 += a00 * b16;
|
||||
c32 += c16 >>> 16;
|
||||
c16 &= 0xFFFF;
|
||||
c32 += a32 * b00;
|
||||
c48 += c32 >>> 16;
|
||||
c32 &= 0xFFFF;
|
||||
c32 += a16 * b16;
|
||||
c48 += c32 >>> 16;
|
||||
c32 &= 0xFFFF;
|
||||
c32 += a00 * b32;
|
||||
c48 += c32 >>> 16;
|
||||
c32 &= 0xFFFF;
|
||||
c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48;
|
||||
c48 &= 0xFFFF;
|
||||
return goog.math.Long.fromBits((c16 << 16) | c00, (c48 << 16) | c32);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns this Long divided by the given one.
|
||||
* @param {goog.math.Long} other Long by which to divide.
|
||||
* @return {!goog.math.Long} This Long divided by the given one.
|
||||
*/
|
||||
goog.math.Long.prototype.div = function(other) {
|
||||
if (other.isZero()) {
|
||||
throw Error('division by zero');
|
||||
} else if (this.isZero()) {
|
||||
return goog.math.Long.getZero();
|
||||
}
|
||||
|
||||
if (this.equals(goog.math.Long.getMinValue())) {
|
||||
if (other.equals(goog.math.Long.getOne()) ||
|
||||
other.equals(goog.math.Long.getNegOne())) {
|
||||
return goog.math.Long.getMinValue(); // recall -MIN_VALUE == MIN_VALUE
|
||||
} else if (other.equals(goog.math.Long.getMinValue())) {
|
||||
return goog.math.Long.getOne();
|
||||
} else {
|
||||
// At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|.
|
||||
var halfThis = this.shiftRight(1);
|
||||
var approx = halfThis.div(other).shiftLeft(1);
|
||||
if (approx.equals(goog.math.Long.getZero())) {
|
||||
return other.isNegative() ? goog.math.Long.getOne() :
|
||||
goog.math.Long.getNegOne();
|
||||
} else {
|
||||
var rem = this.subtract(other.multiply(approx));
|
||||
var result = approx.add(rem.div(other));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
} else if (other.equals(goog.math.Long.getMinValue())) {
|
||||
return goog.math.Long.getZero();
|
||||
}
|
||||
|
||||
if (this.isNegative()) {
|
||||
if (other.isNegative()) {
|
||||
return this.negate().div(other.negate());
|
||||
} else {
|
||||
return this.negate().div(other).negate();
|
||||
}
|
||||
} else if (other.isNegative()) {
|
||||
return this.div(other.negate()).negate();
|
||||
}
|
||||
|
||||
// Repeat the following until the remainder is less than other: find a
|
||||
// floating-point that approximates remainder / other *from below*, add this
|
||||
// into the result, and subtract it from the remainder. It is critical that
|
||||
// the approximate value is less than or equal to the real value so that the
|
||||
// remainder never becomes negative.
|
||||
var res = goog.math.Long.getZero();
|
||||
var rem = this;
|
||||
while (rem.greaterThanOrEqual(other)) {
|
||||
// Approximate the result of division. This may be a little greater or
|
||||
// smaller than the actual value.
|
||||
var approx = Math.max(1, Math.floor(rem.toNumber() / other.toNumber()));
|
||||
|
||||
// We will tweak the approximate result by changing it in the 48-th digit or
|
||||
// the smallest non-fractional digit, whichever is larger.
|
||||
var log2 = Math.ceil(Math.log(approx) / Math.LN2);
|
||||
var delta = (log2 <= 48) ? 1 : Math.pow(2, log2 - 48);
|
||||
|
||||
// Decrease the approximation until it is smaller than the remainder. Note
|
||||
// that if it is too large, the product overflows and is negative.
|
||||
var approxRes = goog.math.Long.fromNumber(approx);
|
||||
var approxRem = approxRes.multiply(other);
|
||||
while (approxRem.isNegative() || approxRem.greaterThan(rem)) {
|
||||
approx -= delta;
|
||||
approxRes = goog.math.Long.fromNumber(approx);
|
||||
approxRem = approxRes.multiply(other);
|
||||
}
|
||||
|
||||
// We know the answer can't be zero... and actually, zero would cause
|
||||
// infinite recursion since we would make no progress.
|
||||
if (approxRes.isZero()) {
|
||||
approxRes = goog.math.Long.getOne();
|
||||
}
|
||||
|
||||
res = res.add(approxRes);
|
||||
rem = rem.subtract(approxRem);
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns this Long modulo the given one.
|
||||
* @param {goog.math.Long} other Long by which to mod.
|
||||
* @return {!goog.math.Long} This Long modulo the given one.
|
||||
*/
|
||||
goog.math.Long.prototype.modulo = function(other) {
|
||||
return this.subtract(this.div(other).multiply(other));
|
||||
};
|
||||
|
||||
|
||||
/** @return {!goog.math.Long} The bitwise-NOT of this value. */
|
||||
goog.math.Long.prototype.not = function() {
|
||||
return goog.math.Long.fromBits(~this.low_, ~this.high_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the bitwise-AND of this Long and the given one.
|
||||
* @param {goog.math.Long} other The Long with which to AND.
|
||||
* @return {!goog.math.Long} The bitwise-AND of this and the other.
|
||||
*/
|
||||
goog.math.Long.prototype.and = function(other) {
|
||||
return goog.math.Long.fromBits(
|
||||
this.low_ & other.low_, this.high_ & other.high_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the bitwise-OR of this Long and the given one.
|
||||
* @param {goog.math.Long} other The Long with which to OR.
|
||||
* @return {!goog.math.Long} The bitwise-OR of this and the other.
|
||||
*/
|
||||
goog.math.Long.prototype.or = function(other) {
|
||||
return goog.math.Long.fromBits(
|
||||
this.low_ | other.low_, this.high_ | other.high_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the bitwise-XOR of this Long and the given one.
|
||||
* @param {goog.math.Long} other The Long with which to XOR.
|
||||
* @return {!goog.math.Long} The bitwise-XOR of this and the other.
|
||||
*/
|
||||
goog.math.Long.prototype.xor = function(other) {
|
||||
return goog.math.Long.fromBits(
|
||||
this.low_ ^ other.low_, this.high_ ^ other.high_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns this Long with bits shifted to the left by the given amount.
|
||||
* @param {number} numBits The number of bits by which to shift.
|
||||
* @return {!goog.math.Long} This shifted to the left by the given amount.
|
||||
*/
|
||||
goog.math.Long.prototype.shiftLeft = function(numBits) {
|
||||
numBits &= 63;
|
||||
if (numBits == 0) {
|
||||
return this;
|
||||
} else {
|
||||
var low = this.low_;
|
||||
if (numBits < 32) {
|
||||
var high = this.high_;
|
||||
return goog.math.Long.fromBits(
|
||||
low << numBits, (high << numBits) | (low >>> (32 - numBits)));
|
||||
} else {
|
||||
return goog.math.Long.fromBits(0, low << (numBits - 32));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns this Long with bits shifted to the right by the given amount.
|
||||
* The new leading bits match the current sign bit.
|
||||
* @param {number} numBits The number of bits by which to shift.
|
||||
* @return {!goog.math.Long} This shifted to the right by the given amount.
|
||||
*/
|
||||
goog.math.Long.prototype.shiftRight = function(numBits) {
|
||||
numBits &= 63;
|
||||
if (numBits == 0) {
|
||||
return this;
|
||||
} else {
|
||||
var high = this.high_;
|
||||
if (numBits < 32) {
|
||||
var low = this.low_;
|
||||
return goog.math.Long.fromBits(
|
||||
(low >>> numBits) | (high << (32 - numBits)), high >> numBits);
|
||||
} else {
|
||||
return goog.math.Long.fromBits(
|
||||
high >> (numBits - 32), high >= 0 ? 0 : -1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns this Long with bits shifted to the right by the given amount, with
|
||||
* zeros placed into the new leading bits.
|
||||
* @param {number} numBits The number of bits by which to shift.
|
||||
* @return {!goog.math.Long} This shifted to the right by the given amount, with
|
||||
* zeros placed into the new leading bits.
|
||||
*/
|
||||
goog.math.Long.prototype.shiftRightUnsigned = function(numBits) {
|
||||
numBits &= 63;
|
||||
if (numBits == 0) {
|
||||
return this;
|
||||
} else {
|
||||
var high = this.high_;
|
||||
if (numBits < 32) {
|
||||
var low = this.low_;
|
||||
return goog.math.Long.fromBits(
|
||||
(low >>> numBits) | (high << (32 - numBits)), high >>> numBits);
|
||||
} else if (numBits == 32) {
|
||||
return goog.math.Long.fromBits(high, 0);
|
||||
} else {
|
||||
return goog.math.Long.fromBits(high >>> (numBits - 32), 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @enum {number} Ids of commonly requested Long instances.
|
||||
* @private
|
||||
*/
|
||||
goog.math.Long.ValueCacheId_ = {
|
||||
MAX_VALUE: 1,
|
||||
MIN_VALUE: 2,
|
||||
TWO_PWR_24: 6
|
||||
};
|
||||
448
resources/public/target/cljsbuild-compiler-1/goog/math/math.js
Normal file
448
resources/public/target/cljsbuild-compiler-1/goog/math/math.js
Normal file
|
|
@ -0,0 +1,448 @@
|
|||
// Copyright 2006 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 Additional mathematical functions.
|
||||
*/
|
||||
|
||||
goog.provide('goog.math');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.asserts');
|
||||
|
||||
|
||||
/**
|
||||
* Returns a random integer greater than or equal to 0 and less than {@code a}.
|
||||
* @param {number} a The upper bound for the random integer (exclusive).
|
||||
* @return {number} A random integer N such that 0 <= N < a.
|
||||
*/
|
||||
goog.math.randomInt = function(a) {
|
||||
return Math.floor(Math.random() * a);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns a random number greater than or equal to {@code a} and less than
|
||||
* {@code b}.
|
||||
* @param {number} a The lower bound for the random number (inclusive).
|
||||
* @param {number} b The upper bound for the random number (exclusive).
|
||||
* @return {number} A random number N such that a <= N < b.
|
||||
*/
|
||||
goog.math.uniformRandom = function(a, b) {
|
||||
return a + Math.random() * (b - a);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Takes a number and clamps it to within the provided bounds.
|
||||
* @param {number} value The input number.
|
||||
* @param {number} min The minimum value to return.
|
||||
* @param {number} max The maximum value to return.
|
||||
* @return {number} The input number if it is within bounds, or the nearest
|
||||
* number within the bounds.
|
||||
*/
|
||||
goog.math.clamp = function(value, min, max) {
|
||||
return Math.min(Math.max(value, min), max);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The % operator in JavaScript returns the remainder of a / b, but differs from
|
||||
* some other languages in that the result will have the same sign as the
|
||||
* dividend. For example, -1 % 8 == -1, whereas in some other languages
|
||||
* (such as Python) the result would be 7. This function emulates the more
|
||||
* correct modulo behavior, which is useful for certain applications such as
|
||||
* calculating an offset index in a circular list.
|
||||
*
|
||||
* @param {number} a The dividend.
|
||||
* @param {number} b The divisor.
|
||||
* @return {number} a % b where the result is between 0 and b (either 0 <= x < b
|
||||
* or b < x <= 0, depending on the sign of b).
|
||||
*/
|
||||
goog.math.modulo = function(a, b) {
|
||||
var r = a % b;
|
||||
// If r and b differ in sign, add b to wrap the result to the correct sign.
|
||||
return (r * b < 0) ? r + b : r;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Performs linear interpolation between values a and b. Returns the value
|
||||
* between a and b proportional to x (when x is between 0 and 1. When x is
|
||||
* outside this range, the return value is a linear extrapolation).
|
||||
* @param {number} a A number.
|
||||
* @param {number} b A number.
|
||||
* @param {number} x The proportion between a and b.
|
||||
* @return {number} The interpolated value between a and b.
|
||||
*/
|
||||
goog.math.lerp = function(a, b, x) {
|
||||
return a + x * (b - a);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Tests whether the two values are equal to each other, within a certain
|
||||
* tolerance to adjust for floating point errors.
|
||||
* @param {number} a A number.
|
||||
* @param {number} b A number.
|
||||
* @param {number=} opt_tolerance Optional tolerance range. Defaults
|
||||
* to 0.000001. If specified, should be greater than 0.
|
||||
* @return {boolean} Whether {@code a} and {@code b} are nearly equal.
|
||||
*/
|
||||
goog.math.nearlyEquals = function(a, b, opt_tolerance) {
|
||||
return Math.abs(a - b) <= (opt_tolerance || 0.000001);
|
||||
};
|
||||
|
||||
|
||||
// TODO(user): Rename to normalizeAngle, retaining old name as deprecated
|
||||
// alias.
|
||||
/**
|
||||
* Normalizes an angle to be in range [0-360). Angles outside this range will
|
||||
* be normalized to be the equivalent angle with that range.
|
||||
* @param {number} angle Angle in degrees.
|
||||
* @return {number} Standardized angle.
|
||||
*/
|
||||
goog.math.standardAngle = function(angle) {
|
||||
return goog.math.modulo(angle, 360);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Normalizes an angle to be in range [0-2*PI). Angles outside this range will
|
||||
* be normalized to be the equivalent angle with that range.
|
||||
* @param {number} angle Angle in radians.
|
||||
* @return {number} Standardized angle.
|
||||
*/
|
||||
goog.math.standardAngleInRadians = function(angle) {
|
||||
return goog.math.modulo(angle, 2 * Math.PI);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Converts degrees to radians.
|
||||
* @param {number} angleDegrees Angle in degrees.
|
||||
* @return {number} Angle in radians.
|
||||
*/
|
||||
goog.math.toRadians = function(angleDegrees) {
|
||||
return angleDegrees * Math.PI / 180;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Converts radians to degrees.
|
||||
* @param {number} angleRadians Angle in radians.
|
||||
* @return {number} Angle in degrees.
|
||||
*/
|
||||
goog.math.toDegrees = function(angleRadians) {
|
||||
return angleRadians * 180 / Math.PI;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* For a given angle and radius, finds the X portion of the offset.
|
||||
* @param {number} degrees Angle in degrees (zero points in +X direction).
|
||||
* @param {number} radius Radius.
|
||||
* @return {number} The x-distance for the angle and radius.
|
||||
*/
|
||||
goog.math.angleDx = function(degrees, radius) {
|
||||
return radius * Math.cos(goog.math.toRadians(degrees));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* For a given angle and radius, finds the Y portion of the offset.
|
||||
* @param {number} degrees Angle in degrees (zero points in +X direction).
|
||||
* @param {number} radius Radius.
|
||||
* @return {number} The y-distance for the angle and radius.
|
||||
*/
|
||||
goog.math.angleDy = function(degrees, radius) {
|
||||
return radius * Math.sin(goog.math.toRadians(degrees));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Computes the angle between two points (x1,y1) and (x2,y2).
|
||||
* Angle zero points in the +X direction, 90 degrees points in the +Y
|
||||
* direction (down) and from there we grow clockwise towards 360 degrees.
|
||||
* @param {number} x1 x of first point.
|
||||
* @param {number} y1 y of first point.
|
||||
* @param {number} x2 x of second point.
|
||||
* @param {number} y2 y of second point.
|
||||
* @return {number} Standardized angle in degrees of the vector from
|
||||
* x1,y1 to x2,y2.
|
||||
*/
|
||||
goog.math.angle = function(x1, y1, x2, y2) {
|
||||
return goog.math.standardAngle(
|
||||
goog.math.toDegrees(Math.atan2(y2 - y1, x2 - x1)));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Computes the difference between startAngle and endAngle (angles in degrees).
|
||||
* @param {number} startAngle Start angle in degrees.
|
||||
* @param {number} endAngle End angle in degrees.
|
||||
* @return {number} The number of degrees that when added to
|
||||
* startAngle will result in endAngle. Positive numbers mean that the
|
||||
* direction is clockwise. Negative numbers indicate a counter-clockwise
|
||||
* direction.
|
||||
* The shortest route (clockwise vs counter-clockwise) between the angles
|
||||
* is used.
|
||||
* When the difference is 180 degrees, the function returns 180 (not -180)
|
||||
* angleDifference(30, 40) is 10, and angleDifference(40, 30) is -10.
|
||||
* angleDifference(350, 10) is 20, and angleDifference(10, 350) is -20.
|
||||
*/
|
||||
goog.math.angleDifference = function(startAngle, endAngle) {
|
||||
var d =
|
||||
goog.math.standardAngle(endAngle) - goog.math.standardAngle(startAngle);
|
||||
if (d > 180) {
|
||||
d = d - 360;
|
||||
} else if (d <= -180) {
|
||||
d = 360 + d;
|
||||
}
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the sign of a number as per the "sign" or "signum" function.
|
||||
* @param {number} x The number to take the sign of.
|
||||
* @return {number} -1 when negative, 1 when positive, 0 when 0. Preserves
|
||||
* signed zeros and NaN.
|
||||
*/
|
||||
goog.math.sign = function(x) {
|
||||
if (x > 0) {
|
||||
return 1;
|
||||
}
|
||||
if (x < 0) {
|
||||
return -1;
|
||||
}
|
||||
return x; // Preserves signed zeros and NaN.
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* JavaScript implementation of Longest Common Subsequence problem.
|
||||
* http://en.wikipedia.org/wiki/Longest_common_subsequence
|
||||
*
|
||||
* Returns the longest possible array that is subarray of both of given arrays.
|
||||
*
|
||||
* @param {IArrayLike<S>} array1 First array of objects.
|
||||
* @param {IArrayLike<T>} array2 Second array of objects.
|
||||
* @param {Function=} opt_compareFn Function that acts as a custom comparator
|
||||
* for the array ojects. Function should return true if objects are equal,
|
||||
* otherwise false.
|
||||
* @param {Function=} opt_collectorFn Function used to decide what to return
|
||||
* as a result subsequence. It accepts 2 arguments: index of common element
|
||||
* in the first array and index in the second. The default function returns
|
||||
* element from the first array.
|
||||
* @return {!Array<S|T>} A list of objects that are common to both arrays
|
||||
* such that there is no common subsequence with size greater than the
|
||||
* length of the list.
|
||||
* @template S,T
|
||||
*/
|
||||
goog.math.longestCommonSubsequence = function(
|
||||
array1, array2, opt_compareFn, opt_collectorFn) {
|
||||
|
||||
var compare = opt_compareFn || function(a, b) { return a == b; };
|
||||
|
||||
var collect = opt_collectorFn || function(i1, i2) { return array1[i1]; };
|
||||
|
||||
var length1 = array1.length;
|
||||
var length2 = array2.length;
|
||||
|
||||
var arr = [];
|
||||
for (var i = 0; i < length1 + 1; i++) {
|
||||
arr[i] = [];
|
||||
arr[i][0] = 0;
|
||||
}
|
||||
|
||||
for (var j = 0; j < length2 + 1; j++) {
|
||||
arr[0][j] = 0;
|
||||
}
|
||||
|
||||
for (i = 1; i <= length1; i++) {
|
||||
for (j = 1; j <= length2; j++) {
|
||||
if (compare(array1[i - 1], array2[j - 1])) {
|
||||
arr[i][j] = arr[i - 1][j - 1] + 1;
|
||||
} else {
|
||||
arr[i][j] = Math.max(arr[i - 1][j], arr[i][j - 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Backtracking
|
||||
var result = [];
|
||||
var i = length1, j = length2;
|
||||
while (i > 0 && j > 0) {
|
||||
if (compare(array1[i - 1], array2[j - 1])) {
|
||||
result.unshift(collect(i - 1, j - 1));
|
||||
i--;
|
||||
j--;
|
||||
} else {
|
||||
if (arr[i - 1][j] > arr[i][j - 1]) {
|
||||
i--;
|
||||
} else {
|
||||
j--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the sum of the arguments.
|
||||
* @param {...number} var_args Numbers to add.
|
||||
* @return {number} The sum of the arguments (0 if no arguments were provided,
|
||||
* {@code NaN} if any of the arguments is not a valid number).
|
||||
*/
|
||||
goog.math.sum = function(var_args) {
|
||||
return /** @type {number} */ (
|
||||
goog.array.reduce(
|
||||
arguments, function(sum, value) { return sum + value; }, 0));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the arithmetic mean of the arguments.
|
||||
* @param {...number} var_args Numbers to average.
|
||||
* @return {number} The average of the arguments ({@code NaN} if no arguments
|
||||
* were provided or any of the arguments is not a valid number).
|
||||
*/
|
||||
goog.math.average = function(var_args) {
|
||||
return goog.math.sum.apply(null, arguments) / arguments.length;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the unbiased sample variance of the arguments. For a definition,
|
||||
* see e.g. http://en.wikipedia.org/wiki/Variance
|
||||
* @param {...number} var_args Number samples to analyze.
|
||||
* @return {number} The unbiased sample variance of the arguments (0 if fewer
|
||||
* than two samples were provided, or {@code NaN} if any of the samples is
|
||||
* not a valid number).
|
||||
*/
|
||||
goog.math.sampleVariance = function(var_args) {
|
||||
var sampleSize = arguments.length;
|
||||
if (sampleSize < 2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
var mean = goog.math.average.apply(null, arguments);
|
||||
var variance =
|
||||
goog.math.sum.apply(null, goog.array.map(arguments, function(val) {
|
||||
return Math.pow(val - mean, 2);
|
||||
})) / (sampleSize - 1);
|
||||
|
||||
return variance;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the sample standard deviation of the arguments. For a definition of
|
||||
* sample standard deviation, see e.g.
|
||||
* http://en.wikipedia.org/wiki/Standard_deviation
|
||||
* @param {...number} var_args Number samples to analyze.
|
||||
* @return {number} The sample standard deviation of the arguments (0 if fewer
|
||||
* than two samples were provided, or {@code NaN} if any of the samples is
|
||||
* not a valid number).
|
||||
*/
|
||||
goog.math.standardDeviation = function(var_args) {
|
||||
return Math.sqrt(goog.math.sampleVariance.apply(null, arguments));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns whether the supplied number represents an integer, i.e. that is has
|
||||
* no fractional component. No range-checking is performed on the number.
|
||||
* @param {number} num The number to test.
|
||||
* @return {boolean} Whether {@code num} is an integer.
|
||||
*/
|
||||
goog.math.isInt = function(num) {
|
||||
return isFinite(num) && num % 1 == 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns whether the supplied number is finite and not NaN.
|
||||
* @param {number} num The number to test.
|
||||
* @return {boolean} Whether {@code num} is a finite number.
|
||||
* @deprecated Use {@link isFinite} instead.
|
||||
*/
|
||||
goog.math.isFiniteNumber = function(num) {
|
||||
return isFinite(num);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} num The number to test.
|
||||
* @return {boolean} Whether it is negative zero.
|
||||
*/
|
||||
goog.math.isNegativeZero = function(num) {
|
||||
return num == 0 && 1 / num < 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the precise value of floor(log10(num)).
|
||||
* Simpler implementations didn't work because of floating point rounding
|
||||
* errors. For example
|
||||
* <ul>
|
||||
* <li>Math.floor(Math.log(num) / Math.LN10) is off by one for num == 1e+3.
|
||||
* <li>Math.floor(Math.log(num) * Math.LOG10E) is off by one for num == 1e+15.
|
||||
* <li>Math.floor(Math.log10(num)) is off by one for num == 1e+15 - 1.
|
||||
* </ul>
|
||||
* @param {number} num A floating point number.
|
||||
* @return {number} Its logarithm to base 10 rounded down to the nearest
|
||||
* integer if num > 0. -Infinity if num == 0. NaN if num < 0.
|
||||
*/
|
||||
goog.math.log10Floor = function(num) {
|
||||
if (num > 0) {
|
||||
var x = Math.round(Math.log(num) * Math.LOG10E);
|
||||
return x - (parseFloat('1e' + x) > num ? 1 : 0);
|
||||
}
|
||||
return num == 0 ? -Infinity : NaN;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A tweaked variant of {@code Math.floor} which tolerates if the passed number
|
||||
* is infinitesimally smaller than the closest integer. It often happens with
|
||||
* the results of floating point calculations because of the finite precision
|
||||
* of the intermediate results. For example {@code Math.floor(Math.log(1000) /
|
||||
* Math.LN10) == 2}, not 3 as one would expect.
|
||||
* @param {number} num A number.
|
||||
* @param {number=} opt_epsilon An infinitesimally small positive number, the
|
||||
* rounding error to tolerate.
|
||||
* @return {number} The largest integer less than or equal to {@code num}.
|
||||
*/
|
||||
goog.math.safeFloor = function(num, opt_epsilon) {
|
||||
goog.asserts.assert(!goog.isDef(opt_epsilon) || opt_epsilon > 0);
|
||||
return Math.floor(num + (opt_epsilon || 2e-15));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A tweaked variant of {@code Math.ceil}. See {@code goog.math.safeFloor} for
|
||||
* details.
|
||||
* @param {number} num A number.
|
||||
* @param {number=} opt_epsilon An infinitesimally small positive number, the
|
||||
* rounding error to tolerate.
|
||||
* @return {number} The smallest integer greater than or equal to {@code num}.
|
||||
*/
|
||||
goog.math.safeCeil = function(num, opt_epsilon) {
|
||||
goog.asserts.assert(!goog.isDef(opt_epsilon) || opt_epsilon > 0);
|
||||
return Math.ceil(num - (opt_epsilon || 2e-15));
|
||||
};
|
||||
227
resources/public/target/cljsbuild-compiler-1/goog/math/size.js
Normal file
227
resources/public/target/cljsbuild-compiler-1/goog/math/size.js
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
// Copyright 2007 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 A utility class for representing two-dimensional sizes.
|
||||
* @author brenneman@google.com (Shawn Brenneman)
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.math.Size');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Class for representing sizes consisting of a width and height. Undefined
|
||||
* width and height support is deprecated and results in compiler warning.
|
||||
* @param {number} width Width.
|
||||
* @param {number} height Height.
|
||||
* @struct
|
||||
* @constructor
|
||||
*/
|
||||
goog.math.Size = function(width, height) {
|
||||
/**
|
||||
* Width
|
||||
* @type {number}
|
||||
*/
|
||||
this.width = width;
|
||||
|
||||
/**
|
||||
* Height
|
||||
* @type {number}
|
||||
*/
|
||||
this.height = height;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Compares sizes for equality.
|
||||
* @param {goog.math.Size} a A Size.
|
||||
* @param {goog.math.Size} b A Size.
|
||||
* @return {boolean} True iff the sizes have equal widths and equal
|
||||
* heights, or if both are null.
|
||||
*/
|
||||
goog.math.Size.equals = function(a, b) {
|
||||
if (a == b) {
|
||||
return true;
|
||||
}
|
||||
if (!a || !b) {
|
||||
return false;
|
||||
}
|
||||
return a.width == b.width && a.height == b.height;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {!goog.math.Size} A new copy of the Size.
|
||||
*/
|
||||
goog.math.Size.prototype.clone = function() {
|
||||
return new goog.math.Size(this.width, this.height);
|
||||
};
|
||||
|
||||
|
||||
if (goog.DEBUG) {
|
||||
/**
|
||||
* Returns a nice string representing size.
|
||||
* @return {string} In the form (50 x 73).
|
||||
* @override
|
||||
*/
|
||||
goog.math.Size.prototype.toString = function() {
|
||||
return '(' + this.width + ' x ' + this.height + ')';
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} The longer of the two dimensions in the size.
|
||||
*/
|
||||
goog.math.Size.prototype.getLongest = function() {
|
||||
return Math.max(this.width, this.height);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} The shorter of the two dimensions in the size.
|
||||
*/
|
||||
goog.math.Size.prototype.getShortest = function() {
|
||||
return Math.min(this.width, this.height);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} The area of the size (width * height).
|
||||
*/
|
||||
goog.math.Size.prototype.area = function() {
|
||||
return this.width * this.height;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} The perimeter of the size (width + height) * 2.
|
||||
*/
|
||||
goog.math.Size.prototype.perimeter = function() {
|
||||
return (this.width + this.height) * 2;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} The ratio of the size's width to its height.
|
||||
*/
|
||||
goog.math.Size.prototype.aspectRatio = function() {
|
||||
return this.width / this.height;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} True if the size has zero area, false if both dimensions
|
||||
* are non-zero numbers.
|
||||
*/
|
||||
goog.math.Size.prototype.isEmpty = function() {
|
||||
return !this.area();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clamps the width and height parameters upward to integer values.
|
||||
* @return {!goog.math.Size} This size with ceil'd components.
|
||||
*/
|
||||
goog.math.Size.prototype.ceil = function() {
|
||||
this.width = Math.ceil(this.width);
|
||||
this.height = Math.ceil(this.height);
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {!goog.math.Size} target The target size.
|
||||
* @return {boolean} True if this Size is the same size or smaller than the
|
||||
* target size in both dimensions.
|
||||
*/
|
||||
goog.math.Size.prototype.fitsInside = function(target) {
|
||||
return this.width <= target.width && this.height <= target.height;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clamps the width and height parameters downward to integer values.
|
||||
* @return {!goog.math.Size} This size with floored components.
|
||||
*/
|
||||
goog.math.Size.prototype.floor = function() {
|
||||
this.width = Math.floor(this.width);
|
||||
this.height = Math.floor(this.height);
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Rounds the width and height parameters to integer values.
|
||||
* @return {!goog.math.Size} This size with rounded components.
|
||||
*/
|
||||
goog.math.Size.prototype.round = function() {
|
||||
this.width = Math.round(this.width);
|
||||
this.height = Math.round(this.height);
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Scales this size by the given scale factors. The width and height are scaled
|
||||
* by {@code sx} and {@code opt_sy} respectively. If {@code opt_sy} is not
|
||||
* given, then {@code sx} is used for both the width and height.
|
||||
* @param {number} sx The scale factor to use for the width.
|
||||
* @param {number=} opt_sy The scale factor to use for the height.
|
||||
* @return {!goog.math.Size} This Size object after scaling.
|
||||
*/
|
||||
goog.math.Size.prototype.scale = function(sx, opt_sy) {
|
||||
var sy = goog.isNumber(opt_sy) ? opt_sy : sx;
|
||||
this.width *= sx;
|
||||
this.height *= sy;
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Uniformly scales the size to perfectly cover the dimensions of a given size.
|
||||
* If the size is already larger than the target, it will be scaled down to the
|
||||
* minimum size at which it still covers the entire target. The original aspect
|
||||
* ratio will be preserved.
|
||||
*
|
||||
* This function assumes that both Sizes contain strictly positive dimensions.
|
||||
* @param {!goog.math.Size} target The target size.
|
||||
* @return {!goog.math.Size} This Size object, after optional scaling.
|
||||
*/
|
||||
goog.math.Size.prototype.scaleToCover = function(target) {
|
||||
var s = this.aspectRatio() <= target.aspectRatio() ?
|
||||
target.width / this.width :
|
||||
target.height / this.height;
|
||||
|
||||
return this.scale(s);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Uniformly scales the size to fit inside the dimensions of a given size. The
|
||||
* original aspect ratio will be preserved.
|
||||
*
|
||||
* This function assumes that both Sizes contain strictly positive dimensions.
|
||||
* @param {!goog.math.Size} target The target size.
|
||||
* @return {!goog.math.Size} This Size object, after optional scaling.
|
||||
*/
|
||||
goog.math.Size.prototype.scaleToFit = function(target) {
|
||||
var s = this.aspectRatio() > target.aspectRatio() ?
|
||||
target.width / this.width :
|
||||
target.height / this.height;
|
||||
|
||||
return this.scale(s);
|
||||
};
|
||||
|
|
@ -0,0 +1,945 @@
|
|||
// Copyright 2007 Bob Ippolito. All Rights Reserved.
|
||||
// Modifications Copyright 2009 The Closure Library Authors. All Rights
|
||||
// Reserved.
|
||||
|
||||
/**
|
||||
* @license Portions of this code are from MochiKit, received by
|
||||
* The Closure Authors under the MIT license. All other code is Copyright
|
||||
* 2005-2009 The Closure Authors. All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Classes for tracking asynchronous operations and handling the
|
||||
* results. The Deferred object here is patterned after the Deferred object in
|
||||
* the Twisted python networking framework.
|
||||
*
|
||||
* See: http://twistedmatrix.com/projects/core/documentation/howto/defer.html
|
||||
*
|
||||
* Based on the Dojo code which in turn is based on the MochiKit code.
|
||||
*
|
||||
* @author arv@google.com (Erik Arvidsson)
|
||||
* @author brenneman@google.com (Shawn Brenneman)
|
||||
*/
|
||||
|
||||
goog.provide('goog.async.Deferred');
|
||||
goog.provide('goog.async.Deferred.AlreadyCalledError');
|
||||
goog.provide('goog.async.Deferred.CanceledError');
|
||||
|
||||
goog.require('goog.Promise');
|
||||
goog.require('goog.Thenable');
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.debug.Error');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A Deferred represents the result of an asynchronous operation. A Deferred
|
||||
* instance has no result when it is created, and is "fired" (given an initial
|
||||
* result) by calling {@code callback} or {@code errback}.
|
||||
*
|
||||
* Once fired, the result is passed through a sequence of callback functions
|
||||
* registered with {@code addCallback} or {@code addErrback}. The functions may
|
||||
* mutate the result before it is passed to the next function in the sequence.
|
||||
*
|
||||
* Callbacks and errbacks may be added at any time, including after the Deferred
|
||||
* has been "fired". If there are no pending actions in the execution sequence
|
||||
* of a fired Deferred, any new callback functions will be called with the last
|
||||
* computed result. Adding a callback function is the only way to access the
|
||||
* result of the Deferred.
|
||||
*
|
||||
* If a Deferred operation is canceled, an optional user-provided cancellation
|
||||
* function is invoked which may perform any special cleanup, followed by firing
|
||||
* the Deferred's errback sequence with a {@code CanceledError}. If the
|
||||
* Deferred has already fired, cancellation is ignored.
|
||||
*
|
||||
* Deferreds may be templated to a specific type they produce using generics
|
||||
* with syntax such as:
|
||||
*
|
||||
* /** @type {goog.async.Deferred<string>} *\
|
||||
* var d = new goog.async.Deferred();
|
||||
* // Compiler can infer that foo is a string.
|
||||
* d.addCallback(function(foo) {...});
|
||||
* d.callback('string'); // Checked to be passed a string
|
||||
*
|
||||
* Since deferreds are often used to produce different values across a chain,
|
||||
* the type information is not propagated across chains, but rather only
|
||||
* associated with specifically cast objects.
|
||||
*
|
||||
* @param {Function=} opt_onCancelFunction A function that will be called if the
|
||||
* Deferred is canceled. If provided, this function runs before the
|
||||
* Deferred is fired with a {@code CanceledError}.
|
||||
* @param {Object=} opt_defaultScope The default object context to call
|
||||
* callbacks and errbacks in.
|
||||
* @constructor
|
||||
* @implements {goog.Thenable<VALUE>}
|
||||
* @template VALUE
|
||||
*/
|
||||
goog.async.Deferred = function(opt_onCancelFunction, opt_defaultScope) {
|
||||
/**
|
||||
* Entries in the sequence are arrays containing a callback, an errback, and
|
||||
* an optional scope. The callback or errback in an entry may be null.
|
||||
* @type {!Array<!Array>}
|
||||
* @private
|
||||
*/
|
||||
this.sequence_ = [];
|
||||
|
||||
/**
|
||||
* Optional function that will be called if the Deferred is canceled.
|
||||
* @type {Function|undefined}
|
||||
* @private
|
||||
*/
|
||||
this.onCancelFunction_ = opt_onCancelFunction;
|
||||
|
||||
/**
|
||||
* The default scope to execute callbacks and errbacks in.
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
this.defaultScope_ = opt_defaultScope || null;
|
||||
|
||||
/**
|
||||
* Whether the Deferred has been fired.
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
this.fired_ = false;
|
||||
|
||||
/**
|
||||
* Whether the last result in the execution sequence was an error.
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
this.hadError_ = false;
|
||||
|
||||
/**
|
||||
* The current Deferred result, updated as callbacks and errbacks are
|
||||
* executed.
|
||||
* @type {*}
|
||||
* @private
|
||||
*/
|
||||
this.result_ = undefined;
|
||||
|
||||
/**
|
||||
* Whether the Deferred is blocked waiting on another Deferred to fire. If a
|
||||
* callback or errback returns a Deferred as a result, the execution sequence
|
||||
* is blocked until that Deferred result becomes available.
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
this.blocked_ = false;
|
||||
|
||||
/**
|
||||
* Whether this Deferred is blocking execution of another Deferred. If this
|
||||
* instance was returned as a result in another Deferred's execution
|
||||
* sequence,that other Deferred becomes blocked until this instance's
|
||||
* execution sequence completes. No additional callbacks may be added to a
|
||||
* Deferred once it is blocking another instance.
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
this.blocking_ = false;
|
||||
|
||||
/**
|
||||
* Whether the Deferred has been canceled without having a custom cancel
|
||||
* function.
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
this.silentlyCanceled_ = false;
|
||||
|
||||
/**
|
||||
* If an error is thrown during Deferred execution with no errback to catch
|
||||
* it, the error is rethrown after a timeout. Reporting the error after a
|
||||
* timeout allows execution to continue in the calling context (empty when
|
||||
* no error is scheduled).
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.unhandledErrorId_ = 0;
|
||||
|
||||
/**
|
||||
* If this Deferred was created by branch(), this will be the "parent"
|
||||
* Deferred.
|
||||
* @type {goog.async.Deferred}
|
||||
* @private
|
||||
*/
|
||||
this.parent_ = null;
|
||||
|
||||
/**
|
||||
* The number of Deferred objects that have been branched off this one. This
|
||||
* will be decremented whenever a branch is fired or canceled.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.branches_ = 0;
|
||||
|
||||
if (goog.async.Deferred.LONG_STACK_TRACES) {
|
||||
/**
|
||||
* Holds the stack trace at time of deferred creation if the JS engine
|
||||
* provides the Error.captureStackTrace API.
|
||||
* @private {?string}
|
||||
*/
|
||||
this.constructorStack_ = null;
|
||||
if (Error.captureStackTrace) {
|
||||
var target = { stack: '' };
|
||||
Error.captureStackTrace(target, goog.async.Deferred);
|
||||
// Check if Error.captureStackTrace worked. It fails in gjstest.
|
||||
if (typeof target.stack == 'string') {
|
||||
// Remove first line and force stringify to prevent memory leak due to
|
||||
// holding on to actual stack frames.
|
||||
this.constructorStack_ = target.stack.replace(/^[^\n]*\n/, '');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Whether unhandled errors should always get rethrown to the
|
||||
* global scope. Defaults to the value of goog.DEBUG.
|
||||
*/
|
||||
goog.define('goog.async.Deferred.STRICT_ERRORS', false);
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Whether to attempt to make stack traces long. Defaults to
|
||||
* the value of goog.DEBUG.
|
||||
*/
|
||||
goog.define('goog.async.Deferred.LONG_STACK_TRACES', false);
|
||||
|
||||
|
||||
/**
|
||||
* Cancels a Deferred that has not yet been fired, or is blocked on another
|
||||
* deferred operation. If this Deferred is waiting for a blocking Deferred to
|
||||
* fire, the blocking Deferred will also be canceled.
|
||||
*
|
||||
* If this Deferred was created by calling branch() on a parent Deferred with
|
||||
* opt_propagateCancel set to true, the parent may also be canceled. If
|
||||
* opt_deepCancel is set, cancel() will be called on the parent (as well as any
|
||||
* other ancestors if the parent is also a branch). If one or more branches were
|
||||
* created with opt_propagateCancel set to true, the parent will be canceled if
|
||||
* cancel() is called on all of those branches.
|
||||
*
|
||||
* @param {boolean=} opt_deepCancel If true, cancels this Deferred's parent even
|
||||
* if cancel() hasn't been called on some of the parent's branches. Has no
|
||||
* effect on a branch without opt_propagateCancel set to true.
|
||||
*/
|
||||
goog.async.Deferred.prototype.cancel = function(opt_deepCancel) {
|
||||
if (!this.hasFired()) {
|
||||
if (this.parent_) {
|
||||
// Get rid of the parent reference before potentially running the parent's
|
||||
// canceler function to ensure that this cancellation isn't
|
||||
// double-counted.
|
||||
var parent = this.parent_;
|
||||
delete this.parent_;
|
||||
if (opt_deepCancel) {
|
||||
parent.cancel(opt_deepCancel);
|
||||
} else {
|
||||
parent.branchCancel_();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.onCancelFunction_) {
|
||||
// Call in user-specified scope.
|
||||
this.onCancelFunction_.call(this.defaultScope_, this);
|
||||
} else {
|
||||
this.silentlyCanceled_ = true;
|
||||
}
|
||||
if (!this.hasFired()) {
|
||||
this.errback(new goog.async.Deferred.CanceledError(this));
|
||||
}
|
||||
} else if (this.result_ instanceof goog.async.Deferred) {
|
||||
this.result_.cancel();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handle a single branch being canceled. Once all branches are canceled, this
|
||||
* Deferred will be canceled as well.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
goog.async.Deferred.prototype.branchCancel_ = function() {
|
||||
this.branches_--;
|
||||
if (this.branches_ <= 0) {
|
||||
this.cancel();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Called after a blocking Deferred fires. Unblocks this Deferred and resumes
|
||||
* its execution sequence.
|
||||
*
|
||||
* @param {boolean} isSuccess Whether the result is a success or an error.
|
||||
* @param {*} res The result of the blocking Deferred.
|
||||
* @private
|
||||
*/
|
||||
goog.async.Deferred.prototype.continue_ = function(isSuccess, res) {
|
||||
this.blocked_ = false;
|
||||
this.updateResult_(isSuccess, res);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Updates the current result based on the success or failure of the last action
|
||||
* in the execution sequence.
|
||||
*
|
||||
* @param {boolean} isSuccess Whether the new result is a success or an error.
|
||||
* @param {*} res The result.
|
||||
* @private
|
||||
*/
|
||||
goog.async.Deferred.prototype.updateResult_ = function(isSuccess, res) {
|
||||
this.fired_ = true;
|
||||
this.result_ = res;
|
||||
this.hadError_ = !isSuccess;
|
||||
this.fire_();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Verifies that the Deferred has not yet been fired.
|
||||
*
|
||||
* @private
|
||||
* @throws {Error} If this has already been fired.
|
||||
*/
|
||||
goog.async.Deferred.prototype.check_ = function() {
|
||||
if (this.hasFired()) {
|
||||
if (!this.silentlyCanceled_) {
|
||||
throw new goog.async.Deferred.AlreadyCalledError(this);
|
||||
}
|
||||
this.silentlyCanceled_ = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Fire the execution sequence for this Deferred by passing the starting result
|
||||
* to the first registered callback.
|
||||
* @param {VALUE=} opt_result The starting result.
|
||||
*/
|
||||
goog.async.Deferred.prototype.callback = function(opt_result) {
|
||||
this.check_();
|
||||
this.assertNotDeferred_(opt_result);
|
||||
this.updateResult_(true /* isSuccess */, opt_result);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Fire the execution sequence for this Deferred by passing the starting error
|
||||
* result to the first registered errback.
|
||||
* @param {*=} opt_result The starting error.
|
||||
*/
|
||||
goog.async.Deferred.prototype.errback = function(opt_result) {
|
||||
this.check_();
|
||||
this.assertNotDeferred_(opt_result);
|
||||
this.makeStackTraceLong_(opt_result);
|
||||
this.updateResult_(false /* isSuccess */, opt_result);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Attempt to make the error's stack trace be long in that it contains the
|
||||
* stack trace from the point where the deferred was created on top of the
|
||||
* current stack trace to give additional context.
|
||||
* @param {*} error
|
||||
* @private
|
||||
*/
|
||||
goog.async.Deferred.prototype.makeStackTraceLong_ = function(error) {
|
||||
if (!goog.async.Deferred.LONG_STACK_TRACES) {
|
||||
return;
|
||||
}
|
||||
if (this.constructorStack_ && goog.isObject(error) && error.stack &&
|
||||
// Stack looks like it was system generated. See
|
||||
// https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi
|
||||
(/^[^\n]+(\n [^\n]+)+/).test(error.stack)) {
|
||||
error.stack = error.stack + '\nDEFERRED OPERATION:\n' +
|
||||
this.constructorStack_;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Asserts that an object is not a Deferred.
|
||||
* @param {*} obj The object to test.
|
||||
* @throws {Error} Throws an exception if the object is a Deferred.
|
||||
* @private
|
||||
*/
|
||||
goog.async.Deferred.prototype.assertNotDeferred_ = function(obj) {
|
||||
goog.asserts.assert(
|
||||
!(obj instanceof goog.async.Deferred),
|
||||
'An execution sequence may not be initiated with a blocking Deferred.');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Register a callback function to be called with a successful result. If no
|
||||
* value is returned by the callback function, the result value is unchanged. If
|
||||
* a new value is returned, it becomes the Deferred result and will be passed to
|
||||
* the next callback in the execution sequence.
|
||||
*
|
||||
* If the function throws an error, the error becomes the new result and will be
|
||||
* passed to the next errback in the execution chain.
|
||||
*
|
||||
* If the function returns a Deferred, the execution sequence will be blocked
|
||||
* until that Deferred fires. Its result will be passed to the next callback (or
|
||||
* errback if it is an error result) in this Deferred's execution sequence.
|
||||
*
|
||||
* @param {function(this:T,VALUE):?} cb The function to be called with a
|
||||
* successful result.
|
||||
* @param {T=} opt_scope An optional scope to call the callback in.
|
||||
* @return {!goog.async.Deferred} This Deferred.
|
||||
* @template T
|
||||
*/
|
||||
goog.async.Deferred.prototype.addCallback = function(cb, opt_scope) {
|
||||
return this.addCallbacks(cb, null, opt_scope);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Register a callback function to be called with an error result. If no value
|
||||
* is returned by the function, the error result is unchanged. If a new error
|
||||
* value is returned or thrown, that error becomes the Deferred result and will
|
||||
* be passed to the next errback in the execution sequence.
|
||||
*
|
||||
* If the errback function handles the error by returning a non-error value,
|
||||
* that result will be passed to the next normal callback in the sequence.
|
||||
*
|
||||
* If the function returns a Deferred, the execution sequence will be blocked
|
||||
* until that Deferred fires. Its result will be passed to the next callback (or
|
||||
* errback if it is an error result) in this Deferred's execution sequence.
|
||||
*
|
||||
* @param {function(this:T,?):?} eb The function to be called on an
|
||||
* unsuccessful result.
|
||||
* @param {T=} opt_scope An optional scope to call the errback in.
|
||||
* @return {!goog.async.Deferred<VALUE>} This Deferred.
|
||||
* @template T
|
||||
*/
|
||||
goog.async.Deferred.prototype.addErrback = function(eb, opt_scope) {
|
||||
return this.addCallbacks(null, eb, opt_scope);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Registers one function as both a callback and errback.
|
||||
*
|
||||
* @param {function(this:T,?):?} f The function to be called on any result.
|
||||
* @param {T=} opt_scope An optional scope to call the function in.
|
||||
* @return {!goog.async.Deferred} This Deferred.
|
||||
* @template T
|
||||
*/
|
||||
goog.async.Deferred.prototype.addBoth = function(f, opt_scope) {
|
||||
return this.addCallbacks(f, f, opt_scope);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Like addBoth, but propagates uncaught exceptions in the errback.
|
||||
*
|
||||
* @param {function(this:T,?):?} f The function to be called on any result.
|
||||
* @param {T=} opt_scope An optional scope to call the function in.
|
||||
* @return {!goog.async.Deferred<VALUE>} This Deferred.
|
||||
* @template T
|
||||
*/
|
||||
goog.async.Deferred.prototype.addFinally = function(f, opt_scope) {
|
||||
return this.addCallbacks(f, function(err) {
|
||||
var result = f.call(/** @type {?} */ (this), err);
|
||||
if (!goog.isDef(result)) {
|
||||
throw err;
|
||||
}
|
||||
return result;
|
||||
}, opt_scope);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Registers a callback function and an errback function at the same position
|
||||
* in the execution sequence. Only one of these functions will execute,
|
||||
* depending on the error state during the execution sequence.
|
||||
*
|
||||
* NOTE: This is not equivalent to {@code def.addCallback().addErrback()}! If
|
||||
* the callback is invoked, the errback will be skipped, and vice versa.
|
||||
*
|
||||
* @param {?(function(this:T,VALUE):?)} cb The function to be called on a
|
||||
* successful result.
|
||||
* @param {?(function(this:T,?):?)} eb The function to be called on an
|
||||
* unsuccessful result.
|
||||
* @param {T=} opt_scope An optional scope to call the functions in.
|
||||
* @return {!goog.async.Deferred} This Deferred.
|
||||
* @template T
|
||||
*/
|
||||
goog.async.Deferred.prototype.addCallbacks = function(cb, eb, opt_scope) {
|
||||
goog.asserts.assert(!this.blocking_, 'Blocking Deferreds can not be re-used');
|
||||
this.sequence_.push([cb, eb, opt_scope]);
|
||||
if (this.hasFired()) {
|
||||
this.fire_();
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Implements {@see goog.Thenable} for seamless integration with
|
||||
* {@see goog.Promise}.
|
||||
* Deferred results are mutable and may represent multiple values over
|
||||
* their lifetime. Calling {@code then} on a Deferred returns a Promise
|
||||
* with the result of the Deferred at that point in its callback chain.
|
||||
* Note that if the Deferred result is never mutated, and only
|
||||
* {@code then} calls are made, the Deferred will behave like a Promise.
|
||||
*
|
||||
* @override
|
||||
*/
|
||||
goog.async.Deferred.prototype.then = function(opt_onFulfilled, opt_onRejected,
|
||||
opt_context) {
|
||||
var resolve, reject;
|
||||
var promise = new goog.Promise(function(res, rej) {
|
||||
// Copying resolvers to outer scope, so that they are available when the
|
||||
// deferred callback fires (which may be synchronous).
|
||||
resolve = res;
|
||||
reject = rej;
|
||||
});
|
||||
this.addCallbacks(resolve, function(reason) {
|
||||
if (reason instanceof goog.async.Deferred.CanceledError) {
|
||||
promise.cancel();
|
||||
} else {
|
||||
reject(reason);
|
||||
}
|
||||
});
|
||||
return promise.then(opt_onFulfilled, opt_onRejected, opt_context);
|
||||
};
|
||||
goog.Thenable.addImplementation(goog.async.Deferred);
|
||||
|
||||
|
||||
/**
|
||||
* Links another Deferred to the end of this Deferred's execution sequence. The
|
||||
* result of this execution sequence will be passed as the starting result for
|
||||
* the chained Deferred, invoking either its first callback or errback.
|
||||
*
|
||||
* @param {!goog.async.Deferred} otherDeferred The Deferred to chain.
|
||||
* @return {!goog.async.Deferred} This Deferred.
|
||||
*/
|
||||
goog.async.Deferred.prototype.chainDeferred = function(otherDeferred) {
|
||||
this.addCallbacks(
|
||||
otherDeferred.callback, otherDeferred.errback, otherDeferred);
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Makes this Deferred wait for another Deferred's execution sequence to
|
||||
* complete before continuing.
|
||||
*
|
||||
* This is equivalent to adding a callback that returns {@code otherDeferred},
|
||||
* but doesn't prevent additional callbacks from being added to
|
||||
* {@code otherDeferred}.
|
||||
*
|
||||
* @param {!goog.async.Deferred|!goog.Thenable} otherDeferred The Deferred
|
||||
* to wait for.
|
||||
* @return {!goog.async.Deferred} This Deferred.
|
||||
*/
|
||||
goog.async.Deferred.prototype.awaitDeferred = function(otherDeferred) {
|
||||
if (!(otherDeferred instanceof goog.async.Deferred)) {
|
||||
// The Thenable case.
|
||||
return this.addCallback(function() {
|
||||
return otherDeferred;
|
||||
});
|
||||
}
|
||||
return this.addCallback(goog.bind(otherDeferred.branch, otherDeferred));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a branch off this Deferred's execution sequence, and returns it as a
|
||||
* new Deferred. The branched Deferred's starting result will be shared with the
|
||||
* parent at the point of the branch, even if further callbacks are added to the
|
||||
* parent.
|
||||
*
|
||||
* All branches at the same stage in the execution sequence will receive the
|
||||
* same starting value.
|
||||
*
|
||||
* @param {boolean=} opt_propagateCancel If cancel() is called on every child
|
||||
* branch created with opt_propagateCancel, the parent will be canceled as
|
||||
* well.
|
||||
* @return {!goog.async.Deferred<VALUE>} A Deferred that will be started with
|
||||
* the computed result from this stage in the execution sequence.
|
||||
*/
|
||||
goog.async.Deferred.prototype.branch = function(opt_propagateCancel) {
|
||||
var d = new goog.async.Deferred();
|
||||
this.chainDeferred(d);
|
||||
if (opt_propagateCancel) {
|
||||
d.parent_ = this;
|
||||
this.branches_++;
|
||||
}
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the execution sequence has been started on this
|
||||
* Deferred by invoking {@code callback} or {@code errback}.
|
||||
*/
|
||||
goog.async.Deferred.prototype.hasFired = function() {
|
||||
return this.fired_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {*} res The latest result in the execution sequence.
|
||||
* @return {boolean} Whether the current result is an error that should cause
|
||||
* the next errback to fire. May be overridden by subclasses to handle
|
||||
* special error types.
|
||||
* @protected
|
||||
*/
|
||||
goog.async.Deferred.prototype.isError = function(res) {
|
||||
return res instanceof Error;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether an errback exists in the remaining sequence.
|
||||
* @private
|
||||
*/
|
||||
goog.async.Deferred.prototype.hasErrback_ = function() {
|
||||
return goog.array.some(this.sequence_, function(sequenceRow) {
|
||||
// The errback is the second element in the array.
|
||||
return goog.isFunction(sequenceRow[1]);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Exhausts the execution sequence while a result is available. The result may
|
||||
* be modified by callbacks or errbacks, and execution will block if the
|
||||
* returned result is an incomplete Deferred.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
goog.async.Deferred.prototype.fire_ = function() {
|
||||
if (this.unhandledErrorId_ && this.hasFired() && this.hasErrback_()) {
|
||||
// It is possible to add errbacks after the Deferred has fired. If a new
|
||||
// errback is added immediately after the Deferred encountered an unhandled
|
||||
// error, but before that error is rethrown, the error is unscheduled.
|
||||
goog.async.Deferred.unscheduleError_(this.unhandledErrorId_);
|
||||
this.unhandledErrorId_ = 0;
|
||||
}
|
||||
|
||||
if (this.parent_) {
|
||||
this.parent_.branches_--;
|
||||
delete this.parent_;
|
||||
}
|
||||
|
||||
var res = this.result_;
|
||||
var unhandledException = false;
|
||||
var isNewlyBlocked = false;
|
||||
|
||||
while (this.sequence_.length && !this.blocked_) {
|
||||
var sequenceEntry = this.sequence_.shift();
|
||||
|
||||
var callback = sequenceEntry[0];
|
||||
var errback = sequenceEntry[1];
|
||||
var scope = sequenceEntry[2];
|
||||
|
||||
var f = this.hadError_ ? errback : callback;
|
||||
if (f) {
|
||||
|
||||
try {
|
||||
var ret = f.call(scope || this.defaultScope_, res);
|
||||
|
||||
// If no result, then use previous result.
|
||||
if (goog.isDef(ret)) {
|
||||
// Bubble up the error as long as the return value hasn't changed.
|
||||
this.hadError_ = this.hadError_ && (ret == res || this.isError(ret));
|
||||
this.result_ = res = ret;
|
||||
}
|
||||
|
||||
if (goog.Thenable.isImplementedBy(res) ||
|
||||
(typeof goog.global['Promise'] === 'function' &&
|
||||
res instanceof goog.global['Promise'])) {
|
||||
isNewlyBlocked = true;
|
||||
this.blocked_ = true;
|
||||
}
|
||||
|
||||
} catch (ex) {
|
||||
res = ex;
|
||||
this.hadError_ = true;
|
||||
this.makeStackTraceLong_(res);
|
||||
|
||||
if (!this.hasErrback_()) {
|
||||
// If an error is thrown with no additional errbacks in the queue,
|
||||
// prepare to rethrow the error.
|
||||
unhandledException = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.result_ = res;
|
||||
|
||||
if (isNewlyBlocked) {
|
||||
var onCallback = goog.bind(this.continue_, this, true /* isSuccess */);
|
||||
var onErrback = goog.bind(this.continue_, this, false /* isSuccess */);
|
||||
|
||||
if (res instanceof goog.async.Deferred) {
|
||||
res.addCallbacks(onCallback, onErrback);
|
||||
res.blocking_ = true;
|
||||
} else {
|
||||
res.then(onCallback, onErrback);
|
||||
}
|
||||
} else if (goog.async.Deferred.STRICT_ERRORS && this.isError(res) &&
|
||||
!(res instanceof goog.async.Deferred.CanceledError)) {
|
||||
this.hadError_ = true;
|
||||
unhandledException = true;
|
||||
}
|
||||
|
||||
if (unhandledException) {
|
||||
// Rethrow the unhandled error after a timeout. Execution will continue, but
|
||||
// the error will be seen by global handlers and the user. The throw will
|
||||
// be canceled if another errback is appended before the timeout executes.
|
||||
// The error's original stack trace is preserved where available.
|
||||
this.unhandledErrorId_ = goog.async.Deferred.scheduleError_(res);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a Deferred that has an initial result.
|
||||
*
|
||||
* @param {*=} opt_result The result.
|
||||
* @return {!goog.async.Deferred} The new Deferred.
|
||||
*/
|
||||
goog.async.Deferred.succeed = function(opt_result) {
|
||||
var d = new goog.async.Deferred();
|
||||
d.callback(opt_result);
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a Deferred that fires when the given promise resolves.
|
||||
* Use only during migration to Promises.
|
||||
*
|
||||
* @param {!goog.Promise<T>} promise
|
||||
* @return {!goog.async.Deferred<T>} The new Deferred.
|
||||
* @template T
|
||||
*/
|
||||
goog.async.Deferred.fromPromise = function(promise) {
|
||||
var d = new goog.async.Deferred();
|
||||
d.callback();
|
||||
d.addCallback(function() {
|
||||
return promise;
|
||||
});
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a Deferred that has an initial error result.
|
||||
*
|
||||
* @param {*} res The error result.
|
||||
* @return {!goog.async.Deferred} The new Deferred.
|
||||
*/
|
||||
goog.async.Deferred.fail = function(res) {
|
||||
var d = new goog.async.Deferred();
|
||||
d.errback(res);
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a Deferred that has already been canceled.
|
||||
*
|
||||
* @return {!goog.async.Deferred} The new Deferred.
|
||||
*/
|
||||
goog.async.Deferred.canceled = function() {
|
||||
var d = new goog.async.Deferred();
|
||||
d.cancel();
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Normalizes values that may or may not be Deferreds.
|
||||
*
|
||||
* If the input value is a Deferred, the Deferred is branched (so the original
|
||||
* execution sequence is not modified) and the input callback added to the new
|
||||
* branch. The branch is returned to the caller.
|
||||
*
|
||||
* If the input value is not a Deferred, the callback will be executed
|
||||
* immediately and an already firing Deferred will be returned to the caller.
|
||||
*
|
||||
* In the following (contrived) example, if <code>isImmediate</code> is true
|
||||
* then 3 is alerted immediately, otherwise 6 is alerted after a 2-second delay.
|
||||
*
|
||||
* <pre>
|
||||
* var value;
|
||||
* if (isImmediate) {
|
||||
* value = 3;
|
||||
* } else {
|
||||
* value = new goog.async.Deferred();
|
||||
* setTimeout(function() { value.callback(6); }, 2000);
|
||||
* }
|
||||
*
|
||||
* var d = goog.async.Deferred.when(value, alert);
|
||||
* </pre>
|
||||
*
|
||||
* @param {*} value Deferred or normal value to pass to the callback.
|
||||
* @param {function(this:T, ?):?} callback The callback to execute.
|
||||
* @param {T=} opt_scope An optional scope to call the callback in.
|
||||
* @return {!goog.async.Deferred} A new Deferred that will call the input
|
||||
* callback with the input value.
|
||||
* @template T
|
||||
*/
|
||||
goog.async.Deferred.when = function(value, callback, opt_scope) {
|
||||
if (value instanceof goog.async.Deferred) {
|
||||
return value.branch(true).addCallback(callback, opt_scope);
|
||||
} else {
|
||||
return goog.async.Deferred.succeed(value).addCallback(callback, opt_scope);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* An error sub class that is used when a Deferred has already been called.
|
||||
* @param {!goog.async.Deferred} deferred The Deferred.
|
||||
*
|
||||
* @constructor
|
||||
* @extends {goog.debug.Error}
|
||||
*/
|
||||
goog.async.Deferred.AlreadyCalledError = function(deferred) {
|
||||
goog.debug.Error.call(this);
|
||||
|
||||
/**
|
||||
* The Deferred that raised this error.
|
||||
* @type {goog.async.Deferred}
|
||||
*/
|
||||
this.deferred = deferred;
|
||||
};
|
||||
goog.inherits(goog.async.Deferred.AlreadyCalledError, goog.debug.Error);
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.async.Deferred.AlreadyCalledError.prototype.message =
|
||||
'Deferred has already fired';
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.async.Deferred.AlreadyCalledError.prototype.name = 'AlreadyCalledError';
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* An error sub class that is used when a Deferred is canceled.
|
||||
*
|
||||
* @param {!goog.async.Deferred} deferred The Deferred object.
|
||||
* @constructor
|
||||
* @extends {goog.debug.Error}
|
||||
*/
|
||||
goog.async.Deferred.CanceledError = function(deferred) {
|
||||
goog.debug.Error.call(this);
|
||||
|
||||
/**
|
||||
* The Deferred that raised this error.
|
||||
* @type {goog.async.Deferred}
|
||||
*/
|
||||
this.deferred = deferred;
|
||||
};
|
||||
goog.inherits(goog.async.Deferred.CanceledError, goog.debug.Error);
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.async.Deferred.CanceledError.prototype.message = 'Deferred was canceled';
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.async.Deferred.CanceledError.prototype.name = 'CanceledError';
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Wrapper around errors that are scheduled to be thrown by failing deferreds
|
||||
* after a timeout.
|
||||
*
|
||||
* @param {*} error Error from a failing deferred.
|
||||
* @constructor
|
||||
* @final
|
||||
* @private
|
||||
* @struct
|
||||
*/
|
||||
goog.async.Deferred.Error_ = function(error) {
|
||||
/** @const @private {number} */
|
||||
this.id_ = goog.global.setTimeout(goog.bind(this.throwError, this), 0);
|
||||
|
||||
/** @const @private {*} */
|
||||
this.error_ = error;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Actually throws the error and removes it from the list of pending
|
||||
* deferred errors.
|
||||
*/
|
||||
goog.async.Deferred.Error_.prototype.throwError = function() {
|
||||
goog.asserts.assert(goog.async.Deferred.errorMap_[this.id_],
|
||||
'Cannot throw an error that is not scheduled.');
|
||||
delete goog.async.Deferred.errorMap_[this.id_];
|
||||
throw this.error_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Resets the error throw timer.
|
||||
*/
|
||||
goog.async.Deferred.Error_.prototype.resetTimer = function() {
|
||||
goog.global.clearTimeout(this.id_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Map of unhandled errors scheduled to be rethrown in a future timestep.
|
||||
* @private {!Object<(number|string), goog.async.Deferred.Error_>}
|
||||
*/
|
||||
goog.async.Deferred.errorMap_ = {};
|
||||
|
||||
|
||||
/**
|
||||
* Schedules an error to be thrown after a delay.
|
||||
* @param {*} error Error from a failing deferred.
|
||||
* @return {number} Id of the error.
|
||||
* @private
|
||||
*/
|
||||
goog.async.Deferred.scheduleError_ = function(error) {
|
||||
var deferredError = new goog.async.Deferred.Error_(error);
|
||||
goog.async.Deferred.errorMap_[deferredError.id_] = deferredError;
|
||||
return deferredError.id_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Unschedules an error from being thrown.
|
||||
* @param {number} id Id of the deferred error to unschedule.
|
||||
* @private
|
||||
*/
|
||||
goog.async.Deferred.unscheduleError_ = function(id) {
|
||||
var error = goog.async.Deferred.errorMap_[id];
|
||||
if (error) {
|
||||
error.resetTimer();
|
||||
delete goog.async.Deferred.errorMap_[id];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Asserts that there are no pending deferred errors. If there are any
|
||||
* scheduled errors, one will be thrown immediately to make this function fail.
|
||||
*/
|
||||
goog.async.Deferred.assertNoErrors = function() {
|
||||
var map = goog.async.Deferred.errorMap_;
|
||||
for (var key in map) {
|
||||
var error = map[key];
|
||||
error.resetTimer();
|
||||
error.throwError();
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
// Copyright 2007 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 Error codes shared between goog.net.IframeIo and
|
||||
* goog.net.XhrIo.
|
||||
*/
|
||||
|
||||
goog.provide('goog.net.ErrorCode');
|
||||
|
||||
|
||||
/**
|
||||
* Error codes
|
||||
* @enum {number}
|
||||
*/
|
||||
goog.net.ErrorCode = {
|
||||
|
||||
/**
|
||||
* There is no error condition.
|
||||
*/
|
||||
NO_ERROR: 0,
|
||||
|
||||
/**
|
||||
* The most common error from iframeio, unfortunately, is that the browser
|
||||
* responded with an error page that is classed as a different domain. The
|
||||
* situations, are when a browser error page is shown -- 404, access denied,
|
||||
* DNS failure, connection reset etc.)
|
||||
*
|
||||
*/
|
||||
ACCESS_DENIED: 1,
|
||||
|
||||
/**
|
||||
* Currently the only case where file not found will be caused is when the
|
||||
* code is running on the local file system and a non-IE browser makes a
|
||||
* request to a file that doesn't exist.
|
||||
*/
|
||||
FILE_NOT_FOUND: 2,
|
||||
|
||||
/**
|
||||
* If Firefox shows a browser error page, such as a connection reset by
|
||||
* server or access denied, then it will fail silently without the error or
|
||||
* load handlers firing.
|
||||
*/
|
||||
FF_SILENT_ERROR: 3,
|
||||
|
||||
/**
|
||||
* Custom error provided by the client through the error check hook.
|
||||
*/
|
||||
CUSTOM_ERROR: 4,
|
||||
|
||||
/**
|
||||
* Exception was thrown while processing the request.
|
||||
*/
|
||||
EXCEPTION: 5,
|
||||
|
||||
/**
|
||||
* The Http response returned a non-successful http status code.
|
||||
*/
|
||||
HTTP_ERROR: 6,
|
||||
|
||||
/**
|
||||
* The request was aborted.
|
||||
*/
|
||||
ABORT: 7,
|
||||
|
||||
/**
|
||||
* The request timed out.
|
||||
*/
|
||||
TIMEOUT: 8,
|
||||
|
||||
/**
|
||||
* The resource is not available offline.
|
||||
*/
|
||||
OFFLINE: 9
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns a friendly error message for an error code. These messages are for
|
||||
* debugging and are not localized.
|
||||
* @param {goog.net.ErrorCode} errorCode An error code.
|
||||
* @return {string} A message for debugging.
|
||||
*/
|
||||
goog.net.ErrorCode.getDebugMessage = function(errorCode) {
|
||||
switch (errorCode) {
|
||||
case goog.net.ErrorCode.NO_ERROR:
|
||||
return 'No Error';
|
||||
|
||||
case goog.net.ErrorCode.ACCESS_DENIED:
|
||||
return 'Access denied to content document';
|
||||
|
||||
case goog.net.ErrorCode.FILE_NOT_FOUND:
|
||||
return 'File not found';
|
||||
|
||||
case goog.net.ErrorCode.FF_SILENT_ERROR:
|
||||
return 'Firefox silently errored';
|
||||
|
||||
case goog.net.ErrorCode.CUSTOM_ERROR:
|
||||
return 'Application custom error';
|
||||
|
||||
case goog.net.ErrorCode.EXCEPTION:
|
||||
return 'An exception occurred';
|
||||
|
||||
case goog.net.ErrorCode.HTTP_ERROR:
|
||||
return 'Http response at 400 or 500 level';
|
||||
|
||||
case goog.net.ErrorCode.ABORT:
|
||||
return 'Request was aborted';
|
||||
|
||||
case goog.net.ErrorCode.TIMEOUT:
|
||||
return 'Request timed out';
|
||||
|
||||
case goog.net.ErrorCode.OFFLINE:
|
||||
return 'The resource is not available offline';
|
||||
|
||||
default:
|
||||
return 'Unrecognized error code';
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright 2006 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 Common events for the network classes.
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.net.EventType');
|
||||
|
||||
|
||||
/**
|
||||
* Event names for network events
|
||||
* @enum {string}
|
||||
*/
|
||||
goog.net.EventType = {
|
||||
COMPLETE: 'complete',
|
||||
SUCCESS: 'success',
|
||||
ERROR: 'error',
|
||||
ABORT: 'abort',
|
||||
READY: 'ready',
|
||||
READY_STATE_CHANGE: 'readystatechange',
|
||||
TIMEOUT: 'timeout',
|
||||
INCREMENTAL_DATA: 'incrementaldata',
|
||||
PROGRESS: 'progress',
|
||||
// DOWNLOAD_PROGRESS and UPLOAD_PROGRESS are special events dispatched by
|
||||
// goog.net.XhrIo to allow binding listeners specific to each type of
|
||||
// progress.
|
||||
DOWNLOAD_PROGRESS: 'downloadprogress',
|
||||
UPLOAD_PROGRESS: 'uploadprogress'
|
||||
};
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
// 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 Constants for HTTP status codes.
|
||||
*/
|
||||
|
||||
goog.provide('goog.net.HttpStatus');
|
||||
|
||||
|
||||
/**
|
||||
* HTTP Status Codes defined in RFC 2616 and RFC 6585.
|
||||
* @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
|
||||
* @see http://tools.ietf.org/html/rfc6585
|
||||
* @enum {number}
|
||||
*/
|
||||
goog.net.HttpStatus = {
|
||||
// Informational 1xx
|
||||
CONTINUE: 100,
|
||||
SWITCHING_PROTOCOLS: 101,
|
||||
|
||||
// Successful 2xx
|
||||
OK: 200,
|
||||
CREATED: 201,
|
||||
ACCEPTED: 202,
|
||||
NON_AUTHORITATIVE_INFORMATION: 203,
|
||||
NO_CONTENT: 204,
|
||||
RESET_CONTENT: 205,
|
||||
PARTIAL_CONTENT: 206,
|
||||
|
||||
// Redirection 3xx
|
||||
MULTIPLE_CHOICES: 300,
|
||||
MOVED_PERMANENTLY: 301,
|
||||
FOUND: 302,
|
||||
SEE_OTHER: 303,
|
||||
NOT_MODIFIED: 304,
|
||||
USE_PROXY: 305,
|
||||
TEMPORARY_REDIRECT: 307,
|
||||
|
||||
// Client Error 4xx
|
||||
BAD_REQUEST: 400,
|
||||
UNAUTHORIZED: 401,
|
||||
PAYMENT_REQUIRED: 402,
|
||||
FORBIDDEN: 403,
|
||||
NOT_FOUND: 404,
|
||||
METHOD_NOT_ALLOWED: 405,
|
||||
NOT_ACCEPTABLE: 406,
|
||||
PROXY_AUTHENTICATION_REQUIRED: 407,
|
||||
REQUEST_TIMEOUT: 408,
|
||||
CONFLICT: 409,
|
||||
GONE: 410,
|
||||
LENGTH_REQUIRED: 411,
|
||||
PRECONDITION_FAILED: 412,
|
||||
REQUEST_ENTITY_TOO_LARGE: 413,
|
||||
REQUEST_URI_TOO_LONG: 414,
|
||||
UNSUPPORTED_MEDIA_TYPE: 415,
|
||||
REQUEST_RANGE_NOT_SATISFIABLE: 416,
|
||||
EXPECTATION_FAILED: 417,
|
||||
PRECONDITION_REQUIRED: 428,
|
||||
TOO_MANY_REQUESTS: 429,
|
||||
REQUEST_HEADER_FIELDS_TOO_LARGE: 431,
|
||||
|
||||
// Server Error 5xx
|
||||
INTERNAL_SERVER_ERROR: 500,
|
||||
NOT_IMPLEMENTED: 501,
|
||||
BAD_GATEWAY: 502,
|
||||
SERVICE_UNAVAILABLE: 503,
|
||||
GATEWAY_TIMEOUT: 504,
|
||||
HTTP_VERSION_NOT_SUPPORTED: 505,
|
||||
NETWORK_AUTHENTICATION_REQUIRED: 511,
|
||||
|
||||
/*
|
||||
* IE returns this code for 204 due to its use of URLMon, which returns this
|
||||
* code for 'Operation Aborted'. The status text is 'Unknown', the response
|
||||
* headers are ''. Known to occur on IE 6 on XP through IE9 on Win7.
|
||||
*/
|
||||
QUIRK_IE_NO_CONTENT: 1223
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns whether the given status should be considered successful.
|
||||
*
|
||||
* Successful codes are OK (200), CREATED (201), ACCEPTED (202),
|
||||
* NO CONTENT (204), PARTIAL CONTENT (206), NOT MODIFIED (304),
|
||||
* and IE's no content code (1223).
|
||||
*
|
||||
* @param {number} status The status code to test.
|
||||
* @return {boolean} Whether the status code should be considered successful.
|
||||
*/
|
||||
goog.net.HttpStatus.isSuccess = function(status) {
|
||||
switch (status) {
|
||||
case goog.net.HttpStatus.OK:
|
||||
case goog.net.HttpStatus.CREATED:
|
||||
case goog.net.HttpStatus.ACCEPTED:
|
||||
case goog.net.HttpStatus.NO_CONTENT:
|
||||
case goog.net.HttpStatus.PARTIAL_CONTENT:
|
||||
case goog.net.HttpStatus.NOT_MODIFIED:
|
||||
case goog.net.HttpStatus.QUIRK_IE_NO_CONTENT:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,393 @@
|
|||
// 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 A utility to load JavaScript files via DOM script tags.
|
||||
* Refactored from goog.net.Jsonp. Works cross-domain.
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.net.jsloader');
|
||||
goog.provide('goog.net.jsloader.Error');
|
||||
goog.provide('goog.net.jsloader.ErrorCode');
|
||||
goog.provide('goog.net.jsloader.Options');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.async.Deferred');
|
||||
goog.require('goog.debug.Error');
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.dom.TagName');
|
||||
goog.require('goog.dom.safe');
|
||||
goog.require('goog.html.TrustedResourceUrl');
|
||||
goog.require('goog.object');
|
||||
|
||||
|
||||
/**
|
||||
* The name of the property of goog.global under which the JavaScript
|
||||
* verification object is stored by the loaded script.
|
||||
* @private {string}
|
||||
*/
|
||||
goog.net.jsloader.GLOBAL_VERIFY_OBJS_ = 'closure_verification';
|
||||
|
||||
|
||||
/**
|
||||
* The default length of time, in milliseconds, we are prepared to wait for a
|
||||
* load request to complete.
|
||||
* @type {number}
|
||||
*/
|
||||
goog.net.jsloader.DEFAULT_TIMEOUT = 5000;
|
||||
|
||||
|
||||
/**
|
||||
* Optional parameters for goog.net.jsloader.send.
|
||||
* timeout: The length of time, in milliseconds, we are prepared to wait
|
||||
* for a load request to complete, or 0 or negative for no timeout. Default
|
||||
* is 5 seconds.
|
||||
* document: The HTML document under which to load the JavaScript. Default is
|
||||
* the current document.
|
||||
* cleanupWhenDone: If true clean up the script tag after script completes to
|
||||
* load. This is important if you just want to read data from the JavaScript
|
||||
* and then throw it away. Default is false.
|
||||
* attributes: Additional attributes to set on the script tag.
|
||||
*
|
||||
* @typedef {{
|
||||
* timeout: (number|undefined),
|
||||
* document: (HTMLDocument|undefined),
|
||||
* cleanupWhenDone: (boolean|undefined),
|
||||
* attributes: (!Object<string, string>|undefined)
|
||||
* }}
|
||||
*/
|
||||
goog.net.jsloader.Options;
|
||||
|
||||
|
||||
/**
|
||||
* Scripts (URIs) waiting to be loaded.
|
||||
* @private {!Array<!goog.html.TrustedResourceUrl>}
|
||||
*/
|
||||
goog.net.jsloader.scriptsToLoad_ = [];
|
||||
|
||||
|
||||
/**
|
||||
* The deferred result of loading the URIs in scriptsToLoad_.
|
||||
* We need to return this to a caller that wants to load URIs while
|
||||
* a deferred is already working on them.
|
||||
* @private {!goog.async.Deferred<null>}
|
||||
*/
|
||||
goog.net.jsloader.scriptLoadingDeferred_;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Loads and evaluates the JavaScript files at the specified URIs, guaranteeing
|
||||
* the order of script loads.
|
||||
*
|
||||
* Because we have to load the scripts in serial (load script 1, exec script 1,
|
||||
* load script 2, exec script 2, and so on), this will be slower than doing
|
||||
* the network fetches in parallel.
|
||||
*
|
||||
* If you need to load a large number of scripts but dependency order doesn't
|
||||
* matter, you should just call goog.net.jsloader.safeLoad N times.
|
||||
*
|
||||
* If you need to load a large number of scripts on the same domain,
|
||||
* you may want to use goog.module.ModuleLoader.
|
||||
*
|
||||
* @param {Array<!goog.html.TrustedResourceUrl>} trustedUris The URIs to load.
|
||||
* @param {goog.net.jsloader.Options=} opt_options Optional parameters. See
|
||||
* goog.net.jsloader.options documentation for details.
|
||||
* @return {!goog.async.Deferred} The deferred result, that may be used to add
|
||||
* callbacks
|
||||
*/
|
||||
goog.net.jsloader.safeLoadMany = function(trustedUris, opt_options) {
|
||||
// Loading the scripts in serial introduces asynchronosity into the flow.
|
||||
// Therefore, there are race conditions where client A can kick off the load
|
||||
// sequence for client B, even though client A's scripts haven't all been
|
||||
// loaded yet.
|
||||
//
|
||||
// To work around this issue, all module loads share a queue.
|
||||
if (!trustedUris.length) {
|
||||
return goog.async.Deferred.succeed(null);
|
||||
}
|
||||
|
||||
var isAnotherModuleLoading = goog.net.jsloader.scriptsToLoad_.length;
|
||||
goog.array.extend(goog.net.jsloader.scriptsToLoad_, trustedUris);
|
||||
if (isAnotherModuleLoading) {
|
||||
// jsloader is still loading some other scripts.
|
||||
// In order to prevent the race condition noted above, we just add
|
||||
// these URIs to the end of the scripts' queue and return the deferred
|
||||
// result of the ongoing script load, so the caller knows when they
|
||||
// finish loading.
|
||||
return goog.net.jsloader.scriptLoadingDeferred_;
|
||||
}
|
||||
|
||||
trustedUris = goog.net.jsloader.scriptsToLoad_;
|
||||
var popAndLoadNextScript = function() {
|
||||
var trustedUri = trustedUris.shift();
|
||||
var deferred = goog.net.jsloader.safeLoad(trustedUri, opt_options);
|
||||
if (trustedUris.length) {
|
||||
deferred.addBoth(popAndLoadNextScript);
|
||||
}
|
||||
return deferred;
|
||||
};
|
||||
goog.net.jsloader.scriptLoadingDeferred_ = popAndLoadNextScript();
|
||||
return goog.net.jsloader.scriptLoadingDeferred_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Loads and evaluates a JavaScript file.
|
||||
* When the script loads, a user callback is called.
|
||||
* It is the client's responsibility to verify that the script ran successfully.
|
||||
*
|
||||
* @param {!goog.html.TrustedResourceUrl} trustedUri The URI of the JavaScript.
|
||||
* @param {goog.net.jsloader.Options=} opt_options Optional parameters. See
|
||||
* goog.net.jsloader.Options documentation for details.
|
||||
* @return {!goog.async.Deferred} The deferred result, that may be used to add
|
||||
* callbacks and/or cancel the transmission.
|
||||
* The error callback will be called with a single goog.net.jsloader.Error
|
||||
* parameter.
|
||||
*/
|
||||
goog.net.jsloader.safeLoad = function(trustedUri, opt_options) {
|
||||
var options = opt_options || {};
|
||||
var doc = options.document || document;
|
||||
var uri = goog.html.TrustedResourceUrl.unwrap(trustedUri);
|
||||
|
||||
var script = goog.dom.createElement(goog.dom.TagName.SCRIPT);
|
||||
var request = {script_: script, timeout_: undefined};
|
||||
var deferred = new goog.async.Deferred(goog.net.jsloader.cancel_, request);
|
||||
|
||||
// Set a timeout.
|
||||
var timeout = null;
|
||||
var timeoutDuration = goog.isDefAndNotNull(options.timeout) ?
|
||||
options.timeout :
|
||||
goog.net.jsloader.DEFAULT_TIMEOUT;
|
||||
if (timeoutDuration > 0) {
|
||||
timeout = window.setTimeout(function() {
|
||||
goog.net.jsloader.cleanup_(script, true);
|
||||
deferred.errback(
|
||||
new goog.net.jsloader.Error(
|
||||
goog.net.jsloader.ErrorCode.TIMEOUT,
|
||||
'Timeout reached for loading script ' + uri));
|
||||
}, timeoutDuration);
|
||||
request.timeout_ = timeout;
|
||||
}
|
||||
|
||||
// Hang the user callback to be called when the script completes to load.
|
||||
// NOTE(user): This callback will be called in IE even upon error. In any
|
||||
// case it is the client's responsibility to verify that the script ran
|
||||
// successfully.
|
||||
script.onload = script.onreadystatechange = function() {
|
||||
if (!script.readyState || script.readyState == 'loaded' ||
|
||||
script.readyState == 'complete') {
|
||||
var removeScriptNode = options.cleanupWhenDone || false;
|
||||
goog.net.jsloader.cleanup_(script, removeScriptNode, timeout);
|
||||
deferred.callback(null);
|
||||
}
|
||||
};
|
||||
|
||||
// Add an error callback.
|
||||
// NOTE(user): Not supported in IE.
|
||||
script.onerror = function() {
|
||||
goog.net.jsloader.cleanup_(script, true, timeout);
|
||||
deferred.errback(
|
||||
new goog.net.jsloader.Error(
|
||||
goog.net.jsloader.ErrorCode.LOAD_ERROR,
|
||||
'Error while loading script ' + uri));
|
||||
};
|
||||
|
||||
var properties = options.attributes || {};
|
||||
goog.object.extend(
|
||||
properties, {'type': 'text/javascript', 'charset': 'UTF-8'});
|
||||
goog.dom.setProperties(script, properties);
|
||||
// NOTE(user): Safari never loads the script if we don't set the src
|
||||
// attribute before appending.
|
||||
goog.dom.safe.setScriptSrc(script, trustedUri);
|
||||
var scriptParent = goog.net.jsloader.getScriptParentElement_(doc);
|
||||
scriptParent.appendChild(script);
|
||||
|
||||
return deferred;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Loads a JavaScript file and verifies it was evaluated successfully, using a
|
||||
* verification object.
|
||||
* The verification object is set by the loaded JavaScript at the end of the
|
||||
* script.
|
||||
* We verify this object was set and return its value in the success callback.
|
||||
* If the object is not defined we trigger an error callback.
|
||||
*
|
||||
* @param {!goog.html.TrustedResourceUrl} trustedUri The URI of the JavaScript.
|
||||
* @param {string} verificationObjName The name of the verification object that
|
||||
* the loaded script should set.
|
||||
* @param {goog.net.jsloader.Options} options Optional parameters. See
|
||||
* goog.net.jsloader.Options documentation for details.
|
||||
* @return {!goog.async.Deferred} The deferred result, that may be used to add
|
||||
* callbacks and/or cancel the transmission.
|
||||
* The success callback will be called with a single parameter containing
|
||||
* the value of the verification object.
|
||||
* The error callback will be called with a single goog.net.jsloader.Error
|
||||
* parameter.
|
||||
*/
|
||||
goog.net.jsloader.safeLoadAndVerify = function(
|
||||
trustedUri, verificationObjName, options) {
|
||||
// Define the global objects variable.
|
||||
if (!goog.global[goog.net.jsloader.GLOBAL_VERIFY_OBJS_]) {
|
||||
goog.global[goog.net.jsloader.GLOBAL_VERIFY_OBJS_] = {};
|
||||
}
|
||||
var verifyObjs = goog.global[goog.net.jsloader.GLOBAL_VERIFY_OBJS_];
|
||||
var uri = goog.html.TrustedResourceUrl.unwrap(trustedUri);
|
||||
|
||||
// Verify that the expected object does not exist yet.
|
||||
if (goog.isDef(verifyObjs[verificationObjName])) {
|
||||
// TODO(user): Error or reset variable?
|
||||
return goog.async.Deferred.fail(
|
||||
new goog.net.jsloader.Error(
|
||||
goog.net.jsloader.ErrorCode.VERIFY_OBJECT_ALREADY_EXISTS,
|
||||
'Verification object ' + verificationObjName +
|
||||
' already defined.'));
|
||||
}
|
||||
|
||||
// Send request to load the JavaScript.
|
||||
var sendDeferred = goog.net.jsloader.safeLoad(trustedUri, options);
|
||||
|
||||
// Create a deferred object wrapping the send result.
|
||||
var deferred =
|
||||
new goog.async.Deferred(goog.bind(sendDeferred.cancel, sendDeferred));
|
||||
|
||||
// Call user back with object that was set by the script.
|
||||
sendDeferred.addCallback(function() {
|
||||
var result = verifyObjs[verificationObjName];
|
||||
if (goog.isDef(result)) {
|
||||
deferred.callback(result);
|
||||
delete verifyObjs[verificationObjName];
|
||||
} else {
|
||||
// Error: script was not loaded properly.
|
||||
deferred.errback(
|
||||
new goog.net.jsloader.Error(
|
||||
goog.net.jsloader.ErrorCode.VERIFY_ERROR, 'Script ' + uri +
|
||||
' loaded, but verification object ' + verificationObjName +
|
||||
' was not defined.'));
|
||||
}
|
||||
});
|
||||
|
||||
// Pass error to new deferred object.
|
||||
sendDeferred.addErrback(function(error) {
|
||||
if (goog.isDef(verifyObjs[verificationObjName])) {
|
||||
delete verifyObjs[verificationObjName];
|
||||
}
|
||||
deferred.errback(error);
|
||||
});
|
||||
|
||||
return deferred;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gets the DOM element under which we should add new script elements.
|
||||
* How? Take the first head element, and if not found take doc.documentElement,
|
||||
* which always exists.
|
||||
*
|
||||
* @param {!HTMLDocument} doc The relevant document.
|
||||
* @return {!Element} The script parent element.
|
||||
* @private
|
||||
*/
|
||||
goog.net.jsloader.getScriptParentElement_ = function(doc) {
|
||||
var headElements = goog.dom.getElementsByTagName(goog.dom.TagName.HEAD, doc);
|
||||
if (!headElements || goog.array.isEmpty(headElements)) {
|
||||
return doc.documentElement;
|
||||
} else {
|
||||
return headElements[0];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Cancels a given request.
|
||||
* @this {{script_: Element, timeout_: number}} The request context.
|
||||
* @private
|
||||
*/
|
||||
goog.net.jsloader.cancel_ = function() {
|
||||
var request = this;
|
||||
if (request && request.script_) {
|
||||
var scriptNode = request.script_;
|
||||
if (scriptNode && scriptNode.tagName == goog.dom.TagName.SCRIPT) {
|
||||
goog.net.jsloader.cleanup_(scriptNode, true, request.timeout_);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes the script node and the timeout.
|
||||
*
|
||||
* @param {Node} scriptNode The node to be cleaned up.
|
||||
* @param {boolean} removeScriptNode If true completely remove the script node.
|
||||
* @param {?number=} opt_timeout The timeout handler to cleanup.
|
||||
* @private
|
||||
*/
|
||||
goog.net.jsloader.cleanup_ = function(
|
||||
scriptNode, removeScriptNode, opt_timeout) {
|
||||
if (goog.isDefAndNotNull(opt_timeout)) {
|
||||
goog.global.clearTimeout(opt_timeout);
|
||||
}
|
||||
|
||||
scriptNode.onload = goog.nullFunction;
|
||||
scriptNode.onerror = goog.nullFunction;
|
||||
scriptNode.onreadystatechange = goog.nullFunction;
|
||||
|
||||
// Do this after a delay (removing the script node of a running script can
|
||||
// confuse older IEs).
|
||||
if (removeScriptNode) {
|
||||
window.setTimeout(function() { goog.dom.removeNode(scriptNode); }, 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Possible error codes for jsloader.
|
||||
* @enum {number}
|
||||
*/
|
||||
goog.net.jsloader.ErrorCode = {
|
||||
LOAD_ERROR: 0,
|
||||
TIMEOUT: 1,
|
||||
VERIFY_ERROR: 2,
|
||||
VERIFY_OBJECT_ALREADY_EXISTS: 3
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A jsloader error.
|
||||
*
|
||||
* @param {goog.net.jsloader.ErrorCode} code The error code.
|
||||
* @param {string=} opt_message Additional message.
|
||||
* @constructor
|
||||
* @extends {goog.debug.Error}
|
||||
* @final
|
||||
*/
|
||||
goog.net.jsloader.Error = function(code, opt_message) {
|
||||
var msg = 'Jsloader error (code #' + code + ')';
|
||||
if (opt_message) {
|
||||
msg += ': ' + opt_message;
|
||||
}
|
||||
goog.net.jsloader.Error.base(this, 'constructor', msg);
|
||||
|
||||
/**
|
||||
* The code for this error.
|
||||
*
|
||||
* @type {goog.net.jsloader.ErrorCode}
|
||||
*/
|
||||
this.code = code;
|
||||
};
|
||||
goog.inherits(goog.net.jsloader.Error, goog.debug.Error);
|
||||
381
resources/public/target/cljsbuild-compiler-1/goog/net/jsonp.js
Normal file
381
resources/public/target/cljsbuild-compiler-1/goog/net/jsonp.js
Normal file
|
|
@ -0,0 +1,381 @@
|
|||
// Copyright 2006 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.
|
||||
|
||||
// The original file lives here: http://go/cross_domain_channel.js
|
||||
|
||||
/**
|
||||
* @fileoverview Implements a cross-domain communication channel. A
|
||||
* typical web page is prevented by browser security from sending
|
||||
* request, such as a XMLHttpRequest, to other servers than the ones
|
||||
* from which it came. The Jsonp class provides a workaround by
|
||||
* using dynamically generated script tags. Typical usage:.
|
||||
*
|
||||
* var jsonp = new goog.net.Jsonp(new goog.Uri('http://my.host.com/servlet'));
|
||||
* var payload = { 'foo': 1, 'bar': true };
|
||||
* jsonp.send(payload, function(reply) { alert(reply) });
|
||||
*
|
||||
* This script works in all browsers that are currently supported by
|
||||
* the Google Maps API, which is IE 6.0+, Firefox 0.8+, Safari 1.2.4+,
|
||||
* Netscape 7.1+, Mozilla 1.4+, Opera 8.02+.
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.net.Jsonp');
|
||||
|
||||
goog.require('goog.Uri');
|
||||
goog.require('goog.html.legacyconversions');
|
||||
goog.require('goog.net.jsloader');
|
||||
|
||||
// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
|
||||
//
|
||||
// This class allows us (Google) to send data from non-Google and thus
|
||||
// UNTRUSTED pages to our servers. Under NO CIRCUMSTANCES return
|
||||
// anything sensitive, such as session or cookie specific data. Return
|
||||
// only data that you want parties external to Google to have. Also
|
||||
// NEVER use this method to send data from web pages to untrusted
|
||||
// servers, or redirects to unknown servers (www.google.com/cache,
|
||||
// /q=xx&btnl, /url, www.googlepages.com, etc.)
|
||||
//
|
||||
// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new cross domain channel that sends data to the specified
|
||||
* host URL. By default, if no reply arrives within 5s, the channel
|
||||
* assumes the call failed to complete successfully.
|
||||
*
|
||||
* @param {goog.Uri|string} uri The Uri of the server side code that receives
|
||||
* data posted through this channel (e.g.,
|
||||
* "http://maps.google.com/maps/geo").
|
||||
*
|
||||
* @param {string=} opt_callbackParamName The parameter name that is used to
|
||||
* specify the callback. Defaults to "callback".
|
||||
*
|
||||
* @constructor
|
||||
* @final
|
||||
*/
|
||||
goog.net.Jsonp = function(uri, opt_callbackParamName) {
|
||||
/**
|
||||
* The uri_ object will be used to encode the payload that is sent to the
|
||||
* server.
|
||||
* @type {goog.Uri}
|
||||
* @private
|
||||
*/
|
||||
this.uri_ = new goog.Uri(uri);
|
||||
|
||||
/**
|
||||
* This is the callback parameter name that is added to the uri.
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
this.callbackParamName_ =
|
||||
opt_callbackParamName ? opt_callbackParamName : 'callback';
|
||||
|
||||
/**
|
||||
* The length of time, in milliseconds, this channel is prepared
|
||||
* to wait for for a request to complete. The default value is 5 seconds.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
this.timeout_ = 5000;
|
||||
|
||||
/**
|
||||
* The nonce to use in the dynamically generated script tags. This is used for
|
||||
* allowing the script callbacks to execute when the page has an enforced
|
||||
* Content Security Policy.
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
this.nonce_ = '';
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The prefix for the callback name which will be stored on goog.global.
|
||||
*/
|
||||
goog.net.Jsonp.CALLBACKS = '_callbacks_';
|
||||
|
||||
|
||||
/**
|
||||
* Used to generate unique callback IDs. The counter must be global because
|
||||
* all channels share a common callback object.
|
||||
* @private
|
||||
*/
|
||||
goog.net.Jsonp.scriptCounter_ = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Static private method which returns the global unique callback id.
|
||||
*
|
||||
* @param {string} id The id of the script node.
|
||||
* @return {string} A global unique id used to store callback on goog.global
|
||||
* object.
|
||||
* @private
|
||||
*/
|
||||
goog.net.Jsonp.getCallbackId_ = function(id) {
|
||||
return goog.net.Jsonp.CALLBACKS + '__' + id;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the length of time, in milliseconds, this channel is prepared
|
||||
* to wait for for a request to complete. If the call is not competed
|
||||
* within the set time span, it is assumed to have failed. To wait
|
||||
* indefinitely for a request to complete set the timout to a negative
|
||||
* number.
|
||||
*
|
||||
* @param {number} timeout The length of time before calls are
|
||||
* interrupted.
|
||||
*/
|
||||
goog.net.Jsonp.prototype.setRequestTimeout = function(timeout) {
|
||||
this.timeout_ = timeout;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the current timeout value, in milliseconds.
|
||||
*
|
||||
* @return {number} The timeout value.
|
||||
*/
|
||||
goog.net.Jsonp.prototype.getRequestTimeout = function() {
|
||||
return this.timeout_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the nonce value for CSP. This nonce value will be added to any created
|
||||
* script elements and must match the nonce provided in the
|
||||
* Content-Security-Policy header sent by the server for the callback to pass
|
||||
* CSP enforcement.
|
||||
*
|
||||
* @param {string} nonce The CSP nonce value.
|
||||
*/
|
||||
goog.net.Jsonp.prototype.setNonce = function(nonce) {
|
||||
this.nonce_ = nonce;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sends the given payload to the URL specified at the construction
|
||||
* time. The reply is delivered to the given replyCallback. If the
|
||||
* errorCallback is specified and the reply does not arrive within the
|
||||
* timeout period set on this channel, the errorCallback is invoked
|
||||
* with the original payload.
|
||||
*
|
||||
* If no reply callback is specified, then the response is expected to
|
||||
* consist of calls to globally registered functions. No &callback=
|
||||
* URL parameter will be sent in the request, and the script element
|
||||
* will be cleaned up after the timeout.
|
||||
*
|
||||
* @param {Object=} opt_payload Name-value pairs. If given, these will be
|
||||
* added as parameters to the supplied URI as GET parameters to the
|
||||
* given server URI.
|
||||
*
|
||||
* @param {Function=} opt_replyCallback A function expecting one
|
||||
* argument, called when the reply arrives, with the response data.
|
||||
*
|
||||
* @param {Function=} opt_errorCallback A function expecting one
|
||||
* argument, called on timeout, with the payload (if given), otherwise
|
||||
* null.
|
||||
*
|
||||
* @param {string=} opt_callbackParamValue Value to be used as the
|
||||
* parameter value for the callback parameter (callbackParamName).
|
||||
* To be used when the value needs to be fixed by the client for a
|
||||
* particular request, to make use of the cached responses for the request.
|
||||
* NOTE: If multiple requests are made with the same
|
||||
* opt_callbackParamValue, only the last call will work whenever the
|
||||
* response comes back.
|
||||
*
|
||||
* @return {!Object} A request descriptor that may be used to cancel this
|
||||
* transmission, or null, if the message may not be cancelled.
|
||||
*/
|
||||
goog.net.Jsonp.prototype.send = function(
|
||||
opt_payload, opt_replyCallback, opt_errorCallback, opt_callbackParamValue) {
|
||||
|
||||
var payload = opt_payload || null;
|
||||
|
||||
var id = opt_callbackParamValue ||
|
||||
'_' + (goog.net.Jsonp.scriptCounter_++).toString(36) +
|
||||
goog.now().toString(36);
|
||||
var callbackId = goog.net.Jsonp.getCallbackId_(id);
|
||||
|
||||
// Create a new Uri object onto which this payload will be added
|
||||
var uri = this.uri_.clone();
|
||||
if (payload) {
|
||||
goog.net.Jsonp.addPayloadToUri_(payload, uri);
|
||||
}
|
||||
|
||||
if (opt_replyCallback) {
|
||||
var reply = goog.net.Jsonp.newReplyHandler_(id, opt_replyCallback);
|
||||
// Register the callback on goog.global to make it discoverable
|
||||
// by jsonp response.
|
||||
goog.global[callbackId] = reply;
|
||||
uri.setParameterValues(this.callbackParamName_, callbackId);
|
||||
}
|
||||
|
||||
var options = {timeout: this.timeout_, cleanupWhenDone: true};
|
||||
if (this.nonce_) {
|
||||
options.attributes = {'nonce': this.nonce_};
|
||||
}
|
||||
|
||||
var deferred = goog.net.jsloader.safeLoad(
|
||||
goog.html.legacyconversions.trustedResourceUrlFromString(uri.toString()),
|
||||
options);
|
||||
var error = goog.net.Jsonp.newErrorHandler_(id, payload, opt_errorCallback);
|
||||
deferred.addErrback(error);
|
||||
|
||||
return {id_: id, deferred_: deferred};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Cancels a given request. The request must be exactly the object returned by
|
||||
* the send method.
|
||||
*
|
||||
* @param {Object} request The request object returned by the send method.
|
||||
*/
|
||||
goog.net.Jsonp.prototype.cancel = function(request) {
|
||||
if (request) {
|
||||
if (request.deferred_) {
|
||||
request.deferred_.cancel();
|
||||
}
|
||||
if (request.id_) {
|
||||
goog.net.Jsonp.cleanup_(request.id_, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a timeout callback that calls the given timeoutCallback with the
|
||||
* original payload.
|
||||
*
|
||||
* @param {string} id The id of the script node.
|
||||
* @param {Object} payload The payload that was sent to the server.
|
||||
* @param {Function=} opt_errorCallback The function called on timeout.
|
||||
* @return {!Function} A zero argument function that handles callback duties.
|
||||
* @private
|
||||
*/
|
||||
goog.net.Jsonp.newErrorHandler_ = function(id, payload, opt_errorCallback) {
|
||||
/**
|
||||
* When we call across domains with a request, this function is the
|
||||
* timeout handler. Once it's done executing the user-specified
|
||||
* error-handler, it removes the script node and original function.
|
||||
*/
|
||||
return function() {
|
||||
goog.net.Jsonp.cleanup_(id, false);
|
||||
if (opt_errorCallback) {
|
||||
opt_errorCallback(payload);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a reply callback that calls the given replyCallback with data
|
||||
* returned by the server.
|
||||
*
|
||||
* @param {string} id The id of the script node.
|
||||
* @param {Function} replyCallback The function called on reply.
|
||||
* @return {!Function} A reply callback function.
|
||||
* @private
|
||||
*/
|
||||
goog.net.Jsonp.newReplyHandler_ = function(id, replyCallback) {
|
||||
/**
|
||||
* This function is the handler for the all-is-well response. It
|
||||
* clears the error timeout handler, calls the user's handler, then
|
||||
* removes the script node and itself.
|
||||
*
|
||||
* @param {...Object} var_args The response data sent from the server.
|
||||
*/
|
||||
var handler = function(var_args) {
|
||||
goog.net.Jsonp.cleanup_(id, true);
|
||||
replyCallback.apply(undefined, arguments);
|
||||
};
|
||||
return handler;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes the reply handler registered on goog.global object.
|
||||
*
|
||||
* @param {string} id The id of the script node to be removed.
|
||||
* @param {boolean} deleteReplyHandler If true, delete the reply handler
|
||||
* instead of setting it to nullFunction (if we know the callback could
|
||||
* never be called again).
|
||||
* @private
|
||||
*/
|
||||
goog.net.Jsonp.cleanup_ = function(id, deleteReplyHandler) {
|
||||
var callbackId = goog.net.Jsonp.getCallbackId_(id);
|
||||
if (goog.global[callbackId]) {
|
||||
if (deleteReplyHandler) {
|
||||
try {
|
||||
delete goog.global[callbackId];
|
||||
} catch (e) {
|
||||
// NOTE: Workaround to delete property on 'window' in IE <= 8, see:
|
||||
// http://stackoverflow.com/questions/1073414/deleting-a-window-property-in-ie
|
||||
goog.global[callbackId] = undefined;
|
||||
}
|
||||
} else {
|
||||
// Removing the script tag doesn't necessarily prevent the script
|
||||
// from firing, so we make the callback a noop.
|
||||
goog.global[callbackId] = goog.nullFunction;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns URL encoded payload. The payload should be a map of name-value
|
||||
* pairs, in the form {"foo": 1, "bar": true, ...}. If the map is empty,
|
||||
* the URI will be unchanged.
|
||||
*
|
||||
* <p>The method uses hasOwnProperty() to assure the properties are on the
|
||||
* object, not on its prototype.
|
||||
*
|
||||
* @param {!Object} payload A map of value name pairs to be encoded.
|
||||
* A value may be specified as an array, in which case a query parameter
|
||||
* will be created for each value, e.g.:
|
||||
* {"foo": [1,2]} will encode to "foo=1&foo=2".
|
||||
*
|
||||
* @param {!goog.Uri} uri A Uri object onto which the payload key value pairs
|
||||
* will be encoded.
|
||||
*
|
||||
* @return {!goog.Uri} A reference to the Uri sent as a parameter.
|
||||
* @private
|
||||
*/
|
||||
goog.net.Jsonp.addPayloadToUri_ = function(payload, uri) {
|
||||
for (var name in payload) {
|
||||
// NOTE(user): Safari/1.3 doesn't have hasOwnProperty(). In that
|
||||
// case, we iterate over all properties as a very lame workaround.
|
||||
if (!payload.hasOwnProperty || payload.hasOwnProperty(name)) {
|
||||
uri.setParameterValues(name, payload[name]);
|
||||
}
|
||||
}
|
||||
return uri;
|
||||
};
|
||||
|
||||
|
||||
// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
|
||||
//
|
||||
// This class allows us (Google) to send data from non-Google and thus
|
||||
// UNTRUSTED pages to our servers. Under NO CIRCUMSTANCES return
|
||||
// anything sensitive, such as session or cookie specific data. Return
|
||||
// only data that you want parties external to Google to have. Also
|
||||
// NEVER use this method to send data from web pages to untrusted
|
||||
// servers, or redirects to unknown servers (www.google.com/cache,
|
||||
// /q=xx&btnl, /url, www.googlepages.com, etc.)
|
||||
//
|
||||
// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
// Copyright 2010 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 Implementation of XmlHttpFactory which allows construction from
|
||||
* simple factory methods.
|
||||
* @author dbk@google.com (David Barrett-Kahn)
|
||||
*/
|
||||
|
||||
goog.provide('goog.net.WrapperXmlHttpFactory');
|
||||
|
||||
/** @suppress {extraRequire} Typedef. */
|
||||
goog.require('goog.net.XhrLike');
|
||||
goog.require('goog.net.XmlHttpFactory');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* An xhr factory subclass which can be constructed using two factory methods.
|
||||
* This exists partly to allow the preservation of goog.net.XmlHttp.setFactory()
|
||||
* with an unchanged signature.
|
||||
* @param {function():!goog.net.XhrLike.OrNative} xhrFactory
|
||||
* A function which returns a new XHR object.
|
||||
* @param {function():!Object} optionsFactory A function which returns the
|
||||
* options associated with xhr objects from this factory.
|
||||
* @extends {goog.net.XmlHttpFactory}
|
||||
* @constructor
|
||||
* @final
|
||||
*/
|
||||
goog.net.WrapperXmlHttpFactory = function(xhrFactory, optionsFactory) {
|
||||
goog.net.XmlHttpFactory.call(this);
|
||||
|
||||
/**
|
||||
* XHR factory method.
|
||||
* @type {function() : !goog.net.XhrLike.OrNative}
|
||||
* @private
|
||||
*/
|
||||
this.xhrFactory_ = xhrFactory;
|
||||
|
||||
/**
|
||||
* Options factory method.
|
||||
* @type {function() : !Object}
|
||||
* @private
|
||||
*/
|
||||
this.optionsFactory_ = optionsFactory;
|
||||
};
|
||||
goog.inherits(goog.net.WrapperXmlHttpFactory, goog.net.XmlHttpFactory);
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.net.WrapperXmlHttpFactory.prototype.createInstance = function() {
|
||||
return this.xhrFactory_();
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.net.WrapperXmlHttpFactory.prototype.getOptions = function() {
|
||||
return this.optionsFactory_();
|
||||
};
|
||||
1362
resources/public/target/cljsbuild-compiler-1/goog/net/xhrio.js
Normal file
1362
resources/public/target/cljsbuild-compiler-1/goog/net/xhrio.js
Normal file
File diff suppressed because it is too large
Load diff
124
resources/public/target/cljsbuild-compiler-1/goog/net/xhrlike.js
Normal file
124
resources/public/target/cljsbuild-compiler-1/goog/net/xhrlike.js
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
// Copyright 2013 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.
|
||||
|
||||
goog.provide('goog.net.XhrLike');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Interface for the common parts of XMLHttpRequest.
|
||||
*
|
||||
* Mostly copied from externs/w3c_xml.js.
|
||||
*
|
||||
* @interface
|
||||
* @see http://www.w3.org/TR/XMLHttpRequest/
|
||||
*/
|
||||
goog.net.XhrLike = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Typedef that refers to either native or custom-implemented XHR objects.
|
||||
* @typedef {!goog.net.XhrLike|!XMLHttpRequest}
|
||||
*/
|
||||
goog.net.XhrLike.OrNative;
|
||||
|
||||
|
||||
/**
|
||||
* @type {function()|null|undefined}
|
||||
* @see http://www.w3.org/TR/XMLHttpRequest/#handler-xhr-onreadystatechange
|
||||
*/
|
||||
goog.net.XhrLike.prototype.onreadystatechange;
|
||||
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
* @see http://www.w3.org/TR/XMLHttpRequest/#the-responsetext-attribute
|
||||
*/
|
||||
goog.net.XhrLike.prototype.responseText;
|
||||
|
||||
|
||||
/**
|
||||
* @type {Document}
|
||||
* @see http://www.w3.org/TR/XMLHttpRequest/#the-responsexml-attribute
|
||||
*/
|
||||
goog.net.XhrLike.prototype.responseXML;
|
||||
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @see http://www.w3.org/TR/XMLHttpRequest/#readystate
|
||||
*/
|
||||
goog.net.XhrLike.prototype.readyState;
|
||||
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @see http://www.w3.org/TR/XMLHttpRequest/#status
|
||||
*/
|
||||
goog.net.XhrLike.prototype.status;
|
||||
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
* @see http://www.w3.org/TR/XMLHttpRequest/#statustext
|
||||
*/
|
||||
goog.net.XhrLike.prototype.statusText;
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} method
|
||||
* @param {string} url
|
||||
* @param {?boolean=} opt_async
|
||||
* @param {?string=} opt_user
|
||||
* @param {?string=} opt_password
|
||||
* @see http://www.w3.org/TR/XMLHttpRequest/#the-open()-method
|
||||
*/
|
||||
goog.net.XhrLike.prototype.open = function(
|
||||
method, url, opt_async, opt_user, opt_password) {};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer|ArrayBufferView|Blob|Document|FormData|string=} opt_data
|
||||
* @see http://www.w3.org/TR/XMLHttpRequest/#the-send()-method
|
||||
*/
|
||||
goog.net.XhrLike.prototype.send = function(opt_data) {};
|
||||
|
||||
|
||||
/**
|
||||
* @see http://www.w3.org/TR/XMLHttpRequest/#the-abort()-method
|
||||
*/
|
||||
goog.net.XhrLike.prototype.abort = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} header
|
||||
* @param {string} value
|
||||
* @see http://www.w3.org/TR/XMLHttpRequest/#the-setrequestheader()-method
|
||||
*/
|
||||
goog.net.XhrLike.prototype.setRequestHeader = function(header, value) {};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} header
|
||||
* @return {string}
|
||||
* @see http://www.w3.org/TR/XMLHttpRequest/#the-getresponseheader()-method
|
||||
*/
|
||||
goog.net.XhrLike.prototype.getResponseHeader = function(header) {};
|
||||
|
||||
|
||||
/**
|
||||
* @return {string}
|
||||
* @see http://www.w3.org/TR/XMLHttpRequest/#the-getallresponseheaders()-method
|
||||
*/
|
||||
goog.net.XhrLike.prototype.getAllResponseHeaders = function() {};
|
||||
248
resources/public/target/cljsbuild-compiler-1/goog/net/xmlhttp.js
Normal file
248
resources/public/target/cljsbuild-compiler-1/goog/net/xmlhttp.js
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
// Copyright 2006 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 Low level handling of XMLHttpRequest.
|
||||
* @author arv@google.com (Erik Arvidsson)
|
||||
* @author dbk@google.com (David Barrett-Kahn)
|
||||
*/
|
||||
|
||||
goog.provide('goog.net.DefaultXmlHttpFactory');
|
||||
goog.provide('goog.net.XmlHttp');
|
||||
goog.provide('goog.net.XmlHttp.OptionType');
|
||||
goog.provide('goog.net.XmlHttp.ReadyState');
|
||||
goog.provide('goog.net.XmlHttpDefines');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.net.WrapperXmlHttpFactory');
|
||||
goog.require('goog.net.XmlHttpFactory');
|
||||
|
||||
|
||||
/**
|
||||
* Static class for creating XMLHttpRequest objects.
|
||||
* @return {!goog.net.XhrLike.OrNative} A new XMLHttpRequest object.
|
||||
*/
|
||||
goog.net.XmlHttp = function() {
|
||||
return goog.net.XmlHttp.factory_.createInstance();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Whether to assume XMLHttpRequest exists. Setting this to
|
||||
* true bypasses the ActiveX probing code.
|
||||
* NOTE(ruilopes): Due to the way JSCompiler works, this define *will not* strip
|
||||
* out the ActiveX probing code from binaries. To achieve this, use
|
||||
* {@code goog.net.XmlHttpDefines.ASSUME_NATIVE_XHR} instead.
|
||||
* TODO(ruilopes): Collapse both defines.
|
||||
*/
|
||||
goog.define('goog.net.XmlHttp.ASSUME_NATIVE_XHR', false);
|
||||
|
||||
|
||||
/** @const */
|
||||
goog.net.XmlHttpDefines = {};
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Whether to assume XMLHttpRequest exists. Setting this to
|
||||
* true eliminates the ActiveX probing code.
|
||||
*/
|
||||
goog.define('goog.net.XmlHttpDefines.ASSUME_NATIVE_XHR', false);
|
||||
|
||||
|
||||
/**
|
||||
* Gets the options to use with the XMLHttpRequest objects obtained using
|
||||
* the static methods.
|
||||
* @return {Object} The options.
|
||||
*/
|
||||
goog.net.XmlHttp.getOptions = function() {
|
||||
return goog.net.XmlHttp.factory_.getOptions();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Type of options that an XmlHttp object can have.
|
||||
* @enum {number}
|
||||
*/
|
||||
goog.net.XmlHttp.OptionType = {
|
||||
/**
|
||||
* Whether a goog.nullFunction should be used to clear the onreadystatechange
|
||||
* handler instead of null.
|
||||
*/
|
||||
USE_NULL_FUNCTION: 0,
|
||||
|
||||
/**
|
||||
* NOTE(user): In IE if send() errors on a *local* request the readystate
|
||||
* is still changed to COMPLETE. We need to ignore it and allow the
|
||||
* try/catch around send() to pick up the error.
|
||||
*/
|
||||
LOCAL_REQUEST_ERROR: 1
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Status constants for XMLHTTP, matches:
|
||||
* https://msdn.microsoft.com/en-us/library/ms534361(v=vs.85).aspx
|
||||
* @enum {number}
|
||||
*/
|
||||
goog.net.XmlHttp.ReadyState = {
|
||||
/**
|
||||
* Constant for when xmlhttprequest.readyState is uninitialized
|
||||
*/
|
||||
UNINITIALIZED: 0,
|
||||
|
||||
/**
|
||||
* Constant for when xmlhttprequest.readyState is loading.
|
||||
*/
|
||||
LOADING: 1,
|
||||
|
||||
/**
|
||||
* Constant for when xmlhttprequest.readyState is loaded.
|
||||
*/
|
||||
LOADED: 2,
|
||||
|
||||
/**
|
||||
* Constant for when xmlhttprequest.readyState is in an interactive state.
|
||||
*/
|
||||
INTERACTIVE: 3,
|
||||
|
||||
/**
|
||||
* Constant for when xmlhttprequest.readyState is completed
|
||||
*/
|
||||
COMPLETE: 4
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The global factory instance for creating XMLHttpRequest objects.
|
||||
* @type {goog.net.XmlHttpFactory}
|
||||
* @private
|
||||
*/
|
||||
goog.net.XmlHttp.factory_;
|
||||
|
||||
|
||||
/**
|
||||
* Sets the factories for creating XMLHttpRequest objects and their options.
|
||||
* @param {Function} factory The factory for XMLHttpRequest objects.
|
||||
* @param {Function} optionsFactory The factory for options.
|
||||
* @deprecated Use setGlobalFactory instead.
|
||||
*/
|
||||
goog.net.XmlHttp.setFactory = function(factory, optionsFactory) {
|
||||
goog.net.XmlHttp.setGlobalFactory(
|
||||
new goog.net.WrapperXmlHttpFactory(
|
||||
goog.asserts.assert(factory), goog.asserts.assert(optionsFactory)));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the global factory object.
|
||||
* @param {!goog.net.XmlHttpFactory} factory New global factory object.
|
||||
*/
|
||||
goog.net.XmlHttp.setGlobalFactory = function(factory) {
|
||||
goog.net.XmlHttp.factory_ = factory;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Default factory to use when creating xhr objects. You probably shouldn't be
|
||||
* instantiating this directly, but rather using it via goog.net.XmlHttp.
|
||||
* @extends {goog.net.XmlHttpFactory}
|
||||
* @constructor
|
||||
*/
|
||||
goog.net.DefaultXmlHttpFactory = function() {
|
||||
goog.net.XmlHttpFactory.call(this);
|
||||
};
|
||||
goog.inherits(goog.net.DefaultXmlHttpFactory, goog.net.XmlHttpFactory);
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.net.DefaultXmlHttpFactory.prototype.createInstance = function() {
|
||||
var progId = this.getProgId_();
|
||||
if (progId) {
|
||||
return new ActiveXObject(progId);
|
||||
} else {
|
||||
return new XMLHttpRequest();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.net.DefaultXmlHttpFactory.prototype.internalGetOptions = function() {
|
||||
var progId = this.getProgId_();
|
||||
var options = {};
|
||||
if (progId) {
|
||||
options[goog.net.XmlHttp.OptionType.USE_NULL_FUNCTION] = true;
|
||||
options[goog.net.XmlHttp.OptionType.LOCAL_REQUEST_ERROR] = true;
|
||||
}
|
||||
return options;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The ActiveX PROG ID string to use to create xhr's in IE. Lazily initialized.
|
||||
* @type {string|undefined}
|
||||
* @private
|
||||
*/
|
||||
goog.net.DefaultXmlHttpFactory.prototype.ieProgId_;
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the private state used by other functions.
|
||||
* @return {string} The ActiveX PROG ID string to use to create xhr's in IE.
|
||||
* @private
|
||||
*/
|
||||
goog.net.DefaultXmlHttpFactory.prototype.getProgId_ = function() {
|
||||
if (goog.net.XmlHttp.ASSUME_NATIVE_XHR ||
|
||||
goog.net.XmlHttpDefines.ASSUME_NATIVE_XHR) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// The following blog post describes what PROG IDs to use to create the
|
||||
// XMLHTTP object in Internet Explorer:
|
||||
// http://blogs.msdn.com/xmlteam/archive/2006/10/23/using-the-right-version-of-msxml-in-internet-explorer.aspx
|
||||
// However we do not (yet) fully trust that this will be OK for old versions
|
||||
// of IE on Win9x so we therefore keep the last 2.
|
||||
if (!this.ieProgId_ && typeof XMLHttpRequest == 'undefined' &&
|
||||
typeof ActiveXObject != 'undefined') {
|
||||
// Candidate Active X types.
|
||||
var ACTIVE_X_IDENTS = [
|
||||
'MSXML2.XMLHTTP.6.0', 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP',
|
||||
'Microsoft.XMLHTTP'
|
||||
];
|
||||
for (var i = 0; i < ACTIVE_X_IDENTS.length; i++) {
|
||||
var candidate = ACTIVE_X_IDENTS[i];
|
||||
|
||||
try {
|
||||
new ActiveXObject(candidate);
|
||||
// NOTE(user): cannot assign progid and return candidate in one line
|
||||
// because JSCompiler complaings: BUG 658126
|
||||
this.ieProgId_ = candidate;
|
||||
return candidate;
|
||||
} catch (e) {
|
||||
// do nothing; try next choice
|
||||
}
|
||||
}
|
||||
|
||||
// couldn't find any matches
|
||||
throw Error(
|
||||
'Could not create ActiveXObject. ActiveX might be disabled,' +
|
||||
' or MSXML might not be installed');
|
||||
}
|
||||
|
||||
return /** @type {string} */ (this.ieProgId_);
|
||||
};
|
||||
|
||||
|
||||
// Set the global factory to an instance of the default factory.
|
||||
goog.net.XmlHttp.setGlobalFactory(new goog.net.DefaultXmlHttpFactory());
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
// Copyright 2010 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 a factory for creating XMLHttpRequest objects
|
||||
* and metadata about them.
|
||||
* @author dbk@google.com (David Barrett-Kahn)
|
||||
*/
|
||||
|
||||
goog.provide('goog.net.XmlHttpFactory');
|
||||
|
||||
/** @suppress {extraRequire} Typedef. */
|
||||
goog.require('goog.net.XhrLike');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Abstract base class for an XmlHttpRequest factory.
|
||||
* @constructor
|
||||
*/
|
||||
goog.net.XmlHttpFactory = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Cache of options - we only actually call internalGetOptions once.
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
goog.net.XmlHttpFactory.prototype.cachedOptions_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* @return {!goog.net.XhrLike.OrNative} A new XhrLike instance.
|
||||
*/
|
||||
goog.net.XmlHttpFactory.prototype.createInstance = goog.abstractMethod;
|
||||
|
||||
|
||||
/**
|
||||
* @return {Object} Options describing how xhr objects obtained from this
|
||||
* factory should be used.
|
||||
*/
|
||||
goog.net.XmlHttpFactory.prototype.getOptions = function() {
|
||||
return this.cachedOptions_ ||
|
||||
(this.cachedOptions_ = this.internalGetOptions());
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Override this method in subclasses to preserve the caching offered by
|
||||
* getOptions().
|
||||
* @return {Object} Options describing how xhr objects obtained from this
|
||||
* factory should be used.
|
||||
* @protected
|
||||
*/
|
||||
goog.net.XmlHttpFactory.prototype.internalGetOptions = goog.abstractMethod;
|
||||
|
|
@ -0,0 +1,751 @@
|
|||
// Copyright 2006 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 Utilities for manipulating objects/maps/hashes.
|
||||
* @author arv@google.com (Erik Arvidsson)
|
||||
*/
|
||||
|
||||
goog.provide('goog.object');
|
||||
|
||||
|
||||
/**
|
||||
* Whether two values are not observably distinguishable. This
|
||||
* correctly detects that 0 is not the same as -0 and two NaNs are
|
||||
* practically equivalent.
|
||||
*
|
||||
* The implementation is as suggested by harmony:egal proposal.
|
||||
*
|
||||
* @param {*} v The first value to compare.
|
||||
* @param {*} v2 The second value to compare.
|
||||
* @return {boolean} Whether two values are not observably distinguishable.
|
||||
* @see http://wiki.ecmascript.org/doku.php?id=harmony:egal
|
||||
*/
|
||||
goog.object.is = function(v, v2) {
|
||||
if (v === v2) {
|
||||
// 0 === -0, but they are not identical.
|
||||
// We need the cast because the compiler requires that v2 is a
|
||||
// number (although 1/v2 works with non-number). We cast to ? to
|
||||
// stop the compiler from type-checking this statement.
|
||||
return v !== 0 || 1 / v === 1 / /** @type {?} */ (v2);
|
||||
}
|
||||
|
||||
// NaN is non-reflexive: NaN !== NaN, although they are identical.
|
||||
return v !== v && v2 !== v2;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls a function for each element in an object/map/hash.
|
||||
*
|
||||
* @param {Object<K,V>} obj The object over which to iterate.
|
||||
* @param {function(this:T,V,?,Object<K,V>):?} f The function to call
|
||||
* for every element. This function takes 3 arguments (the value, the
|
||||
* key and the object) and the return value is ignored.
|
||||
* @param {T=} opt_obj This is used as the 'this' object within f.
|
||||
* @template T,K,V
|
||||
*/
|
||||
goog.object.forEach = function(obj, f, opt_obj) {
|
||||
for (var key in obj) {
|
||||
f.call(/** @type {?} */ (opt_obj), obj[key], key, obj);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls a function for each element in an object/map/hash. If that call returns
|
||||
* true, adds the element to a new object.
|
||||
*
|
||||
* @param {Object<K,V>} obj The object over which to iterate.
|
||||
* @param {function(this:T,V,?,Object<K,V>):boolean} f The function to call
|
||||
* for every element. This
|
||||
* function takes 3 arguments (the value, the key and the object)
|
||||
* and should return a boolean. If the return value is true the
|
||||
* element is added to the result object. If it is false the
|
||||
* element is not included.
|
||||
* @param {T=} opt_obj This is used as the 'this' object within f.
|
||||
* @return {!Object<K,V>} a new object in which only elements that passed the
|
||||
* test are present.
|
||||
* @template T,K,V
|
||||
*/
|
||||
goog.object.filter = function(obj, f, opt_obj) {
|
||||
var res = {};
|
||||
for (var key in obj) {
|
||||
if (f.call(/** @type {?} */ (opt_obj), obj[key], key, obj)) {
|
||||
res[key] = obj[key];
|
||||
}
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* For every element in an object/map/hash calls a function and inserts the
|
||||
* result into a new object.
|
||||
*
|
||||
* @param {Object<K,V>} obj The object over which to iterate.
|
||||
* @param {function(this:T,V,?,Object<K,V>):R} f The function to call
|
||||
* for every element. This function
|
||||
* takes 3 arguments (the value, the key and the object)
|
||||
* and should return something. The result will be inserted
|
||||
* into a new object.
|
||||
* @param {T=} opt_obj This is used as the 'this' object within f.
|
||||
* @return {!Object<K,R>} a new object with the results from f.
|
||||
* @template T,K,V,R
|
||||
*/
|
||||
goog.object.map = function(obj, f, opt_obj) {
|
||||
var res = {};
|
||||
for (var key in obj) {
|
||||
res[key] = f.call(/** @type {?} */ (opt_obj), obj[key], key, obj);
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls a function for each element in an object/map/hash. If any
|
||||
* call returns true, returns true (without checking the rest). If
|
||||
* all calls return false, returns false.
|
||||
*
|
||||
* @param {Object<K,V>} obj The object to check.
|
||||
* @param {function(this:T,V,?,Object<K,V>):boolean} f The function to
|
||||
* call for every element. This function
|
||||
* takes 3 arguments (the value, the key and the object) and should
|
||||
* return a boolean.
|
||||
* @param {T=} opt_obj This is used as the 'this' object within f.
|
||||
* @return {boolean} true if any element passes the test.
|
||||
* @template T,K,V
|
||||
*/
|
||||
goog.object.some = function(obj, f, opt_obj) {
|
||||
for (var key in obj) {
|
||||
if (f.call(/** @type {?} */ (opt_obj), obj[key], key, obj)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls a function for each element in an object/map/hash. If
|
||||
* all calls return true, returns true. If any call returns false, returns
|
||||
* false at this point and does not continue to check the remaining elements.
|
||||
*
|
||||
* @param {Object<K,V>} obj The object to check.
|
||||
* @param {?function(this:T,V,?,Object<K,V>):boolean} f The function to
|
||||
* call for every element. This function
|
||||
* takes 3 arguments (the value, the key and the object) and should
|
||||
* return a boolean.
|
||||
* @param {T=} opt_obj This is used as the 'this' object within f.
|
||||
* @return {boolean} false if any element fails the test.
|
||||
* @template T,K,V
|
||||
*/
|
||||
goog.object.every = function(obj, f, opt_obj) {
|
||||
for (var key in obj) {
|
||||
if (!f.call(/** @type {?} */ (opt_obj), obj[key], key, obj)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of key-value pairs in the object map.
|
||||
*
|
||||
* @param {Object} obj The object for which to get the number of key-value
|
||||
* pairs.
|
||||
* @return {number} The number of key-value pairs in the object map.
|
||||
*/
|
||||
goog.object.getCount = function(obj) {
|
||||
var rv = 0;
|
||||
for (var key in obj) {
|
||||
rv++;
|
||||
}
|
||||
return rv;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns one key from the object map, if any exists.
|
||||
* For map literals the returned key will be the first one in most of the
|
||||
* browsers (a know exception is Konqueror).
|
||||
*
|
||||
* @param {Object} obj The object to pick a key from.
|
||||
* @return {string|undefined} The key or undefined if the object is empty.
|
||||
*/
|
||||
goog.object.getAnyKey = function(obj) {
|
||||
for (var key in obj) {
|
||||
return key;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns one value from the object map, if any exists.
|
||||
* For map literals the returned value will be the first one in most of the
|
||||
* browsers (a know exception is Konqueror).
|
||||
*
|
||||
* @param {Object<K,V>} obj The object to pick a value from.
|
||||
* @return {V|undefined} The value or undefined if the object is empty.
|
||||
* @template K,V
|
||||
*/
|
||||
goog.object.getAnyValue = function(obj) {
|
||||
for (var key in obj) {
|
||||
return obj[key];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether the object/hash/map contains the given object as a value.
|
||||
* An alias for goog.object.containsValue(obj, val).
|
||||
*
|
||||
* @param {Object<K,V>} obj The object in which to look for val.
|
||||
* @param {V} val The object for which to check.
|
||||
* @return {boolean} true if val is present.
|
||||
* @template K,V
|
||||
*/
|
||||
goog.object.contains = function(obj, val) {
|
||||
return goog.object.containsValue(obj, val);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the values of the object/map/hash.
|
||||
*
|
||||
* @param {Object<K,V>} obj The object from which to get the values.
|
||||
* @return {!Array<V>} The values in the object/map/hash.
|
||||
* @template K,V
|
||||
*/
|
||||
goog.object.getValues = function(obj) {
|
||||
var res = [];
|
||||
var i = 0;
|
||||
for (var key in obj) {
|
||||
res[i++] = obj[key];
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the keys of the object/map/hash.
|
||||
*
|
||||
* @param {Object} obj The object from which to get the keys.
|
||||
* @return {!Array<string>} Array of property keys.
|
||||
*/
|
||||
goog.object.getKeys = function(obj) {
|
||||
var res = [];
|
||||
var i = 0;
|
||||
for (var key in obj) {
|
||||
res[i++] = key;
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get a value from an object multiple levels deep. This is useful for
|
||||
* pulling values from deeply nested objects, such as JSON responses.
|
||||
* Example usage: getValueByKeys(jsonObj, 'foo', 'entries', 3)
|
||||
*
|
||||
* @param {!Object} obj An object to get the value from. Can be array-like.
|
||||
* @param {...(string|number|!IArrayLike<number|string>)}
|
||||
* var_args A number of keys
|
||||
* (as strings, or numbers, for array-like objects). Can also be
|
||||
* specified as a single array of keys.
|
||||
* @return {*} The resulting value. If, at any point, the value for a key
|
||||
* is undefined, returns undefined.
|
||||
*/
|
||||
goog.object.getValueByKeys = function(obj, var_args) {
|
||||
var isArrayLike = goog.isArrayLike(var_args);
|
||||
var keys = isArrayLike ? var_args : arguments;
|
||||
|
||||
// Start with the 2nd parameter for the variable parameters syntax.
|
||||
for (var i = isArrayLike ? 0 : 1; i < keys.length; i++) {
|
||||
obj = obj[keys[i]];
|
||||
if (!goog.isDef(obj)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether the object/map/hash contains the given key.
|
||||
*
|
||||
* @param {Object} obj The object in which to look for key.
|
||||
* @param {?} key The key for which to check.
|
||||
* @return {boolean} true If the map contains the key.
|
||||
*/
|
||||
goog.object.containsKey = function(obj, key) {
|
||||
return obj !== null && key in obj;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether the object/map/hash contains the given value. This is O(n).
|
||||
*
|
||||
* @param {Object<K,V>} obj The object in which to look for val.
|
||||
* @param {V} val The value for which to check.
|
||||
* @return {boolean} true If the map contains the value.
|
||||
* @template K,V
|
||||
*/
|
||||
goog.object.containsValue = function(obj, val) {
|
||||
for (var key in obj) {
|
||||
if (obj[key] == val) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Searches an object for an element that satisfies the given condition and
|
||||
* returns its key.
|
||||
* @param {Object<K,V>} obj The object to search in.
|
||||
* @param {function(this:T,V,string,Object<K,V>):boolean} f The
|
||||
* function to call for every element. Takes 3 arguments (the value,
|
||||
* the key and the object) and should return a boolean.
|
||||
* @param {T=} opt_this An optional "this" context for the function.
|
||||
* @return {string|undefined} The key of an element for which the function
|
||||
* returns true or undefined if no such element is found.
|
||||
* @template T,K,V
|
||||
*/
|
||||
goog.object.findKey = function(obj, f, opt_this) {
|
||||
for (var key in obj) {
|
||||
if (f.call(/** @type {?} */ (opt_this), obj[key], key, obj)) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Searches an object for an element that satisfies the given condition and
|
||||
* returns its value.
|
||||
* @param {Object<K,V>} obj The object to search in.
|
||||
* @param {function(this:T,V,string,Object<K,V>):boolean} f The function
|
||||
* to call for every element. Takes 3 arguments (the value, the key
|
||||
* and the object) and should return a boolean.
|
||||
* @param {T=} opt_this An optional "this" context for the function.
|
||||
* @return {V} The value of an element for which the function returns true or
|
||||
* undefined if no such element is found.
|
||||
* @template T,K,V
|
||||
*/
|
||||
goog.object.findValue = function(obj, f, opt_this) {
|
||||
var key = goog.object.findKey(obj, f, opt_this);
|
||||
return key && obj[key];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether the object/map/hash is empty.
|
||||
*
|
||||
* @param {Object} obj The object to test.
|
||||
* @return {boolean} true if obj is empty.
|
||||
*/
|
||||
goog.object.isEmpty = function(obj) {
|
||||
for (var key in obj) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes all key value pairs from the object/map/hash.
|
||||
*
|
||||
* @param {Object} obj The object to clear.
|
||||
*/
|
||||
goog.object.clear = function(obj) {
|
||||
for (var i in obj) {
|
||||
delete obj[i];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes a key-value pair based on the key.
|
||||
*
|
||||
* @param {Object} obj The object from which to remove the key.
|
||||
* @param {?} key The key to remove.
|
||||
* @return {boolean} Whether an element was removed.
|
||||
*/
|
||||
goog.object.remove = function(obj, key) {
|
||||
var rv;
|
||||
if (rv = key in /** @type {!Object} */ (obj)) {
|
||||
delete obj[key];
|
||||
}
|
||||
return rv;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds a key-value pair to the object. Throws an exception if the key is
|
||||
* already in use. Use set if you want to change an existing pair.
|
||||
*
|
||||
* @param {Object<K,V>} obj The object to which to add the key-value pair.
|
||||
* @param {string} key The key to add.
|
||||
* @param {V} val The value to add.
|
||||
* @template K,V
|
||||
*/
|
||||
goog.object.add = function(obj, key, val) {
|
||||
if (obj !== null && key in obj) {
|
||||
throw Error('The object already contains the key "' + key + '"');
|
||||
}
|
||||
goog.object.set(obj, key, val);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the value for the given key.
|
||||
*
|
||||
* @param {Object<K,V>} obj The object from which to get the value.
|
||||
* @param {string} key The key for which to get the value.
|
||||
* @param {R=} opt_val The value to return if no item is found for the given
|
||||
* key (default is undefined).
|
||||
* @return {V|R|undefined} The value for the given key.
|
||||
* @template K,V,R
|
||||
*/
|
||||
goog.object.get = function(obj, key, opt_val) {
|
||||
if (obj !== null && key in obj) {
|
||||
return obj[key];
|
||||
}
|
||||
return opt_val;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds a key-value pair to the object/map/hash.
|
||||
*
|
||||
* @param {Object<K,V>} obj The object to which to add the key-value pair.
|
||||
* @param {string} key The key to add.
|
||||
* @param {V} value The value to add.
|
||||
* @template K,V
|
||||
*/
|
||||
goog.object.set = function(obj, key, value) {
|
||||
obj[key] = value;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds a key-value pair to the object/map/hash if it doesn't exist yet.
|
||||
*
|
||||
* @param {Object<K,V>} obj The object to which to add the key-value pair.
|
||||
* @param {string} key The key to add.
|
||||
* @param {V} value The value to add if the key wasn't present.
|
||||
* @return {V} The value of the entry at the end of the function.
|
||||
* @template K,V
|
||||
*/
|
||||
goog.object.setIfUndefined = function(obj, key, value) {
|
||||
return key in /** @type {!Object} */ (obj) ? obj[key] : (obj[key] = value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets a key and value to an object if the key is not set. The value will be
|
||||
* the return value of the given function. If the key already exists, the
|
||||
* object will not be changed and the function will not be called (the function
|
||||
* will be lazily evaluated -- only called if necessary).
|
||||
*
|
||||
* This function is particularly useful for use with a map used a as a cache.
|
||||
*
|
||||
* @param {!Object<K,V>} obj The object to which to add the key-value pair.
|
||||
* @param {string} key The key to add.
|
||||
* @param {function():V} f The value to add if the key wasn't present.
|
||||
* @return {V} The value of the entry at the end of the function.
|
||||
* @template K,V
|
||||
*/
|
||||
goog.object.setWithReturnValueIfNotSet = function(obj, key, f) {
|
||||
if (key in obj) {
|
||||
return obj[key];
|
||||
}
|
||||
|
||||
var val = f();
|
||||
obj[key] = val;
|
||||
return val;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Compares two objects for equality using === on the values.
|
||||
*
|
||||
* @param {!Object<K,V>} a
|
||||
* @param {!Object<K,V>} b
|
||||
* @return {boolean}
|
||||
* @template K,V
|
||||
*/
|
||||
goog.object.equals = function(a, b) {
|
||||
for (var k in a) {
|
||||
if (!(k in b) || a[k] !== b[k]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (var k in b) {
|
||||
if (!(k in a)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns a shallow clone of the object.
|
||||
*
|
||||
* @param {Object<K,V>} obj Object to clone.
|
||||
* @return {!Object<K,V>} Clone of the input object.
|
||||
* @template K,V
|
||||
*/
|
||||
goog.object.clone = function(obj) {
|
||||
// We cannot use the prototype trick because a lot of methods depend on where
|
||||
// the actual key is set.
|
||||
|
||||
var res = {};
|
||||
for (var key in obj) {
|
||||
res[key] = obj[key];
|
||||
}
|
||||
return res;
|
||||
// We could also use goog.mixin but I wanted this to be independent from that.
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clones a value. The input may be an Object, Array, or basic type. Objects and
|
||||
* arrays will be cloned recursively.
|
||||
*
|
||||
* WARNINGS:
|
||||
* <code>goog.object.unsafeClone</code> does not detect reference loops. Objects
|
||||
* that refer to themselves will cause infinite recursion.
|
||||
*
|
||||
* <code>goog.object.unsafeClone</code> is unaware of unique identifiers, and
|
||||
* copies UIDs created by <code>getUid</code> into cloned results.
|
||||
*
|
||||
* @param {T} obj The value to clone.
|
||||
* @return {T} A clone of the input value.
|
||||
* @template T
|
||||
*/
|
||||
goog.object.unsafeClone = function(obj) {
|
||||
var type = goog.typeOf(obj);
|
||||
if (type == 'object' || type == 'array') {
|
||||
if (goog.isFunction(obj.clone)) {
|
||||
return obj.clone();
|
||||
}
|
||||
var clone = type == 'array' ? [] : {};
|
||||
for (var key in obj) {
|
||||
clone[key] = goog.object.unsafeClone(obj[key]);
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
return obj;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns a new object in which all the keys and values are interchanged
|
||||
* (keys become values and values become keys). If multiple keys map to the
|
||||
* same value, the chosen transposed value is implementation-dependent.
|
||||
*
|
||||
* @param {Object} obj The object to transpose.
|
||||
* @return {!Object} The transposed object.
|
||||
*/
|
||||
goog.object.transpose = function(obj) {
|
||||
var transposed = {};
|
||||
for (var key in obj) {
|
||||
transposed[obj[key]] = key;
|
||||
}
|
||||
return transposed;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The names of the fields that are defined on Object.prototype.
|
||||
* @type {Array<string>}
|
||||
* @private
|
||||
*/
|
||||
goog.object.PROTOTYPE_FIELDS_ = [
|
||||
'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable',
|
||||
'toLocaleString', 'toString', 'valueOf'
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Extends an object with another object.
|
||||
* This operates 'in-place'; it does not create a new Object.
|
||||
*
|
||||
* Example:
|
||||
* var o = {};
|
||||
* goog.object.extend(o, {a: 0, b: 1});
|
||||
* o; // {a: 0, b: 1}
|
||||
* goog.object.extend(o, {b: 2, c: 3});
|
||||
* o; // {a: 0, b: 2, c: 3}
|
||||
*
|
||||
* @param {Object} target The object to modify. Existing properties will be
|
||||
* overwritten if they are also present in one of the objects in
|
||||
* {@code var_args}.
|
||||
* @param {...Object} var_args The objects from which values will be copied.
|
||||
*/
|
||||
goog.object.extend = function(target, var_args) {
|
||||
var key, source;
|
||||
for (var i = 1; i < arguments.length; i++) {
|
||||
source = arguments[i];
|
||||
for (key in source) {
|
||||
target[key] = source[key];
|
||||
}
|
||||
|
||||
// For IE the for-in-loop does not contain any properties that are not
|
||||
// enumerable on the prototype object (for example isPrototypeOf from
|
||||
// Object.prototype) and it will also not include 'replace' on objects that
|
||||
// extend String and change 'replace' (not that it is common for anyone to
|
||||
// extend anything except Object).
|
||||
|
||||
for (var j = 0; j < goog.object.PROTOTYPE_FIELDS_.length; j++) {
|
||||
key = goog.object.PROTOTYPE_FIELDS_[j];
|
||||
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
||||
target[key] = source[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new object built from the key-value pairs provided as arguments.
|
||||
* @param {...*} var_args If only one argument is provided and it is an array
|
||||
* then this is used as the arguments, otherwise even arguments are used as
|
||||
* the property names and odd arguments are used as the property values.
|
||||
* @return {!Object} The new object.
|
||||
* @throws {Error} If there are uneven number of arguments or there is only one
|
||||
* non array argument.
|
||||
*/
|
||||
goog.object.create = function(var_args) {
|
||||
var argLength = arguments.length;
|
||||
if (argLength == 1 && goog.isArray(arguments[0])) {
|
||||
return goog.object.create.apply(null, arguments[0]);
|
||||
}
|
||||
|
||||
if (argLength % 2) {
|
||||
throw Error('Uneven number of arguments');
|
||||
}
|
||||
|
||||
var rv = {};
|
||||
for (var i = 0; i < argLength; i += 2) {
|
||||
rv[arguments[i]] = arguments[i + 1];
|
||||
}
|
||||
return rv;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new object where the property names come from the arguments but
|
||||
* the value is always set to true
|
||||
* @param {...*} var_args If only one argument is provided and it is an array
|
||||
* then this is used as the arguments, otherwise the arguments are used
|
||||
* as the property names.
|
||||
* @return {!Object} The new object.
|
||||
*/
|
||||
goog.object.createSet = function(var_args) {
|
||||
var argLength = arguments.length;
|
||||
if (argLength == 1 && goog.isArray(arguments[0])) {
|
||||
return goog.object.createSet.apply(null, arguments[0]);
|
||||
}
|
||||
|
||||
var rv = {};
|
||||
for (var i = 0; i < argLength; i++) {
|
||||
rv[arguments[i]] = true;
|
||||
}
|
||||
return rv;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates an immutable view of the underlying object, if the browser
|
||||
* supports immutable objects.
|
||||
*
|
||||
* In default mode, writes to this view will fail silently. In strict mode,
|
||||
* they will throw an error.
|
||||
*
|
||||
* @param {!Object<K,V>} obj An object.
|
||||
* @return {!Object<K,V>} An immutable view of that object, or the
|
||||
* original object if this browser does not support immutables.
|
||||
* @template K,V
|
||||
*/
|
||||
goog.object.createImmutableView = function(obj) {
|
||||
var result = obj;
|
||||
if (Object.isFrozen && !Object.isFrozen(obj)) {
|
||||
result = Object.create(obj);
|
||||
Object.freeze(result);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {!Object} obj An object.
|
||||
* @return {boolean} Whether this is an immutable view of the object.
|
||||
*/
|
||||
goog.object.isImmutableView = function(obj) {
|
||||
return !!Object.isFrozen && Object.isFrozen(obj);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get all properties names on a given Object regardless of enumerability.
|
||||
*
|
||||
* <p> If the browser does not support {@code Object.getOwnPropertyNames} nor
|
||||
* {@code Object.getPrototypeOf} then this is equivalent to using {@code
|
||||
* goog.object.getKeys}
|
||||
*
|
||||
* @param {?Object} obj The object to get the properties of.
|
||||
* @param {boolean=} opt_includeObjectPrototype Whether properties defined on
|
||||
* {@code Object.prototype} should be included in the result.
|
||||
* @param {boolean=} opt_includeFunctionPrototype Whether properties defined on
|
||||
* {@code Function.prototype} should be included in the result.
|
||||
* @return {!Array<string>}
|
||||
* @public
|
||||
*/
|
||||
goog.object.getAllPropertyNames = function(
|
||||
obj, opt_includeObjectPrototype, opt_includeFunctionPrototype) {
|
||||
if (!obj) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Naively use a for..in loop to get the property names if the browser doesn't
|
||||
// support any other APIs for getting it.
|
||||
if (!Object.getOwnPropertyNames || !Object.getPrototypeOf) {
|
||||
return goog.object.getKeys(obj);
|
||||
}
|
||||
|
||||
var visitedSet = {};
|
||||
|
||||
// Traverse the prototype chain and add all properties to the visited set.
|
||||
var proto = obj;
|
||||
while (proto &&
|
||||
(proto !== Object.prototype || !!opt_includeObjectPrototype) &&
|
||||
(proto !== Function.prototype || !!opt_includeFunctionPrototype)) {
|
||||
var names = Object.getOwnPropertyNames(proto);
|
||||
for (var i = 0; i < names.length; i++) {
|
||||
visitedSet[names[i]] = true;
|
||||
}
|
||||
proto = Object.getPrototypeOf(proto);
|
||||
}
|
||||
|
||||
return goog.object.getKeys(visitedSet);
|
||||
};
|
||||
1344
resources/public/target/cljsbuild-compiler-1/goog/promise/promise.js
Normal file
1344
resources/public/target/cljsbuild-compiler-1/goog/promise/promise.js
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,48 @@
|
|||
// Copyright 2013 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.
|
||||
|
||||
goog.provide('goog.promise.Resolver');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Resolver interface for promises. The resolver is a convenience interface that
|
||||
* bundles the promise and its associated resolve and reject functions together,
|
||||
* for cases where the resolver needs to be persisted internally.
|
||||
*
|
||||
* @interface
|
||||
* @template TYPE
|
||||
*/
|
||||
goog.promise.Resolver = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* The promise that created this resolver.
|
||||
* @type {!goog.Promise<TYPE>}
|
||||
*/
|
||||
goog.promise.Resolver.prototype.promise;
|
||||
|
||||
|
||||
/**
|
||||
* Resolves this resolver with the specified value.
|
||||
* @type {function((TYPE|goog.Promise<TYPE>|Thenable)=)}
|
||||
*/
|
||||
goog.promise.Resolver.prototype.resolve;
|
||||
|
||||
|
||||
/**
|
||||
* Rejects this resolver with the specified reason.
|
||||
* @type {function(*=): void}
|
||||
*/
|
||||
goog.promise.Resolver.prototype.reject;
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
// Copyright 2013 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.
|
||||
|
||||
goog.provide('goog.Thenable');
|
||||
|
||||
/** @suppress {extraRequire} */
|
||||
goog.forwardDeclare('goog.Promise'); // for the type reference.
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Provides a more strict interface for Thenables in terms of
|
||||
* http://promisesaplus.com for interop with {@see goog.Promise}.
|
||||
*
|
||||
* @interface
|
||||
* @extends {IThenable<TYPE>}
|
||||
* @template TYPE
|
||||
*/
|
||||
goog.Thenable = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Adds callbacks that will operate on the result of the Thenable, returning a
|
||||
* new child Promise.
|
||||
*
|
||||
* If the Thenable is fulfilled, the {@code onFulfilled} callback will be
|
||||
* invoked with the fulfillment value as argument, and the child Promise will
|
||||
* be fulfilled with the return value of the callback. If the callback throws
|
||||
* an exception, the child Promise will be rejected with the thrown value
|
||||
* instead.
|
||||
*
|
||||
* If the Thenable is rejected, the {@code onRejected} callback will be invoked
|
||||
* with the rejection reason as argument, and the child Promise will be rejected
|
||||
* with the return value of the callback or thrown value.
|
||||
*
|
||||
* @param {?(function(this:THIS, TYPE): VALUE)=} opt_onFulfilled A
|
||||
* function that will be invoked with the fulfillment value if the Promise
|
||||
* is fulfilled.
|
||||
* @param {?(function(this:THIS, *): *)=} opt_onRejected A function that will
|
||||
* be invoked with the rejection reason if the Promise is rejected.
|
||||
* @param {THIS=} opt_context An optional context object that will be the
|
||||
* execution context for the callbacks. By default, functions are executed
|
||||
* with the default this.
|
||||
*
|
||||
* @return {RESULT} A new Promise that will receive the result
|
||||
* of the fulfillment or rejection callback.
|
||||
* @template VALUE
|
||||
* @template THIS
|
||||
*
|
||||
* When a Promise (or thenable) is returned from the fulfilled callback,
|
||||
* the result is the payload of that promise, not the promise itself.
|
||||
*
|
||||
* @template RESULT := type('goog.Promise',
|
||||
* cond(isUnknown(VALUE), unknown(),
|
||||
* mapunion(VALUE, (V) =>
|
||||
* cond(isTemplatized(V) && sub(rawTypeOf(V), 'IThenable'),
|
||||
* templateTypeOf(V, 0),
|
||||
* cond(sub(V, 'Thenable'),
|
||||
* unknown(),
|
||||
* V)))))
|
||||
* =:
|
||||
*
|
||||
*/
|
||||
goog.Thenable.prototype.then = function(
|
||||
opt_onFulfilled, opt_onRejected, opt_context) {};
|
||||
|
||||
|
||||
/**
|
||||
* An expando property to indicate that an object implements
|
||||
* {@code goog.Thenable}.
|
||||
*
|
||||
* {@see addImplementation}.
|
||||
*
|
||||
* @const
|
||||
*/
|
||||
goog.Thenable.IMPLEMENTED_BY_PROP = '$goog_Thenable';
|
||||
|
||||
|
||||
/**
|
||||
* Marks a given class (constructor) as an implementation of Thenable, so
|
||||
* that we can query that fact at runtime. The class must have already
|
||||
* implemented the interface.
|
||||
* Exports a 'then' method on the constructor prototype, so that the objects
|
||||
* also implement the extern {@see goog.Thenable} interface for interop with
|
||||
* other Promise implementations.
|
||||
* @param {function(new:goog.Thenable,...?)} ctor The class constructor. The
|
||||
* corresponding class must have already implemented the interface.
|
||||
*/
|
||||
goog.Thenable.addImplementation = function(ctor) {
|
||||
// Use bracket notation instead of goog.exportSymbol() so that the compiler
|
||||
// won't create a 'var ctor;' extern when the "create externs from exports"
|
||||
// mode is enabled.
|
||||
ctor.prototype['then'] = ctor.prototype.then;
|
||||
if (COMPILED) {
|
||||
ctor.prototype[goog.Thenable.IMPLEMENTED_BY_PROP] = true;
|
||||
} else {
|
||||
// Avoids dictionary access in uncompiled mode.
|
||||
ctor.prototype.$goog_Thenable = true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {?} object
|
||||
* @return {boolean} Whether a given instance implements {@code goog.Thenable}.
|
||||
* The class/superclass of the instance must call {@code addImplementation}.
|
||||
*/
|
||||
goog.Thenable.isImplementedBy = function(object) {
|
||||
if (!object) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
if (COMPILED) {
|
||||
return !!object[goog.Thenable.IMPLEMENTED_BY_PROP];
|
||||
}
|
||||
return !!object.$goog_Thenable;
|
||||
} catch (e) {
|
||||
// Property access seems to be forbidden.
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
// Copyright 2009 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 Useful compiler idioms.
|
||||
*
|
||||
* @author johnlenz@google.com (John Lenz)
|
||||
*/
|
||||
|
||||
goog.provide('goog.reflect');
|
||||
|
||||
|
||||
/**
|
||||
* Syntax for object literal casts.
|
||||
* @see http://go/jscompiler-renaming
|
||||
* @see https://goo.gl/CRs09P
|
||||
*
|
||||
* Use this if you have an object literal whose keys need to have the same names
|
||||
* as the properties of some class even after they are renamed by the compiler.
|
||||
*
|
||||
* @param {!Function} type Type to cast to.
|
||||
* @param {Object} object Object literal to cast.
|
||||
* @return {Object} The object literal.
|
||||
*/
|
||||
goog.reflect.object = function(type, object) {
|
||||
return object;
|
||||
};
|
||||
|
||||
/**
|
||||
* Syntax for renaming property strings.
|
||||
* @see http://go/jscompiler-renaming
|
||||
* @see https://goo.gl/CRs09P
|
||||
*
|
||||
* Use this if you have an need to access a property as a string, but want
|
||||
* to also have the property renamed by the compiler. In contrast to
|
||||
* goog.reflect.object, this method takes an instance of an object.
|
||||
*
|
||||
* Properties must be simple names (not qualified names).
|
||||
*
|
||||
* @param {string} prop Name of the property
|
||||
* @param {!Object} object Instance of the object whose type will be used
|
||||
* for renaming
|
||||
* @return {string} The renamed property.
|
||||
*/
|
||||
goog.reflect.objectProperty = function(prop, object) {
|
||||
return prop;
|
||||
};
|
||||
|
||||
/**
|
||||
* To assert to the compiler that an operation is needed when it would
|
||||
* otherwise be stripped. For example:
|
||||
* <code>
|
||||
* // Force a layout
|
||||
* goog.reflect.sinkValue(dialog.offsetHeight);
|
||||
* </code>
|
||||
* @param {T} x
|
||||
* @return {T}
|
||||
* @template T
|
||||
*/
|
||||
goog.reflect.sinkValue = function(x) {
|
||||
goog.reflect.sinkValue[' '](x);
|
||||
return x;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The compiler should optimize this function away iff no one ever uses
|
||||
* goog.reflect.sinkValue.
|
||||
*/
|
||||
goog.reflect.sinkValue[' '] = goog.nullFunction;
|
||||
|
||||
|
||||
/**
|
||||
* Check if a property can be accessed without throwing an exception.
|
||||
* @param {Object} obj The owner of the property.
|
||||
* @param {string} prop The property name.
|
||||
* @return {boolean} Whether the property is accessible. Will also return true
|
||||
* if obj is null.
|
||||
*/
|
||||
goog.reflect.canAccessProperty = function(obj, prop) {
|
||||
|
||||
try {
|
||||
goog.reflect.sinkValue(obj[prop]);
|
||||
return true;
|
||||
} catch (e) {
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves a value from a cache given a key. The compiler provides special
|
||||
* consideration for this call such that it is generally considered side-effect
|
||||
* free. However, if the {@code opt_keyFn} or {@code valueFn} have side-effects
|
||||
* then the entire call is considered to have side-effects.
|
||||
*
|
||||
* Conventionally storing the value on the cache would be considered a
|
||||
* side-effect and preclude unused calls from being pruned, ie. even if
|
||||
* the value was never used, it would still always be stored in the cache.
|
||||
*
|
||||
* Providing a side-effect free {@code valueFn} and {@code opt_keyFn}
|
||||
* allows unused calls to {@code goog.reflect.cache} to be pruned.
|
||||
*
|
||||
* @param {!Object<K, V>} cacheObj The object that contains the cached values.
|
||||
* @param {?} key The key to lookup in the cache. If it is not string or number
|
||||
* then a {@code opt_keyFn} should be provided. The key is also used as the
|
||||
* parameter to the {@code valueFn}.
|
||||
* @param {function(?):V} valueFn The value provider to use to calculate the
|
||||
* value to store in the cache. This function should be side-effect free
|
||||
* to take advantage of the optimization.
|
||||
* @param {function(?):K=} opt_keyFn The key provider to determine the cache
|
||||
* map key. This should be used if the given key is not a string or number.
|
||||
* If not provided then the given key is used. This function should be
|
||||
* side-effect free to take advantage of the optimization.
|
||||
* @return {V} The cached or calculated value.
|
||||
* @template K
|
||||
* @template V
|
||||
*/
|
||||
goog.reflect.cache = function(cacheObj, key, valueFn, opt_keyFn) {
|
||||
var storedKey = opt_keyFn ? opt_keyFn(key) : key;
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(cacheObj, storedKey)) {
|
||||
return cacheObj[storedKey];
|
||||
}
|
||||
|
||||
return (cacheObj[storedKey] = valueFn(key));
|
||||
};
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
// Copyright 2013 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.
|
||||
|
||||
goog.provide('goog.string.Const');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.string.TypedString');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Wrapper for compile-time-constant strings.
|
||||
*
|
||||
* Const is a wrapper for strings that can only be created from program
|
||||
* constants (i.e., string literals). This property relies on a custom Closure
|
||||
* compiler check that {@code goog.string.Const.from} is only invoked on
|
||||
* compile-time-constant expressions.
|
||||
*
|
||||
* Const is useful in APIs whose correct and secure use requires that certain
|
||||
* arguments are not attacker controlled: Compile-time constants are inherently
|
||||
* under the control of the application and not under control of external
|
||||
* attackers, and hence are safe to use in such contexts.
|
||||
*
|
||||
* Instances of this type must be created via its factory method
|
||||
* {@code goog.string.Const.from} and not by invoking its constructor. The
|
||||
* constructor intentionally takes no parameters and the type is immutable;
|
||||
* hence only a default instance corresponding to the empty string can be
|
||||
* obtained via constructor invocation.
|
||||
*
|
||||
* @see goog.string.Const#from
|
||||
* @constructor
|
||||
* @final
|
||||
* @struct
|
||||
* @implements {goog.string.TypedString}
|
||||
*/
|
||||
goog.string.Const = function() {
|
||||
/**
|
||||
* The wrapped value of this Const object. The field has a purposely ugly
|
||||
* name to make (non-compiled) code that attempts to directly access this
|
||||
* field stand out.
|
||||
* @private {string}
|
||||
*/
|
||||
this.stringConstValueWithSecurityContract__googStringSecurityPrivate_ = '';
|
||||
|
||||
/**
|
||||
* A type marker used to implement additional run-time type checking.
|
||||
* @see goog.string.Const#unwrap
|
||||
* @const {!Object}
|
||||
* @private
|
||||
*/
|
||||
this.STRING_CONST_TYPE_MARKER__GOOG_STRING_SECURITY_PRIVATE_ =
|
||||
goog.string.Const.TYPE_MARKER_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @const
|
||||
*/
|
||||
goog.string.Const.prototype.implementsGoogStringTypedString = true;
|
||||
|
||||
|
||||
/**
|
||||
* Returns this Const's value a string.
|
||||
*
|
||||
* IMPORTANT: In code where it is security-relevant that an object's type is
|
||||
* indeed {@code goog.string.Const}, use {@code goog.string.Const.unwrap}
|
||||
* instead of this method.
|
||||
*
|
||||
* @see goog.string.Const#unwrap
|
||||
* @override
|
||||
*/
|
||||
goog.string.Const.prototype.getTypedStringValue = function() {
|
||||
return this.stringConstValueWithSecurityContract__googStringSecurityPrivate_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns a debug-string representation of this value.
|
||||
*
|
||||
* To obtain the actual string value wrapped inside an object of this type,
|
||||
* use {@code goog.string.Const.unwrap}.
|
||||
*
|
||||
* @see goog.string.Const#unwrap
|
||||
* @override
|
||||
*/
|
||||
goog.string.Const.prototype.toString = function() {
|
||||
return 'Const{' +
|
||||
this.stringConstValueWithSecurityContract__googStringSecurityPrivate_ +
|
||||
'}';
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Performs a runtime check that the provided object is indeed an instance
|
||||
* of {@code goog.string.Const}, and returns its value.
|
||||
* @param {!goog.string.Const} stringConst The object to extract from.
|
||||
* @return {string} The Const object's contained string, unless the run-time
|
||||
* type check fails. In that case, {@code unwrap} returns an innocuous
|
||||
* string, or, if assertions are enabled, throws
|
||||
* {@code goog.asserts.AssertionError}.
|
||||
*/
|
||||
goog.string.Const.unwrap = function(stringConst) {
|
||||
// Perform additional run-time type-checking to ensure that stringConst is
|
||||
// indeed an instance of the expected type. This provides some additional
|
||||
// protection against security bugs due to application code that disables type
|
||||
// checks.
|
||||
if (stringConst instanceof goog.string.Const &&
|
||||
stringConst.constructor === goog.string.Const &&
|
||||
stringConst.STRING_CONST_TYPE_MARKER__GOOG_STRING_SECURITY_PRIVATE_ ===
|
||||
goog.string.Const.TYPE_MARKER_) {
|
||||
return stringConst
|
||||
.stringConstValueWithSecurityContract__googStringSecurityPrivate_;
|
||||
} else {
|
||||
goog.asserts.fail(
|
||||
'expected object of type Const, got \'' + stringConst + '\'');
|
||||
return 'type_error:Const';
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a Const object from a compile-time constant string.
|
||||
*
|
||||
* It is illegal to invoke this function on an expression whose
|
||||
* compile-time-contant value cannot be determined by the Closure compiler.
|
||||
*
|
||||
* Correct invocations include,
|
||||
* <pre>
|
||||
* var s = goog.string.Const.from('hello');
|
||||
* var t = goog.string.Const.from('hello' + 'world');
|
||||
* </pre>
|
||||
*
|
||||
* In contrast, the following are illegal:
|
||||
* <pre>
|
||||
* var s = goog.string.Const.from(getHello());
|
||||
* var t = goog.string.Const.from('hello' + world);
|
||||
* </pre>
|
||||
*
|
||||
* @param {string} s A constant string from which to create a Const.
|
||||
* @return {!goog.string.Const} A Const object initialized to stringConst.
|
||||
*/
|
||||
goog.string.Const.from = function(s) {
|
||||
return goog.string.Const.create__googStringSecurityPrivate_(s);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Type marker for the Const type, used to implement additional run-time
|
||||
* type checking.
|
||||
* @const {!Object}
|
||||
* @private
|
||||
*/
|
||||
goog.string.Const.TYPE_MARKER_ = {};
|
||||
|
||||
|
||||
/**
|
||||
* Utility method to create Const instances.
|
||||
* @param {string} s The string to initialize the Const object with.
|
||||
* @return {!goog.string.Const} The initialized Const object.
|
||||
* @private
|
||||
*/
|
||||
goog.string.Const.create__googStringSecurityPrivate_ = function(s) {
|
||||
var stringConst = new goog.string.Const();
|
||||
stringConst.stringConstValueWithSecurityContract__googStringSecurityPrivate_ =
|
||||
s;
|
||||
return stringConst;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A Const instance wrapping the empty string.
|
||||
* @const {!goog.string.Const}
|
||||
*/
|
||||
goog.string.Const.EMPTY = goog.string.Const.from('');
|
||||
1641
resources/public/target/cljsbuild-compiler-1/goog/string/string.js
Normal file
1641
resources/public/target/cljsbuild-compiler-1/goog/string/string.js
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,103 @@
|
|||
// Copyright 2006 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 Utility for fast string concatenation.
|
||||
*/
|
||||
|
||||
goog.provide('goog.string.StringBuffer');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Utility class to facilitate string concatenation.
|
||||
*
|
||||
* @param {*=} opt_a1 Optional first initial item to append.
|
||||
* @param {...*} var_args Other initial items to
|
||||
* append, e.g., new goog.string.StringBuffer('foo', 'bar').
|
||||
* @constructor
|
||||
*/
|
||||
goog.string.StringBuffer = function(opt_a1, var_args) {
|
||||
if (opt_a1 != null) {
|
||||
this.append.apply(this, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Internal buffer for the string to be concatenated.
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
goog.string.StringBuffer.prototype.buffer_ = '';
|
||||
|
||||
|
||||
/**
|
||||
* Sets the contents of the string buffer object, replacing what's currently
|
||||
* there.
|
||||
*
|
||||
* @param {*} s String to set.
|
||||
*/
|
||||
goog.string.StringBuffer.prototype.set = function(s) {
|
||||
this.buffer_ = '' + s;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Appends one or more items to the buffer.
|
||||
*
|
||||
* Calling this with null, undefined, or empty arguments is an error.
|
||||
*
|
||||
* @param {*} a1 Required first string.
|
||||
* @param {*=} opt_a2 Optional second string.
|
||||
* @param {...?} var_args Other items to append,
|
||||
* e.g., sb.append('foo', 'bar', 'baz').
|
||||
* @return {!goog.string.StringBuffer} This same StringBuffer object.
|
||||
* @suppress {duplicate}
|
||||
*/
|
||||
goog.string.StringBuffer.prototype.append = function(a1, opt_a2, var_args) {
|
||||
// Use a1 directly to avoid arguments instantiation for single-arg case.
|
||||
this.buffer_ += String(a1);
|
||||
if (opt_a2 != null) { // second argument is undefined (null == undefined)
|
||||
for (var i = 1; i < arguments.length; i++) {
|
||||
this.buffer_ += arguments[i];
|
||||
}
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clears the internal buffer.
|
||||
*/
|
||||
goog.string.StringBuffer.prototype.clear = function() {
|
||||
this.buffer_ = '';
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} the length of the current contents of the buffer.
|
||||
*/
|
||||
goog.string.StringBuffer.prototype.getLength = function() {
|
||||
return this.buffer_.length;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {string} The concatenated string.
|
||||
* @override
|
||||
*/
|
||||
goog.string.StringBuffer.prototype.toString = function() {
|
||||
return this.buffer_;
|
||||
};
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
// Copyright 2013 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.
|
||||
|
||||
goog.provide('goog.string.TypedString');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Wrapper for strings that conform to a data type or language.
|
||||
*
|
||||
* Implementations of this interface are wrappers for strings, and typically
|
||||
* associate a type contract with the wrapped string. Concrete implementations
|
||||
* of this interface may choose to implement additional run-time type checking,
|
||||
* see for example {@code goog.html.SafeHtml}. If available, client code that
|
||||
* needs to ensure type membership of an object should use the type's function
|
||||
* to assert type membership, such as {@code goog.html.SafeHtml.unwrap}.
|
||||
* @interface
|
||||
*/
|
||||
goog.string.TypedString = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* Interface marker of the TypedString interface.
|
||||
*
|
||||
* This property can be used to determine at runtime whether or not an object
|
||||
* implements this interface. All implementations of this interface set this
|
||||
* property to {@code true}.
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.string.TypedString.prototype.implementsGoogStringTypedString;
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves this wrapped string's value.
|
||||
* @return {string} The wrapped string's value.
|
||||
*/
|
||||
goog.string.TypedString.prototype.getTypedStringValue;
|
||||
458
resources/public/target/cljsbuild-compiler-1/goog/structs/map.js
Normal file
458
resources/public/target/cljsbuild-compiler-1/goog/structs/map.js
Normal file
|
|
@ -0,0 +1,458 @@
|
|||
// Copyright 2006 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 Datastructure: Hash Map.
|
||||
*
|
||||
* @author arv@google.com (Erik Arvidsson)
|
||||
*
|
||||
* This file contains an implementation of a Map structure. It implements a lot
|
||||
* of the methods used in goog.structs so those functions work on hashes. This
|
||||
* is best suited for complex key types. For simple keys such as numbers and
|
||||
* strings consider using the lighter-weight utilities in goog.object.
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.structs.Map');
|
||||
|
||||
goog.require('goog.iter.Iterator');
|
||||
goog.require('goog.iter.StopIteration');
|
||||
goog.require('goog.object');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Class for Hash Map datastructure.
|
||||
* @param {*=} opt_map Map or Object to initialize the map with.
|
||||
* @param {...*} var_args If 2 or more arguments are present then they
|
||||
* will be used as key-value pairs.
|
||||
* @constructor
|
||||
* @template K, V
|
||||
* @deprecated This type is misleading: use ES6 Map instead.
|
||||
*/
|
||||
goog.structs.Map = function(opt_map, var_args) {
|
||||
|
||||
/**
|
||||
* Underlying JS object used to implement the map.
|
||||
* @private {!Object}
|
||||
*/
|
||||
this.map_ = {};
|
||||
|
||||
/**
|
||||
* An array of keys. This is necessary for two reasons:
|
||||
* 1. Iterating the keys using for (var key in this.map_) allocates an
|
||||
* object for every key in IE which is really bad for IE6 GC perf.
|
||||
* 2. Without a side data structure, we would need to escape all the keys
|
||||
* as that would be the only way we could tell during iteration if the
|
||||
* key was an internal key or a property of the object.
|
||||
*
|
||||
* This array can contain deleted keys so it's necessary to check the map
|
||||
* as well to see if the key is still in the map (this doesn't require a
|
||||
* memory allocation in IE).
|
||||
* @private {!Array<string>}
|
||||
*/
|
||||
this.keys_ = [];
|
||||
|
||||
/**
|
||||
* The number of key value pairs in the map.
|
||||
* @private {number}
|
||||
*/
|
||||
this.count_ = 0;
|
||||
|
||||
/**
|
||||
* Version used to detect changes while iterating.
|
||||
* @private {number}
|
||||
*/
|
||||
this.version_ = 0;
|
||||
|
||||
var argLength = arguments.length;
|
||||
|
||||
if (argLength > 1) {
|
||||
if (argLength % 2) {
|
||||
throw Error('Uneven number of arguments');
|
||||
}
|
||||
for (var i = 0; i < argLength; i += 2) {
|
||||
this.set(arguments[i], arguments[i + 1]);
|
||||
}
|
||||
} else if (opt_map) {
|
||||
this.addAll(/** @type {Object} */ (opt_map));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number} The number of key-value pairs in the map.
|
||||
*/
|
||||
goog.structs.Map.prototype.getCount = function() {
|
||||
return this.count_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the values of the map.
|
||||
* @return {!Array<V>} The values in the map.
|
||||
*/
|
||||
goog.structs.Map.prototype.getValues = function() {
|
||||
this.cleanupKeysArray_();
|
||||
|
||||
var rv = [];
|
||||
for (var i = 0; i < this.keys_.length; i++) {
|
||||
var key = this.keys_[i];
|
||||
rv.push(this.map_[key]);
|
||||
}
|
||||
return rv;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the keys of the map.
|
||||
* @return {!Array<string>} Array of string values.
|
||||
*/
|
||||
goog.structs.Map.prototype.getKeys = function() {
|
||||
this.cleanupKeysArray_();
|
||||
return /** @type {!Array<string>} */ (this.keys_.concat());
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether the map contains the given key.
|
||||
* @param {*} key The key to check for.
|
||||
* @return {boolean} Whether the map contains the key.
|
||||
*/
|
||||
goog.structs.Map.prototype.containsKey = function(key) {
|
||||
return goog.structs.Map.hasKey_(this.map_, key);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether the map contains the given value. This is O(n).
|
||||
* @param {V} val The value to check for.
|
||||
* @return {boolean} Whether the map contains the value.
|
||||
*/
|
||||
goog.structs.Map.prototype.containsValue = function(val) {
|
||||
for (var i = 0; i < this.keys_.length; i++) {
|
||||
var key = this.keys_[i];
|
||||
if (goog.structs.Map.hasKey_(this.map_, key) && this.map_[key] == val) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether this map is equal to the argument map.
|
||||
* @param {goog.structs.Map} otherMap The map against which to test equality.
|
||||
* @param {function(V, V): boolean=} opt_equalityFn Optional equality function
|
||||
* to test equality of values. If not specified, this will test whether
|
||||
* the values contained in each map are identical objects.
|
||||
* @return {boolean} Whether the maps are equal.
|
||||
*/
|
||||
goog.structs.Map.prototype.equals = function(otherMap, opt_equalityFn) {
|
||||
if (this === otherMap) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.count_ != otherMap.getCount()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var equalityFn = opt_equalityFn || goog.structs.Map.defaultEquals;
|
||||
|
||||
this.cleanupKeysArray_();
|
||||
for (var key, i = 0; key = this.keys_[i]; i++) {
|
||||
if (!equalityFn(this.get(key), otherMap.get(key))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Default equality test for values.
|
||||
* @param {*} a The first value.
|
||||
* @param {*} b The second value.
|
||||
* @return {boolean} Whether a and b reference the same object.
|
||||
*/
|
||||
goog.structs.Map.defaultEquals = function(a, b) {
|
||||
return a === b;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the map is empty.
|
||||
*/
|
||||
goog.structs.Map.prototype.isEmpty = function() {
|
||||
return this.count_ == 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes all key-value pairs from the map.
|
||||
*/
|
||||
goog.structs.Map.prototype.clear = function() {
|
||||
this.map_ = {};
|
||||
this.keys_.length = 0;
|
||||
this.count_ = 0;
|
||||
this.version_ = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes a key-value pair based on the key. This is O(logN) amortized due to
|
||||
* updating the keys array whenever the count becomes half the size of the keys
|
||||
* in the keys array.
|
||||
* @param {*} key The key to remove.
|
||||
* @return {boolean} Whether object was removed.
|
||||
*/
|
||||
goog.structs.Map.prototype.remove = function(key) {
|
||||
if (goog.structs.Map.hasKey_(this.map_, key)) {
|
||||
delete this.map_[key];
|
||||
this.count_--;
|
||||
this.version_++;
|
||||
|
||||
// clean up the keys array if the threshold is hit
|
||||
if (this.keys_.length > 2 * this.count_) {
|
||||
this.cleanupKeysArray_();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Cleans up the temp keys array by removing entries that are no longer in the
|
||||
* map.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.Map.prototype.cleanupKeysArray_ = function() {
|
||||
if (this.count_ != this.keys_.length) {
|
||||
// First remove keys that are no longer in the map.
|
||||
var srcIndex = 0;
|
||||
var destIndex = 0;
|
||||
while (srcIndex < this.keys_.length) {
|
||||
var key = this.keys_[srcIndex];
|
||||
if (goog.structs.Map.hasKey_(this.map_, key)) {
|
||||
this.keys_[destIndex++] = key;
|
||||
}
|
||||
srcIndex++;
|
||||
}
|
||||
this.keys_.length = destIndex;
|
||||
}
|
||||
|
||||
if (this.count_ != this.keys_.length) {
|
||||
// If the count still isn't correct, that means we have duplicates. This can
|
||||
// happen when the same key is added and removed multiple times. Now we have
|
||||
// to allocate one extra Object to remove the duplicates. This could have
|
||||
// been done in the first pass, but in the common case, we can avoid
|
||||
// allocating an extra object by only doing this when necessary.
|
||||
var seen = {};
|
||||
var srcIndex = 0;
|
||||
var destIndex = 0;
|
||||
while (srcIndex < this.keys_.length) {
|
||||
var key = this.keys_[srcIndex];
|
||||
if (!(goog.structs.Map.hasKey_(seen, key))) {
|
||||
this.keys_[destIndex++] = key;
|
||||
seen[key] = 1;
|
||||
}
|
||||
srcIndex++;
|
||||
}
|
||||
this.keys_.length = destIndex;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the value for the given key. If the key is not found and the default
|
||||
* value is not given this will return {@code undefined}.
|
||||
* @param {*} key The key to get the value for.
|
||||
* @param {DEFAULT=} opt_val The value to return if no item is found for the
|
||||
* given key, defaults to undefined.
|
||||
* @return {V|DEFAULT} The value for the given key.
|
||||
* @template DEFAULT
|
||||
*/
|
||||
goog.structs.Map.prototype.get = function(key, opt_val) {
|
||||
if (goog.structs.Map.hasKey_(this.map_, key)) {
|
||||
return this.map_[key];
|
||||
}
|
||||
return opt_val;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds a key-value pair to the map.
|
||||
* @param {*} key The key.
|
||||
* @param {V} value The value to add.
|
||||
* @return {*} Some subclasses return a value.
|
||||
*/
|
||||
goog.structs.Map.prototype.set = function(key, value) {
|
||||
if (!(goog.structs.Map.hasKey_(this.map_, key))) {
|
||||
this.count_++;
|
||||
// TODO(johnlenz): This class lies, it claims to return an array of string
|
||||
// keys, but instead returns the original object used.
|
||||
this.keys_.push(/** @type {?} */ (key));
|
||||
// Only change the version if we add a new key.
|
||||
this.version_++;
|
||||
}
|
||||
this.map_[key] = value;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Adds multiple key-value pairs from another goog.structs.Map or Object.
|
||||
* @param {Object} map Object containing the data to add.
|
||||
*/
|
||||
goog.structs.Map.prototype.addAll = function(map) {
|
||||
var keys, values;
|
||||
if (map instanceof goog.structs.Map) {
|
||||
keys = map.getKeys();
|
||||
values = map.getValues();
|
||||
} else {
|
||||
keys = goog.object.getKeys(map);
|
||||
values = goog.object.getValues(map);
|
||||
}
|
||||
// we could use goog.array.forEach here but I don't want to introduce that
|
||||
// dependency just for this.
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
this.set(keys[i], values[i]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls the given function on each entry in the map.
|
||||
* @param {function(this:T, V, K, goog.structs.Map<K,V>)} f
|
||||
* @param {T=} opt_obj The value of "this" inside f.
|
||||
* @template T
|
||||
*/
|
||||
goog.structs.Map.prototype.forEach = function(f, opt_obj) {
|
||||
var keys = this.getKeys();
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
var key = keys[i];
|
||||
var value = this.get(key);
|
||||
f.call(opt_obj, value, key, this);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clones a map and returns a new map.
|
||||
* @return {!goog.structs.Map} A new map with the same key-value pairs.
|
||||
*/
|
||||
goog.structs.Map.prototype.clone = function() {
|
||||
return new goog.structs.Map(this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns a new map in which all the keys and values are interchanged
|
||||
* (keys become values and values become keys). If multiple keys map to the
|
||||
* same value, the chosen transposed value is implementation-dependent.
|
||||
*
|
||||
* It acts very similarly to {goog.object.transpose(Object)}.
|
||||
*
|
||||
* @return {!goog.structs.Map} The transposed map.
|
||||
*/
|
||||
goog.structs.Map.prototype.transpose = function() {
|
||||
var transposed = new goog.structs.Map();
|
||||
for (var i = 0; i < this.keys_.length; i++) {
|
||||
var key = this.keys_[i];
|
||||
var value = this.map_[key];
|
||||
transposed.set(value, key);
|
||||
}
|
||||
|
||||
return transposed;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {!Object} Object representation of the map.
|
||||
*/
|
||||
goog.structs.Map.prototype.toObject = function() {
|
||||
this.cleanupKeysArray_();
|
||||
var obj = {};
|
||||
for (var i = 0; i < this.keys_.length; i++) {
|
||||
var key = this.keys_[i];
|
||||
obj[key] = this.map_[key];
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns an iterator that iterates over the keys in the map. Removal of keys
|
||||
* while iterating might have undesired side effects.
|
||||
* @return {!goog.iter.Iterator} An iterator over the keys in the map.
|
||||
*/
|
||||
goog.structs.Map.prototype.getKeyIterator = function() {
|
||||
return this.__iterator__(true);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns an iterator that iterates over the values in the map. Removal of
|
||||
* keys while iterating might have undesired side effects.
|
||||
* @return {!goog.iter.Iterator} An iterator over the values in the map.
|
||||
*/
|
||||
goog.structs.Map.prototype.getValueIterator = function() {
|
||||
return this.__iterator__(false);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns an iterator that iterates over the values or the keys in the map.
|
||||
* This throws an exception if the map was mutated since the iterator was
|
||||
* created.
|
||||
* @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} An iterator over the values or keys in the map.
|
||||
*/
|
||||
goog.structs.Map.prototype.__iterator__ = function(opt_keys) {
|
||||
// Clean up keys to minimize the risk of iterating over dead keys.
|
||||
this.cleanupKeysArray_();
|
||||
|
||||
var i = 0;
|
||||
var version = this.version_;
|
||||
var selfObj = this;
|
||||
|
||||
var newIter = new goog.iter.Iterator;
|
||||
newIter.next = function() {
|
||||
if (version != selfObj.version_) {
|
||||
throw Error('The map has changed since the iterator was created');
|
||||
}
|
||||
if (i >= selfObj.keys_.length) {
|
||||
throw goog.iter.StopIteration;
|
||||
}
|
||||
var key = selfObj.keys_[i++];
|
||||
return opt_keys ? key : selfObj.map_[key];
|
||||
};
|
||||
return newIter;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Safe way to test for hasOwnProperty. It even allows testing for
|
||||
* 'hasOwnProperty'.
|
||||
* @param {Object} obj The object to test for presence of the given key.
|
||||
* @param {*} key The key to check for.
|
||||
* @return {boolean} Whether the object has the key.
|
||||
* @private
|
||||
*/
|
||||
goog.structs.Map.hasKey_ = function(obj, key) {
|
||||
return Object.prototype.hasOwnProperty.call(obj, key);
|
||||
};
|
||||
|
|
@ -0,0 +1,354 @@
|
|||
// Copyright 2006 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 Generics method for collection-like classes and objects.
|
||||
*
|
||||
* @author arv@google.com (Erik Arvidsson)
|
||||
*
|
||||
* This file contains functions to work with collections. It supports using
|
||||
* Map, Set, Array and Object and other classes that implement collection-like
|
||||
* methods.
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.structs');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.object');
|
||||
|
||||
|
||||
// We treat an object as a dictionary if it has getKeys or it is an object that
|
||||
// isn't arrayLike.
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of values in the collection-like object.
|
||||
* @param {Object} col The collection-like object.
|
||||
* @return {number} The number of values in the collection-like object.
|
||||
*/
|
||||
goog.structs.getCount = function(col) {
|
||||
if (col.getCount && typeof col.getCount == 'function') {
|
||||
return col.getCount();
|
||||
}
|
||||
if (goog.isArrayLike(col) || goog.isString(col)) {
|
||||
return col.length;
|
||||
}
|
||||
return goog.object.getCount(col);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the values of the collection-like object.
|
||||
* @param {Object} col The collection-like object.
|
||||
* @return {!Array<?>} The values in the collection-like object.
|
||||
*/
|
||||
goog.structs.getValues = function(col) {
|
||||
if (col.getValues && typeof col.getValues == 'function') {
|
||||
return col.getValues();
|
||||
}
|
||||
if (goog.isString(col)) {
|
||||
return col.split('');
|
||||
}
|
||||
if (goog.isArrayLike(col)) {
|
||||
var rv = [];
|
||||
var l = col.length;
|
||||
for (var i = 0; i < l; i++) {
|
||||
rv.push(col[i]);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
return goog.object.getValues(col);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns the keys of the collection. Some collections have no notion of
|
||||
* keys/indexes and this function will return undefined in those cases.
|
||||
* @param {Object} col The collection-like object.
|
||||
* @return {!Array|undefined} The keys in the collection.
|
||||
*/
|
||||
goog.structs.getKeys = function(col) {
|
||||
if (col.getKeys && typeof col.getKeys == 'function') {
|
||||
return col.getKeys();
|
||||
}
|
||||
// if we have getValues but no getKeys we know this is a key-less collection
|
||||
if (col.getValues && typeof col.getValues == 'function') {
|
||||
return undefined;
|
||||
}
|
||||
if (goog.isArrayLike(col) || goog.isString(col)) {
|
||||
var rv = [];
|
||||
var l = col.length;
|
||||
for (var i = 0; i < l; i++) {
|
||||
rv.push(i);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
return goog.object.getKeys(col);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether the collection contains the given value. This is O(n) and uses
|
||||
* equals (==) to test the existence.
|
||||
* @param {Object} col The collection-like object.
|
||||
* @param {*} val The value to check for.
|
||||
* @return {boolean} True if the map contains the value.
|
||||
*/
|
||||
goog.structs.contains = function(col, val) {
|
||||
if (col.contains && typeof col.contains == 'function') {
|
||||
return col.contains(val);
|
||||
}
|
||||
if (col.containsValue && typeof col.containsValue == 'function') {
|
||||
return col.containsValue(val);
|
||||
}
|
||||
if (goog.isArrayLike(col) || goog.isString(col)) {
|
||||
return goog.array.contains(/** @type {!Array<?>} */ (col), val);
|
||||
}
|
||||
return goog.object.containsValue(col, val);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether the collection is empty.
|
||||
* @param {Object} col The collection-like object.
|
||||
* @return {boolean} True if empty.
|
||||
*/
|
||||
goog.structs.isEmpty = function(col) {
|
||||
if (col.isEmpty && typeof col.isEmpty == 'function') {
|
||||
return col.isEmpty();
|
||||
}
|
||||
|
||||
// We do not use goog.string.isEmptyOrWhitespace because here we treat the
|
||||
// string as
|
||||
// collection and as such even whitespace matters
|
||||
|
||||
if (goog.isArrayLike(col) || goog.isString(col)) {
|
||||
return goog.array.isEmpty(/** @type {!Array<?>} */ (col));
|
||||
}
|
||||
return goog.object.isEmpty(col);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Removes all the elements from the collection.
|
||||
* @param {Object} col The collection-like object.
|
||||
*/
|
||||
goog.structs.clear = function(col) {
|
||||
// NOTE(arv): This should not contain strings because strings are immutable
|
||||
if (col.clear && typeof col.clear == 'function') {
|
||||
col.clear();
|
||||
} else if (goog.isArrayLike(col)) {
|
||||
goog.array.clear(/** @type {IArrayLike<?>} */ (col));
|
||||
} else {
|
||||
goog.object.clear(col);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls a function for each value in a collection. The function takes
|
||||
* three arguments; the value, the key and the collection.
|
||||
*
|
||||
* @param {S} col The collection-like object.
|
||||
* @param {function(this:T,?,?,S):?} f The function to call for every value.
|
||||
* This function takes
|
||||
* 3 arguments (the value, the key or undefined if the collection has no
|
||||
* notion of keys, and the collection) and the return value is irrelevant.
|
||||
* @param {T=} opt_obj The object to be used as the value of 'this'
|
||||
* within {@code f}.
|
||||
* @template T,S
|
||||
* @deprecated Use a more specific method, e.g. goog.array.forEach,
|
||||
* goog.object.forEach, or for-of.
|
||||
*/
|
||||
goog.structs.forEach = function(col, f, opt_obj) {
|
||||
if (col.forEach && typeof col.forEach == 'function') {
|
||||
col.forEach(f, opt_obj);
|
||||
} else if (goog.isArrayLike(col) || goog.isString(col)) {
|
||||
goog.array.forEach(/** @type {!Array<?>} */ (col), f, opt_obj);
|
||||
} else {
|
||||
var keys = goog.structs.getKeys(col);
|
||||
var values = goog.structs.getValues(col);
|
||||
var l = values.length;
|
||||
for (var i = 0; i < l; i++) {
|
||||
f.call(/** @type {?} */ (opt_obj), values[i], keys && keys[i], col);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls a function for every value in the collection. When a call returns true,
|
||||
* adds the value to a new collection (Array is returned by default).
|
||||
*
|
||||
* @param {S} col The collection-like object.
|
||||
* @param {function(this:T,?,?,S):boolean} f The function to call for every
|
||||
* value. This function takes
|
||||
* 3 arguments (the value, the key or undefined if the collection has no
|
||||
* notion of keys, and the collection) and should return a Boolean. If the
|
||||
* return value is true the value is added to the result collection. If it
|
||||
* is false the value is not included.
|
||||
* @param {T=} opt_obj The object to be used as the value of 'this'
|
||||
* within {@code f}.
|
||||
* @return {!Object|!Array<?>} A new collection where the passed values are
|
||||
* present. If col is a key-less collection an array is returned. If col
|
||||
* has keys and values a plain old JS object is returned.
|
||||
* @template T,S
|
||||
*/
|
||||
goog.structs.filter = function(col, f, opt_obj) {
|
||||
if (typeof col.filter == 'function') {
|
||||
return col.filter(f, opt_obj);
|
||||
}
|
||||
if (goog.isArrayLike(col) || goog.isString(col)) {
|
||||
return goog.array.filter(/** @type {!Array<?>} */ (col), f, opt_obj);
|
||||
}
|
||||
|
||||
var rv;
|
||||
var keys = goog.structs.getKeys(col);
|
||||
var values = goog.structs.getValues(col);
|
||||
var l = values.length;
|
||||
if (keys) {
|
||||
rv = {};
|
||||
for (var i = 0; i < l; i++) {
|
||||
if (f.call(/** @type {?} */ (opt_obj), values[i], keys[i], col)) {
|
||||
rv[keys[i]] = values[i];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// We should not use goog.array.filter here since we want to make sure that
|
||||
// the index is undefined as well as make sure that col is passed to the
|
||||
// function.
|
||||
rv = [];
|
||||
for (var i = 0; i < l; i++) {
|
||||
if (f.call(opt_obj, values[i], undefined, col)) {
|
||||
rv.push(values[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls a function for every value in the collection and adds the result into a
|
||||
* new collection (defaults to creating a new Array).
|
||||
*
|
||||
* @param {S} col The collection-like object.
|
||||
* @param {function(this:T,?,?,S):V} f The function to call for every value.
|
||||
* This function takes 3 arguments (the value, the key or undefined if the
|
||||
* collection has no notion of keys, and the collection) and should return
|
||||
* something. The result will be used as the value in the new collection.
|
||||
* @param {T=} opt_obj The object to be used as the value of 'this'
|
||||
* within {@code f}.
|
||||
* @return {!Object<V>|!Array<V>} A new collection with the new values. If
|
||||
* col is a key-less collection an array is returned. If col has keys and
|
||||
* values a plain old JS object is returned.
|
||||
* @template T,S,V
|
||||
*/
|
||||
goog.structs.map = function(col, f, opt_obj) {
|
||||
if (typeof col.map == 'function') {
|
||||
return col.map(f, opt_obj);
|
||||
}
|
||||
if (goog.isArrayLike(col) || goog.isString(col)) {
|
||||
return goog.array.map(/** @type {!Array<?>} */ (col), f, opt_obj);
|
||||
}
|
||||
|
||||
var rv;
|
||||
var keys = goog.structs.getKeys(col);
|
||||
var values = goog.structs.getValues(col);
|
||||
var l = values.length;
|
||||
if (keys) {
|
||||
rv = {};
|
||||
for (var i = 0; i < l; i++) {
|
||||
rv[keys[i]] = f.call(/** @type {?} */ (opt_obj), values[i], keys[i], col);
|
||||
}
|
||||
} else {
|
||||
// We should not use goog.array.map here since we want to make sure that
|
||||
// the index is undefined as well as make sure that col is passed to the
|
||||
// function.
|
||||
rv = [];
|
||||
for (var i = 0; i < l; i++) {
|
||||
rv[i] = f.call(/** @type {?} */ (opt_obj), values[i], undefined, col);
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls f for each value in a collection. If any call returns true this returns
|
||||
* true (without checking the rest). If all returns false this returns false.
|
||||
*
|
||||
* @param {S} col The collection-like object.
|
||||
* @param {function(this:T,?,?,S):boolean} f The function to call for every
|
||||
* value. This function takes 3 arguments (the value, the key or undefined
|
||||
* if the collection has no notion of keys, and the collection) and should
|
||||
* return a boolean.
|
||||
* @param {T=} opt_obj The object to be used as the value of 'this'
|
||||
* within {@code f}.
|
||||
* @return {boolean} True if any value passes the test.
|
||||
* @template T,S
|
||||
*/
|
||||
goog.structs.some = function(col, f, opt_obj) {
|
||||
if (typeof col.some == 'function') {
|
||||
return col.some(f, opt_obj);
|
||||
}
|
||||
if (goog.isArrayLike(col) || goog.isString(col)) {
|
||||
return goog.array.some(/** @type {!Array<?>} */ (col), f, opt_obj);
|
||||
}
|
||||
var keys = goog.structs.getKeys(col);
|
||||
var values = goog.structs.getValues(col);
|
||||
var l = values.length;
|
||||
for (var i = 0; i < l; i++) {
|
||||
if (f.call(/** @type {?} */ (opt_obj), values[i], keys && keys[i], col)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls f for each value in a collection. If all calls return true this return
|
||||
* true this returns true. If any returns false this returns false at this point
|
||||
* and does not continue to check the remaining values.
|
||||
*
|
||||
* @param {S} col The collection-like object.
|
||||
* @param {function(this:T,?,?,S):boolean} f The function to call for every
|
||||
* value. This function takes 3 arguments (the value, the key or
|
||||
* undefined if the collection has no notion of keys, and the collection)
|
||||
* and should return a boolean.
|
||||
* @param {T=} opt_obj The object to be used as the value of 'this'
|
||||
* within {@code f}.
|
||||
* @return {boolean} True if all key-value pairs pass the test.
|
||||
* @template T,S
|
||||
*/
|
||||
goog.structs.every = function(col, f, opt_obj) {
|
||||
if (typeof col.every == 'function') {
|
||||
return col.every(f, opt_obj);
|
||||
}
|
||||
if (goog.isArrayLike(col) || goog.isString(col)) {
|
||||
return goog.array.every(/** @type {!Array<?>} */ (col), f, opt_obj);
|
||||
}
|
||||
var keys = goog.structs.getKeys(col);
|
||||
var values = goog.structs.getValues(col);
|
||||
var l = values.length;
|
||||
for (var i = 0; i < l; i++) {
|
||||
if (!f.call(/** @type {?} */ (opt_obj), values[i], keys && keys[i], col)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
324
resources/public/target/cljsbuild-compiler-1/goog/timer/timer.js
Normal file
324
resources/public/target/cljsbuild-compiler-1/goog/timer/timer.js
Normal file
|
|
@ -0,0 +1,324 @@
|
|||
// Copyright 2006 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 A timer class to which other classes and objects can listen on.
|
||||
* This is only an abstraction above {@code setInterval}.
|
||||
*
|
||||
* @see ../demos/timers.html
|
||||
*/
|
||||
|
||||
goog.provide('goog.Timer');
|
||||
|
||||
goog.require('goog.Promise');
|
||||
goog.require('goog.events.EventTarget');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Class for handling timing events.
|
||||
*
|
||||
* @param {number=} opt_interval Number of ms between ticks (default: 1ms).
|
||||
* @param {Object=} opt_timerObject An object that has {@code setTimeout},
|
||||
* {@code setInterval}, {@code clearTimeout} and {@code clearInterval}
|
||||
* (e.g., {@code window}).
|
||||
* @constructor
|
||||
* @extends {goog.events.EventTarget}
|
||||
*/
|
||||
goog.Timer = function(opt_interval, opt_timerObject) {
|
||||
goog.events.EventTarget.call(this);
|
||||
|
||||
/**
|
||||
* Number of ms between ticks
|
||||
* @private {number}
|
||||
*/
|
||||
this.interval_ = opt_interval || 1;
|
||||
|
||||
/**
|
||||
* An object that implements {@code setTimeout}, {@code setInterval},
|
||||
* {@code clearTimeout} and {@code clearInterval}. We default to the window
|
||||
* object. Changing this on {@link goog.Timer.prototype} changes the object
|
||||
* for all timer instances which can be useful if your environment has some
|
||||
* other implementation of timers than the {@code window} object.
|
||||
* @private {{setTimeout:!Function, clearTimeout:!Function}}
|
||||
*/
|
||||
this.timerObject_ = /** @type {{setTimeout, clearTimeout}} */ (
|
||||
opt_timerObject || goog.Timer.defaultTimerObject);
|
||||
|
||||
/**
|
||||
* Cached {@code tick_} bound to the object for later use in the timer.
|
||||
* @private {Function}
|
||||
* @const
|
||||
*/
|
||||
this.boundTick_ = goog.bind(this.tick_, this);
|
||||
|
||||
/**
|
||||
* Firefox browser often fires the timer event sooner (sometimes MUCH sooner)
|
||||
* than the requested timeout. So we compare the time to when the event was
|
||||
* last fired, and reschedule if appropriate. See also
|
||||
* {@link goog.Timer.intervalScale}.
|
||||
* @private {number}
|
||||
*/
|
||||
this.last_ = goog.now();
|
||||
};
|
||||
goog.inherits(goog.Timer, goog.events.EventTarget);
|
||||
|
||||
|
||||
/**
|
||||
* Maximum timeout value.
|
||||
*
|
||||
* Timeout values too big to fit into a signed 32-bit integer may cause overflow
|
||||
* in FF, Safari, and Chrome, resulting in the timeout being scheduled
|
||||
* immediately. It makes more sense simply not to schedule these timeouts, since
|
||||
* 24.8 days is beyond a reasonable expectation for the browser to stay open.
|
||||
*
|
||||
* @private {number}
|
||||
* @const
|
||||
*/
|
||||
goog.Timer.MAX_TIMEOUT_ = 2147483647;
|
||||
|
||||
|
||||
/**
|
||||
* A timer ID that cannot be returned by any known implementation of
|
||||
* {@code window.setTimeout}. Passing this value to {@code window.clearTimeout}
|
||||
* should therefore be a no-op.
|
||||
*
|
||||
* @private {number}
|
||||
* @const
|
||||
*/
|
||||
goog.Timer.INVALID_TIMEOUT_ID_ = -1;
|
||||
|
||||
|
||||
/**
|
||||
* Whether this timer is enabled
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.Timer.prototype.enabled = false;
|
||||
|
||||
|
||||
/**
|
||||
* An object that implements {@code setTimeout}, {@code setInterval},
|
||||
* {@code clearTimeout} and {@code clearInterval}. We default to the global
|
||||
* object. Changing {@code goog.Timer.defaultTimerObject} changes the object for
|
||||
* all timer instances which can be useful if your environment has some other
|
||||
* implementation of timers you'd like to use.
|
||||
* @type {{setTimeout, clearTimeout}}
|
||||
*/
|
||||
goog.Timer.defaultTimerObject = goog.global;
|
||||
|
||||
|
||||
/**
|
||||
* Variable that controls the timer error correction. If the timer is called
|
||||
* before the requested interval times {@code intervalScale}, which often
|
||||
* happens on Mozilla, the timer is rescheduled.
|
||||
* @see {@link #last_}
|
||||
* @type {number}
|
||||
*/
|
||||
goog.Timer.intervalScale = 0.8;
|
||||
|
||||
|
||||
/**
|
||||
* Variable for storing the result of {@code setInterval}.
|
||||
* @private {?number}
|
||||
*/
|
||||
goog.Timer.prototype.timer_ = null;
|
||||
|
||||
|
||||
/**
|
||||
* Gets the interval of the timer.
|
||||
* @return {number} interval Number of ms between ticks.
|
||||
*/
|
||||
goog.Timer.prototype.getInterval = function() {
|
||||
return this.interval_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the interval of the timer.
|
||||
* @param {number} interval Number of ms between ticks.
|
||||
*/
|
||||
goog.Timer.prototype.setInterval = function(interval) {
|
||||
this.interval_ = interval;
|
||||
if (this.timer_ && this.enabled) {
|
||||
// Stop and then start the timer to reset the interval.
|
||||
this.stop();
|
||||
this.start();
|
||||
} else if (this.timer_) {
|
||||
this.stop();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Callback for the {@code setTimeout} used by the timer.
|
||||
* @private
|
||||
*/
|
||||
goog.Timer.prototype.tick_ = function() {
|
||||
if (this.enabled) {
|
||||
var elapsed = goog.now() - this.last_;
|
||||
if (elapsed > 0 && elapsed < this.interval_ * goog.Timer.intervalScale) {
|
||||
this.timer_ = this.timerObject_.setTimeout(
|
||||
this.boundTick_, this.interval_ - elapsed);
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevents setInterval from registering a duplicate timeout when called
|
||||
// in the timer event handler.
|
||||
if (this.timer_) {
|
||||
this.timerObject_.clearTimeout(this.timer_);
|
||||
this.timer_ = null;
|
||||
}
|
||||
|
||||
this.dispatchTick();
|
||||
// The timer could be stopped in the timer event handler.
|
||||
if (this.enabled) {
|
||||
this.timer_ =
|
||||
this.timerObject_.setTimeout(this.boundTick_, this.interval_);
|
||||
this.last_ = goog.now();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Dispatches the TICK event. This is its own method so subclasses can override.
|
||||
*/
|
||||
goog.Timer.prototype.dispatchTick = function() {
|
||||
this.dispatchEvent(goog.Timer.TICK);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Starts the timer.
|
||||
*/
|
||||
goog.Timer.prototype.start = function() {
|
||||
this.enabled = true;
|
||||
|
||||
// If there is no interval already registered, start it now
|
||||
if (!this.timer_) {
|
||||
// IMPORTANT!
|
||||
// window.setInterval in FireFox has a bug - it fires based on
|
||||
// absolute time, rather than on relative time. What this means
|
||||
// is that if a computer is sleeping/hibernating for 24 hours
|
||||
// and the timer interval was configured to fire every 1000ms,
|
||||
// then after the PC wakes up the timer will fire, in rapid
|
||||
// succession, 3600*24 times.
|
||||
// This bug is described here and is already fixed, but it will
|
||||
// take time to propagate, so for now I am switching this over
|
||||
// to setTimeout logic.
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=376643
|
||||
//
|
||||
this.timer_ = this.timerObject_.setTimeout(this.boundTick_, this.interval_);
|
||||
this.last_ = goog.now();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Stops the timer.
|
||||
*/
|
||||
goog.Timer.prototype.stop = function() {
|
||||
this.enabled = false;
|
||||
if (this.timer_) {
|
||||
this.timerObject_.clearTimeout(this.timer_);
|
||||
this.timer_ = null;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.Timer.prototype.disposeInternal = function() {
|
||||
goog.Timer.superClass_.disposeInternal.call(this);
|
||||
this.stop();
|
||||
delete this.timerObject_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Constant for the timer's event type.
|
||||
* @const
|
||||
*/
|
||||
goog.Timer.TICK = 'tick';
|
||||
|
||||
|
||||
/**
|
||||
* Calls the given function once, after the optional pause.
|
||||
* <p>
|
||||
* The function is always called asynchronously, even if the delay is 0. This
|
||||
* is a common trick to schedule a function to run after a batch of browser
|
||||
* event processing.
|
||||
*
|
||||
* @param {function(this:SCOPE)|{handleEvent:function()}|null} listener Function
|
||||
* or object that has a handleEvent method.
|
||||
* @param {number=} opt_delay Milliseconds to wait; default is 0.
|
||||
* @param {SCOPE=} opt_handler Object in whose scope to call the listener.
|
||||
* @return {number} A handle to the timer ID.
|
||||
* @template SCOPE
|
||||
*/
|
||||
goog.Timer.callOnce = function(listener, opt_delay, opt_handler) {
|
||||
if (goog.isFunction(listener)) {
|
||||
if (opt_handler) {
|
||||
listener = goog.bind(listener, opt_handler);
|
||||
}
|
||||
} else if (listener && typeof listener.handleEvent == 'function') {
|
||||
// using typeof to prevent strict js warning
|
||||
listener = goog.bind(listener.handleEvent, listener);
|
||||
} else {
|
||||
throw Error('Invalid listener argument');
|
||||
}
|
||||
|
||||
if (Number(opt_delay) > goog.Timer.MAX_TIMEOUT_) {
|
||||
// Timeouts greater than MAX_INT return immediately due to integer
|
||||
// overflow in many browsers. Since MAX_INT is 24.8 days, just don't
|
||||
// schedule anything at all.
|
||||
return goog.Timer.INVALID_TIMEOUT_ID_;
|
||||
} else {
|
||||
return goog.Timer.defaultTimerObject.setTimeout(listener, opt_delay || 0);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clears a timeout initiated by {@link #callOnce}.
|
||||
* @param {?number} timerId A timer ID.
|
||||
*/
|
||||
goog.Timer.clear = function(timerId) {
|
||||
goog.Timer.defaultTimerObject.clearTimeout(timerId);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} delay Milliseconds to wait.
|
||||
* @param {(RESULT|goog.Thenable<RESULT>|Thenable)=} opt_result The value
|
||||
* with which the promise will be resolved.
|
||||
* @return {!goog.Promise<RESULT>} A promise that will be resolved after
|
||||
* the specified delay, unless it is canceled first.
|
||||
* @template RESULT
|
||||
*/
|
||||
goog.Timer.promise = function(delay, opt_result) {
|
||||
var timerKey = null;
|
||||
return new goog
|
||||
.Promise(function(resolve, reject) {
|
||||
timerKey =
|
||||
goog.Timer.callOnce(function() { resolve(opt_result); }, delay);
|
||||
if (timerKey == goog.Timer.INVALID_TIMEOUT_ID_) {
|
||||
reject(new Error('Failed to schedule timer.'));
|
||||
}
|
||||
})
|
||||
.thenCatch(function(error) {
|
||||
// Clear the timer. The most likely reason is "cancel" signal.
|
||||
goog.Timer.clear(timerKey);
|
||||
throw error;
|
||||
});
|
||||
};
|
||||
1547
resources/public/target/cljsbuild-compiler-1/goog/uri/uri.js
Normal file
1547
resources/public/target/cljsbuild-compiler-1/goog/uri/uri.js
Normal file
File diff suppressed because it is too large
Load diff
1103
resources/public/target/cljsbuild-compiler-1/goog/uri/utils.js
Normal file
1103
resources/public/target/cljsbuild-compiler-1/goog/uri/utils.js
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,181 @@
|
|||
// Copyright 2008 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 Detects the specific browser and not just the rendering engine.
|
||||
*
|
||||
*/
|
||||
|
||||
goog.provide('goog.userAgent.product');
|
||||
|
||||
goog.require('goog.labs.userAgent.browser');
|
||||
goog.require('goog.labs.userAgent.platform');
|
||||
goog.require('goog.userAgent');
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Whether the code is running on the Firefox web browser.
|
||||
*/
|
||||
goog.define('goog.userAgent.product.ASSUME_FIREFOX', false);
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Whether we know at compile-time that the product is an
|
||||
* iPhone.
|
||||
*/
|
||||
goog.define('goog.userAgent.product.ASSUME_IPHONE', false);
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Whether we know at compile-time that the product is an
|
||||
* iPad.
|
||||
*/
|
||||
goog.define('goog.userAgent.product.ASSUME_IPAD', false);
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Whether we know at compile-time that the product is an
|
||||
* AOSP browser or WebView inside a pre KitKat Android phone or tablet.
|
||||
*/
|
||||
goog.define('goog.userAgent.product.ASSUME_ANDROID', false);
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Whether the code is running on the Chrome web browser on
|
||||
* any platform or AOSP browser or WebView in a KitKat+ Android phone or tablet.
|
||||
*/
|
||||
goog.define('goog.userAgent.product.ASSUME_CHROME', false);
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Whether the code is running on the Safari web browser.
|
||||
*/
|
||||
goog.define('goog.userAgent.product.ASSUME_SAFARI', false);
|
||||
|
||||
|
||||
/**
|
||||
* Whether we know the product type at compile-time.
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
goog.userAgent.product.PRODUCT_KNOWN_ = goog.userAgent.ASSUME_IE ||
|
||||
goog.userAgent.ASSUME_EDGE || goog.userAgent.ASSUME_OPERA ||
|
||||
goog.userAgent.product.ASSUME_FIREFOX ||
|
||||
goog.userAgent.product.ASSUME_IPHONE ||
|
||||
goog.userAgent.product.ASSUME_IPAD ||
|
||||
goog.userAgent.product.ASSUME_ANDROID ||
|
||||
goog.userAgent.product.ASSUME_CHROME ||
|
||||
goog.userAgent.product.ASSUME_SAFARI;
|
||||
|
||||
|
||||
/**
|
||||
* Whether the code is running on the Opera web browser.
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.userAgent.product.OPERA = goog.userAgent.OPERA;
|
||||
|
||||
|
||||
/**
|
||||
* Whether the code is running on an IE web browser.
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.userAgent.product.IE = goog.userAgent.IE;
|
||||
|
||||
|
||||
/**
|
||||
* Whether the code is running on an Edge web browser.
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.userAgent.product.EDGE = goog.userAgent.EDGE;
|
||||
|
||||
|
||||
/**
|
||||
* Whether the code is running on the Firefox web browser.
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.userAgent.product.FIREFOX = goog.userAgent.product.PRODUCT_KNOWN_ ?
|
||||
goog.userAgent.product.ASSUME_FIREFOX :
|
||||
goog.labs.userAgent.browser.isFirefox();
|
||||
|
||||
|
||||
/**
|
||||
* Whether the user agent is an iPhone or iPod (as in iPod touch).
|
||||
* @return {boolean}
|
||||
* @private
|
||||
*/
|
||||
goog.userAgent.product.isIphoneOrIpod_ = function() {
|
||||
return goog.labs.userAgent.platform.isIphone() ||
|
||||
goog.labs.userAgent.platform.isIpod();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether the code is running on an iPhone or iPod touch.
|
||||
*
|
||||
* iPod touch is considered an iPhone for legacy reasons.
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.userAgent.product.IPHONE = goog.userAgent.product.PRODUCT_KNOWN_ ?
|
||||
goog.userAgent.product.ASSUME_IPHONE :
|
||||
goog.userAgent.product.isIphoneOrIpod_();
|
||||
|
||||
|
||||
/**
|
||||
* Whether the code is running on an iPad.
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.userAgent.product.IPAD = goog.userAgent.product.PRODUCT_KNOWN_ ?
|
||||
goog.userAgent.product.ASSUME_IPAD :
|
||||
goog.labs.userAgent.platform.isIpad();
|
||||
|
||||
|
||||
/**
|
||||
* Whether the code is running on AOSP browser or WebView inside
|
||||
* a pre KitKat Android phone or tablet.
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.userAgent.product.ANDROID = goog.userAgent.product.PRODUCT_KNOWN_ ?
|
||||
goog.userAgent.product.ASSUME_ANDROID :
|
||||
goog.labs.userAgent.browser.isAndroidBrowser();
|
||||
|
||||
|
||||
/**
|
||||
* Whether the code is running on the Chrome web browser on any platform
|
||||
* or AOSP browser or WebView in a KitKat+ Android phone or tablet.
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.userAgent.product.CHROME = goog.userAgent.product.PRODUCT_KNOWN_ ?
|
||||
goog.userAgent.product.ASSUME_CHROME :
|
||||
goog.labs.userAgent.browser.isChrome();
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the browser is Safari on desktop.
|
||||
* @private
|
||||
*/
|
||||
goog.userAgent.product.isSafariDesktop_ = function() {
|
||||
return goog.labs.userAgent.browser.isSafari() &&
|
||||
!goog.labs.userAgent.platform.isIos();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether the code is running on the desktop Safari web browser.
|
||||
* Note: the legacy behavior here is only true for Safari not running
|
||||
* on iOS.
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.userAgent.product.SAFARI = goog.userAgent.product.PRODUCT_KNOWN_ ?
|
||||
goog.userAgent.product.ASSUME_SAFARI :
|
||||
goog.userAgent.product.isSafariDesktop_();
|
||||
|
|
@ -0,0 +1,580 @@
|
|||
// Copyright 2006 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 Rendering engine detection.
|
||||
* @see <a href="http://www.useragentstring.com/">User agent strings</a>
|
||||
* For information on the browser brand (such as Safari versus Chrome), see
|
||||
* goog.userAgent.product.
|
||||
* @author arv@google.com (Erik Arvidsson)
|
||||
* @see ../demos/useragent.html
|
||||
*/
|
||||
|
||||
goog.provide('goog.userAgent');
|
||||
|
||||
goog.require('goog.labs.userAgent.browser');
|
||||
goog.require('goog.labs.userAgent.engine');
|
||||
goog.require('goog.labs.userAgent.platform');
|
||||
goog.require('goog.labs.userAgent.util');
|
||||
goog.require('goog.reflect');
|
||||
goog.require('goog.string');
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Whether we know at compile-time that the browser is IE.
|
||||
*/
|
||||
goog.define('goog.userAgent.ASSUME_IE', false);
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Whether we know at compile-time that the browser is EDGE.
|
||||
*/
|
||||
goog.define('goog.userAgent.ASSUME_EDGE', false);
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Whether we know at compile-time that the browser is GECKO.
|
||||
*/
|
||||
goog.define('goog.userAgent.ASSUME_GECKO', false);
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Whether we know at compile-time that the browser is WEBKIT.
|
||||
*/
|
||||
goog.define('goog.userAgent.ASSUME_WEBKIT', false);
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Whether we know at compile-time that the browser is a
|
||||
* mobile device running WebKit e.g. iPhone or Android.
|
||||
*/
|
||||
goog.define('goog.userAgent.ASSUME_MOBILE_WEBKIT', false);
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Whether we know at compile-time that the browser is OPERA.
|
||||
*/
|
||||
goog.define('goog.userAgent.ASSUME_OPERA', false);
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Whether the
|
||||
* {@code goog.userAgent.isVersionOrHigher}
|
||||
* function will return true for any version.
|
||||
*/
|
||||
goog.define('goog.userAgent.ASSUME_ANY_VERSION', false);
|
||||
|
||||
|
||||
/**
|
||||
* Whether we know the browser engine at compile-time.
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
goog.userAgent.BROWSER_KNOWN_ = goog.userAgent.ASSUME_IE ||
|
||||
goog.userAgent.ASSUME_EDGE || goog.userAgent.ASSUME_GECKO ||
|
||||
goog.userAgent.ASSUME_MOBILE_WEBKIT || goog.userAgent.ASSUME_WEBKIT ||
|
||||
goog.userAgent.ASSUME_OPERA;
|
||||
|
||||
|
||||
/**
|
||||
* Returns the userAgent string for the current browser.
|
||||
*
|
||||
* @return {string} The userAgent string.
|
||||
*/
|
||||
goog.userAgent.getUserAgentString = function() {
|
||||
return goog.labs.userAgent.util.getUserAgent();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* TODO(nnaze): Change type to "Navigator" and update compilation targets.
|
||||
* @return {?Object} The native navigator object.
|
||||
*/
|
||||
goog.userAgent.getNavigator = function() {
|
||||
// Need a local navigator reference instead of using the global one,
|
||||
// to avoid the rare case where they reference different objects.
|
||||
// (in a WorkerPool, for example).
|
||||
return goog.global['navigator'] || null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether the user agent is Opera.
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.userAgent.OPERA = goog.userAgent.BROWSER_KNOWN_ ?
|
||||
goog.userAgent.ASSUME_OPERA :
|
||||
goog.labs.userAgent.browser.isOpera();
|
||||
|
||||
|
||||
/**
|
||||
* Whether the user agent is Internet Explorer.
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.userAgent.IE = goog.userAgent.BROWSER_KNOWN_ ?
|
||||
goog.userAgent.ASSUME_IE :
|
||||
goog.labs.userAgent.browser.isIE();
|
||||
|
||||
|
||||
/**
|
||||
* Whether the user agent is Microsoft Edge.
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.userAgent.EDGE = goog.userAgent.BROWSER_KNOWN_ ?
|
||||
goog.userAgent.ASSUME_EDGE :
|
||||
goog.labs.userAgent.engine.isEdge();
|
||||
|
||||
|
||||
/**
|
||||
* Whether the user agent is MS Internet Explorer or MS Edge.
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.userAgent.EDGE_OR_IE = goog.userAgent.EDGE || goog.userAgent.IE;
|
||||
|
||||
|
||||
/**
|
||||
* Whether the user agent is Gecko. Gecko is the rendering engine used by
|
||||
* Mozilla, Firefox, and others.
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.userAgent.GECKO = goog.userAgent.BROWSER_KNOWN_ ?
|
||||
goog.userAgent.ASSUME_GECKO :
|
||||
goog.labs.userAgent.engine.isGecko();
|
||||
|
||||
|
||||
/**
|
||||
* Whether the user agent is WebKit. WebKit is the rendering engine that
|
||||
* Safari, Android and others use.
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.userAgent.WEBKIT = goog.userAgent.BROWSER_KNOWN_ ?
|
||||
goog.userAgent.ASSUME_WEBKIT || goog.userAgent.ASSUME_MOBILE_WEBKIT :
|
||||
goog.labs.userAgent.engine.isWebKit();
|
||||
|
||||
|
||||
/**
|
||||
* Whether the user agent is running on a mobile device.
|
||||
*
|
||||
* This is a separate function so that the logic can be tested.
|
||||
*
|
||||
* TODO(nnaze): Investigate swapping in goog.labs.userAgent.device.isMobile().
|
||||
*
|
||||
* @return {boolean} Whether the user agent is running on a mobile device.
|
||||
* @private
|
||||
*/
|
||||
goog.userAgent.isMobile_ = function() {
|
||||
return goog.userAgent.WEBKIT &&
|
||||
goog.labs.userAgent.util.matchUserAgent('Mobile');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether the user agent is running on a mobile device.
|
||||
*
|
||||
* TODO(nnaze): Consider deprecating MOBILE when labs.userAgent
|
||||
* is promoted as the gecko/webkit logic is likely inaccurate.
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.userAgent.MOBILE =
|
||||
goog.userAgent.ASSUME_MOBILE_WEBKIT || goog.userAgent.isMobile_();
|
||||
|
||||
|
||||
/**
|
||||
* Used while transitioning code to use WEBKIT instead.
|
||||
* @type {boolean}
|
||||
* @deprecated Use {@link goog.userAgent.product.SAFARI} instead.
|
||||
* TODO(nicksantos): Delete this from goog.userAgent.
|
||||
*/
|
||||
goog.userAgent.SAFARI = goog.userAgent.WEBKIT;
|
||||
|
||||
|
||||
/**
|
||||
* @return {string} the platform (operating system) the user agent is running
|
||||
* on. Default to empty string because navigator.platform may not be defined
|
||||
* (on Rhino, for example).
|
||||
* @private
|
||||
*/
|
||||
goog.userAgent.determinePlatform_ = function() {
|
||||
var navigator = goog.userAgent.getNavigator();
|
||||
return navigator && navigator.platform || '';
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The platform (operating system) the user agent is running on. Default to
|
||||
* empty string because navigator.platform may not be defined (on Rhino, for
|
||||
* example).
|
||||
* @type {string}
|
||||
*/
|
||||
goog.userAgent.PLATFORM = goog.userAgent.determinePlatform_();
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Whether the user agent is running on a Macintosh operating
|
||||
* system.
|
||||
*/
|
||||
goog.define('goog.userAgent.ASSUME_MAC', false);
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Whether the user agent is running on a Windows operating
|
||||
* system.
|
||||
*/
|
||||
goog.define('goog.userAgent.ASSUME_WINDOWS', false);
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Whether the user agent is running on a Linux operating
|
||||
* system.
|
||||
*/
|
||||
goog.define('goog.userAgent.ASSUME_LINUX', false);
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Whether the user agent is running on a X11 windowing
|
||||
* system.
|
||||
*/
|
||||
goog.define('goog.userAgent.ASSUME_X11', false);
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Whether the user agent is running on Android.
|
||||
*/
|
||||
goog.define('goog.userAgent.ASSUME_ANDROID', false);
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Whether the user agent is running on an iPhone.
|
||||
*/
|
||||
goog.define('goog.userAgent.ASSUME_IPHONE', false);
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Whether the user agent is running on an iPad.
|
||||
*/
|
||||
goog.define('goog.userAgent.ASSUME_IPAD', false);
|
||||
|
||||
|
||||
/**
|
||||
* @define {boolean} Whether the user agent is running on an iPod.
|
||||
*/
|
||||
goog.define('goog.userAgent.ASSUME_IPOD', false);
|
||||
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
goog.userAgent.PLATFORM_KNOWN_ = goog.userAgent.ASSUME_MAC ||
|
||||
goog.userAgent.ASSUME_WINDOWS || goog.userAgent.ASSUME_LINUX ||
|
||||
goog.userAgent.ASSUME_X11 || goog.userAgent.ASSUME_ANDROID ||
|
||||
goog.userAgent.ASSUME_IPHONE || goog.userAgent.ASSUME_IPAD ||
|
||||
goog.userAgent.ASSUME_IPOD;
|
||||
|
||||
|
||||
/**
|
||||
* Whether the user agent is running on a Macintosh operating system.
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.userAgent.MAC = goog.userAgent.PLATFORM_KNOWN_ ?
|
||||
goog.userAgent.ASSUME_MAC :
|
||||
goog.labs.userAgent.platform.isMacintosh();
|
||||
|
||||
|
||||
/**
|
||||
* Whether the user agent is running on a Windows operating system.
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.userAgent.WINDOWS = goog.userAgent.PLATFORM_KNOWN_ ?
|
||||
goog.userAgent.ASSUME_WINDOWS :
|
||||
goog.labs.userAgent.platform.isWindows();
|
||||
|
||||
|
||||
/**
|
||||
* Whether the user agent is Linux per the legacy behavior of
|
||||
* goog.userAgent.LINUX, which considered ChromeOS to also be
|
||||
* Linux.
|
||||
* @return {boolean}
|
||||
* @private
|
||||
*/
|
||||
goog.userAgent.isLegacyLinux_ = function() {
|
||||
return goog.labs.userAgent.platform.isLinux() ||
|
||||
goog.labs.userAgent.platform.isChromeOS();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether the user agent is running on a Linux operating system.
|
||||
*
|
||||
* Note that goog.userAgent.LINUX considers ChromeOS to be Linux,
|
||||
* while goog.labs.userAgent.platform considers ChromeOS and
|
||||
* Linux to be different OSes.
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.userAgent.LINUX = goog.userAgent.PLATFORM_KNOWN_ ?
|
||||
goog.userAgent.ASSUME_LINUX :
|
||||
goog.userAgent.isLegacyLinux_();
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether the user agent is an X11 windowing system.
|
||||
* @private
|
||||
*/
|
||||
goog.userAgent.isX11_ = function() {
|
||||
var navigator = goog.userAgent.getNavigator();
|
||||
return !!navigator &&
|
||||
goog.string.contains(navigator['appVersion'] || '', 'X11');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Whether the user agent is running on a X11 windowing system.
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.userAgent.X11 = goog.userAgent.PLATFORM_KNOWN_ ?
|
||||
goog.userAgent.ASSUME_X11 :
|
||||
goog.userAgent.isX11_();
|
||||
|
||||
|
||||
/**
|
||||
* Whether the user agent is running on Android.
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.userAgent.ANDROID = goog.userAgent.PLATFORM_KNOWN_ ?
|
||||
goog.userAgent.ASSUME_ANDROID :
|
||||
goog.labs.userAgent.platform.isAndroid();
|
||||
|
||||
|
||||
/**
|
||||
* Whether the user agent is running on an iPhone.
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.userAgent.IPHONE = goog.userAgent.PLATFORM_KNOWN_ ?
|
||||
goog.userAgent.ASSUME_IPHONE :
|
||||
goog.labs.userAgent.platform.isIphone();
|
||||
|
||||
|
||||
/**
|
||||
* Whether the user agent is running on an iPad.
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.userAgent.IPAD = goog.userAgent.PLATFORM_KNOWN_ ?
|
||||
goog.userAgent.ASSUME_IPAD :
|
||||
goog.labs.userAgent.platform.isIpad();
|
||||
|
||||
|
||||
/**
|
||||
* Whether the user agent is running on an iPod.
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.userAgent.IPOD = goog.userAgent.PLATFORM_KNOWN_ ?
|
||||
goog.userAgent.ASSUME_IPOD :
|
||||
goog.labs.userAgent.platform.isIpod();
|
||||
|
||||
|
||||
/**
|
||||
* Whether the user agent is running on iOS.
|
||||
* @type {boolean}
|
||||
*/
|
||||
goog.userAgent.IOS = goog.userAgent.PLATFORM_KNOWN_ ?
|
||||
(goog.userAgent.ASSUME_IPHONE || goog.userAgent.ASSUME_IPAD ||
|
||||
goog.userAgent.ASSUME_IPOD) :
|
||||
goog.labs.userAgent.platform.isIos();
|
||||
|
||||
/**
|
||||
* @return {string} The string that describes the version number of the user
|
||||
* agent.
|
||||
* @private
|
||||
*/
|
||||
goog.userAgent.determineVersion_ = function() {
|
||||
// All browsers have different ways to detect the version and they all have
|
||||
// different naming schemes.
|
||||
// version is a string rather than a number because it may contain 'b', 'a',
|
||||
// and so on.
|
||||
var version = '';
|
||||
var arr = goog.userAgent.getVersionRegexResult_();
|
||||
if (arr) {
|
||||
version = arr ? arr[1] : '';
|
||||
}
|
||||
|
||||
if (goog.userAgent.IE) {
|
||||
// IE9 can be in document mode 9 but be reporting an inconsistent user agent
|
||||
// version. If it is identifying as a version lower than 9 we take the
|
||||
// documentMode as the version instead. IE8 has similar behavior.
|
||||
// It is recommended to set the X-UA-Compatible header to ensure that IE9
|
||||
// uses documentMode 9.
|
||||
var docMode = goog.userAgent.getDocumentMode_();
|
||||
if (docMode != null && docMode > parseFloat(version)) {
|
||||
return String(docMode);
|
||||
}
|
||||
}
|
||||
|
||||
return version;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {?Array|undefined} The version regex matches from parsing the user
|
||||
* agent string. These regex statements must be executed inline so they can
|
||||
* be compiled out by the closure compiler with the rest of the useragent
|
||||
* detection logic when ASSUME_* is specified.
|
||||
* @private
|
||||
*/
|
||||
goog.userAgent.getVersionRegexResult_ = function() {
|
||||
var userAgent = goog.userAgent.getUserAgentString();
|
||||
if (goog.userAgent.GECKO) {
|
||||
return /rv\:([^\);]+)(\)|;)/.exec(userAgent);
|
||||
}
|
||||
if (goog.userAgent.EDGE) {
|
||||
return /Edge\/([\d\.]+)/.exec(userAgent);
|
||||
}
|
||||
if (goog.userAgent.IE) {
|
||||
return /\b(?:MSIE|rv)[: ]([^\);]+)(\)|;)/.exec(userAgent);
|
||||
}
|
||||
if (goog.userAgent.WEBKIT) {
|
||||
// WebKit/125.4
|
||||
return /WebKit\/(\S+)/.exec(userAgent);
|
||||
}
|
||||
if (goog.userAgent.OPERA) {
|
||||
// If none of the above browsers were detected but the browser is Opera, the
|
||||
// only string that is of interest is 'Version/<number>'.
|
||||
return /(?:Version)[ \/]?(\S+)/.exec(userAgent);
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {number|undefined} Returns the document mode (for testing).
|
||||
* @private
|
||||
*/
|
||||
goog.userAgent.getDocumentMode_ = function() {
|
||||
// NOTE(user): goog.userAgent may be used in context where there is no DOM.
|
||||
var doc = goog.global['document'];
|
||||
return doc ? doc['documentMode'] : undefined;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The version of the user agent. This is a string because it might contain
|
||||
* 'b' (as in beta) as well as multiple dots.
|
||||
* @type {string}
|
||||
*/
|
||||
goog.userAgent.VERSION = goog.userAgent.determineVersion_();
|
||||
|
||||
|
||||
/**
|
||||
* Compares two version numbers.
|
||||
*
|
||||
* @param {string} v1 Version of first item.
|
||||
* @param {string} v2 Version of second item.
|
||||
*
|
||||
* @return {number} 1 if first argument is higher
|
||||
* 0 if arguments are equal
|
||||
* -1 if second argument is higher.
|
||||
* @deprecated Use goog.string.compareVersions.
|
||||
*/
|
||||
goog.userAgent.compare = function(v1, v2) {
|
||||
return goog.string.compareVersions(v1, v2);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Cache for {@link goog.userAgent.isVersionOrHigher}.
|
||||
* Calls to compareVersions are surprisingly expensive and, as a browser's
|
||||
* version number is unlikely to change during a session, we cache the results.
|
||||
* @const
|
||||
* @private
|
||||
*/
|
||||
goog.userAgent.isVersionOrHigherCache_ = {};
|
||||
|
||||
|
||||
/**
|
||||
* Whether the user agent version is higher or the same as the given version.
|
||||
* NOTE: When checking the version numbers for Firefox and Safari, be sure to
|
||||
* use the engine's version, not the browser's version number. For example,
|
||||
* Firefox 3.0 corresponds to Gecko 1.9 and Safari 3.0 to Webkit 522.11.
|
||||
* Opera and Internet Explorer versions match the product release number.<br>
|
||||
* @see <a href="http://en.wikipedia.org/wiki/Safari_version_history">
|
||||
* Webkit</a>
|
||||
* @see <a href="http://en.wikipedia.org/wiki/Gecko_engine">Gecko</a>
|
||||
*
|
||||
* @param {string|number} version The version to check.
|
||||
* @return {boolean} Whether the user agent version is higher or the same as
|
||||
* the given version.
|
||||
*/
|
||||
goog.userAgent.isVersionOrHigher = function(version) {
|
||||
return goog.userAgent.ASSUME_ANY_VERSION ||
|
||||
goog.reflect.cache(
|
||||
goog.userAgent.isVersionOrHigherCache_, version, function() {
|
||||
return goog.string.compareVersions(
|
||||
goog.userAgent.VERSION, version) >= 0;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Deprecated alias to {@code goog.userAgent.isVersionOrHigher}.
|
||||
* @param {string|number} version The version to check.
|
||||
* @return {boolean} Whether the user agent version is higher or the same as
|
||||
* the given version.
|
||||
* @deprecated Use goog.userAgent.isVersionOrHigher().
|
||||
*/
|
||||
goog.userAgent.isVersion = goog.userAgent.isVersionOrHigher;
|
||||
|
||||
|
||||
/**
|
||||
* Whether the IE effective document mode is higher or the same as the given
|
||||
* document mode version.
|
||||
* NOTE: Only for IE, return false for another browser.
|
||||
*
|
||||
* @param {number} documentMode The document mode version to check.
|
||||
* @return {boolean} Whether the IE effective document mode is higher or the
|
||||
* same as the given version.
|
||||
*/
|
||||
goog.userAgent.isDocumentModeOrHigher = function(documentMode) {
|
||||
return Number(goog.userAgent.DOCUMENT_MODE) >= documentMode;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Deprecated alias to {@code goog.userAgent.isDocumentModeOrHigher}.
|
||||
* @param {number} version The version to check.
|
||||
* @return {boolean} Whether the IE effective document mode is higher or the
|
||||
* same as the given version.
|
||||
* @deprecated Use goog.userAgent.isDocumentModeOrHigher().
|
||||
*/
|
||||
goog.userAgent.isDocumentMode = goog.userAgent.isDocumentModeOrHigher;
|
||||
|
||||
|
||||
/**
|
||||
* For IE version < 7, documentMode is undefined, so attempt to use the
|
||||
* CSS1Compat property to see if we are in standards mode. If we are in
|
||||
* standards mode, treat the browser version as the document mode. Otherwise,
|
||||
* IE is emulating version 5.
|
||||
* @type {number|undefined}
|
||||
* @const
|
||||
*/
|
||||
goog.userAgent.DOCUMENT_MODE = (function() {
|
||||
var doc = goog.global['document'];
|
||||
var mode = goog.userAgent.getDocumentMode_();
|
||||
if (!doc || !goog.userAgent.IE) {
|
||||
return undefined;
|
||||
}
|
||||
return mode || (doc['compatMode'] == 'CSS1Compat' ?
|
||||
parseInt(goog.userAgent.VERSION, 10) :
|
||||
5);
|
||||
})();
|
||||
Loading…
Add table
Add a link
Reference in a new issue