1 /*
  2  * ***** BEGIN LICENSE BLOCK *****
  3  * Zimbra Collaboration Suite Web Client
  4  * Copyright (C) 2007, 2009, 2010, 2012, 2013, 2014, 2015, 2016 Synacor, Inc.
  5  *
  6  * The contents of this file are subject to the Common Public Attribution License Version 1.0 (the "License");
  7  * you may not use this file except in compliance with the License.
  8  * You may obtain a copy of the License at: https://www.zimbra.com/license
  9  * The License is based on the Mozilla Public License Version 1.1 but Sections 14 and 15
 10  * have been added to cover use of software over a computer network and provide for limited attribution
 11  * for the Original Developer. In addition, Exhibit A has been modified to be consistent with Exhibit B.
 12  *
 13  * Software distributed under the License is distributed on an "AS IS" basis,
 14  * WITHOUT WARRANTY OF ANY KIND, either express or implied.
 15  * See the License for the specific language governing rights and limitations under the License.
 16  * The Original Code is Zimbra Open Source Web Client.
 17  * The Initial Developer of the Original Code is Zimbra, Inc.  All rights to the Original Code were
 18  * transferred by Zimbra, Inc. to Synacor, Inc. on September 14, 2015.
 19  *
 20  * All portions of the code are Copyright (C) 2007, 2009, 2010, 2012, 2013, 2014, 2015, 2016 Synacor, Inc. All Rights Reserved.
 21  * ***** END LICENSE BLOCK *****
 22  */
 23 
 24 /**
 25  * @class
 26  * Simple manager for "idle" events. Add a handler like this:
 27  *
 28  * <pre>
 29  *    var idleTimer = new DwtIdleTimer(10000, new AjxCallback(obj, obj.handler));
 30  *
 31  *    obj.handler = function(idle) {
 32  *       if (idle) {
 33  *          // do idle stuff here
 34  *       } else {
 35  *          // user is back
 36  *       }
 37  *    }
 38  * </pre>
 39  * 
 40  * With this code, when the user is idle for 10 seconds obj.handler(true) will
 41  * be called.  When the user gets back from idle, obj.handler(false) will be
 42  * called and the timer restarted.
 43  * </p>
 44  * <p>
 45  * To cancel a timer, call <code>idleTimer.kill()</code>. To restart it later, you can
 46  * <code>idleTimer.resurrect(timeout)</code>. The timeout parameter is optional, pass it only if you
 47  * want to modify it.
 48  * </p>
 49  * <p>
 50  * You can create multiple handlers, each with its own callback and timeout.  A
 51  * new {@link DwtIdleTimer} will start running right away and will continue to do so
 52  * until you <code>kill()</code> it.
 53  * </p>
 54  * 
 55  * @param	{number}	[timeout]		the timeout 
 56  * @param	{AjxCallback}	handler		the callback
 57  * 
 58  * @private
 59  */
 60 DwtIdleTimer = function(timeout, handler) {
 61 	DwtIdleTimer._initEvents();
 62 	this.timeout = timeout;
 63 	this.handler = handler;
 64 	this.idle = false;
 65 	this._onIdle = AjxCallback.simpleClosure(this.setIdle, this);
 66 	this._startTimer();
 67 	DwtIdleTimer.getHandlers().add(this);
 68 };
 69 
 70 DwtIdleTimer.idleHandlers = 0;
 71 
 72 DwtIdleTimer.prototype.toString =
 73 function() {
 74 	return "DwtIdleTimer";
 75 };
 76 
 77 DwtIdleTimer.prototype.kill =
 78 function() {
 79 	this._stopTimer();
 80 	this.idle = false;
 81 	DwtIdleTimer.getHandlers().remove(this);
 82 };
 83 
 84 DwtIdleTimer.prototype.resurrect =
 85 function(timeout) {
 86 	this.idle = false; // make sure we start "unidle"
 87 	DwtIdleTimer.getHandlers().add(this, null, true);
 88 	if (timeout != null) {
 89 		this.timeout = timeout;
 90 	}
 91 	this._startTimer();
 92 };
 93 
 94 DwtIdleTimer.prototype.setIdle =
 95 function() {
 96 	if (!this.idle) {
 97 		DwtIdleTimer.idleHandlers++;
 98 		this.idle = true;
 99 		this.handler.run(true);
100 	}
101 };
102 
103 DwtIdleTimer.prototype.resume =
104 function() {
105 	if (this.idle) {
106 		this.idle = false;
107 		this.handler.run(false);
108 		DwtIdleTimer.idleHandlers--;
109 	}
110 };
111 
112 DwtIdleTimer.prototype._startTimer =
113 function() {
114 	this._stopTimer();
115 	this._timer = setTimeout(this._onIdle, this.timeout);
116 };
117 
118 DwtIdleTimer.prototype._stopTimer =
119 function() {
120 	if (this._timer) {
121 		clearTimeout(this._timer);
122 		this._timer = null;
123 	}
124 };
125 
126 DwtIdleTimer._initEvents =
127 function() {
128 	// execute only once per session
129 	if (!DwtIdleTimer._initialized) {
130 		if (window.addEventListener) {
131 			window.addEventListener("keydown", DwtIdleTimer.resetIdle, true);
132 			window.addEventListener("mousemove", DwtIdleTimer.resetIdle, true);
133 			window.addEventListener("mousedown", DwtIdleTimer.resetIdle, true);
134 			window.addEventListener("focus", DwtIdleTimer.resetIdle, true);
135 		}
136         else if (window.attachEvent) {
137 			document.body.attachEvent("onkeydown", DwtIdleTimer.resetIdle);
138 			document.body.attachEvent("onkeyup", DwtIdleTimer.resetIdle);
139 			document.body.attachEvent("onmousedown", DwtIdleTimer.resetIdle);
140 			document.body.attachEvent("onmousemove", DwtIdleTimer.resetIdle);
141 			document.body.attachEvent("onmouseover", DwtIdleTimer.resetIdle);
142 			document.body.attachEvent("onmouseout", DwtIdleTimer.resetIdle);
143 			window.attachEvent("onfocus", DwtIdleTimer.resetIdle);
144 		}
145 		DwtIdleTimer._initialized = true;
146 	}
147 };
148 
149 DwtIdleTimer.getHandlers =
150 function() {
151 	var a = DwtIdleTimer.HANDLERS;
152 	if (!a) {
153 		a = DwtIdleTimer.HANDLERS = new AjxVector();
154 	}
155 	return a;
156 };
157 
158 DwtIdleTimer.resetIdle =
159 function() {
160 	var a = DwtIdleTimer.getHandlers();
161 	a.foreach("_startTimer"); // we need to restart timers anyway...
162 	if (DwtIdleTimer.idleHandlers > 0) {
163 		a.foreach("resume");
164 	}
165 };
166