Index: third_party/google_input_tools/third_party/closure_library/closure/goog/async/animationdelay.js |
diff --git a/third_party/google_input_tools/third_party/closure_library/closure/goog/async/animationdelay.js b/third_party/google_input_tools/third_party/closure_library/closure/goog/async/animationdelay.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..1e24b346d24b8fdaadc4d9de815f6d9f9d376cdc |
--- /dev/null |
+++ b/third_party/google_input_tools/third_party/closure_library/closure/goog/async/animationdelay.js |
@@ -0,0 +1,267 @@ |
+// 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 A delayed callback that pegs to the next animation frame |
+ * instead of a user-configurable timeout. |
+ * |
+ * @author nicksantos@google.com (Nick Santos) |
+ */ |
+ |
+goog.provide('goog.async.AnimationDelay'); |
+ |
+goog.require('goog.Disposable'); |
+goog.require('goog.events'); |
+goog.require('goog.functions'); |
+ |
+ |
+ |
+// TODO(nicksantos): Should we factor out the common code between this and |
+// goog.async.Delay? I'm not sure if there's enough code for this to really |
+// make sense. Subclassing seems like the wrong approach for a variety of |
+// reasons. Maybe there should be a common interface? |
+ |
+ |
+ |
+/** |
+ * A delayed callback that pegs to the next animation frame |
+ * instead of a user configurable timeout. By design, this should have |
+ * the same interface as goog.async.Delay. |
+ * |
+ * Uses requestAnimationFrame and friends when available, but falls |
+ * back to a timeout of goog.async.AnimationDelay.TIMEOUT. |
+ * |
+ * For more on requestAnimationFrame and how you can use it to create smoother |
+ * animations, see: |
+ * @see http://paulirish.com/2011/requestanimationframe-for-smart-animating/ |
+ * |
+ * @param {function(number)} listener Function to call when the delay completes. |
+ * Will be passed the timestamp when it's called, in unix ms. |
+ * @param {Window=} opt_window The window object to execute the delay in. |
+ * Defaults to the global object. |
+ * @param {Object=} opt_handler The object scope to invoke the function in. |
+ * @constructor |
+ * @struct |
+ * @suppress {checkStructDictInheritance} |
+ * @extends {goog.Disposable} |
+ * @final |
+ */ |
+goog.async.AnimationDelay = function(listener, opt_window, opt_handler) { |
+ goog.async.AnimationDelay.base(this, 'constructor'); |
+ |
+ /** |
+ * Identifier of the active delay timeout, or event listener, |
+ * or null when inactive. |
+ * @private {goog.events.Key|number} |
+ */ |
+ this.id_ = null; |
+ |
+ /** |
+ * If we're using dom listeners. |
+ * @private {?boolean} |
+ */ |
+ this.usingListeners_ = false; |
+ |
+ /** |
+ * The function that will be invoked after a delay. |
+ * @private {function(number)} |
+ */ |
+ this.listener_ = listener; |
+ |
+ /** |
+ * The object context to invoke the callback in. |
+ * @private {Object|undefined} |
+ */ |
+ this.handler_ = opt_handler; |
+ |
+ /** |
+ * @private {Window} |
+ */ |
+ this.win_ = opt_window || window; |
+ |
+ /** |
+ * Cached callback function invoked when the delay finishes. |
+ * @private {function()} |
+ */ |
+ this.callback_ = goog.bind(this.doAction_, this); |
+}; |
+goog.inherits(goog.async.AnimationDelay, goog.Disposable); |
+ |
+ |
+/** |
+ * Default wait timeout for animations (in milliseconds). Only used for timed |
+ * animation, which uses a timer (setTimeout) to schedule animation. |
+ * |
+ * @type {number} |
+ * @const |
+ */ |
+goog.async.AnimationDelay.TIMEOUT = 20; |
+ |
+ |
+/** |
+ * Name of event received from the requestAnimationFrame in Firefox. |
+ * |
+ * @type {string} |
+ * @const |
+ * @private |
+ */ |
+goog.async.AnimationDelay.MOZ_BEFORE_PAINT_EVENT_ = 'MozBeforePaint'; |
+ |
+ |
+/** |
+ * Starts the delay timer. The provided listener function will be called |
+ * before the next animation frame. |
+ */ |
+goog.async.AnimationDelay.prototype.start = function() { |
+ this.stop(); |
+ this.usingListeners_ = false; |
+ |
+ var raf = this.getRaf_(); |
+ var cancelRaf = this.getCancelRaf_(); |
+ if (raf && !cancelRaf && this.win_.mozRequestAnimationFrame) { |
+ // Because Firefox (Gecko) runs animation in separate threads, it also saves |
+ // time by running the requestAnimationFrame callbacks in that same thread. |
+ // Sadly this breaks the assumption of implicit thread-safety in JS, and can |
+ // thus create thread-based inconsistencies on counters etc. |
+ // |
+ // Calling cycleAnimations_ using the MozBeforePaint event instead of as |
+ // callback fixes this. |
+ // |
+ // Trigger this condition only if the mozRequestAnimationFrame is available, |
+ // but not the W3C requestAnimationFrame function (as in draft) or the |
+ // equivalent cancel functions. |
+ this.id_ = goog.events.listen( |
+ this.win_, |
+ goog.async.AnimationDelay.MOZ_BEFORE_PAINT_EVENT_, |
+ this.callback_); |
+ this.win_.mozRequestAnimationFrame(null); |
+ this.usingListeners_ = true; |
+ } else if (raf && cancelRaf) { |
+ this.id_ = raf.call(this.win_, this.callback_); |
+ } else { |
+ this.id_ = this.win_.setTimeout( |
+ // Prior to Firefox 13, Gecko passed a non-standard parameter |
+ // to the callback that we want to ignore. |
+ goog.functions.lock(this.callback_), |
+ goog.async.AnimationDelay.TIMEOUT); |
+ } |
+}; |
+ |
+ |
+/** |
+ * Stops the delay timer if it is active. No action is taken if the timer is not |
+ * in use. |
+ */ |
+goog.async.AnimationDelay.prototype.stop = function() { |
+ if (this.isActive()) { |
+ var raf = this.getRaf_(); |
+ var cancelRaf = this.getCancelRaf_(); |
+ if (raf && !cancelRaf && this.win_.mozRequestAnimationFrame) { |
+ goog.events.unlistenByKey(this.id_); |
+ } else if (raf && cancelRaf) { |
+ cancelRaf.call(this.win_, /** @type {number} */ (this.id_)); |
+ } else { |
+ this.win_.clearTimeout(/** @type {number} */ (this.id_)); |
+ } |
+ } |
+ this.id_ = null; |
+}; |
+ |
+ |
+/** |
+ * Fires delay's action even if timer has already gone off or has not been |
+ * started yet; guarantees action firing. Stops the delay timer. |
+ */ |
+goog.async.AnimationDelay.prototype.fire = function() { |
+ this.stop(); |
+ this.doAction_(); |
+}; |
+ |
+ |
+/** |
+ * Fires delay's action only if timer is currently active. Stops the delay |
+ * timer. |
+ */ |
+goog.async.AnimationDelay.prototype.fireIfActive = function() { |
+ if (this.isActive()) { |
+ this.fire(); |
+ } |
+}; |
+ |
+ |
+/** |
+ * @return {boolean} True if the delay is currently active, false otherwise. |
+ */ |
+goog.async.AnimationDelay.prototype.isActive = function() { |
+ return this.id_ != null; |
+}; |
+ |
+ |
+/** |
+ * Invokes the callback function after the delay successfully completes. |
+ * @private |
+ */ |
+goog.async.AnimationDelay.prototype.doAction_ = function() { |
+ if (this.usingListeners_ && this.id_) { |
+ goog.events.unlistenByKey(this.id_); |
+ } |
+ this.id_ = null; |
+ |
+ // We are not using the timestamp returned by requestAnimationFrame |
+ // because it may be either a Date.now-style time or a |
+ // high-resolution time (depending on browser implementation). Using |
+ // goog.now() will ensure that the timestamp used is consistent and |
+ // compatible with goog.fx.Animation. |
+ this.listener_.call(this.handler_, goog.now()); |
+}; |
+ |
+ |
+/** @override */ |
+goog.async.AnimationDelay.prototype.disposeInternal = function() { |
+ this.stop(); |
+ goog.async.AnimationDelay.base(this, 'disposeInternal'); |
+}; |
+ |
+ |
+/** |
+ * @return {?function(function(number)): number} The requestAnimationFrame |
+ * function, or null if not available on this browser. |
+ * @private |
+ */ |
+goog.async.AnimationDelay.prototype.getRaf_ = function() { |
+ var win = this.win_; |
+ return win.requestAnimationFrame || |
+ win.webkitRequestAnimationFrame || |
+ win.mozRequestAnimationFrame || |
+ win.oRequestAnimationFrame || |
+ win.msRequestAnimationFrame || |
+ null; |
+}; |
+ |
+ |
+/** |
+ * @return {?function(number): number} The cancelAnimationFrame function, |
+ * or null if not available on this browser. |
+ * @private |
+ */ |
+goog.async.AnimationDelay.prototype.getCancelRaf_ = function() { |
+ var win = this.win_; |
+ return win.cancelAnimationFrame || |
+ win.cancelRequestAnimationFrame || |
+ win.webkitCancelRequestAnimationFrame || |
+ win.mozCancelRequestAnimationFrame || |
+ win.oCancelRequestAnimationFrame || |
+ win.msCancelRequestAnimationFrame || |
+ null; |
+}; |