dommy 0.5.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +31 -13
  3. data/lib/dommy/animation.rb +288 -0
  4. data/lib/dommy/attr.rb +23 -11
  5. data/lib/dommy/backend/nokogiri_adapter.rb +51 -0
  6. data/lib/dommy/backend/nokolexbor_adapter.rb +80 -0
  7. data/lib/dommy/backend.rb +129 -0
  8. data/lib/dommy/blob.rb +2 -2
  9. data/lib/dommy/compression_streams.rb +147 -0
  10. data/lib/dommy/cookie_store.rb +128 -0
  11. data/lib/dommy/crypto.rb +396 -0
  12. data/lib/dommy/css.rb +7 -7
  13. data/lib/dommy/custom_elements.rb +6 -6
  14. data/lib/dommy/document.rb +190 -32
  15. data/lib/dommy/dom_parser.rb +5 -4
  16. data/lib/dommy/element.rb +356 -53
  17. data/lib/dommy/event.rb +431 -25
  18. data/lib/dommy/event_source.rb +131 -0
  19. data/lib/dommy/fetch.rb +76 -6
  20. data/lib/dommy/file_reader.rb +176 -0
  21. data/lib/dommy/form_data.rb +1 -3
  22. data/lib/dommy/history.rb +82 -0
  23. data/lib/dommy/html_collection.rb +4 -4
  24. data/lib/dommy/html_elements.rb +130 -67
  25. data/lib/dommy/internal/cookie_jar.rb +2 -0
  26. data/lib/dommy/internal/css_pseudo_handlers.rb +28 -0
  27. data/lib/dommy/internal/dom_matching.rb +4 -4
  28. data/lib/dommy/internal/idna.rb +443 -0
  29. data/lib/dommy/internal/idna_data.rb +10379 -0
  30. data/lib/dommy/internal/ipv4_parser.rb +78 -0
  31. data/lib/dommy/internal/node_traversal.rb +1 -1
  32. data/lib/dommy/internal/node_wrapper_cache.rb +23 -12
  33. data/lib/dommy/internal/observable_callback.rb +25 -0
  34. data/lib/dommy/internal/punycode.rb +202 -0
  35. data/lib/dommy/internal/range_text_serializer.rb +72 -0
  36. data/lib/dommy/internal/reflected_attributes.rb +45 -0
  37. data/lib/dommy/internal/template_content_registry.rb +6 -6
  38. data/lib/dommy/intersection_observer.rb +82 -0
  39. data/lib/dommy/{router.rb → location.rb} +8 -142
  40. data/lib/dommy/media_query_list.rb +118 -0
  41. data/lib/dommy/message_channel.rb +249 -0
  42. data/lib/dommy/{observer.rb → mutation_observer.rb} +21 -11
  43. data/lib/dommy/navigator.rb +365 -5
  44. data/lib/dommy/node.rb +12 -0
  45. data/lib/dommy/notification.rb +89 -0
  46. data/lib/dommy/parser.rb +13 -13
  47. data/lib/dommy/performance.rb +146 -0
  48. data/lib/dommy/performance_observer.rb +55 -0
  49. data/lib/dommy/range.rb +597 -0
  50. data/lib/dommy/resize_observer.rb +53 -0
  51. data/lib/dommy/shadow_root.rb +10 -8
  52. data/lib/dommy/streams.rb +386 -0
  53. data/lib/dommy/svg_elements.rb +3863 -0
  54. data/lib/dommy/text_codec.rb +175 -0
  55. data/lib/dommy/tree_walker.rb +21 -21
  56. data/lib/dommy/url.rb +274 -29
  57. data/lib/dommy/url_pattern.rb +144 -0
  58. data/lib/dommy/version.rb +1 -1
  59. data/lib/dommy/web_socket.rb +209 -0
  60. data/lib/dommy/window.rb +369 -0
  61. data/lib/dommy/worker.rb +143 -0
  62. data/lib/dommy/xml_http_request.rb +438 -0
  63. data/lib/dommy.rb +43 -5
  64. metadata +44 -29
  65. data/lib/dommy/world.rb +0 -209
data/lib/dommy/event.rb CHANGED
@@ -54,24 +54,30 @@ module Dommy
54
54
  # Per spec, dispatchEvent must receive an Event instance.
55
55
  raise TypeError, "dispatchEvent requires an Event, got #{event.class}" unless event.is_a?(Event)
56
56
 
57
- event.__prepare_for_dispatch__(self)
57
+ event.__internal_prepare_for_dispatch__(self)
58
58
  path = if event.bubbles?
59
59
  event.__js_get__("composed") ? composed_bubble_path(event) : event_bubble_path
60
60
  else
61
61
  [self]
62
62
  end
63
63
 
64
- event.__record_path__(path) if event.respond_to?(:__record_path__)
64
+ event.__internal_record_path__(path) if event.respond_to?(:__internal_record_path__)
65
65
  path.each do |target|
66
- event.__set_current_target__(target)
67
- target.__deliver_event__(event)
66
+ event.__internal_set_current_target__(target)
67
+ target.__internal_deliver_event__(event)
68
68
  break if event.propagation_stopped?
69
69
  end
70
70
 
71
+ # WHATWG: after dispatch completes, currentTarget reverts to
72
+ # null and eventPhase reverts to NONE. Dommy derives
73
+ # eventPhase from currentTarget, so clearing it here covers
74
+ # both spec requirements.
75
+ event.__internal_set_current_target__(nil)
76
+
71
77
  !event.default_prevented?
72
78
  end
73
79
 
74
- def __deliver_event__(event)
80
+ def __internal_deliver_event__(event)
75
81
  listeners = listeners_for(event.type).dup
76
82
  listeners.each do |entry|
77
83
  invoke_listener(entry.listener, event)
@@ -106,7 +112,7 @@ module Dommy
106
112
  def event_bubble_path
107
113
  path = [self]
108
114
  current = self
109
- while (current = current.send(:__event_parent__))
115
+ while (current = current.send(:__internal_event_parent__))
110
116
  path << current
111
117
  end
112
118
 
@@ -116,12 +122,12 @@ module Dommy
116
122
  # Build the propagation path with optional shadow-boundary
117
123
  # crossing. When the in-flight event has `composed: true`, the
118
124
  # walk continues from a ShadowRoot to its host; otherwise it
119
- # stops at the shadow boundary (nil from `__event_parent__`).
125
+ # stops at the shadow boundary (nil from `__internal_event_parent__`).
120
126
  def composed_bubble_path(event)
121
127
  path = [self]
122
128
  current = self
123
129
  loop do
124
- nxt = current.send(:__event_parent__)
130
+ nxt = current.send(:__internal_event_parent__)
125
131
  if nxt.nil? && event.respond_to?(:__js_get__) && event.__js_get__("composed")
126
132
  # Try to cross a shadow boundary
127
133
  if current.is_a?(ShadowRoot)
@@ -148,12 +154,12 @@ module Dommy
148
154
  private
149
155
 
150
156
  def enclosing_shadow_root_of(target)
151
- return nil unless target.respond_to?(:__node__)
157
+ return nil unless target.respond_to?(:__dommy_backend_node__)
152
158
 
153
159
  doc = target.instance_variable_get(:@document)
154
- return nil unless doc && doc.respond_to?(:__shadow_root_containing__)
160
+ return nil unless doc && doc.respond_to?(:__internal_shadow_root_containing__)
155
161
 
156
- doc.__shadow_root_containing__(target.__node__)
162
+ doc.__internal_shadow_root_containing__(target.__dommy_backend_node__)
157
163
  end
158
164
 
159
165
  public
@@ -178,6 +184,12 @@ module Dommy
178
184
  class StandaloneEventTarget
179
185
  include EventTarget
180
186
 
187
+ # Methods routed through __js_call__ (keep in sync with its when-arms).
188
+ JS_METHOD_NAMES = %w[addEventListener removeEventListener dispatchEvent].freeze
189
+ def __js_method_names__
190
+ JS_METHOD_NAMES
191
+ end
192
+
181
193
  def __js_call__(method, args)
182
194
  case method
183
195
  when "addEventListener"
@@ -191,7 +203,7 @@ module Dommy
191
203
  end
192
204
  end
193
205
 
194
- def __event_parent__
206
+ def __internal_event_parent__
195
207
  nil
196
208
  end
197
209
  end
@@ -232,11 +244,11 @@ module Dommy
232
244
  @immediate_propagation_stopped
233
245
  end
234
246
 
235
- def __prepare_for_dispatch__(target)
247
+ def __internal_prepare_for_dispatch__(target)
236
248
  @target ||= target
237
249
  end
238
250
 
239
- def __set_current_target__(target)
251
+ def __internal_set_current_target__(target)
240
252
  @current_target = target
241
253
  end
242
254
 
@@ -276,6 +288,12 @@ module Dommy
276
288
  nil
277
289
  end
278
290
 
291
+ # Methods routed through __js_call__ (keep in sync with its when-arms).
292
+ JS_METHOD_NAMES = %w[preventDefault stopPropagation stopImmediatePropagation composedPath initEvent].freeze
293
+ def __js_method_names__
294
+ JS_METHOD_NAMES
295
+ end
296
+
279
297
  def __js_call__(method, args)
280
298
  case method
281
299
  when "preventDefault"
@@ -314,7 +332,7 @@ module Dommy
314
332
  # Per spec, `load` events do not propagate to the Window when
315
333
  # composed paths are computed (resource-finished signal stays at
316
334
  # the target).
317
- def __record_path__(targets)
335
+ def __internal_record_path__(targets)
318
336
  @composed_path = if @type == "load"
319
337
  targets.reject { |t| t.is_a?(Window) }
320
338
  else
@@ -348,6 +366,8 @@ module Dommy
348
366
  end
349
367
 
350
368
  class CustomEvent < Event
369
+ attr_reader :detail
370
+
351
371
  def initialize(type, init = nil)
352
372
  super
353
373
  @detail = read_init(init, "detail")
@@ -443,6 +463,380 @@ module Dommy
443
463
  end
444
464
  end
445
465
 
466
+ # `InputEvent` — fired by `input` / `beforeinput`. Carries `data`
467
+ # (the inserted text, if any) and `inputType` (insertText,
468
+ # deleteContentBackward, etc.).
469
+ class InputEvent < Event
470
+ def initialize(type, init = nil)
471
+ super
472
+ @data = read_init(init, "data")
473
+ @input_type = (read_init(init, "inputType") || "").to_s
474
+ @is_composing = !!read_init(init, "isComposing")
475
+ end
476
+
477
+ def __js_get__(key)
478
+ case key
479
+ when "data"
480
+ @data
481
+ when "inputType"
482
+ @input_type
483
+ when "isComposing"
484
+ @is_composing
485
+ else
486
+ super
487
+ end
488
+ end
489
+ end
490
+
491
+ # `PointerEvent` — pointer (mouse / touch / pen) unified events.
492
+ # Inherits from MouseEvent for coords / modifier keys; adds
493
+ # pointerId, pointerType, pressure, width, height, etc.
494
+ class PointerEvent < MouseEvent
495
+ def initialize(type, init = nil)
496
+ super
497
+ @pointer_id = (read_init(init, "pointerId") || 0).to_i
498
+ @pointer_type = (read_init(init, "pointerType") || "mouse").to_s
499
+ @pressure = (read_init(init, "pressure") || 0).to_f
500
+ @tangential_pressure = (read_init(init, "tangentialPressure") || 0).to_f
501
+ @width = (read_init(init, "width") || 1).to_f
502
+ @height = (read_init(init, "height") || 1).to_f
503
+ @tilt_x = (read_init(init, "tiltX") || 0).to_i
504
+ @tilt_y = (read_init(init, "tiltY") || 0).to_i
505
+ @twist = (read_init(init, "twist") || 0).to_i
506
+ @is_primary = !!read_init(init, "isPrimary")
507
+ end
508
+
509
+ def __js_get__(key)
510
+ case key
511
+ when "pointerId"
512
+ @pointer_id
513
+ when "pointerType"
514
+ @pointer_type
515
+ when "pressure"
516
+ @pressure
517
+ when "tangentialPressure"
518
+ @tangential_pressure
519
+ when "width"
520
+ @width
521
+ when "height"
522
+ @height
523
+ when "tiltX"
524
+ @tilt_x
525
+ when "tiltY"
526
+ @tilt_y
527
+ when "twist"
528
+ @twist
529
+ when "isPrimary"
530
+ @is_primary
531
+ else
532
+ super
533
+ end
534
+ end
535
+ end
536
+
537
+ # `ProgressEvent` — fired during long-running operations (XHR,
538
+ # fetch upload/download progress). Carries `loaded` / `total` /
539
+ # `lengthComputable`.
540
+ class ProgressEvent < Event
541
+ def initialize(type, init = nil)
542
+ super
543
+ @loaded = (read_init(init, "loaded") || 0).to_i
544
+ @total = (read_init(init, "total") || 0).to_i
545
+ @length_computable = !!read_init(init, "lengthComputable")
546
+ end
547
+
548
+ def __js_get__(key)
549
+ case key
550
+ when "loaded"
551
+ @loaded
552
+ when "total"
553
+ @total
554
+ when "lengthComputable"
555
+ @length_computable
556
+ else
557
+ super
558
+ end
559
+ end
560
+ end
561
+
562
+ # `Touch` — a single touch point on a touch-capable surface.
563
+ # Constructed by tests; tied to a target element and coordinate set.
564
+ #
565
+ # Spec: https://w3c.github.io/touch-events/#touch-interface
566
+ class Touch
567
+ attr_reader(
568
+ :identifier,
569
+ :target,
570
+ :client_x,
571
+ :client_y,
572
+ :page_x,
573
+ :page_y,
574
+ :screen_x,
575
+ :screen_y,
576
+ :radius_x,
577
+ :radius_y,
578
+ :rotation_angle,
579
+ :force
580
+ )
581
+
582
+ def initialize(init = {})
583
+ @identifier = (init["identifier"] || init[:identifier] || 0).to_i
584
+ @target = init["target"] || init[:target]
585
+ @client_x = (init["clientX"] || init[:clientX] || 0).to_f
586
+ @client_y = (init["clientY"] || init[:clientY] || 0).to_f
587
+ @page_x = (init["pageX"] || init[:pageX] || @client_x).to_f
588
+ @page_y = (init["pageY"] || init[:pageY] || @client_y).to_f
589
+ @screen_x = (init["screenX"] || init[:screenX] || @client_x).to_f
590
+ @screen_y = (init["screenY"] || init[:screenY] || @client_y).to_f
591
+ @radius_x = (init["radiusX"] || init[:radiusX] || 0).to_f
592
+ @radius_y = (init["radiusY"] || init[:radiusY] || 0).to_f
593
+ @rotation_angle = (init["rotationAngle"] || init[:rotationAngle] || 0).to_f
594
+ @force = (init["force"] || init[:force] || 0).to_f
595
+ end
596
+
597
+ def __js_get__(key)
598
+ case key
599
+ when "identifier"
600
+ @identifier
601
+ when "target"
602
+ @target
603
+ when "clientX"
604
+ @client_x
605
+ when "clientY"
606
+ @client_y
607
+ when "pageX"
608
+ @page_x
609
+ when "pageY"
610
+ @page_y
611
+ when "screenX"
612
+ @screen_x
613
+ when "screenY"
614
+ @screen_y
615
+ when "radiusX"
616
+ @radius_x
617
+ when "radiusY"
618
+ @radius_y
619
+ when "rotationAngle"
620
+ @rotation_angle
621
+ when "force"
622
+ @force
623
+ end
624
+ end
625
+ end
626
+
627
+ # `TouchList` — immutable, indexed collection of Touch points.
628
+ class TouchList
629
+ include Enumerable
630
+
631
+ def initialize(touches = [])
632
+ @touches = touches.to_a.freeze
633
+ end
634
+
635
+ def length
636
+ @touches.length
637
+ end
638
+
639
+ def item(index)
640
+ @touches[index.to_i]
641
+ end
642
+
643
+ def [](index)
644
+ item(index)
645
+ end
646
+
647
+ def each(&block)
648
+ @touches.each(&block)
649
+ self
650
+ end
651
+
652
+ def __js_get__(key)
653
+ case key
654
+ when "length"
655
+ length
656
+ else
657
+ item(key.to_i) if key.is_a?(Integer) || key.to_s.match?(/\A-?\d+\z/)
658
+ end
659
+ end
660
+
661
+ # Methods routed through __js_call__ (keep in sync with its when-arms).
662
+ JS_METHOD_NAMES = %w[item].freeze
663
+ def __js_method_names__
664
+ JS_METHOD_NAMES
665
+ end
666
+
667
+ def __js_call__(method, args)
668
+ case method
669
+ when "item"
670
+ item(args[0])
671
+ end
672
+ end
673
+ end
674
+
675
+ # `TouchEvent` — fires for touchstart / touchmove / touchend /
676
+ # touchcancel. Carries three TouchLists plus modifier keys.
677
+ #
678
+ # Spec: https://w3c.github.io/touch-events/#touchevent-interface
679
+ class TouchEvent < Event
680
+ def initialize(type, init = nil)
681
+ super
682
+ @touches = TouchList.new(Array(read_init(init, "touches") || []))
683
+ @target_touches = TouchList.new(Array(read_init(init, "targetTouches") || []))
684
+ @changed_touches = TouchList.new(Array(read_init(init, "changedTouches") || []))
685
+ @alt_key = !!read_init(init, "altKey")
686
+ @ctrl_key = !!read_init(init, "ctrlKey")
687
+ @shift_key = !!read_init(init, "shiftKey")
688
+ @meta_key = !!read_init(init, "metaKey")
689
+ end
690
+
691
+ attr_reader :touches, :target_touches, :changed_touches
692
+
693
+ def __js_get__(key)
694
+ case key
695
+ when "touches"
696
+ @touches
697
+ when "targetTouches"
698
+ @target_touches
699
+ when "changedTouches"
700
+ @changed_touches
701
+ when "altKey"
702
+ @alt_key
703
+ when "ctrlKey"
704
+ @ctrl_key
705
+ when "shiftKey"
706
+ @shift_key
707
+ when "metaKey"
708
+ @meta_key
709
+ else
710
+ super
711
+ end
712
+ end
713
+ end
714
+
715
+ # `ClipboardEvent` — fires for copy / cut / paste. Carries the
716
+ # `clipboardData` payload as a DataTransfer.
717
+ #
718
+ # Spec: https://w3c.github.io/clipboard-apis/#clipboard-event-interface
719
+ class ClipboardEvent < Event
720
+ def initialize(type, init = nil)
721
+ super
722
+ @clipboard_data = read_init(init, "clipboardData")
723
+ end
724
+
725
+ attr_reader :clipboard_data
726
+
727
+ def __js_get__(key)
728
+ case key
729
+ when "clipboardData"
730
+ @clipboard_data
731
+ else
732
+ super
733
+ end
734
+ end
735
+ end
736
+
737
+ # `CompositionEvent` — IME composition events (compositionstart /
738
+ # compositionupdate / compositionend). `data` holds the composing text.
739
+ class CompositionEvent < Event
740
+ def initialize(type, init = nil)
741
+ super
742
+ @data = (read_init(init, "data") || "").to_s
743
+ end
744
+
745
+ attr_reader :data
746
+
747
+ def __js_get__(key)
748
+ case key
749
+ when "data"
750
+ @data
751
+ else
752
+ super
753
+ end
754
+ end
755
+ end
756
+
757
+ # `WheelEvent` — wheel-scroll events. Inherits MouseEvent (coords +
758
+ # modifier keys) and adds delta values + a delta mode.
759
+ class WheelEvent < MouseEvent
760
+ DOM_DELTA_PIXEL = 0
761
+ DOM_DELTA_LINE = 1
762
+ DOM_DELTA_PAGE = 2
763
+
764
+ def initialize(type, init = nil)
765
+ super
766
+ @delta_x = (read_init(init, "deltaX") || 0).to_f
767
+ @delta_y = (read_init(init, "deltaY") || 0).to_f
768
+ @delta_z = (read_init(init, "deltaZ") || 0).to_f
769
+ @delta_mode = (read_init(init, "deltaMode") || 0).to_i
770
+ end
771
+
772
+ attr_reader :delta_x, :delta_y, :delta_z, :delta_mode
773
+
774
+ def __js_get__(key)
775
+ case key
776
+ when "deltaX"
777
+ @delta_x
778
+ when "deltaY"
779
+ @delta_y
780
+ when "deltaZ"
781
+ @delta_z
782
+ when "deltaMode"
783
+ @delta_mode
784
+ else
785
+ super
786
+ end
787
+ end
788
+ end
789
+
790
+ # `FocusEvent` — focus / blur / focusin / focusout. `relatedTarget`
791
+ # is the element gaining/losing focus on the other side.
792
+ class FocusEvent < Event
793
+ def initialize(type, init = nil)
794
+ super
795
+ @related_target = read_init(init, "relatedTarget")
796
+ end
797
+
798
+ attr_reader :related_target
799
+
800
+ def __js_get__(key)
801
+ case key
802
+ when "relatedTarget"
803
+ @related_target
804
+ else
805
+ super
806
+ end
807
+ end
808
+ end
809
+
810
+ # `BeforeUnloadEvent` — `beforeunload` event. Setting `return_value`
811
+ # to a non-empty string (or calling `preventDefault`) signals the
812
+ # browser to prompt the user before navigating away.
813
+ class BeforeUnloadEvent < Event
814
+ def initialize(type = "beforeunload", init = nil)
815
+ super
816
+ @return_value = (read_init(init, "returnValue") || "").to_s
817
+ end
818
+
819
+ attr_accessor :return_value
820
+
821
+ def __js_get__(key)
822
+ case key
823
+ when "returnValue"
824
+ @return_value
825
+ else
826
+ super
827
+ end
828
+ end
829
+
830
+ def __js_set__(key, value)
831
+ case key
832
+ when "returnValue"
833
+ @return_value = value.to_s
834
+ else
835
+ super
836
+ end
837
+ end
838
+ end
839
+
446
840
  # `AbortController` + `AbortSignal` subset. Signal fires an
447
841
  # "abort" event and flips `[:aborted]` to true when the controller's
448
842
  # `abort()` is called; otherwise it stays inert.
@@ -453,7 +847,7 @@ module Dommy
453
847
  # signal. Convenient for APIs that need an already-cancelled token.
454
848
  def self.abort(reason = nil)
455
849
  signal = new
456
- signal.__mark_aborted__(reason)
850
+ signal.__internal_mark_aborted__(reason)
457
851
  signal
458
852
  end
459
853
 
@@ -466,9 +860,9 @@ module Dommy
466
860
  signal = new
467
861
  reason = DOMException::TimeoutError.new("operation timed out")
468
862
  if scheduler
469
- scheduler.set_timeout(proc { signal.__mark_aborted__(reason) }, ms.to_i)
863
+ scheduler.set_timeout(proc { signal.__internal_mark_aborted__(reason) }, ms.to_i)
470
864
  else
471
- signal.__schedule_thread_timeout__(ms.to_i, reason)
865
+ signal.__internal_schedule_thread_timeout__(ms.to_i, reason)
472
866
  end
473
867
 
474
868
  signal
@@ -483,12 +877,12 @@ module Dommy
483
877
  list = Array(signals).select { |s| s.is_a?(AbortSignal) }
484
878
  already = list.find(&:aborted?)
485
879
  if already
486
- composite.__mark_aborted__(already.reason)
880
+ composite.__internal_mark_aborted__(already.reason)
487
881
  return composite
488
882
  end
489
883
 
490
884
  list.each do |sig|
491
- sig.add_event_listener("abort", proc { composite.__mark_aborted__(sig.reason) })
885
+ sig.add_event_listener("abort", proc { composite.__internal_mark_aborted__(sig.reason) })
492
886
  end
493
887
 
494
888
  composite
@@ -501,11 +895,11 @@ module Dommy
501
895
 
502
896
  # Background-thread timeout used by `AbortSignal.timeout` when no
503
897
  # scheduler is provided. Kept package-private; tests can also
504
- # drive the abort manually via `__mark_aborted__`.
505
- def __schedule_thread_timeout__(ms, reason)
898
+ # drive the abort manually via `__internal_mark_aborted__`.
899
+ def __internal_schedule_thread_timeout__(ms, reason)
506
900
  Thread.new do
507
901
  sleep(ms.to_f / 1000.0)
508
- __mark_aborted__(reason)
902
+ __internal_mark_aborted__(reason)
509
903
  end
510
904
 
511
905
  nil
@@ -542,6 +936,12 @@ module Dommy
542
936
  nil
543
937
  end
544
938
 
939
+ # Methods routed through __js_call__ (keep in sync with its when-arms).
940
+ JS_METHOD_NAMES = %w[addEventListener removeEventListener dispatchEvent throwIfAborted].freeze
941
+ def __js_method_names__
942
+ JS_METHOD_NAMES
943
+ end
944
+
545
945
  def __js_call__(method, args)
546
946
  case method
547
947
  when "addEventListener"
@@ -555,7 +955,7 @@ module Dommy
555
955
  end
556
956
  end
557
957
 
558
- def __mark_aborted__(reason = nil)
958
+ def __internal_mark_aborted__(reason = nil)
559
959
  return if @aborted
560
960
 
561
961
  @aborted = true
@@ -579,10 +979,16 @@ module Dommy
579
979
  nil
580
980
  end
581
981
 
982
+ # Methods routed through __js_call__ (keep in sync with its when-arms).
983
+ JS_METHOD_NAMES = %w[abort].freeze
984
+ def __js_method_names__
985
+ JS_METHOD_NAMES
986
+ end
987
+
582
988
  def __js_call__(method, args)
583
989
  case method
584
990
  when "abort"
585
- @signal.__mark_aborted__(args[0])
991
+ @signal.__internal_mark_aborted__(args[0])
586
992
  end
587
993
  end
588
994
  end