1// Copyright (c) 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5'use strict'; 6 7/** 8 * A controller class detects mouse inactivity and hides "tool" elements. 9 * 10 * @param {Element} container The main DOM container. 11 * @param {number=} opt_timeout Hide timeout in ms. 12 * @param {function():boolean=} opt_toolsActive Function that returns |true| 13 * if the tools are active and should not be hidden. 14 * @constructor 15 */ 16function MouseInactivityWatcher(container, opt_timeout, opt_toolsActive) { 17 this.container_ = container; 18 this.timeout_ = opt_timeout || MouseInactivityWatcher.DEFAULT_TIMEOUT; 19 this.toolsActive_ = opt_toolsActive || function() { return false; }; 20 21 this.onTimeoutBound_ = this.onTimeout_.bind(this); 22 this.timeoutID_ = null; 23 this.mouseOverTool_ = false; 24 25 this.clientX_ = 0; 26 this.clientY_ = 0; 27 28 /** 29 * Indicates if the inactivity watcher is enabled or disabled. Use getters 30 * and setters. 31 * @type {boolean} 32 * @private 33 **/ 34 this.disabled_ = false; 35 this.__defineSetter__('disabled', function(value) { 36 this.disabled_ = value; 37 if (value) 38 this.kick(); 39 else 40 this.check(); 41 }); 42 this.__defineGetter__('disabled', function() { 43 return this.disabled_; 44 }); 45 46 this.container_.addEventListener('mousemove', this.onMouseMove_.bind(this)); 47 var tools = this.container_.querySelector('.tool'); 48 for (var i = 0; i < tools.length; i++) { 49 tools[i].addEventListener('mouseover', this.onToolMouseOver_.bind(this)); 50 tools[i].addEventListener('mouseout', this.onToolMouseOut_.bind(this)); 51 } 52 53 // Show tools when the user touches the screen. 54 this.container_.addEventListener( 55 'touchstart', this.activityStarted_.bind(this)); 56 var initiateFading = this.activityStopped_.bind(this, this.timeout_); 57 this.container_.addEventListener('touchend', initiateFading); 58 this.container_.addEventListener('touchcancel', initiateFading); 59} 60 61/** 62 * Default inactivity timeout. 63 */ 64MouseInactivityWatcher.DEFAULT_TIMEOUT = 3000; 65 66/** 67 * @param {boolean} on True if show, false if hide. 68 */ 69MouseInactivityWatcher.prototype.showTools = function(on) { 70 if (on) 71 this.container_.setAttribute('tools', 'true'); 72 else 73 this.container_.removeAttribute('tools'); 74}; 75 76/** 77 * To be called when the user started activity. Shows the tools 78 * and cancels the countdown. 79 * @private 80 */ 81MouseInactivityWatcher.prototype.activityStarted_ = function() { 82 this.showTools(true); 83 84 if (this.timeoutID_) { 85 clearTimeout(this.timeoutID_); 86 this.timeoutID_ = null; 87 } 88}; 89 90/** 91 * Called when user activity has stopped. Re-starts the countdown. 92 * @param {number=} opt_timeout Timeout. 93 * @private 94 */ 95MouseInactivityWatcher.prototype.activityStopped_ = function(opt_timeout) { 96 if (this.disabled_ || this.mouseOverTool_ || this.toolsActive_()) 97 return; 98 99 if (this.timeoutID_) 100 clearTimeout(this.timeoutID_); 101 102 this.timeoutID_ = setTimeout( 103 this.onTimeoutBound_, opt_timeout || this.timeout_); 104}; 105 106/** 107 * Called when a user performed a short action (such as a click or a key press) 108 * that should show the tools if they are not visible. 109 * @param {number=} opt_timeout Timeout. 110 */ 111MouseInactivityWatcher.prototype.kick = function(opt_timeout) { 112 this.activityStarted_(); 113 this.activityStopped_(opt_timeout); 114}; 115 116/** 117 * Check if the tools are active and update the tools visibility accordingly. 118 */ 119MouseInactivityWatcher.prototype.check = function() { 120 if (this.toolsActive_()) 121 this.activityStarted_(); 122 else 123 this.activityStopped_(); 124}; 125 126/** 127 * Mouse move handler. 128 * 129 * @param {Event} e Event. 130 * @private 131 */ 132MouseInactivityWatcher.prototype.onMouseMove_ = function(e) { 133 if (this.clientX_ == e.clientX && this.clientY_ == e.clientY) { 134 // The mouse has not moved, must be the cursor change triggered by 135 // some of the attributes on the root container. Ignore the event. 136 return; 137 } 138 this.clientX_ = e.clientX; 139 this.clientY_ = e.clientY; 140 141 if (this.disabled_) 142 return; 143 144 this.kick(); 145}; 146 147/** 148 * Mouse over handler on a tool element. 149 * 150 * @param {Event} e Event. 151 * @private 152 */ 153MouseInactivityWatcher.prototype.onToolMouseOver_ = function(e) { 154 this.mouseOverTool_ = true; 155 if (!this.disabled_) 156 this.kick(); 157}; 158 159/** 160 * Mouse out handler on a tool element. 161 * 162 * @param {Event} e Event. 163 * @private 164 */ 165MouseInactivityWatcher.prototype.onToolMouseOut_ = function(e) { 166 this.mouseOverTool_ = false; 167 if (!this.disabled_) 168 this.kick(); 169}; 170 171/** 172 * Timeout handler. 173 * @private 174 */ 175MouseInactivityWatcher.prototype.onTimeout_ = function() { 176 this.timeoutID_ = null; 177 if (!this.disabled_ && !this.toolsActive_()) 178 this.showTools(false); 179}; 180