| // 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 Idle Timer. |
| * |
| * Keeps track of transitions between active and idle. This class is built on |
| * top of ActivityMonitor. Whenever an active user becomes idle, this class |
| * dispatches a BECOME_IDLE event. Whenever an idle user becomes active, this |
| * class dispatches a BECOME_ACTIVE event. The amount of inactive time it |
| * takes for a user to be considered idle is specified by the client, and |
| * different instances of this class can all use different thresholds. |
| * |
| */ |
| |
| goog.provide('goog.ui.IdleTimer'); |
| goog.require('goog.Timer'); |
| goog.require('goog.events'); |
| goog.require('goog.events.EventTarget'); |
| goog.require('goog.structs.Set'); |
| goog.require('goog.ui.ActivityMonitor'); |
| |
| |
| |
| /** |
| * Event target that will give notification of state changes between active and |
| * idle. This class is designed to require few resources while the user is |
| * active. |
| * @param {number} idleThreshold Amount of time in ms at which we consider the |
| * user has gone idle. |
| * @param {goog.ui.ActivityMonitor=} opt_activityMonitor The activity monitor |
| * keeping track of user interaction. Defaults to a default-constructed |
| * activity monitor. If a default activity monitor is used then this class |
| * will dispose of it. If an activity monitor is passed in then the caller |
| * remains responsible for disposing of it. |
| * @constructor |
| * @extends {goog.events.EventTarget} |
| * @final |
| */ |
| goog.ui.IdleTimer = function(idleThreshold, opt_activityMonitor) { |
| goog.events.EventTarget.call(this); |
| |
| var activityMonitor = opt_activityMonitor || |
| this.getDefaultActivityMonitor_(); |
| |
| /** |
| * The amount of time in ms at which we consider the user has gone idle |
| * @type {number} |
| * @private |
| */ |
| this.idleThreshold_ = idleThreshold; |
| |
| /** |
| * The activity monitor keeping track of user interaction |
| * @type {goog.ui.ActivityMonitor} |
| * @private |
| */ |
| this.activityMonitor_ = activityMonitor; |
| |
| /** |
| * Cached onActivityTick_ bound to the object for later use |
| * @type {Function} |
| * @private |
| */ |
| this.boundOnActivityTick_ = goog.bind(this.onActivityTick_, this); |
| |
| // Decide whether the user is currently active or idle. This method will |
| // check whether it is correct to start with the user in the active state. |
| this.maybeStillActive_(); |
| }; |
| goog.inherits(goog.ui.IdleTimer, goog.events.EventTarget); |
| |
| |
| /** |
| * Whether a listener is currently registered for an idle timer event. On |
| * initialization, the user is assumed to be active. |
| * @type {boolean} |
| * @private |
| */ |
| goog.ui.IdleTimer.prototype.hasActivityListener_ = false; |
| |
| |
| /** |
| * Handle to the timer ID used for checking ongoing activity, or null |
| * @type {?number} |
| * @private |
| */ |
| goog.ui.IdleTimer.prototype.onActivityTimerId_ = null; |
| |
| |
| /** |
| * Whether the user is currently idle |
| * @type {boolean} |
| * @private |
| */ |
| goog.ui.IdleTimer.prototype.isIdle_ = false; |
| |
| |
| /** |
| * The default activity monitor created by this class, if any |
| * @type {goog.ui.ActivityMonitor?} |
| * @private |
| */ |
| goog.ui.IdleTimer.defaultActivityMonitor_ = null; |
| |
| |
| /** |
| * The idle timers that currently reference the default activity monitor |
| * @type {goog.structs.Set} |
| * @private |
| */ |
| goog.ui.IdleTimer.defaultActivityMonitorReferences_ = new goog.structs.Set(); |
| |
| |
| /** |
| * Event constants for the idle timer event target |
| * @enum {string} |
| */ |
| goog.ui.IdleTimer.Event = { |
| /** Event fired when an idle user transitions into the active state */ |
| BECOME_ACTIVE: 'active', |
| /** Event fired when an active user transitions into the idle state */ |
| BECOME_IDLE: 'idle' |
| }; |
| |
| |
| /** |
| * Gets the default activity monitor used by this class. If a default has not |
| * been created yet, then a new one will be created. |
| * @return {!goog.ui.ActivityMonitor} The default activity monitor. |
| * @private |
| */ |
| goog.ui.IdleTimer.prototype.getDefaultActivityMonitor_ = function() { |
| goog.ui.IdleTimer.defaultActivityMonitorReferences_.add(this); |
| if (goog.ui.IdleTimer.defaultActivityMonitor_ == null) { |
| goog.ui.IdleTimer.defaultActivityMonitor_ = new goog.ui.ActivityMonitor(); |
| } |
| return goog.ui.IdleTimer.defaultActivityMonitor_; |
| }; |
| |
| |
| /** |
| * Removes the reference to the default activity monitor. If there are no more |
| * references then the default activity monitor gets disposed. |
| * @private |
| */ |
| goog.ui.IdleTimer.prototype.maybeDisposeDefaultActivityMonitor_ = function() { |
| goog.ui.IdleTimer.defaultActivityMonitorReferences_.remove(this); |
| if (goog.ui.IdleTimer.defaultActivityMonitor_ != null && |
| goog.ui.IdleTimer.defaultActivityMonitorReferences_.isEmpty()) { |
| goog.ui.IdleTimer.defaultActivityMonitor_.dispose(); |
| goog.ui.IdleTimer.defaultActivityMonitor_ = null; |
| } |
| }; |
| |
| |
| /** |
| * Checks whether the user is active. If the user is still active, then a timer |
| * is started to check again later. |
| * @private |
| */ |
| goog.ui.IdleTimer.prototype.maybeStillActive_ = function() { |
| // See how long before the user would go idle. The user is considered idle |
| // after the idle time has passed, not exactly when the idle time arrives. |
| var remainingIdleThreshold = this.idleThreshold_ + 1 - |
| (goog.now() - this.activityMonitor_.getLastEventTime()); |
| if (remainingIdleThreshold > 0) { |
| // The user is still active. Check again later. |
| this.onActivityTimerId_ = goog.Timer.callOnce( |
| this.boundOnActivityTick_, remainingIdleThreshold); |
| } else { |
| // The user has not been active recently. |
| this.becomeIdle_(); |
| } |
| }; |
| |
| |
| /** |
| * Handler for the timeout used for checking ongoing activity |
| * @private |
| */ |
| goog.ui.IdleTimer.prototype.onActivityTick_ = function() { |
| // The timer has fired. |
| this.onActivityTimerId_ = null; |
| |
| // The maybeStillActive method will restart the timer, if appropriate. |
| this.maybeStillActive_(); |
| }; |
| |
| |
| /** |
| * Transitions from the active state to the idle state |
| * @private |
| */ |
| goog.ui.IdleTimer.prototype.becomeIdle_ = function() { |
| this.isIdle_ = true; |
| |
| // The idle timer will send notification when the user does something |
| // interactive. |
| goog.events.listen(this.activityMonitor_, |
| goog.ui.ActivityMonitor.Event.ACTIVITY, |
| this.onActivity_, false, this); |
| this.hasActivityListener_ = true; |
| |
| // Notify clients of the state change. |
| this.dispatchEvent(goog.ui.IdleTimer.Event.BECOME_IDLE); |
| }; |
| |
| |
| /** |
| * Handler for idle timer events when the user does something interactive |
| * @param {goog.events.Event} e The event object. |
| * @private |
| */ |
| goog.ui.IdleTimer.prototype.onActivity_ = function(e) { |
| this.becomeActive_(); |
| }; |
| |
| |
| /** |
| * Transitions from the idle state to the active state |
| * @private |
| */ |
| goog.ui.IdleTimer.prototype.becomeActive_ = function() { |
| this.isIdle_ = false; |
| |
| // Stop listening to every interactive event. |
| this.removeActivityListener_(); |
| |
| // Notify clients of the state change. |
| this.dispatchEvent(goog.ui.IdleTimer.Event.BECOME_ACTIVE); |
| |
| // Periodically check whether the user has gone inactive. |
| this.maybeStillActive_(); |
| }; |
| |
| |
| /** |
| * Removes the activity listener, if necessary |
| * @private |
| */ |
| goog.ui.IdleTimer.prototype.removeActivityListener_ = function() { |
| if (this.hasActivityListener_) { |
| goog.events.unlisten(this.activityMonitor_, |
| goog.ui.ActivityMonitor.Event.ACTIVITY, |
| this.onActivity_, false, this); |
| this.hasActivityListener_ = false; |
| } |
| }; |
| |
| |
| /** @override */ |
| goog.ui.IdleTimer.prototype.disposeInternal = function() { |
| this.removeActivityListener_(); |
| if (this.onActivityTimerId_ != null) { |
| goog.global.clearTimeout(this.onActivityTimerId_); |
| this.onActivityTimerId_ = null; |
| } |
| this.maybeDisposeDefaultActivityMonitor_(); |
| goog.ui.IdleTimer.superClass_.disposeInternal.call(this); |
| }; |
| |
| |
| /** |
| * @return {number} the amount of time at which we consider the user has gone |
| * idle in ms. |
| */ |
| goog.ui.IdleTimer.prototype.getIdleThreshold = function() { |
| return this.idleThreshold_; |
| }; |
| |
| |
| /** |
| * @return {goog.ui.ActivityMonitor} the activity monitor keeping track of user |
| * interaction. |
| */ |
| goog.ui.IdleTimer.prototype.getActivityMonitor = function() { |
| return this.activityMonitor_; |
| }; |
| |
| |
| /** |
| * Returns true if there has been no user action for at least the specified |
| * interval, and false otherwise |
| * @return {boolean} true if the user is idle, false otherwise. |
| */ |
| goog.ui.IdleTimer.prototype.isIdle = function() { |
| return this.isIdle_; |
| }; |