1<!DOCTYPE html> 2<!-- 3Copyright (c) 2014 The Chromium Authors. All rights reserved. 4Use of this source code is governed by a BSD-style license that can be 5found in the LICENSE file. 6--> 7 8<link rel="import" href="/tracing/base/base.html"> 9 10<script> 11'use strict'; 12 13/** 14 * @fileoverview This contains an implementation of the EventTarget interface 15 * as defined by DOM Level 2 Events. 16 */ 17tr.exportTo('tr.b', function() { 18 19 /** 20 * Creates a new EventTarget. This class implements the DOM level 2 21 * EventTarget interface and can be used wherever those are used. 22 * @constructor 23 */ 24 function EventTarget() { 25 } 26 EventTarget.decorate = function(target) { 27 for (var k in EventTarget.prototype) { 28 if (k == 'decorate') 29 continue; 30 var v = EventTarget.prototype[k]; 31 if (typeof v !== 'function') 32 continue; 33 target[k] = v; 34 } 35 }; 36 37 EventTarget.prototype = { 38 39 /** 40 * Adds an event listener to the target. 41 * @param {string} type The name of the event. 42 * @param {!Function|{handleEvent:Function}} handler The handler for the 43 * event. This is called when the event is dispatched. 44 */ 45 addEventListener: function(type, handler) { 46 if (!this.listeners_) 47 this.listeners_ = Object.create(null); 48 if (!(type in this.listeners_)) { 49 this.listeners_[type] = [handler]; 50 } else { 51 var handlers = this.listeners_[type]; 52 if (handlers.indexOf(handler) < 0) 53 handlers.push(handler); 54 } 55 }, 56 57 /** 58 * Removes an event listener from the target. 59 * @param {string} type The name of the event. 60 * @param {!Function|{handleEvent:Function}} handler The handler for the 61 * event. 62 */ 63 removeEventListener: function(type, handler) { 64 if (!this.listeners_) 65 return; 66 if (type in this.listeners_) { 67 var handlers = this.listeners_[type]; 68 var index = handlers.indexOf(handler); 69 if (index >= 0) { 70 // Clean up if this was the last listener. 71 if (handlers.length == 1) 72 delete this.listeners_[type]; 73 else 74 handlers.splice(index, 1); 75 } 76 } 77 }, 78 79 /** 80 * Dispatches an event and calls all the listeners that are listening to 81 * the type of the event. 82 * @param {!cr.event.Event} event The event to dispatch. 83 * @return {boolean} Whether the default action was prevented. If someone 84 * calls preventDefault on the event object then this returns false. 85 */ 86 dispatchEvent: function(event) { 87 if (!this.listeners_) 88 return true; 89 90 // Since we are using DOM Event objects we need to override some of the 91 // properties and methods so that we can emulate this correctly. 92 var self = this; 93 event.__defineGetter__('target', function() { 94 return self; 95 }); 96 var realPreventDefault = event.preventDefault; 97 event.preventDefault = function() { 98 realPreventDefault.call(this); 99 this.rawReturnValue = false; 100 }; 101 102 var type = event.type; 103 var prevented = 0; 104 if (type in this.listeners_) { 105 // Clone to prevent removal during dispatch 106 var handlers = this.listeners_[type].concat(); 107 for (var i = 0, handler; handler = handlers[i]; i++) { 108 if (handler.handleEvent) 109 prevented |= handler.handleEvent.call(handler, event) === false; 110 else 111 prevented |= handler.call(this, event) === false; 112 } 113 } 114 115 return !prevented && event.rawReturnValue; 116 }, 117 118 hasEventListener: function(type) { 119 return this.listeners_[type] !== undefined; 120 } 121 }; 122 123 var EventTargetHelper = { 124 decorate: function(target) { 125 for (var k in EventTargetHelper) { 126 if (k == 'decorate') 127 continue; 128 var v = EventTargetHelper[k]; 129 if (typeof v !== 'function') 130 continue; 131 target[k] = v; 132 } 133 target.listenerCounts_ = {}; 134 }, 135 136 addEventListener: function(type, listener, useCapture) { 137 this.__proto__.addEventListener.call( 138 this, type, listener, useCapture); 139 if (this.listenerCounts_[type] === undefined) 140 this.listenerCounts_[type] = 0; 141 this.listenerCounts_[type]++; 142 }, 143 144 removeEventListener: function(type, listener, useCapture) { 145 this.__proto__.removeEventListener.call( 146 this, type, listener, useCapture); 147 this.listenerCounts_[type]--; 148 }, 149 150 hasEventListener: function(type) { 151 return this.listenerCounts_[type] > 0; 152 } 153 }; 154 155 // Export 156 return { 157 EventTarget: EventTarget, 158 EventTargetHelper: EventTargetHelper 159 }; 160}); 161</script> 162