• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (c) 2011 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/**
6 * @fileoverview EventTracker is a simple class that manages the addition and
7 * removal of DOM event listeners. In particular, it keeps track of all
8 * listeners that have been added and makes it easy to remove some or all of
9 * them without requiring all the information again. This is particularly handy
10 * when the listener is a generated function such as a lambda or the result of
11 * calling Function.bind.
12 */
13
14/**
15 * The type of the internal tracking entry. TODO(dbeam): move this back to
16 * EventTracker.Entry when https://github.com/google/closure-compiler/issues/544
17 * is fixed.
18 * @typedef {{node: !Node,
19 *            eventType: string,
20 *            listener: Function,
21 *            capture: boolean}}
22 */
23var EventTrackerEntry;
24
25/**
26 * Create an EventTracker to track a set of events.
27 * EventTracker instances are typically tied 1:1 with other objects or
28 * DOM elements whose listeners should be removed when the object is disposed
29 * or the corresponding elements are removed from the DOM.
30 * @constructor
31 */
32function EventTracker() {
33  /**
34   * @type {Array.<EventTrackerEntry>}
35   * @private
36   */
37  this.listeners_ = [];
38}
39
40EventTracker.prototype = {
41  /**
42   * Add an event listener - replacement for Node.addEventListener.
43   * @param {!Node} node The DOM node to add a listener to.
44   * @param {string} eventType The type of event to subscribe to.
45   * @param {EventListener|Function} listener The listener to add.
46   * @param {boolean=} opt_capture Whether to invoke during the capture phase.
47   */
48  add: function(node, eventType, listener, opt_capture) {
49    var capture = !!opt_capture;
50    var h = {
51      node: node,
52      eventType: eventType,
53      listener: listener,
54      capture: capture,
55    };
56    this.listeners_.push(h);
57    node.addEventListener(eventType, listener, capture);
58  },
59
60  /**
61   * Remove any specified event listeners added with this EventTracker.
62   * @param {!Node} node The DOM node to remove a listener from.
63   * @param {?string} eventType The type of event to remove.
64   */
65  remove: function(node, eventType) {
66    this.listeners_ = this.listeners_.filter(function(h) {
67      if (h.node == node && (!eventType || (h.eventType == eventType))) {
68        EventTracker.removeEventListener_(h);
69        return false;
70      }
71      return true;
72    });
73  },
74
75  /**
76   * Remove all event listeners added with this EventTracker.
77   */
78  removeAll: function() {
79    this.listeners_.forEach(EventTracker.removeEventListener_);
80    this.listeners_ = [];
81  }
82};
83
84/**
85 * Remove a single event listener given it's tracking entry. It's up to the
86 * caller to ensure the entry is removed from listeners_.
87 * @param {EventTrackerEntry} h The entry describing the listener to remove.
88 * @private
89 */
90EventTracker.removeEventListener_ = function(h) {
91  h.node.removeEventListener(h.eventType, h.listener, h.capture);
92};
93