Adding float-no-zero branch hosted build

This commit is contained in:
ahocevar
2014-03-07 10:55:12 +01:00
parent 84cad42f6d
commit bd9092199b
1664 changed files with 731463 additions and 0 deletions
@@ -0,0 +1,270 @@
// 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.
*
*/
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
* @extends {goog.Disposable}
*/
goog.async.AnimationDelay = function(listener, opt_window, opt_handler) {
goog.base(this);
/**
* The function that will be invoked after a delay.
* @type {function(number)}
* @private
*/
this.listener_ = listener;
/**
* The object context to invoke the callback in.
* @type {Object|undefined}
* @private
*/
this.handler_ = opt_handler;
/**
* @type {Window}
* @private
*/
this.win_ = opt_window || window;
/**
* Cached callback function invoked when the delay finishes.
* @type {function()}
* @private
*/
this.callback_ = goog.bind(this.doAction_, this);
};
goog.inherits(goog.async.AnimationDelay, goog.Disposable);
/**
* Identifier of the active delay timeout, or event listener,
* or null when inactive.
* @type {goog.events.Key|number|null}
* @private
*/
goog.async.AnimationDelay.prototype.id_ = null;
/**
* If we're using dom listeners.
* @type {?boolean}
* @private
*/
goog.async.AnimationDelay.prototype.usingListeners_ = false;
/**
* 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.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.cancelRequestAnimationFrame ||
win.webkitCancelRequestAnimationFrame ||
win.mozCancelRequestAnimationFrame ||
win.oCancelRequestAnimationFrame ||
win.msCancelRequestAnimationFrame ||
null;
};
@@ -0,0 +1,235 @@
// 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 Defines a class useful for handling functions that must be
* invoked later when some condition holds. Examples include deferred function
* calls that return a boolean flag whether it succedeed or not.
*
* Example:
*
* function deferred() {
* var succeeded = false;
* // ... custom code
* return succeeded;
* }
*
* var deferredCall = new goog.async.ConditionalDelay(deferred);
* deferredCall.onSuccess = function() {
* alert('Success: The deferred function has been successfully executed.');
* }
* deferredCall.onFailure = function() {
* alert('Failure: Time limit exceeded.');
* }
*
* // Call the deferred() every 100 msec until it returns true,
* // or 5 seconds pass.
* deferredCall.start(100, 5000);
*
* // Stop the deferred function call (does nothing if it's not active).
* deferredCall.stop();
*
*/
goog.provide('goog.async.ConditionalDelay');
goog.require('goog.Disposable');
goog.require('goog.async.Delay');
/**
* A ConditionalDelay object invokes the associated function after a specified
* interval delay and checks its return value. If the function returns
* {@code true} the conditional delay is cancelled and {@see #onSuccess}
* is called. Otherwise this object keeps to invoke the deferred function until
* either it returns {@code true} or the timeout is exceeded. In the latter case
* the {@see #onFailure} method will be called.
*
* The interval duration and timeout can be specified each time the delay is
* started. Calling start on an active delay will reset the timer.
*
* @param {function():boolean} listener Function to call when the delay
* completes. Should return a value that type-converts to {@code true} if
* the call succeeded and this delay should be stopped.
* @param {Object=} opt_handler The object scope to invoke the function in.
* @constructor
* @extends {goog.Disposable}
*/
goog.async.ConditionalDelay = function(listener, opt_handler) {
goog.Disposable.call(this);
/**
* The function that will be invoked after a delay.
* @type {function():boolean}
* @private
*/
this.listener_ = listener;
/**
* The object context to invoke the callback in.
* @type {Object|undefined}
* @private
*/
this.handler_ = opt_handler;
/**
* The underlying goog.async.Delay delegate object.
* @type {goog.async.Delay}
* @private
*/
this.delay_ = new goog.async.Delay(
goog.bind(this.onTick_, this), 0 /*interval*/, this /*scope*/);
};
goog.inherits(goog.async.ConditionalDelay, goog.Disposable);
/**
* The delay interval in milliseconds to between the calls to the callback.
* Note, that the callback may be invoked earlier than this interval if the
* timeout is exceeded.
* @type {number}
* @private
*/
goog.async.ConditionalDelay.prototype.interval_ = 0;
/**
* The timeout timestamp until which the delay is to be executed.
* A negative value means no timeout.
* @type {number}
* @private
*/
goog.async.ConditionalDelay.prototype.runUntil_ = 0;
/**
* True if the listener has been executed, and it returned {@code true}.
* @type {boolean}
* @private
*/
goog.async.ConditionalDelay.prototype.isDone_ = false;
/** @override */
goog.async.ConditionalDelay.prototype.disposeInternal = function() {
this.delay_.dispose();
delete this.listener_;
delete this.handler_;
goog.async.ConditionalDelay.superClass_.disposeInternal.call(this);
};
/**
* Starts the delay timer. The provided listener function will be called
* repeatedly after the specified interval until the function returns
* {@code true} or the timeout is exceeded. Calling start on an active timer
* will stop the timer first.
* @param {number=} opt_interval The time interval between the function
* invocations (in milliseconds). Default is 0.
* @param {number=} opt_timeout The timeout interval (in milliseconds). Takes
* precedence over the {@code opt_interval}, i.e. if the timeout is less
* than the invocation interval, the function will be called when the
* timeout is exceeded. A negative value means no timeout. Default is 0.
*/
goog.async.ConditionalDelay.prototype.start = function(opt_interval,
opt_timeout) {
this.stop();
this.isDone_ = false;
var timeout = opt_timeout || 0;
this.interval_ = Math.max(opt_interval || 0, 0);
this.runUntil_ = timeout < 0 ? -1 : (goog.now() + timeout);
this.delay_.start(
timeout < 0 ? this.interval_ : Math.min(this.interval_, timeout));
};
/**
* Stops the delay timer if it is active. No action is taken if the timer is not
* in use.
*/
goog.async.ConditionalDelay.prototype.stop = function() {
this.delay_.stop();
};
/**
* @return {boolean} True if the delay is currently active, false otherwise.
*/
goog.async.ConditionalDelay.prototype.isActive = function() {
return this.delay_.isActive();
};
/**
* @return {boolean} True if the listener has been executed and returned
* {@code true} since the last call to {@see #start}.
*/
goog.async.ConditionalDelay.prototype.isDone = function() {
return this.isDone_;
};
/**
* Called when the listener has been successfully executed and returned
* {@code true}. The {@see #isDone} method should return {@code true} by now.
* Designed for inheritance, should be overridden by subclasses or on the
* instances if they care.
*/
goog.async.ConditionalDelay.prototype.onSuccess = function() {
// Do nothing by default.
};
/**
* Called when this delayed call is cancelled because the timeout has been
* exceeded, and the listener has never returned {@code true}.
* Designed for inheritance, should be overridden by subclasses or on the
* instances if they care.
*/
goog.async.ConditionalDelay.prototype.onFailure = function() {
// Do nothing by default.
};
/**
* A callback function for the underlying {@code goog.async.Delay} object. When
* executed the listener function is called, and if it returns {@code true}
* the delay is stopped and the {@see #onSuccess} method is invoked.
* If the timeout is exceeded the delay is stopped and the
* {@see #onFailure} method is called.
* @private
*/
goog.async.ConditionalDelay.prototype.onTick_ = function() {
var successful = this.listener_.call(this.handler_);
if (successful) {
this.isDone_ = true;
this.onSuccess();
} else {
// Try to reschedule the task.
if (this.runUntil_ < 0) {
// No timeout.
this.delay_.start(this.interval_);
} else {
var timeLeft = this.runUntil_ - goog.now();
if (timeLeft <= 0) {
this.onFailure();
} else {
this.delay_.start(Math.min(this.interval_, timeLeft));
}
}
}
};
@@ -0,0 +1,177 @@
// 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 a class useful for handling functions that must be
* invoked after a delay, especially when that delay is frequently restarted.
* Examples include delaying before displaying a tooltip, menu hysteresis,
* idle timers, etc.
* @author brenneman@google.com (Shawn Brenneman)
* @see ../demos/timers.html
*/
goog.provide('goog.Delay');
goog.provide('goog.async.Delay');
goog.require('goog.Disposable');
goog.require('goog.Timer');
/**
* A Delay object invokes the associated function after a specified delay. The
* interval duration can be specified once in the constructor, or can be defined
* each time the delay is started. Calling start on an active delay will reset
* the timer.
*
* @param {Function} listener Function to call when the delay completes.
* @param {number=} opt_interval The default length of the invocation delay (in
* milliseconds).
* @param {Object=} opt_handler The object scope to invoke the function in.
* @constructor
* @extends {goog.Disposable}
*/
goog.async.Delay = function(listener, opt_interval, opt_handler) {
goog.Disposable.call(this);
/**
* The function that will be invoked after a delay.
* @type {Function}
* @private
*/
this.listener_ = listener;
/**
* The default amount of time to delay before invoking the callback.
* @type {number}
* @private
*/
this.interval_ = opt_interval || 0;
/**
* The object context to invoke the callback in.
* @type {Object|undefined}
* @private
*/
this.handler_ = opt_handler;
/**
* Cached callback function invoked when the delay finishes.
* @type {Function}
* @private
*/
this.callback_ = goog.bind(this.doAction_, this);
};
goog.inherits(goog.async.Delay, goog.Disposable);
/**
* A deprecated alias.
* @deprecated Use goog.async.Delay instead.
* @constructor
*/
goog.Delay = goog.async.Delay;
/**
* Identifier of the active delay timeout, or 0 when inactive.
* @type {number}
* @private
*/
goog.async.Delay.prototype.id_ = 0;
/**
* Disposes of the object, cancelling the timeout if it is still outstanding and
* removing all object references.
* @override
* @protected
*/
goog.async.Delay.prototype.disposeInternal = function() {
goog.async.Delay.superClass_.disposeInternal.call(this);
this.stop();
delete this.listener_;
delete this.handler_;
};
/**
* Starts the delay timer. The provided listener function will be called after
* the specified interval. Calling start on an active timer will reset the
* delay interval.
* @param {number=} opt_interval If specified, overrides the object's default
* interval with this one (in milliseconds).
*/
goog.async.Delay.prototype.start = function(opt_interval) {
this.stop();
this.id_ = goog.Timer.callOnce(
this.callback_,
goog.isDef(opt_interval) ? opt_interval : this.interval_);
};
/**
* Stops the delay timer if it is active. No action is taken if the timer is not
* in use.
*/
goog.async.Delay.prototype.stop = function() {
if (this.isActive()) {
goog.Timer.clear(this.id_);
}
this.id_ = 0;
};
/**
* 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.Delay.prototype.fire = function() {
this.stop();
this.doAction_();
};
/**
* Fires delay's action only if timer is currently active. Stops the delay
* timer.
*/
goog.async.Delay.prototype.fireIfActive = function() {
if (this.isActive()) {
this.fire();
}
};
/**
* @return {boolean} True if the delay is currently active, false otherwise.
*/
goog.async.Delay.prototype.isActive = function() {
return this.id_ != 0;
};
/**
* Invokes the callback function after the delay successfully completes.
* @private
*/
goog.async.Delay.prototype.doAction_ = function() {
this.id_ = 0;
if (this.listener_) {
this.listener_.call(this.handler_);
}
};
@@ -0,0 +1,174 @@
// 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.require('goog.debug.entryPointRegistry');
goog.require('goog.functions');
/**
* Fires the provided callbacks as soon as possible after the current JS
* execution context. setTimeout(…, 0) always takes at least 5ms for legacy
* reasons.
* @param {function()} callback Callback function to fire as soon as possible.
* @param {Object=} opt_context Object in whose scope to call the listener.
*/
goog.async.nextTick = function(callback, opt_context) {
var cb = callback;
if (opt_context) {
cb = goog.bind(callback, opt_context);
}
cb = goog.async.nextTick.wrapCallback_(cb);
// Introduced and currently only supported by IE10.
if (goog.isFunction(goog.global.setImmediate)) {
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);
};
/**
* 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.
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) {
/** @constructor */
Channel = function() {
// Make an empty, invisible iframe.
var iframe = document.createElement('iframe');
iframe.style.display = 'none';
iframe.src = '';
document.body.appendChild(iframe);
var win = iframe.contentWindow;
var doc = win.document;
doc.open();
doc.write('');
doc.close();
var message = 'callImmediate' + Math.random();
var origin = 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 (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') {
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() {
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-8: Script elements fire an asynchronous
// onreadystatechange event when inserted into the DOM.
if (typeof document !== 'undefined' && 'onreadystatechange' in
document.createElement('script')) {
return function(cb) {
var script = document.createElement('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.
return function(cb) {
goog.global.setTimeout(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;
});
@@ -0,0 +1,189 @@
// 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 Definition of the goog.async.Throttle class.
*
* @see ../demos/timers.html
*/
goog.provide('goog.Throttle');
goog.provide('goog.async.Throttle');
goog.require('goog.Disposable');
goog.require('goog.Timer');
/**
* Throttle will perform an action that is passed in no more than once
* per interval (specified in milliseconds). If it gets multiple signals
* to perform the action while it is waiting, it will only perform the action
* once at the end of the interval.
* @param {Function} listener Function to callback when the action is triggered.
* @param {number} interval Interval over which to throttle. The handler can
* only be called once per interval.
* @param {Object=} opt_handler Object in whose scope to call the listener.
* @constructor
* @extends {goog.Disposable}
*/
goog.async.Throttle = function(listener, interval, opt_handler) {
goog.Disposable.call(this);
/**
* Function to callback
* @type {Function}
* @private
*/
this.listener_ = listener;
/**
* Interval for the throttle time
* @type {number}
* @private
*/
this.interval_ = interval;
/**
* "this" context for the listener
* @type {Object|undefined}
* @private
*/
this.handler_ = opt_handler;
/**
* Cached callback function invoked after the throttle timeout completes
* @type {Function}
* @private
*/
this.callback_ = goog.bind(this.onTimer_, this);
};
goog.inherits(goog.async.Throttle, goog.Disposable);
/**
* A deprecated alias.
* @deprecated Use goog.async.Throttle instead.
* @constructor
*/
goog.Throttle = goog.async.Throttle;
/**
* Indicates that the action is pending and needs to be fired.
* @type {boolean}
* @private
*/
goog.async.Throttle.prototype.shouldFire_ = false;
/**
* Indicates the count of nested pauses currently in effect on the throttle.
* When this count is not zero, fired actions will be postponed until the
* throttle is resumed enough times to drop the pause count to zero.
* @type {number}
* @private
*/
goog.async.Throttle.prototype.pauseCount_ = 0;
/**
* Timer for scheduling the next callback
* @type {?number}
* @private
*/
goog.async.Throttle.prototype.timer_ = null;
/**
* Notifies the throttle that the action has happened. It will throttle the call
* so that the callback is not called too often according to the interval
* parameter passed to the constructor.
*/
goog.async.Throttle.prototype.fire = function() {
if (!this.timer_ && !this.pauseCount_) {
this.doAction_();
} else {
this.shouldFire_ = true;
}
};
/**
* Cancels any pending action callback. The throttle can be restarted by
* calling {@link #fire}.
*/
goog.async.Throttle.prototype.stop = function() {
if (this.timer_) {
goog.Timer.clear(this.timer_);
this.timer_ = null;
this.shouldFire_ = false;
}
};
/**
* Pauses the throttle. All pending and future action callbacks will be
* delayed until the throttle is resumed. Pauses can be nested.
*/
goog.async.Throttle.prototype.pause = function() {
this.pauseCount_++;
};
/**
* Resumes the throttle. If doing so drops the pausing count to zero, pending
* action callbacks will be executed as soon as possible, but still no sooner
* than an interval's delay after the previous call. Future action callbacks
* will be executed as normal.
*/
goog.async.Throttle.prototype.resume = function() {
this.pauseCount_--;
if (!this.pauseCount_ && this.shouldFire_ && !this.timer_) {
this.shouldFire_ = false;
this.doAction_();
}
};
/** @override */
goog.async.Throttle.prototype.disposeInternal = function() {
goog.async.Throttle.superClass_.disposeInternal.call(this);
this.stop();
};
/**
* Handler for the timer to fire the throttle
* @private
*/
goog.async.Throttle.prototype.onTimer_ = function() {
this.timer_ = null;
if (this.shouldFire_ && !this.pauseCount_) {
this.shouldFire_ = false;
this.doAction_();
}
};
/**
* Calls the callback
* @private
*/
goog.async.Throttle.prototype.doAction_ = function() {
this.timer_ = goog.Timer.callOnce(this.callback_, this.interval_);
this.listener_.call(this.handler_);
};