GT2/GT2-Android/node_modules/event-target-shim/lib/event-target.js

191 lines
6.2 KiB
JavaScript

/**
* @author Toru Nagashima
* @copyright 2015 Toru Nagashima. All rights reserved.
* See LICENSE file in root directory for full license.
*/
"use strict";
//-----------------------------------------------------------------------------
// Requirements
//-----------------------------------------------------------------------------
var Commons = require("./commons");
var CustomEventTarget = require("./custom-event-target");
var EventWrapper = require("./event-wrapper");
var LISTENERS = Commons.LISTENERS;
var CAPTURE = Commons.CAPTURE;
var BUBBLE = Commons.BUBBLE;
var ATTRIBUTE = Commons.ATTRIBUTE;
var newNode = Commons.newNode;
var defineCustomEventTarget = CustomEventTarget.defineCustomEventTarget;
var createEventWrapper = EventWrapper.createEventWrapper;
var STOP_IMMEDIATE_PROPAGATION_FLAG =
EventWrapper.STOP_IMMEDIATE_PROPAGATION_FLAG;
//-----------------------------------------------------------------------------
// Constants
//-----------------------------------------------------------------------------
/**
* A flag which shows there is the native `EventTarget` interface object.
*
* @type {boolean}
* @private
*/
var HAS_EVENTTARGET_INTERFACE = (
typeof window !== "undefined" &&
typeof window.EventTarget !== "undefined"
);
//-----------------------------------------------------------------------------
// Public Interface
//-----------------------------------------------------------------------------
/**
* An implementation for `EventTarget` interface.
*
* @constructor
* @public
*/
var EventTarget = module.exports = function EventTarget() {
if (this instanceof EventTarget) {
// this[LISTENERS] is a Map.
// Its key is event type.
// Its value is ListenerNode object or null.
//
// interface ListenerNode {
// var listener: Function
// var kind: CAPTURE|BUBBLE|ATTRIBUTE
// var next: ListenerNode|null
// }
Object.defineProperty(this, LISTENERS, {value: Object.create(null)});
}
else if (arguments.length === 1 && Array.isArray(arguments[0])) {
return defineCustomEventTarget(EventTarget, arguments[0]);
}
else if (arguments.length > 0) {
var types = Array(arguments.length);
for (var i = 0; i < arguments.length; ++i) {
types[i] = arguments[i];
}
// To use to extend with attribute listener properties.
// e.g.
// class MyCustomObject extends EventTarget("message", "error") {
// //...
// }
return defineCustomEventTarget(EventTarget, types);
}
else {
throw new TypeError("Cannot call a class as a function");
}
};
EventTarget.prototype = Object.create(
(HAS_EVENTTARGET_INTERFACE ? window.EventTarget : Object).prototype,
{
constructor: {
value: EventTarget,
writable: true,
configurable: true
},
addEventListener: {
value: function addEventListener(type, listener, capture) {
if (listener == null) {
return false;
}
if (typeof listener !== "function" && typeof listener !== "object") {
throw new TypeError("\"listener\" is not an object.");
}
var kind = (capture ? CAPTURE : BUBBLE);
var node = this[LISTENERS][type];
if (node == null) {
this[LISTENERS][type] = newNode(listener, kind);
return true;
}
var prev = null;
while (node != null) {
if (node.listener === listener && node.kind === kind) {
// Should ignore a duplicated listener.
return false;
}
prev = node;
node = node.next;
}
prev.next = newNode(listener, kind);
return true;
},
configurable: true,
writable: true
},
removeEventListener: {
value: function removeEventListener(type, listener, capture) {
if (listener == null) {
return false;
}
var kind = (capture ? CAPTURE : BUBBLE);
var prev = null;
var node = this[LISTENERS][type];
while (node != null) {
if (node.listener === listener && node.kind === kind) {
if (prev == null) {
this[LISTENERS][type] = node.next;
}
else {
prev.next = node.next;
}
return true;
}
prev = node;
node = node.next;
}
return false;
},
configurable: true,
writable: true
},
dispatchEvent: {
value: function dispatchEvent(event) {
// If listeners aren't registered, terminate.
var node = this[LISTENERS][event.type];
if (node == null) {
return true;
}
// Since we cannot rewrite several properties, so wrap object.
var wrapped = createEventWrapper(event, this);
// This doesn't process capturing phase and bubbling phase.
// This isn't participating in a tree.
while (node != null) {
if (typeof node.listener === "function") {
node.listener.call(this, wrapped);
}
else if (node.kind !== ATTRIBUTE && typeof node.listener.handleEvent === "function") {
node.listener.handleEvent(wrapped);
}
if (wrapped[STOP_IMMEDIATE_PROPAGATION_FLAG]) {
break;
}
node = node.next;
}
return !wrapped.defaultPrevented;
},
configurable: true,
writable: true
}
}
);