blob: 1205d6a5ad11c5a088bf2dc3d85cdb60d39f1a9b [file] [log] [blame]
<!DOCTYPE html>
<!--
Copyright (c) 2014 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<link rel="import" href="/base/base.html">
<script>
'use strict';
/**
* @fileoverview This contains an implementation of the EventTarget interface
* as defined by DOM Level 2 Events.
*/
tr.exportTo('tr.b', function() {
/**
* Creates a new EventTarget. This class implements the DOM level 2
* EventTarget interface and can be used wherever those are used.
* @constructor
*/
function EventTarget() {
}
EventTarget.decorate = function(target) {
for (var k in EventTarget.prototype) {
if (k == 'decorate')
continue;
var v = EventTarget.prototype[k];
if (typeof v !== 'function')
continue;
target[k] = v;
}
};
EventTarget.prototype = {
/**
* Adds an event listener to the target.
* @param {string} type The name of the event.
* @param {!Function|{handleEvent:Function}} handler The handler for the
* event. This is called when the event is dispatched.
*/
addEventListener: function(type, handler) {
if (!this.listeners_)
this.listeners_ = Object.create(null);
if (!(type in this.listeners_)) {
this.listeners_[type] = [handler];
} else {
var handlers = this.listeners_[type];
if (handlers.indexOf(handler) < 0)
handlers.push(handler);
}
},
/**
* Removes an event listener from the target.
* @param {string} type The name of the event.
* @param {!Function|{handleEvent:Function}} handler The handler for the
* event.
*/
removeEventListener: function(type, handler) {
if (!this.listeners_)
return;
if (type in this.listeners_) {
var handlers = this.listeners_[type];
var index = handlers.indexOf(handler);
if (index >= 0) {
// Clean up if this was the last listener.
if (handlers.length == 1)
delete this.listeners_[type];
else
handlers.splice(index, 1);
}
}
},
/**
* Dispatches an event and calls all the listeners that are listening to
* the type of the event.
* @param {!cr.event.Event} event The event to dispatch.
* @return {boolean} Whether the default action was prevented. If someone
* calls preventDefault on the event object then this returns false.
*/
dispatchEvent: function(event) {
if (!this.listeners_)
return true;
// Since we are using DOM Event objects we need to override some of the
// properties and methods so that we can emulate this correctly.
var self = this;
event.__defineGetter__('target', function() {
return self;
});
var realPreventDefault = event.preventDefault;
event.preventDefault = function() {
realPreventDefault.call(this);
this.rawReturnValue = false;
};
var type = event.type;
var prevented = 0;
if (type in this.listeners_) {
// Clone to prevent removal during dispatch
var handlers = this.listeners_[type].concat();
for (var i = 0, handler; handler = handlers[i]; i++) {
if (handler.handleEvent)
prevented |= handler.handleEvent.call(handler, event) === false;
else
prevented |= handler.call(this, event) === false;
}
}
return !prevented && event.rawReturnValue;
},
hasEventListener: function(type) {
return this.listeners_[type] !== undefined;
}
};
var EventTargetHelper = {
decorate: function(target) {
for (var k in EventTargetHelper) {
if (k == 'decorate')
continue;
var v = EventTargetHelper[k];
if (typeof v !== 'function')
continue;
target[k] = v;
}
target.listenerCounts_ = {};
},
addEventListener: function(type, listener, useCapture) {
this.__proto__.addEventListener.call(
this, type, listener, useCapture);
if (this.listenerCounts_[type] === undefined)
this.listenerCounts_[type] = 0;
this.listenerCounts_[type]++;
},
removeEventListener: function(type, listener, useCapture) {
this.__proto__.removeEventListener.call(
this, type, listener, useCapture);
this.listenerCounts_[type]--;
},
hasEventListener: function(type) {
return this.listenerCounts_[type] > 0;
}
};
// Export
return {
EventTarget: EventTarget,
EventTargetHelper: EventTargetHelper
};
});
</script>