| |
| const BUBBLES = 0x1 |
| const CANCELABLE = 0x2 |
| const COMPOSED = 0x4 |
| const CANCELED = 0x8 |
| const DISPATCH = 0x10 |
| const STOP = 0x20 |
|
|
| |
| const CAPTURE = 0x1 |
| const PASSIVE = 0x2 |
| const ONCE = 0x4 |
|
|
| |
| class Event { |
| |
| constructor(type, options = {}) { |
| const { bubbles = false, cancelable = false, composed = false } = options |
|
|
| this._type = type |
| this._target = null |
| this._state = 0 |
|
|
| if (bubbles) this._state |= BUBBLES |
| if (cancelable) this._state |= CANCELABLE |
| if (composed) this._state |= COMPOSED |
| } |
|
|
| |
| get type() { |
| return this._type |
| } |
|
|
| |
| get target() { |
| return this._target |
| } |
|
|
| |
| get currentTarget() { |
| return null |
| } |
|
|
| |
| get bubbles() { |
| return (this._state & BUBBLES) !== 0 |
| } |
|
|
| |
| get cancelable() { |
| return (this._state & CANCELABLE) !== 0 |
| } |
|
|
| |
| get composed() { |
| return (this._state & COMPOSED) !== 0 |
| } |
|
|
| |
| get defaultPrevented() { |
| return (this._state & CANCELED) !== 0 |
| } |
|
|
| |
| get isTrusted() { |
| return false |
| } |
|
|
| |
| preventDefault() { |
| if (this._state & CANCELABLE) this._state |= CANCELED |
| } |
|
|
| |
| stopPropagation() {} |
|
|
| |
| stopImmediatePropagation() { |
| this._state |= STOP |
| } |
|
|
| toJSON() { |
| return { |
| type: this.type, |
| target: this.target, |
| bubbles: this.bubbles, |
| cancelable: this.cancelable, |
| composed: this.composed, |
| defaultPrevented: this.defaultPrevented, |
| isTrusted: this.isTrusted |
| } |
| } |
|
|
| [Symbol.for('bare.inspect')]() { |
| return { |
| __proto__: { constructor: Event }, |
|
|
| type: this.type, |
| target: this.target, |
| bubbles: this.bubbles, |
| cancelable: this.cancelable, |
| composed: this.composed, |
| defaultPrevented: this.defaultPrevented, |
| isTrusted: this.isTrusted |
| } |
| } |
| } |
|
|
| exports.Event = Event |
|
|
| |
| exports.CustomEvent = class CustomEvent extends Event { |
| constructor(type, options = {}) { |
| super(type, options) |
|
|
| const { detail = null } = options |
|
|
| this._detail = detail |
| } |
|
|
| |
| get detail() { |
| return this._detail |
| } |
| } |
|
|
| |
| exports.EventTarget = class EventTarget { |
| |
| constructor() { |
| this._listeners = new Map() |
| } |
|
|
| |
| addEventListener(type, callback = null, options = {}) { |
| if (typeof options === 'boolean') options = { capture: options } |
|
|
| const { capture = false, passive = false, once = false, signal = null } = options |
|
|
| if (signal !== null && signal.aborted) return |
| if (callback === null) return |
|
|
| const listener = new EventListener(type, callback, capture, passive, once, signal) |
|
|
| const listeners = this._listeners.get(type) |
|
|
| if (listeners === undefined) this._listeners.set(type, listener) |
| else { |
| for (const existing of listeners) { |
| if (callback === existing.callback && capture === existing.capture) { |
| return |
| } |
| } |
|
|
| listener.link(listeners) |
|
|
| if (signal !== null) { |
| signal.addEventListener('abort', onabort) |
|
|
| function onabort() { |
| listener.unlink() |
| } |
| } |
| } |
| } |
|
|
| |
| removeEventListener(type, callback = null, options = {}) { |
| if (typeof options === 'boolean') options = { capture: options } |
|
|
| const { capture = false } = options |
|
|
| const listeners = this._listeners.get(type) |
|
|
| if (listeners === undefined) return |
|
|
| for (const existing of listeners) { |
| if (callback === existing.callback && capture === existing.capture) { |
| const next = existing.unlink() |
|
|
| if (listeners === existing) this._listeners.set(type, next) |
|
|
| return |
| } |
| } |
| } |
|
|
| |
| dispatchEvent(event) { |
| event._target = this |
| event._state |= DISPATCH |
|
|
| const listeners = this._listeners.get(event.type) |
|
|
| try { |
| if (listeners === undefined) return true |
|
|
| for (const listener of listeners) { |
| |
|
|
| if (listener.once) listener.unlink() |
|
|
| let callback = listener.callback |
| let context = this |
|
|
| if (typeof callback === 'object') { |
| context = callback |
| callback = callback.handleEvent |
| } |
|
|
| Reflect.apply(callback, context, [event]) |
|
|
| if (event._state & STOP) break |
| } |
|
|
| return (event._state & CANCELED) === 0 |
| } finally { |
| event._state &= ~DISPATCH |
| event._state &= ~STOP |
| } |
| } |
|
|
| toJSON() { |
| return {} |
| } |
|
|
| [Symbol.for('bare.inspect')]() { |
| return { |
| __proto__: { constructor: EventTarget } |
| } |
| } |
| } |
|
|
| |
| class EventListener { |
| constructor(type, callback, capture, passive, once, signal) { |
| this._type = type |
| this._callback = callback |
| this._signal = signal |
| this._state = 0 |
|
|
| if (capture) this._state |= CAPTURE |
| if (passive) this._state |= PASSIVE |
| if (once) this._state |= ONCE |
|
|
| this._previous = this |
| this._next = this |
| } |
|
|
| get type() { |
| return this._type |
| } |
|
|
| get callback() { |
| return this._callback |
| } |
|
|
| get capture() { |
| return (this._state & CAPTURE) !== 0 |
| } |
|
|
| get passive() { |
| return (this._state & PASSIVE) !== 0 |
| } |
|
|
| get once() { |
| return (this._state & ONCE) !== 0 |
| } |
|
|
| get removed() { |
| return this._previous === this && this._next === this |
| } |
|
|
| link(listener) { |
| const next = this._next |
| const previous = listener._previous |
|
|
| this._next = listener |
| listener._previous = this |
|
|
| previous._next = next |
| next._previous = previous |
|
|
| return listener |
| } |
|
|
| unlink() { |
| if (this.removed) return this |
|
|
| const next = this._next |
| const previous = this._previous |
|
|
| this._next = this |
| this._previous = this |
|
|
| previous._next = next |
| next._previous = previous |
|
|
| return next |
| } |
|
|
| *[Symbol.iterator]() { |
| let current = this |
|
|
| while (true) { |
| const next = current._next |
| yield current |
| if (next === this) break |
| current = next |
| } |
| } |
|
|
| toJSON() { |
| return { |
| type: this.type, |
| capture: this.capture, |
| passive: this.passive, |
| once: this.once, |
| removed: this.removed |
| } |
| } |
|
|
| [Symbol.for('bare.inspect')]() { |
| return { |
| __proto__: { constructor: EventListener }, |
|
|
| type: this.type, |
| callback: this.callback, |
| capture: this.capture, |
| passive: this.passive, |
| once: this.once, |
| removed: this.removed |
| } |
| } |
| } |
|
|