/** * @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; };