Module: Dommy::EventTarget
- Included in:
- AbortSignal, Clipboard, Document, Element, Fragment, PermissionStatus, ShadowRoot, StandaloneEventTarget, Window
- Defined in:
- lib/dommy/event.rb
Overview
Note: ‘Callback` and `Constructor` live in `Dommy::Bridge::*` —they’re bridge-adapter classes, not part of the public DOM surface.
Defined Under Namespace
Classes: Listener
Instance Method Summary collapse
- #__deliver_event__(event) ⇒ Object
- #add_event_listener(type, listener = nil, options = nil, &block) ⇒ Object
- #dispatch_event(event) ⇒ Object
- #invoke_listener(listener, event) ⇒ Object
- #remove_event_listener(type, listener) ⇒ Object
Instance Method Details
#__deliver_event__(event) ⇒ Object
74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/dommy/event.rb', line 74 def __deliver_event__(event) listeners = listeners_for(event.type).dup listeners.each do |entry| invoke_listener(entry.listener, event) if entry.once? listeners_for(event.type).reject! { |candidate| candidate.listener.equal?(entry.listener) } end break if event.immediate_propagation_stopped? end nil end |
#add_event_listener(type, listener = nil, options = nil, &block) ⇒ Object
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/dommy/event.rb', line 9 def add_event_listener(type, listener = nil, = nil, &block) cb = listener || block return nil if type.nil? || cb.nil? list = listeners_for(type.to_s) # Per spec, the same listener (by identity) registered on the # same type is silently deduplicated. return nil if list.any? { |entry| entry.listener.equal?(cb) } list << Listener.new(cb, ) # `{ signal: AbortSignal }` — when the signal aborts, auto- # remove the listener. Per spec, if the signal is already aborted # the listener must not be registered at all. signal = .is_a?(Hash) ? (["signal"] || [:signal]) : nil if signal.respond_to?(:__js_get__) if signal.__js_get__("aborted") remove_event_listener(type, cb) else target = self signal.__js_call__( "addEventListener", [ "abort", proc { target.remove_event_listener(type, cb) } ] ) end end nil end |
#dispatch_event(event) ⇒ Object
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/dommy/event.rb', line 51 def dispatch_event(event) return true if event.nil? # Per spec, dispatchEvent must receive an Event instance. raise TypeError, "dispatchEvent requires an Event, got #{event.class}" unless event.is_a?(Event) event.__prepare_for_dispatch__(self) path = if event.bubbles? event.__js_get__("composed") ? composed_bubble_path(event) : event_bubble_path else [self] end event.__record_path__(path) if event.respond_to?(:__record_path__) path.each do |target| event.__set_current_target__(target) target.__deliver_event__(event) break if event.propagation_stopped? end !event.default_prevented? end |
#invoke_listener(listener, event) ⇒ Object
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/dommy/event.rb', line 161 def invoke_listener(listener, event) # DOM spec: a listener can be (a) a function, or (b) an object # with a `handleEvent` method. Both Ruby and JS-bridged callables # are supported. if listener.respond_to?(:handle_event) listener.handle_event(event) elsif listener.respond_to?(:call) && !listener.is_a?(Module) listener.call(event) elsif listener.respond_to?(:__js_call__) # Prefer handleEvent if the bridge object advertises it; fall # back to call. We can't introspect on the JS side, so we just # try call (the common case for JS.callback {}). listener.__js_call__("call", [event]) end end |
#remove_event_listener(type, listener) ⇒ Object
44 45 46 47 48 49 |
# File 'lib/dommy/event.rb', line 44 def remove_event_listener(type, listener) return nil if type.nil? || listener.nil? listeners_for(type.to_s).reject! { |entry| entry.listener.equal?(listener) } nil end |