| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 |
- // Event state
- const BUBBLES = 0x1
- const CANCELABLE = 0x2
- const COMPOSED = 0x4
- const CANCELED = 0x8
- const DISPATCH = 0x10
- const STOP = 0x20
- // EventTarget state
- const CAPTURE = 0x1
- const PASSIVE = 0x2
- const ONCE = 0x4
- // https://dom.spec.whatwg.org/#event
- class Event {
- // https://dom.spec.whatwg.org/#dom-event-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
- }
- // https://dom.spec.whatwg.org/#dom-event-type
- get type() {
- return this._type
- }
- // https://dom.spec.whatwg.org/#dom-event-target
- get target() {
- return this._target
- }
- // https://dom.spec.whatwg.org/#dom-event-currenttarget
- get currentTarget() {
- return null
- }
- // https://dom.spec.whatwg.org/#dom-event-bubbles
- get bubbles() {
- return (this._state & BUBBLES) !== 0
- }
- // https://dom.spec.whatwg.org/#dom-event-cancelable
- get cancelable() {
- return (this._state & CANCELABLE) !== 0
- }
- // https://dom.spec.whatwg.org/#dom-event-composed
- get composed() {
- return (this._state & COMPOSED) !== 0
- }
- // https://dom.spec.whatwg.org/#dom-event-defaultprevented
- get defaultPrevented() {
- return (this._state & CANCELED) !== 0
- }
- // https://dom.spec.whatwg.org/#dom-event-istrusted
- get isTrusted() {
- return false
- }
- // https://dom.spec.whatwg.org/#dom-event-preventdefault
- preventDefault() {
- if (this._state & CANCELABLE) this._state |= CANCELED
- }
- // https://dom.spec.whatwg.org/#dom-event-stoppropagation
- stopPropagation() {}
- // https://dom.spec.whatwg.org/#dom-event-stopimmediatepropagation
- 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
- // https://dom.spec.whatwg.org/#customevent
- exports.CustomEvent = class CustomEvent extends Event {
- constructor(type, options = {}) {
- super(type, options)
- const { detail = null } = options
- this._detail = detail
- }
- // https://dom.spec.whatwg.org/#dom-customevent-detail
- get detail() {
- return this._detail
- }
- }
- // https://dom.spec.whatwg.org/#eventtarget
- exports.EventTarget = class EventTarget {
- // https://dom.spec.whatwg.org/#dom-eventtarget-eventtarget
- constructor() {
- this._listeners = new Map()
- }
- // https://dom.spec.whatwg.org/#dom-eventtarget-addeventlistener
- 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 // Duplicate listener
- }
- }
- listener.link(listeners)
- if (signal !== null) {
- signal.addEventListener('abort', onabort)
- function onabort() {
- listener.unlink()
- }
- }
- }
- }
- // https://dom.spec.whatwg.org/#dom-eventtarget-removeeventlistener
- 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
- }
- }
- }
- // https://dom.spec.whatwg.org/#dom-eventtarget-dispatchevent
- 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) {
- // https://dom.spec.whatwg.org/#concept-event-listener-inner-invoke
- 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 }
- }
- }
- }
- // https://dom.spec.whatwg.org/#concept-event-listener
- 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
- }
- }
- }
|