1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Use of this source code is governed by a BSD-style license that can be
3ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// found in the LICENSE file.
4ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
5ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen/** @fileoverview EventTracker is a simple class that manages the addition and
6ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen *  removal of DOM event listeners. In particular, it keeps track of all
7ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen *  listeners that have been added and makes it easy to remove some or all of
8ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen *  them without requiring all the information again. This is particularly
9ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen *  handy when the listener is a generated function such as a lambda or the
10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen *  result of calling Function.bind.
11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen */
12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Use an anonymous function to enable strict mode just for this file (which
14ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// will be concatenated with other files when embedded in Chrome)
15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvar EventTracker = (function() {
16ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  'use strict';
17ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  /**
19ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   *  Create an EventTracker to track a set of events.
20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   *  EventTracker instances are typically tied 1:1 with other objects or
21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   *  DOM elements whose listeners should be removed when the object is disposed
22ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   *  or the corresponding elements are removed from the DOM.
23ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   *  @constructor
24ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   */
25ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  function EventTracker() {
26ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    /**
27ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     *  @type {Array.<EventTracker.Entry>}
28ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     *  @private
29ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     */
30ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    this.listeners_ = [];
31ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
32ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
33ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  /**
34ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   * The type of the internal tracking entry.
35ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   *  @typedef {{node: !Node,
36ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   *            eventType: string,
37ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   *            listener: Function,
38ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   *            capture: boolean}}
39ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   */
40ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EventTracker.Entry;
41ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
42ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EventTracker.prototype = {
43ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    /**
44ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * Add an event listener - replacement for Node.addEventListener.
45ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {!Node} node The DOM node to add a listener to.
46ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {string} eventType The type of event to subscribe to.
47ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {Function} listener The listener to add.
48ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {boolean} capture Whether to invoke during the capture phase.
49ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     */
50ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    add: function(node, eventType, listener, capture) {
51ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      var h = {
52ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        node: node,
53ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        eventType: eventType,
54ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        listener: listener,
55ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        capture: capture
56ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      };
57ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.listeners_.push(h);
58ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      node.addEventListener(eventType, listener, capture);
59ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
60ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
61ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    /**
62ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * Remove any specified event listeners added with this EventTracker.
63ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {!Node} node The DOM node to remove a listener from.
64ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @param {string} eventType The type of event to remove.
65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     */
66ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    remove: function(node, eventType) {
67ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.listeners_ = this.listeners_.filter(function(h) {
68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        if (h.node == node && h.eventType == eventType) {
69ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          EventTracker.removeEventListener_(h);
70ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          return false;
71ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        }
72ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        return true;
73ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      });
74ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
75ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
76ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    /**
77ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * Remove all event listeners added with this EventTracker.
78ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     */
79ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    removeAll: function() {
80ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.listeners_.forEach(EventTracker.removeEventListener_);
81ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      this.listeners_ = [];
82ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
83ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  };
84ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
85ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  /**
86ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   * Remove a single event listener given it's tracker entry.  It's up to the
87ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   * caller to ensure the entry is removed from listeners_.
88ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   * @param {EventTracker.Entry} h The entry describing the listener to remove.
89ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   * @private
90ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   */
91ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  EventTracker.removeEventListener_ = function(h) {
92ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    h.node.removeEventListener(h.eventType, h.listener, h.capture);
93ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  };
94ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
95ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return EventTracker;
96ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen})();
97ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
98