1116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Copyright (c) 2014 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)'use strict';
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * A controller class detects mouse inactivity and hides "tool" elements.
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Element} container The main DOM container.
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_timeout Hide timeout in ms.
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {function():boolean=} opt_toolsActive Function that returns |true|
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *     if the tools are active and should not be hidden.
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @constructor
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)function MouseInactivityWatcher(container, opt_timeout, opt_toolsActive) {
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.container_ = container;
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.timeout_ = opt_timeout || MouseInactivityWatcher.DEFAULT_TIMEOUT;
19116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  this.toolsActive_ = opt_toolsActive || function() { return false; };
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.onTimeoutBound_ = this.onTimeout_.bind(this);
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.timeoutID_ = null;
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.mouseOverTool_ = false;
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.clientX_ = 0;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.clientY_ = 0;
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  /**
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   * Indicates if the inactivity watcher is enabled or disabled. Use getters
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   * and setters.
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   * @type {boolean}
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   * @private
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   **/
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.disabled_ = false;
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.__defineSetter__('disabled', function(value) {
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    this.disabled_ = value;
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (value)
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      this.kick();
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    else
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      this.check();
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  });
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.__defineGetter__('disabled', function() {
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return this.disabled_;
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  });
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.container_.addEventListener('mousemove', this.onMouseMove_.bind(this));
47eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  var tools = this.container_.querySelector('.tool');
48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (var i = 0; i < tools.length; i++) {
49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    tools[i].addEventListener('mouseover', this.onToolMouseOver_.bind(this));
50eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    tools[i].addEventListener('mouseout', this.onToolMouseOut_.bind(this));
51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Show tools when the user touches the screen.
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.container_.addEventListener(
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      'touchstart', this.activityStarted_.bind(this));
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var initiateFading = this.activityStopped_.bind(this, this.timeout_);
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.container_.addEventListener('touchend', initiateFading);
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.container_.addEventListener('touchcancel', initiateFading);
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Default inactivity timeout.
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MouseInactivityWatcher.DEFAULT_TIMEOUT = 3000;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {boolean} on True if show, false if hide.
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MouseInactivityWatcher.prototype.showTools = function(on) {
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (on)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.container_.setAttribute('tools', 'true');
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.container_.removeAttribute('tools');
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * To be called when the user started activity. Shows the tools
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * and cancels the countdown.
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @private
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)MouseInactivityWatcher.prototype.activityStarted_ = function() {
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.showTools(true);
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (this.timeoutID_) {
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    clearTimeout(this.timeoutID_);
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.timeoutID_ = null;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Called when user activity has stopped. Re-starts the countdown.
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_timeout Timeout.
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @private
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)MouseInactivityWatcher.prototype.activityStopped_ = function(opt_timeout) {
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (this.disabled_ || this.mouseOverTool_ || this.toolsActive_())
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (this.timeoutID_)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    clearTimeout(this.timeoutID_);
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.timeoutID_ = setTimeout(
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this.onTimeoutBound_, opt_timeout || this.timeout_);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Called when a user performed a short action (such as a click or a key press)
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * that should show the tools if they are not visible.
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number=} opt_timeout Timeout.
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)MouseInactivityWatcher.prototype.kick = function(opt_timeout) {
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.activityStarted_();
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.activityStopped_(opt_timeout);
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Check if the tools are active and update the tools visibility accordingly.
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)MouseInactivityWatcher.prototype.check = function() {
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (this.toolsActive_())
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    this.activityStarted_();
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    this.activityStopped_();
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Mouse move handler.
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @param {Event} e Event.
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MouseInactivityWatcher.prototype.onMouseMove_ = function(e) {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (this.clientX_ == e.clientX && this.clientY_ == e.clientY) {
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The mouse has not moved, must be the cursor change triggered by
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // some of the attributes on the root container. Ignore the event.
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.clientX_ = e.clientX;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.clientY_ = e.clientY;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (this.disabled_)
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
144eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  this.kick();
145eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch};
146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch/**
148eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * Mouse over handler on a tool element.
149eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch *
150eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * @param {Event} e Event.
151eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * @private
152eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch */
153eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochMouseInactivityWatcher.prototype.onToolMouseOver_ = function(e) {
154eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  this.mouseOverTool_ = true;
155eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!this.disabled_)
156eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    this.kick();
157eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch};
158eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
159eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch/**
160eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * Mouse out handler on a tool element.
161eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch *
162eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * @param {Event} e Event.
163eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch * @private
164eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch */
165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochMouseInactivityWatcher.prototype.onToolMouseOut_ = function(e) {
166eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  this.mouseOverTool_ = false;
167eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!this.disabled_)
168eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    this.kick();
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Timeout handler.
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * @private
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MouseInactivityWatcher.prototype.onTimeout_ = function() {
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  this.timeoutID_ = null;
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!this.disabled_ && !this.toolsActive_())
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    this.showTools(false);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
180