15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 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) 55f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)/** 65f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * @fileoverview EventTracker is a simple class that manages the addition and 75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * removal of DOM event listeners. In particular, it keeps track of all 85f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * listeners that have been added and makes it easy to remove some or all of 95f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * them without requiring all the information again. This is particularly handy 105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * when the listener is a generated function such as a lambda or the result of 115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * calling Function.bind. 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)/** 155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * The type of the internal tracking entry. TODO(dbeam): move this back to 165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * EventTracker.Entry when https://github.com/google/closure-compiler/issues/544 175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * is fixed. 185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * @typedef {{node: !Node, 195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * eventType: string, 205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * listener: Function, 215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) * capture: boolean}} 225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) */ 235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)var EventTrackerEntry; 245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 2503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)/** 2603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * Create an EventTracker to track a set of events. 2703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * EventTracker instances are typically tied 1:1 with other objects or 2803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * DOM elements whose listeners should be removed when the object is disposed 2903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * or the corresponding elements are removed from the DOM. 3003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * @constructor 3103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) */ 3203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)function EventTracker() { 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 3403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * @type {Array.<EventTrackerEntry>} 3503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * @private 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 3703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) this.listeners_ = []; 3803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)} 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)EventTracker.prototype = { 4103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) /** 4203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * Add an event listener - replacement for Node.addEventListener. 4303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * @param {!Node} node The DOM node to add a listener to. 4403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * @param {string} eventType The type of event to subscribe to. 451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * @param {EventListener|Function} listener The listener to add. 4603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * @param {boolean=} opt_capture Whether to invoke during the capture phase. 4703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) */ 4803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) add: function(node, eventType, listener, opt_capture) { 4903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) var capture = !!opt_capture; 5003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) var h = { 5103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) node: node, 5203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) eventType: eventType, 5303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) listener: listener, 5403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) capture: capture, 5503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) }; 5603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) this.listeners_.push(h); 5703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) node.addEventListener(eventType, listener, capture); 5803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) }, 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /** 6103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * Remove any specified event listeners added with this EventTracker. 6203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * @param {!Node} node The DOM node to remove a listener from. 6303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * @param {?string} eventType The type of event to remove. 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */ 6503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) remove: function(node, eventType) { 6603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) this.listeners_ = this.listeners_.filter(function(h) { 6703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) if (h.node == node && (!eventType || (h.eventType == eventType))) { 6803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) EventTracker.removeEventListener_(h); 6903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return false; 7003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 7103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) return true; 7203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) }); 7303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) }, 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) /** 7603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * Remove all event listeners added with this EventTracker. 7703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) */ 7803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) removeAll: function() { 7903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) this.listeners_.forEach(EventTracker.removeEventListener_); 8003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) this.listeners_ = []; 8103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) } 8203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)/** 8503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * Remove a single event listener given it's tracking entry. It's up to the 8603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * caller to ensure the entry is removed from listeners_. 8703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * @param {EventTrackerEntry} h The entry describing the listener to remove. 8803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) * @private 8903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) */ 9003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)EventTracker.removeEventListener_ = function(h) { 9103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles) h.node.removeEventListener(h.eventType, h.listener, h.capture); 9203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}; 93