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 */ 23 var 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 */ 32 function EventTracker() { 33 /** 34 * @type {Array.<EventTrackerEntry>} 35 * @private 36 */ 37 this.listeners_ = []; 38 } 39 40 EventTracker.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 */ 90 EventTracker.removeEventListener_ = function(h) { 91 h.node.removeEventListener(h.eventType, h.listener, h.capture); 92 }; 93