120 lines
3.5 KiB
JavaScript
120 lines
3.5 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 LISTENERS = Commons.LISTENERS;
|
||
|
var ATTRIBUTE = Commons.ATTRIBUTE;
|
||
|
var newNode = Commons.newNode;
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Helpers
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
/**
|
||
|
* Gets a specified attribute listener from a given EventTarget object.
|
||
|
*
|
||
|
* @param {EventTarget} eventTarget - An EventTarget object to get.
|
||
|
* @param {string} type - An event type to get.
|
||
|
* @returns {function|null} The found attribute listener.
|
||
|
*/
|
||
|
function getAttributeListener(eventTarget, type) {
|
||
|
var node = eventTarget[LISTENERS][type];
|
||
|
while (node != null) {
|
||
|
if (node.kind === ATTRIBUTE) {
|
||
|
return node.listener;
|
||
|
}
|
||
|
node = node.next;
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets a specified attribute listener to a given EventTarget object.
|
||
|
*
|
||
|
* @param {EventTarget} eventTarget - An EventTarget object to set.
|
||
|
* @param {string} type - An event type to set.
|
||
|
* @param {function|null} listener - A listener to be set.
|
||
|
* @returns {void}
|
||
|
*/
|
||
|
function setAttributeListener(eventTarget, type, listener) {
|
||
|
if (typeof listener !== "function" && typeof listener !== "object") {
|
||
|
listener = null; // eslint-disable-line no-param-reassign
|
||
|
}
|
||
|
|
||
|
var prev = null;
|
||
|
var node = eventTarget[LISTENERS][type];
|
||
|
while (node != null) {
|
||
|
if (node.kind === ATTRIBUTE) {
|
||
|
// Remove old value.
|
||
|
if (prev == null) {
|
||
|
eventTarget[LISTENERS][type] = node.next;
|
||
|
}
|
||
|
else {
|
||
|
prev.next = node.next;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
prev = node;
|
||
|
}
|
||
|
|
||
|
node = node.next;
|
||
|
}
|
||
|
|
||
|
// Add new value.
|
||
|
if (listener != null) {
|
||
|
if (prev == null) {
|
||
|
eventTarget[LISTENERS][type] = newNode(listener, ATTRIBUTE);
|
||
|
}
|
||
|
else {
|
||
|
prev.next = newNode(listener, ATTRIBUTE);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Public Interface
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
/**
|
||
|
* Defines an `EventTarget` implementation which has `onfoobar` attributes.
|
||
|
*
|
||
|
* @param {EventTarget} EventTargetBase - A base implementation of EventTarget.
|
||
|
* @param {string[]} types - A list of event types which are defined as attribute listeners.
|
||
|
* @returns {EventTarget} The defined `EventTarget` implementation which has attribute listeners.
|
||
|
*/
|
||
|
exports.defineCustomEventTarget = function(EventTargetBase, types) {
|
||
|
function EventTarget() {
|
||
|
EventTargetBase.call(this);
|
||
|
}
|
||
|
|
||
|
var descripter = {
|
||
|
constructor: {
|
||
|
value: EventTarget,
|
||
|
configurable: true,
|
||
|
writable: true
|
||
|
}
|
||
|
};
|
||
|
|
||
|
types.forEach(function(type) {
|
||
|
descripter["on" + type] = {
|
||
|
get: function() { return getAttributeListener(this, type); },
|
||
|
set: function(listener) { setAttributeListener(this, type, listener); },
|
||
|
configurable: true,
|
||
|
enumerable: true
|
||
|
};
|
||
|
});
|
||
|
|
||
|
EventTarget.prototype = Object.create(EventTargetBase.prototype, descripter);
|
||
|
|
||
|
return EventTarget;
|
||
|
};
|