tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

event-target.js (6590B)


      1 'use strict';
      2 
      3 const { kForOnEventAttribute, kListener } = require('./constants');
      4 
      5 const kCode = Symbol('kCode');
      6 const kData = Symbol('kData');
      7 const kError = Symbol('kError');
      8 const kMessage = Symbol('kMessage');
      9 const kReason = Symbol('kReason');
     10 const kTarget = Symbol('kTarget');
     11 const kType = Symbol('kType');
     12 const kWasClean = Symbol('kWasClean');
     13 
     14 /**
     15 * Class representing an event.
     16 */
     17 class Event {
     18  /**
     19   * Create a new `Event`.
     20   *
     21   * @param {String} type The name of the event
     22   * @throws {TypeError} If the `type` argument is not specified
     23   */
     24  constructor(type) {
     25    this[kTarget] = null;
     26    this[kType] = type;
     27  }
     28 
     29  /**
     30   * @type {*}
     31   */
     32  get target() {
     33    return this[kTarget];
     34  }
     35 
     36  /**
     37   * @type {String}
     38   */
     39  get type() {
     40    return this[kType];
     41  }
     42 }
     43 
     44 Object.defineProperty(Event.prototype, 'target', { enumerable: true });
     45 Object.defineProperty(Event.prototype, 'type', { enumerable: true });
     46 
     47 /**
     48 * Class representing a close event.
     49 *
     50 * @extends Event
     51 */
     52 class CloseEvent extends Event {
     53  /**
     54   * Create a new `CloseEvent`.
     55   *
     56   * @param {String} type The name of the event
     57   * @param {Object} [options] A dictionary object that allows for setting
     58   *     attributes via object members of the same name
     59   * @param {Number} [options.code=0] The status code explaining why the
     60   *     connection was closed
     61   * @param {String} [options.reason=''] A human-readable string explaining why
     62   *     the connection was closed
     63   * @param {Boolean} [options.wasClean=false] Indicates whether or not the
     64   *     connection was cleanly closed
     65   */
     66  constructor(type, options = {}) {
     67    super(type);
     68 
     69    this[kCode] = options.code === undefined ? 0 : options.code;
     70    this[kReason] = options.reason === undefined ? '' : options.reason;
     71    this[kWasClean] = options.wasClean === undefined ? false : options.wasClean;
     72  }
     73 
     74  /**
     75   * @type {Number}
     76   */
     77  get code() {
     78    return this[kCode];
     79  }
     80 
     81  /**
     82   * @type {String}
     83   */
     84  get reason() {
     85    return this[kReason];
     86  }
     87 
     88  /**
     89   * @type {Boolean}
     90   */
     91  get wasClean() {
     92    return this[kWasClean];
     93  }
     94 }
     95 
     96 Object.defineProperty(CloseEvent.prototype, 'code', { enumerable: true });
     97 Object.defineProperty(CloseEvent.prototype, 'reason', { enumerable: true });
     98 Object.defineProperty(CloseEvent.prototype, 'wasClean', { enumerable: true });
     99 
    100 /**
    101 * Class representing an error event.
    102 *
    103 * @extends Event
    104 */
    105 class ErrorEvent extends Event {
    106  /**
    107   * Create a new `ErrorEvent`.
    108   *
    109   * @param {String} type The name of the event
    110   * @param {Object} [options] A dictionary object that allows for setting
    111   *     attributes via object members of the same name
    112   * @param {*} [options.error=null] The error that generated this event
    113   * @param {String} [options.message=''] The error message
    114   */
    115  constructor(type, options = {}) {
    116    super(type);
    117 
    118    this[kError] = options.error === undefined ? null : options.error;
    119    this[kMessage] = options.message === undefined ? '' : options.message;
    120  }
    121 
    122  /**
    123   * @type {*}
    124   */
    125  get error() {
    126    return this[kError];
    127  }
    128 
    129  /**
    130   * @type {String}
    131   */
    132  get message() {
    133    return this[kMessage];
    134  }
    135 }
    136 
    137 Object.defineProperty(ErrorEvent.prototype, 'error', { enumerable: true });
    138 Object.defineProperty(ErrorEvent.prototype, 'message', { enumerable: true });
    139 
    140 /**
    141 * Class representing a message event.
    142 *
    143 * @extends Event
    144 */
    145 class MessageEvent extends Event {
    146  /**
    147   * Create a new `MessageEvent`.
    148   *
    149   * @param {String} type The name of the event
    150   * @param {Object} [options] A dictionary object that allows for setting
    151   *     attributes via object members of the same name
    152   * @param {*} [options.data=null] The message content
    153   */
    154  constructor(type, options = {}) {
    155    super(type);
    156 
    157    this[kData] = options.data === undefined ? null : options.data;
    158  }
    159 
    160  /**
    161   * @type {*}
    162   */
    163  get data() {
    164    return this[kData];
    165  }
    166 }
    167 
    168 Object.defineProperty(MessageEvent.prototype, 'data', { enumerable: true });
    169 
    170 /**
    171 * This provides methods for emulating the `EventTarget` interface. It's not
    172 * meant to be used directly.
    173 *
    174 * @mixin
    175 */
    176 const EventTarget = {
    177  /**
    178   * Register an event listener.
    179   *
    180   * @param {String} type A string representing the event type to listen for
    181   * @param {Function} listener The listener to add
    182   * @param {Object} [options] An options object specifies characteristics about
    183   *     the event listener
    184   * @param {Boolean} [options.once=false] A `Boolean` indicating that the
    185   *     listener should be invoked at most once after being added. If `true`,
    186   *     the listener would be automatically removed when invoked.
    187   * @public
    188   */
    189  addEventListener(type, listener, options = {}) {
    190    let wrapper;
    191 
    192    if (type === 'message') {
    193      wrapper = function onMessage(data, isBinary) {
    194        const event = new MessageEvent('message', {
    195          data: isBinary ? data : data.toString()
    196        });
    197 
    198        event[kTarget] = this;
    199        listener.call(this, event);
    200      };
    201    } else if (type === 'close') {
    202      wrapper = function onClose(code, message) {
    203        const event = new CloseEvent('close', {
    204          code,
    205          reason: message.toString(),
    206          wasClean: this._closeFrameReceived && this._closeFrameSent
    207        });
    208 
    209        event[kTarget] = this;
    210        listener.call(this, event);
    211      };
    212    } else if (type === 'error') {
    213      wrapper = function onError(error) {
    214        const event = new ErrorEvent('error', {
    215          error,
    216          message: error.message
    217        });
    218 
    219        event[kTarget] = this;
    220        listener.call(this, event);
    221      };
    222    } else if (type === 'open') {
    223      wrapper = function onOpen() {
    224        const event = new Event('open');
    225 
    226        event[kTarget] = this;
    227        listener.call(this, event);
    228      };
    229    } else {
    230      return;
    231    }
    232 
    233    wrapper[kForOnEventAttribute] = !!options[kForOnEventAttribute];
    234    wrapper[kListener] = listener;
    235 
    236    if (options.once) {
    237      this.once(type, wrapper);
    238    } else {
    239      this.on(type, wrapper);
    240    }
    241  },
    242 
    243  /**
    244   * Remove an event listener.
    245   *
    246   * @param {String} type A string representing the event type to remove
    247   * @param {Function} handler The listener to remove
    248   * @public
    249   */
    250  removeEventListener(type, handler) {
    251    for (const listener of this.listeners(type)) {
    252      if (listener[kListener] === handler && !listener[kForOnEventAttribute]) {
    253        this.removeListener(type, listener);
    254        break;
    255      }
    256    }
    257  }
    258 };
    259 
    260 module.exports = {
    261  CloseEvent,
    262  ErrorEvent,
    263  Event,
    264  EventTarget,
    265  MessageEvent
    266 };