/** * @author Toru Nagashima * @copyright 2015 Toru Nagashima. All rights reserved. * See LICENSE file in root directory for full license. */ "use strict"; //----------------------------------------------------------------------------- // Requirements //----------------------------------------------------------------------------- var createUniqueKey = require("./commons").createUniqueKey; //----------------------------------------------------------------------------- // Constsnts //----------------------------------------------------------------------------- /** * The key of the flag which is turned on by `stopImmediatePropagation` method. * * @type {symbol|string} * @private */ var STOP_IMMEDIATE_PROPAGATION_FLAG = createUniqueKey("stop_immediate_propagation_flag"); /** * The key of the flag which is turned on by `preventDefault` method. * * @type {symbol|string} * @private */ var CANCELED_FLAG = createUniqueKey("canceled_flag"); /** * The key of the original event object. * * @type {symbol|string} * @private */ var ORIGINAL_EVENT = createUniqueKey("original_event"); /** * Method definitions for the event wrapper. * * @type {object} * @private */ var wrapperPrototypeDefinition = Object.freeze({ stopPropagation: Object.freeze({ value: function stopPropagation() { var e = this[ORIGINAL_EVENT]; if (typeof e.stopPropagation === "function") { e.stopPropagation(); } }, writable: true, configurable: true }), stopImmediatePropagation: Object.freeze({ value: function stopImmediatePropagation() { this[STOP_IMMEDIATE_PROPAGATION_FLAG] = true; var e = this[ORIGINAL_EVENT]; if (typeof e.stopImmediatePropagation === "function") { e.stopImmediatePropagation(); } }, writable: true, configurable: true }), preventDefault: Object.freeze({ value: function preventDefault() { if (this.cancelable === true) { this[CANCELED_FLAG] = true; } var e = this[ORIGINAL_EVENT]; if (typeof e.preventDefault === "function") { e.preventDefault(); } }, writable: true, configurable: true }), defaultPrevented: Object.freeze({ get: function defaultPrevented() { return this[CANCELED_FLAG]; }, enumerable: true, configurable: true }) }); //----------------------------------------------------------------------------- // Public Interface //----------------------------------------------------------------------------- exports.STOP_IMMEDIATE_PROPAGATION_FLAG = STOP_IMMEDIATE_PROPAGATION_FLAG; /** * Creates an event wrapper. * * We cannot modify several properties of `Event` object, so we need to create the wrapper. * Plus, this wrapper supports non `Event` objects. * * @param {Event|{type: string}} event - An original event to create the wrapper. * @param {EventTarget} eventTarget - The event target of the event. * @returns {Event} The created wrapper. This object is implemented `Event` interface. * @private */ exports.createEventWrapper = function createEventWrapper(event, eventTarget) { var timeStamp = ( typeof event.timeStamp === "number" ? event.timeStamp : Date.now() ); var propertyDefinition = { type: {value: event.type, enumerable: true}, target: {value: eventTarget, enumerable: true}, currentTarget: {value: eventTarget, enumerable: true}, eventPhase: {value: 2, enumerable: true}, bubbles: {value: Boolean(event.bubbles), enumerable: true}, cancelable: {value: Boolean(event.cancelable), enumerable: true}, timeStamp: {value: timeStamp, enumerable: true}, isTrusted: {value: false, enumerable: true} }; propertyDefinition[STOP_IMMEDIATE_PROPAGATION_FLAG] = {value: false, writable: true}; propertyDefinition[CANCELED_FLAG] = {value: false, writable: true}; propertyDefinition[ORIGINAL_EVENT] = {value: event}; // For CustomEvent. if (typeof event.detail !== "undefined") { propertyDefinition.detail = {value: event.detail, enumerable: true}; } return Object.create( Object.create(event, wrapperPrototypeDefinition), propertyDefinition ); };