dommy 0.7.0 → 0.8.1

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 (69) hide show
  1. checksums.yaml +4 -4
  2. data/lib/dommy/animation.rb +9 -1
  3. data/lib/dommy/attr.rb +192 -39
  4. data/lib/dommy/backend/nokogiri_adapter.rb +76 -0
  5. data/lib/dommy/backend/nokolexbor_adapter.rb +37 -0
  6. data/lib/dommy/backend.rb +46 -0
  7. data/lib/dommy/blob.rb +28 -9
  8. data/lib/dommy/bridge/constructor_registry.rb +28 -0
  9. data/lib/dommy/bridge/methods.rb +57 -0
  10. data/lib/dommy/bridge.rb +97 -0
  11. data/lib/dommy/callable_invoker.rb +36 -0
  12. data/lib/dommy/cookie_store.rb +3 -1
  13. data/lib/dommy/crypto.rb +7 -1
  14. data/lib/dommy/css.rb +46 -0
  15. data/lib/dommy/custom_elements.rb +27 -3
  16. data/lib/dommy/data_transfer.rb +4 -0
  17. data/lib/dommy/document.rb +615 -48
  18. data/lib/dommy/dom_parser.rb +28 -15
  19. data/lib/dommy/element.rb +999 -471
  20. data/lib/dommy/event.rb +260 -96
  21. data/lib/dommy/event_source.rb +6 -2
  22. data/lib/dommy/fetch.rb +505 -43
  23. data/lib/dommy/file_reader.rb +11 -3
  24. data/lib/dommy/form_data.rb +2 -0
  25. data/lib/dommy/history.rb +43 -8
  26. data/lib/dommy/html_collection.rb +55 -2
  27. data/lib/dommy/html_elements.rb +102 -1519
  28. data/lib/dommy/internal/css_pseudo_handlers.rb +109 -0
  29. data/lib/dommy/internal/global_functions.rb +26 -0
  30. data/lib/dommy/internal/idna.rb +16 -7
  31. data/lib/dommy/internal/ipv4_parser.rb +22 -7
  32. data/lib/dommy/internal/mutation_coordinator.rb +11 -2
  33. data/lib/dommy/internal/namespaces.rb +70 -0
  34. data/lib/dommy/internal/node_equality.rb +86 -0
  35. data/lib/dommy/internal/node_wrapper_cache.rb +62 -27
  36. data/lib/dommy/internal/observable_callback.rb +1 -5
  37. data/lib/dommy/internal/parent_node.rb +126 -0
  38. data/lib/dommy/internal/reflected_attributes.rb +103 -13
  39. data/lib/dommy/internal/selector_parser.rb +664 -0
  40. data/lib/dommy/internal/url_parser.rb +677 -0
  41. data/lib/dommy/intersection_observer.rb +2 -0
  42. data/lib/dommy/location.rb +2 -0
  43. data/lib/dommy/media_query_list.rb +7 -1
  44. data/lib/dommy/message_channel.rb +32 -2
  45. data/lib/dommy/mutation_observer.rb +55 -12
  46. data/lib/dommy/navigator.rb +26 -12
  47. data/lib/dommy/node.rb +158 -28
  48. data/lib/dommy/notification.rb +3 -1
  49. data/lib/dommy/performance.rb +4 -0
  50. data/lib/dommy/performance_observer.rb +2 -0
  51. data/lib/dommy/promise.rb +14 -14
  52. data/lib/dommy/range.rb +74 -5
  53. data/lib/dommy/resize_observer.rb +2 -0
  54. data/lib/dommy/scheduler.rb +34 -13
  55. data/lib/dommy/shadow_root.rb +23 -54
  56. data/lib/dommy/storage.rb +2 -0
  57. data/lib/dommy/streams.rb +18 -27
  58. data/lib/dommy/svg_elements.rb +204 -3606
  59. data/lib/dommy/text_codec.rb +174 -21
  60. data/lib/dommy/tree_walker.rb +255 -66
  61. data/lib/dommy/url.rb +287 -449
  62. data/lib/dommy/url_pattern.rb +2 -0
  63. data/lib/dommy/version.rb +1 -1
  64. data/lib/dommy/web_socket.rb +37 -7
  65. data/lib/dommy/window.rb +202 -213
  66. data/lib/dommy/worker.rb +7 -7
  67. data/lib/dommy/xml_http_request.rb +15 -5
  68. data/lib/dommy.rb +7 -0
  69. metadata +27 -4
@@ -20,38 +20,7 @@ module Dommy
20
20
  # `<a>` — exposes URL-component getters/setters via the `href`
21
21
  # attribute, plus reflected `target` / `download` / `rel` / `type`.
22
22
  class HTMLAnchorElement < HTMLElement
23
- def target
24
- reflected_string("target")
25
- end
26
-
27
- def target=(v)
28
- set_reflected_string("target", v)
29
- end
30
-
31
- def download
32
- reflected_string("download")
33
- end
34
-
35
- def download=(v)
36
- set_reflected_string("download", v)
37
- end
38
-
39
- def rel
40
- reflected_string("rel")
41
- end
42
-
43
- def rel=(v)
44
- set_reflected_string("rel", v)
45
- end
46
-
47
- def hreflang
48
- reflected_string("hreflang")
49
- end
50
-
51
- def type
52
- reflected_string("type")
53
- end
54
-
23
+ reflect_string :target, :download, :rel, :hreflang, :type
55
24
  # URL-decomposition helpers. The anchor's `href` is resolved to
56
25
  # an absolute URL (inherited from Element#anchor_href); break it
57
26
  # into the standard components on demand.
@@ -89,16 +58,6 @@ module Dommy
89
58
 
90
59
  def __js_get__(key)
91
60
  case key
92
- when "target"
93
- target
94
- when "download"
95
- download
96
- when "rel"
97
- rel
98
- when "hreflang"
99
- hreflang
100
- when "type"
101
- type
102
61
  when "hash"
103
62
  self.hash
104
63
  when "host"
@@ -120,15 +79,6 @@ module Dommy
120
79
  end
121
80
  end
122
81
 
123
- def __js_set__(key, value)
124
- case key
125
- when "target", "download", "rel", "hreflang"
126
- set_reflected_string(key, value)
127
- else
128
- super
129
- end
130
- end
131
-
132
82
  private
133
83
 
134
84
  def uri
@@ -154,59 +104,9 @@ module Dommy
154
104
  # `<form>` — element collection, submit/reset, and a stubbed
155
105
  # validation surface.
156
106
  class HTMLFormElement < HTMLElement
107
+ reflect_string :name, :action, :enctype, :target, :autocomplete, method_attr: { attr: "method", js: "method" }, accept_charset: "accept-charset"
108
+ reflect_boolean no_validate: "novalidate"
157
109
  # Own __js_call__ methods, on top of Element's.
158
- JS_METHOD_NAMES = %w[submit reset requestSubmit checkValidity reportValidity].freeze
159
- def __js_method_names__
160
- super + JS_METHOD_NAMES
161
- end
162
-
163
- def name
164
- reflected_string("name")
165
- end
166
-
167
- def name=(v)
168
- set_reflected_string("name", v)
169
- end
170
-
171
- def action
172
- reflected_string("action")
173
- end
174
-
175
- def action=(v)
176
- set_reflected_string("action", v)
177
- end
178
-
179
- def method_attr
180
- reflected_string("method")
181
- end
182
-
183
- def method_attr=(v)
184
- set_reflected_string("method", v)
185
- end
186
-
187
- def enctype
188
- reflected_string("enctype")
189
- end
190
-
191
- def target
192
- reflected_string("target")
193
- end
194
-
195
- def autocomplete
196
- reflected_string("autocomplete")
197
- end
198
-
199
- def accept_charset
200
- reflected_string("accept-charset")
201
- end
202
-
203
- def no_validate
204
- reflected_boolean("novalidate")
205
- end
206
-
207
- def no_validate=(v)
208
- set_reflected_boolean("novalidate", v)
209
- end
210
110
 
211
111
  # `form.elements` — listed elements inside the form (excludes
212
112
  # nested forms per spec; we approximate by walking
@@ -292,46 +192,12 @@ module Dommy
292
192
  elements
293
193
  when "length"
294
194
  length
295
- when "name"
296
- name
297
- when "action"
298
- action
299
- when "method"
300
- method_attr
301
- when "enctype"
302
- enctype
303
- when "target"
304
- target
305
- when "autocomplete"
306
- autocomplete
307
- when "acceptCharset"
308
- accept_charset
309
- when "noValidate"
310
- no_validate
311
- else
312
- super
313
- end
314
- end
315
-
316
- def __js_set__(key, value)
317
- case key
318
- when "name"
319
- set_reflected_string("name", value)
320
- when "action"
321
- set_reflected_string("action", value)
322
- when "method"
323
- set_reflected_string("method", value)
324
- when "enctype"
325
- set_reflected_string("enctype", value)
326
- when "target"
327
- set_reflected_string("target", value)
328
- when "noValidate"
329
- set_reflected_boolean("novalidate", value)
330
195
  else
331
196
  super
332
197
  end
333
198
  end
334
199
 
200
+ js_methods %w[submit reset requestSubmit checkValidity reportValidity]
335
201
  def __js_call__(method, args)
336
202
  case method
337
203
  when "submit"
@@ -352,15 +218,9 @@ module Dommy
352
218
 
353
219
  # `<input>` — covers the most-used form control surface.
354
220
  class HTMLInputElement < HTMLElement
221
+ reflect_string :name, :placeholder, :min, :max, :step, :pattern, :autocomplete, default_value: "value"
222
+ reflect_boolean :autofocus, :disabled, :required, :readonly, default_checked: "checked"
355
223
  # Own __js_call__ methods, on top of Element's.
356
- JS_METHOD_NAMES = %w[
357
- select setSelectionRange setRangeText stepUp stepDown
358
- checkValidity reportValidity setCustomValidity
359
- ].freeze
360
- def __js_method_names__
361
- super + JS_METHOD_NAMES
362
- end
363
-
364
224
  def type
365
225
  raw = @__node__["type"].to_s
366
226
  raw.empty? ? "text" : raw.downcase
@@ -370,58 +230,6 @@ module Dommy
370
230
  set_reflected_string("type", v)
371
231
  end
372
232
 
373
- def name
374
- reflected_string("name")
375
- end
376
-
377
- def name=(v)
378
- set_reflected_string("name", v)
379
- end
380
-
381
- def placeholder
382
- reflected_string("placeholder")
383
- end
384
-
385
- def placeholder=(v)
386
- set_reflected_string("placeholder", v)
387
- end
388
-
389
- def min
390
- reflected_string("min")
391
- end
392
-
393
- def max
394
- reflected_string("max")
395
- end
396
-
397
- def step
398
- reflected_string("step")
399
- end
400
-
401
- def pattern
402
- reflected_string("pattern")
403
- end
404
-
405
- def autocomplete
406
- reflected_string("autocomplete")
407
- end
408
-
409
- def autofocus
410
- reflected_boolean("autofocus")
411
- end
412
-
413
- def autofocus=(v)
414
- set_reflected_boolean("autofocus", v)
415
- end
416
-
417
- def default_value
418
- reflected_string("value")
419
- end
420
-
421
- def default_checked
422
- reflected_boolean("checked")
423
- end
424
-
425
233
  # Runtime value/checked. Dommy has no UI, so the runtime state is
426
234
  # initialized from the attribute on first access and tracked
427
235
  # separately thereafter — matching browser semantics where the
@@ -496,30 +304,6 @@ module Dommy
496
304
  @__checked = !!v
497
305
  end
498
306
 
499
- def disabled
500
- reflected_boolean("disabled")
501
- end
502
-
503
- def disabled=(v)
504
- set_reflected_boolean("disabled", v)
505
- end
506
-
507
- def required
508
- reflected_boolean("required")
509
- end
510
-
511
- def required=(v)
512
- set_reflected_boolean("required", v)
513
- end
514
-
515
- def readonly
516
- reflected_boolean("readonly")
517
- end
518
-
519
- def readonly=(v)
520
- set_reflected_boolean("readonly", v)
521
- end
522
-
523
307
  def labels
524
308
  return [] if id.empty?
525
309
 
@@ -598,34 +382,10 @@ module Dommy
598
382
  case key
599
383
  when "type"
600
384
  type
601
- when "name"
602
- name
603
- when "placeholder"
604
- placeholder
605
- when "min"
606
- min
607
- when "max"
608
- max
609
- when "step"
610
- step
611
- when "pattern"
612
- pattern
613
- when "autocomplete"
614
- autocomplete
615
- when "autofocus"
616
- autofocus
617
- when "defaultValue"
618
- default_value
619
- when "defaultChecked"
620
- default_checked
621
385
  when "value"
622
386
  value
623
387
  when "checked"
624
388
  checked
625
- when "disabled"
626
- disabled
627
- when "required"
628
- required
629
389
  when "readonly", "readOnly"
630
390
  readonly
631
391
  when "labels"
@@ -649,22 +409,10 @@ module Dommy
649
409
  case key
650
410
  when "type"
651
411
  set_reflected_string("type", value)
652
- when "name"
653
- set_reflected_string("name", value)
654
- when "placeholder"
655
- set_reflected_string("placeholder", value)
656
- when "min", "max", "step", "pattern", "autocomplete"
657
- set_reflected_string(key, value)
658
- when "autofocus"
659
- set_reflected_boolean("autofocus", value)
660
412
  when "value"
661
413
  self.value = value
662
414
  when "checked"
663
415
  self.checked = value
664
- when "disabled"
665
- self.disabled = value
666
- when "required"
667
- self.required = value
668
416
  when "readonly", "readOnly"
669
417
  self.readonly = value
670
418
  else
@@ -672,6 +420,10 @@ module Dommy
672
420
  end
673
421
  end
674
422
 
423
+ js_methods %w[
424
+ select setSelectionRange setRangeText stepUp stepDown checkValidity reportValidity
425
+ setCustomValidity
426
+ ]
675
427
  def __js_call__(method, args)
676
428
  case method
677
429
  when "select"
@@ -698,6 +450,8 @@ module Dommy
698
450
 
699
451
  # `<button>` — type defaults to "submit" per spec.
700
452
  class HTMLButtonElement < HTMLElement
453
+ reflect_string :name, form_action: "formaction", form_enctype: "formenctype", form_method: "formmethod", form_target: "formtarget"
454
+ reflect_boolean form_no_validate: "formnovalidate"
701
455
  def type
702
456
  raw = @__node__["type"].to_s.downcase
703
457
  %w[submit reset button].include?(raw) ? raw : "submit"
@@ -707,38 +461,6 @@ module Dommy
707
461
  set_reflected_string("type", v)
708
462
  end
709
463
 
710
- def name
711
- reflected_string("name")
712
- end
713
-
714
- def name=(v)
715
- set_reflected_string("name", v)
716
- end
717
-
718
- def form_action
719
- reflected_string("formaction")
720
- end
721
-
722
- def form_enctype
723
- reflected_string("formenctype")
724
- end
725
-
726
- def form_method
727
- reflected_string("formmethod")
728
- end
729
-
730
- def form_target
731
- reflected_string("formtarget")
732
- end
733
-
734
- def form_no_validate
735
- reflected_boolean("formnovalidate")
736
- end
737
-
738
- def form_no_validate=(v)
739
- set_reflected_boolean("formnovalidate", v)
740
- end
741
-
742
464
  def form
743
465
  closest("form")
744
466
  end
@@ -779,18 +501,6 @@ module Dommy
779
501
  case key
780
502
  when "type"
781
503
  type
782
- when "name"
783
- name
784
- when "formAction"
785
- form_action
786
- when "formEnctype"
787
- form_enctype
788
- when "formMethod"
789
- form_method
790
- when "formTarget"
791
- form_target
792
- when "formNoValidate"
793
- form_no_validate
794
504
  when "form"
795
505
  form
796
506
  when "labels"
@@ -810,18 +520,6 @@ module Dommy
810
520
  case key
811
521
  when "type"
812
522
  set_reflected_string("type", value)
813
- when "name"
814
- set_reflected_string("name", value)
815
- when "formAction"
816
- set_reflected_string("formaction", value)
817
- when "formEnctype"
818
- set_reflected_string("formenctype", value)
819
- when "formMethod"
820
- set_reflected_string("formmethod", value)
821
- when "formTarget"
822
- set_reflected_string("formtarget", value)
823
- when "formNoValidate"
824
- set_reflected_boolean("formnovalidate", value)
825
523
  else
826
524
  super
827
525
  end
@@ -832,22 +530,7 @@ module Dommy
832
530
  # image loading, so `complete`/`naturalWidth`/`naturalHeight` are
833
531
  # static (complete=true, dimensions=0).
834
532
  class HTMLImageElement < HTMLElement
835
- def src
836
- reflected_string("src")
837
- end
838
-
839
- def src=(v)
840
- set_reflected_string("src", v)
841
- end
842
-
843
- def alt
844
- reflected_string("alt")
845
- end
846
-
847
- def alt=(v)
848
- set_reflected_string("alt", v)
849
- end
850
-
533
+ reflect_string :src, :alt, :decoding, :loading, :sizes, :srcset, crossorigin: { js: "crossOrigin" }, referrer_policy: "referrerpolicy"
851
534
  def width
852
535
  @__node__["width"].to_s.to_i
853
536
  end
@@ -864,30 +547,6 @@ module Dommy
864
547
  set_reflected_string("height", v.to_s)
865
548
  end
866
549
 
867
- def crossorigin
868
- reflected_string("crossorigin")
869
- end
870
-
871
- def decoding
872
- reflected_string("decoding")
873
- end
874
-
875
- def loading
876
- reflected_string("loading")
877
- end
878
-
879
- def referrer_policy
880
- reflected_string("referrerpolicy")
881
- end
882
-
883
- def sizes
884
- reflected_string("sizes")
885
- end
886
-
887
- def srcset
888
- reflected_string("srcset")
889
- end
890
-
891
550
  # No real loader → these are constants.
892
551
  def natural_width
893
552
  0
@@ -907,10 +566,6 @@ module Dommy
907
566
 
908
567
  def __js_get__(key)
909
568
  case key
910
- when "src"
911
- src
912
- when "alt"
913
- alt
914
569
  when "width"
915
570
  width
916
571
  when "height"
@@ -923,18 +578,6 @@ module Dommy
923
578
  complete
924
579
  when "currentSrc"
925
580
  current_src
926
- when "crossOrigin"
927
- crossorigin
928
- when "decoding"
929
- decoding
930
- when "loading"
931
- loading
932
- when "referrerPolicy"
933
- referrer_policy
934
- when "sizes"
935
- sizes
936
- when "srcset"
937
- srcset
938
581
  else
939
582
  super
940
583
  end
@@ -942,14 +585,8 @@ module Dommy
942
585
 
943
586
  def __js_set__(key, value)
944
587
  case key
945
- when "src", "alt", "decoding", "loading", "sizes", "srcset"
946
- set_reflected_string(key, value)
947
588
  when "width", "height"
948
589
  set_reflected_string(key, value.to_s)
949
- when "crossOrigin"
950
- set_reflected_string("crossorigin", value)
951
- when "referrerPolicy"
952
- set_reflected_string("referrerpolicy", value)
953
590
  else
954
591
  super
955
592
  end
@@ -958,58 +595,8 @@ module Dommy
958
595
 
959
596
  # `<script>` — `src` / `type` / `async` / `defer` / `text`.
960
597
  class HTMLScriptElement < HTMLElement
961
- def src
962
- reflected_string("src")
963
- end
964
-
965
- def src=(v)
966
- set_reflected_string("src", v)
967
- end
968
-
969
- def type
970
- reflected_string("type")
971
- end
972
-
973
- def type=(v)
974
- set_reflected_string("type", v)
975
- end
976
-
977
- def integrity
978
- reflected_string("integrity")
979
- end
980
-
981
- def nonce
982
- reflected_string("nonce")
983
- end
984
-
985
- def referrer_policy
986
- reflected_string("referrerpolicy")
987
- end
988
-
989
- def async
990
- reflected_boolean("async")
991
- end
992
-
993
- def async=(v)
994
- set_reflected_boolean("async", v)
995
- end
996
-
997
- def defer
998
- reflected_boolean("defer")
999
- end
1000
-
1001
- def defer=(v)
1002
- set_reflected_boolean("defer", v)
1003
- end
1004
-
1005
- def no_module
1006
- reflected_boolean("nomodule")
1007
- end
1008
-
1009
- def no_module=(v)
1010
- set_reflected_boolean("nomodule", v)
1011
- end
1012
-
598
+ reflect_string :src, :type, :integrity, :nonce, referrer_policy: "referrerpolicy"
599
+ reflect_boolean :async, :defer, no_module: "nomodule"
1013
600
  # `text` is an alias for textContent on <script>.
1014
601
  def text
1015
602
  text_content
@@ -1021,22 +608,6 @@ module Dommy
1021
608
 
1022
609
  def __js_get__(key)
1023
610
  case key
1024
- when "src"
1025
- src
1026
- when "type"
1027
- type
1028
- when "async"
1029
- async
1030
- when "defer"
1031
- defer
1032
- when "noModule"
1033
- no_module
1034
- when "integrity"
1035
- integrity
1036
- when "nonce"
1037
- nonce
1038
- when "referrerPolicy"
1039
- referrer_policy
1040
611
  when "text"
1041
612
  text
1042
613
  else
@@ -1046,16 +617,6 @@ module Dommy
1046
617
 
1047
618
  def __js_set__(key, value)
1048
619
  case key
1049
- when "src", "type", "integrity", "nonce"
1050
- set_reflected_string(key, value)
1051
- when "async"
1052
- set_reflected_boolean("async", value)
1053
- when "defer"
1054
- set_reflected_boolean("defer", value)
1055
- when "noModule"
1056
- set_reflected_boolean("nomodule", value)
1057
- when "referrerPolicy"
1058
- set_reflected_string("referrerpolicy", value)
1059
620
  when "text"
1060
621
  self.text_content = value
1061
622
  else
@@ -1066,58 +627,7 @@ module Dommy
1066
627
 
1067
628
  # `<link>` — primarily for stylesheets, icons, preload, manifests.
1068
629
  class HTMLLinkElement < HTMLElement
1069
- def href
1070
- reflected_string("href")
1071
- end
1072
-
1073
- def href=(v)
1074
- set_reflected_string("href", v)
1075
- end
1076
-
1077
- def rel
1078
- reflected_string("rel")
1079
- end
1080
-
1081
- def rel=(v)
1082
- set_reflected_string("rel", v)
1083
- end
1084
-
1085
- def type
1086
- reflected_string("type")
1087
- end
1088
-
1089
- def type=(v)
1090
- set_reflected_string("type", v)
1091
- end
1092
-
1093
- def media
1094
- reflected_string("media")
1095
- end
1096
-
1097
- def sizes
1098
- reflected_string("sizes")
1099
- end
1100
-
1101
- def hreflang
1102
- reflected_string("hreflang")
1103
- end
1104
-
1105
- def as_attr
1106
- reflected_string("as")
1107
- end
1108
-
1109
- def crossorigin
1110
- reflected_string("crossorigin")
1111
- end
1112
-
1113
- def integrity
1114
- reflected_string("integrity")
1115
- end
1116
-
1117
- def referrer_policy
1118
- reflected_string("referrerpolicy")
1119
- end
1120
-
630
+ reflect_string :href, :rel, :type, :media, :sizes, :hreflang, :integrity, as_attr: { attr: "as", js: "as" }, crossorigin: { js: "crossOrigin" }, referrer_policy: "referrerpolicy"
1121
631
  # `link.sheet` — non-nil only when this link is a stylesheet
1122
632
  # (`rel` contains "stylesheet"). The sheet itself is a stub:
1123
633
  # Dommy doesn't fetch or parse CSS, but consumers can still
@@ -1136,41 +646,11 @@ module Dommy
1136
646
 
1137
647
  def __js_get__(key)
1138
648
  case key
1139
- when "href"
1140
- href
1141
- when "rel"
1142
- rel
1143
- when "type"
1144
- type
1145
- when "media"
1146
- media
1147
- when "sizes"
1148
- sizes
1149
- when "hreflang"
1150
- hreflang
1151
- when "as"
1152
- as_attr
1153
- when "crossOrigin"
1154
- crossorigin
1155
- when "integrity"
1156
- integrity
1157
- when "referrerPolicy"
1158
- referrer_policy
1159
649
  when "sheet"
1160
650
  sheet
1161
- else
1162
- super
1163
- end
1164
- end
1165
-
1166
- def __js_set__(key, value)
1167
- case key
1168
- when "href", "rel", "type", "media", "sizes", "hreflang", "as", "integrity"
1169
- set_reflected_string(key, value)
1170
- when "crossOrigin"
1171
- set_reflected_string("crossorigin", value)
1172
- when "referrerPolicy"
1173
- set_reflected_string("referrerpolicy", value)
651
+ when "sizes"
652
+ # `link.sizes` is a DOMTokenList (`img`/`source` `sizes` stay strings).
653
+ reflected_token_list("sizes", "sizes")
1174
654
  else
1175
655
  super
1176
656
  end
@@ -1438,6 +918,7 @@ module Dommy
1438
918
 
1439
919
  # `<option>` — value, label, selected, disabled, text, index, form.
1440
920
  class HTMLOptionElement < HTMLElement
921
+ reflect_boolean :selected, :disabled
1441
922
  def value
1442
923
  # Per spec, value defaults to text content if the `value`
1443
924
  # attribute is absent.
@@ -1456,14 +937,6 @@ module Dommy
1456
937
  set_reflected_string("label", v)
1457
938
  end
1458
939
 
1459
- def selected
1460
- reflected_boolean("selected")
1461
- end
1462
-
1463
- def selected=(v)
1464
- set_reflected_boolean("selected", v)
1465
- end
1466
-
1467
940
  def default_selected
1468
941
  selected
1469
942
  end
@@ -1472,14 +945,6 @@ module Dommy
1472
945
  self.selected = v
1473
946
  end
1474
947
 
1475
- def disabled
1476
- reflected_boolean("disabled")
1477
- end
1478
-
1479
- def disabled=(v)
1480
- set_reflected_boolean("disabled", v)
1481
- end
1482
-
1483
948
  def text
1484
949
  text_content
1485
950
  end
@@ -1506,12 +971,8 @@ module Dommy
1506
971
  value
1507
972
  when "label"
1508
973
  label
1509
- when "selected"
1510
- selected
1511
974
  when "defaultSelected"
1512
975
  default_selected
1513
- when "disabled"
1514
- disabled
1515
976
  when "text"
1516
977
  text
1517
978
  when "form"
@@ -1531,8 +992,6 @@ module Dommy
1531
992
  self.label = v
1532
993
  when "selected", "defaultSelected"
1533
994
  self.selected = v
1534
- when "disabled"
1535
- self.disabled = v
1536
995
  when "text"
1537
996
  self.text = v
1538
997
  else
@@ -1543,86 +1002,29 @@ module Dommy
1543
1002
 
1544
1003
  # `<optgroup>` — label + disabled, container for options.
1545
1004
  class HTMLOptGroupElement < HTMLElement
1546
- def label
1547
- reflected_string("label")
1005
+ reflect_string :label
1006
+ reflect_boolean :disabled
1007
+ end
1008
+
1009
+ # `<textarea>` — multi-line text input.
1010
+ class HTMLTextAreaElement < HTMLElement
1011
+ reflect_string :name, :placeholder, :wrap, :autocomplete
1012
+ # Own __js_call__ methods, on top of Element's.
1013
+ def value
1014
+ @__node__["value"] || text_content
1548
1015
  end
1549
1016
 
1550
- def label=(v)
1551
- set_reflected_string("label", v)
1017
+ def value=(v)
1018
+ @__node__["value"] = v.to_s
1019
+ self.text_content = v.to_s
1552
1020
  end
1553
1021
 
1554
- def disabled
1555
- reflected_boolean("disabled")
1022
+ def default_value
1023
+ text_content
1556
1024
  end
1557
1025
 
1558
- def disabled=(v)
1559
- set_reflected_boolean("disabled", v)
1560
- end
1561
-
1562
- def __js_get__(key)
1563
- case key
1564
- when "label"
1565
- label
1566
- when "disabled"
1567
- disabled
1568
- else
1569
- super
1570
- end
1571
- end
1572
-
1573
- def __js_set__(key, v)
1574
- case key
1575
- when "label"
1576
- self.label = v
1577
- when "disabled"
1578
- self.disabled = v
1579
- else
1580
- super
1581
- end
1582
- end
1583
- end
1584
-
1585
- # `<textarea>` — multi-line text input.
1586
- class HTMLTextAreaElement < HTMLElement
1587
- # Own __js_call__ methods, on top of Element's.
1588
- JS_METHOD_NAMES = %w[
1589
- select setSelectionRange setRangeText checkValidity reportValidity setCustomValidity
1590
- ].freeze
1591
- def __js_method_names__
1592
- super + JS_METHOD_NAMES
1593
- end
1594
-
1595
- def value
1596
- @__node__["value"] || text_content
1597
- end
1598
-
1599
- def value=(v)
1600
- @__node__["value"] = v.to_s
1601
- self.text_content = v.to_s
1602
- end
1603
-
1604
- def default_value
1605
- text_content
1606
- end
1607
-
1608
- def default_value=(v)
1609
- self.text_content = v
1610
- end
1611
-
1612
- def name
1613
- reflected_string("name")
1614
- end
1615
-
1616
- def name=(v)
1617
- set_reflected_string("name", v)
1618
- end
1619
-
1620
- def placeholder
1621
- reflected_string("placeholder")
1622
- end
1623
-
1624
- def placeholder=(v)
1625
- set_reflected_string("placeholder", v)
1026
+ def default_value=(v)
1027
+ self.text_content = v
1626
1028
  end
1627
1029
 
1628
1030
  def rows
@@ -1641,10 +1043,6 @@ module Dommy
1641
1043
  set_reflected_string("cols", v.to_s)
1642
1044
  end
1643
1045
 
1644
- def wrap
1645
- reflected_string("wrap")
1646
- end
1647
-
1648
1046
  def max_length
1649
1047
  (@__node__["maxlength"] || "-1").to_i
1650
1048
  end
@@ -1657,10 +1055,6 @@ module Dommy
1657
1055
  value.length
1658
1056
  end
1659
1057
 
1660
- def autocomplete
1661
- reflected_string("autocomplete")
1662
- end
1663
-
1664
1058
  def type
1665
1059
  "textarea"
1666
1060
  end
@@ -1727,24 +1121,16 @@ module Dommy
1727
1121
  value
1728
1122
  when "defaultValue"
1729
1123
  default_value
1730
- when "name"
1731
- name
1732
- when "placeholder"
1733
- placeholder
1734
1124
  when "rows"
1735
1125
  rows
1736
1126
  when "cols"
1737
1127
  cols
1738
- when "wrap"
1739
- wrap
1740
1128
  when "maxLength"
1741
1129
  max_length
1742
1130
  when "minLength"
1743
1131
  min_length
1744
1132
  when "textLength"
1745
1133
  text_length
1746
- when "autocomplete"
1747
- autocomplete
1748
1134
  when "type"
1749
1135
  type
1750
1136
  when "form"
@@ -1768,16 +1154,10 @@ module Dommy
1768
1154
  self.value = v
1769
1155
  when "defaultValue"
1770
1156
  self.default_value = v
1771
- when "name"
1772
- set_reflected_string("name", v)
1773
- when "placeholder"
1774
- set_reflected_string("placeholder", v)
1775
1157
  when "rows"
1776
1158
  self.rows = v
1777
1159
  when "cols"
1778
1160
  self.cols = v
1779
- when "wrap"
1780
- set_reflected_string("wrap", v)
1781
1161
  when "maxLength"
1782
1162
  set_reflected_string("maxlength", v.to_s)
1783
1163
  when "minLength"
@@ -1787,6 +1167,9 @@ module Dommy
1787
1167
  end
1788
1168
  end
1789
1169
 
1170
+ js_methods %w[
1171
+ select setSelectionRange setRangeText checkValidity reportValidity setCustomValidity
1172
+ ]
1790
1173
  def __js_call__(method, args)
1791
1174
  case method
1792
1175
  when "select"
@@ -1811,14 +1194,7 @@ module Dommy
1811
1194
  # `<label>` — `htmlFor` IDL maps to the HTML `for` attribute;
1812
1195
  # `control` returns the labelled form control.
1813
1196
  class HTMLLabelElement < HTMLElement
1814
- def html_for
1815
- reflected_string("for")
1816
- end
1817
-
1818
- def html_for=(v)
1819
- set_reflected_string("for", v)
1820
- end
1821
-
1197
+ reflect_string html_for: "for"
1822
1198
  # `label.control` — the form control associated with this label.
1823
1199
  # Priority: explicit `for=`, then first form control descendant.
1824
1200
  def control
@@ -1836,8 +1212,6 @@ module Dommy
1836
1212
 
1837
1213
  def __js_get__(key)
1838
1214
  case key
1839
- when "htmlFor"
1840
- html_for
1841
1215
  when "control"
1842
1216
  control
1843
1217
  when "form"
@@ -1846,36 +1220,13 @@ module Dommy
1846
1220
  super
1847
1221
  end
1848
1222
  end
1849
-
1850
- def __js_set__(key, v)
1851
- case key
1852
- when "htmlFor"
1853
- self.html_for = v
1854
- else
1855
- super
1856
- end
1857
- end
1858
1223
  end
1859
1224
 
1860
1225
  # `<fieldset>` — disabled-state-propagating wrapper; exposes
1861
1226
  # `elements` collection like form.
1862
1227
  class HTMLFieldsetElement < HTMLElement
1863
- def name
1864
- reflected_string("name")
1865
- end
1866
-
1867
- def name=(v)
1868
- set_reflected_string("name", v)
1869
- end
1870
-
1871
- def disabled
1872
- reflected_boolean("disabled")
1873
- end
1874
-
1875
- def disabled=(v)
1876
- set_reflected_boolean("disabled", v)
1877
- end
1878
-
1228
+ reflect_string :name
1229
+ reflect_boolean :disabled
1879
1230
  def type
1880
1231
  "fieldset"
1881
1232
  end
@@ -1911,10 +1262,6 @@ module Dommy
1911
1262
 
1912
1263
  def __js_get__(key)
1913
1264
  case key
1914
- when "name"
1915
- name
1916
- when "disabled"
1917
- disabled
1918
1265
  when "type"
1919
1266
  type
1920
1267
  when "form"
@@ -1927,21 +1274,11 @@ module Dommy
1927
1274
  super
1928
1275
  end
1929
1276
  end
1930
-
1931
- def __js_set__(key, v)
1932
- case key
1933
- when "name"
1934
- self.name = v
1935
- when "disabled"
1936
- self.disabled = v
1937
- else
1938
- super
1939
- end
1940
- end
1941
1277
  end
1942
1278
 
1943
1279
  # `<output>` — calculation result element.
1944
1280
  class HTMLOutputElement < HTMLElement
1281
+ reflect_string :name
1945
1282
  def value
1946
1283
  text_content
1947
1284
  end
@@ -1958,14 +1295,6 @@ module Dommy
1958
1295
  self.text_content = v
1959
1296
  end
1960
1297
 
1961
- def name
1962
- reflected_string("name")
1963
- end
1964
-
1965
- def name=(v)
1966
- set_reflected_string("name", v)
1967
- end
1968
-
1969
1298
  # `for` attribute is a space-separated list of IDs.
1970
1299
  def html_for_tokens
1971
1300
  reflected_string("for").split(/\s+/).reject(&:empty?)
@@ -2003,8 +1332,6 @@ module Dommy
2003
1332
  value
2004
1333
  when "defaultValue"
2005
1334
  default_value
2006
- when "name"
2007
- name
2008
1335
  when "type"
2009
1336
  type
2010
1337
  when "form"
@@ -2014,7 +1341,8 @@ module Dommy
2014
1341
  when "validity"
2015
1342
  validity
2016
1343
  when "htmlFor"
2017
- reflected_string("for")
1344
+ # `output.htmlFor` is a DOMTokenList (unlike `label.htmlFor`, a string).
1345
+ reflected_token_list("htmlFor", "for")
2018
1346
  else
2019
1347
  super
2020
1348
  end
@@ -2026,8 +1354,6 @@ module Dommy
2026
1354
  self.value = v
2027
1355
  when "defaultValue"
2028
1356
  self.default_value = v
2029
- when "name"
2030
- self.name = v
2031
1357
  when "htmlFor"
2032
1358
  set_reflected_string("for", v)
2033
1359
  else
@@ -2054,19 +1380,8 @@ module Dommy
2054
1380
  # `slot` attribute go to the unnamed default slot. If nothing is
2055
1381
  # assigned, the slot's own children render as fallback content.
2056
1382
  class HTMLSlotElement < HTMLElement
1383
+ reflect_string :name
2057
1384
  # Own __js_call__ methods, on top of Element's.
2058
- JS_METHOD_NAMES = %w[assignedNodes assignedElements assign].freeze
2059
- def __js_method_names__
2060
- super + JS_METHOD_NAMES
2061
- end
2062
-
2063
- def name
2064
- reflected_string("name")
2065
- end
2066
-
2067
- def name=(v)
2068
- set_reflected_string("name", v)
2069
- end
2070
1385
 
2071
1386
  # `slot.assignedNodes({ flatten: true|false })` — returns the
2072
1387
  # light DOM children currently composed into this slot. With
@@ -2098,8 +1413,6 @@ module Dommy
2098
1413
 
2099
1414
  def __js_get__(key)
2100
1415
  case key
2101
- when "name"
2102
- name
2103
1416
  when "assignedNodes"
2104
1417
  assigned_nodes
2105
1418
  when "assignedElements"
@@ -2109,15 +1422,7 @@ module Dommy
2109
1422
  end
2110
1423
  end
2111
1424
 
2112
- def __js_set__(key, value)
2113
- case key
2114
- when "name"
2115
- self.name = value
2116
- else
2117
- super
2118
- end
2119
- end
2120
-
1425
+ js_methods %w[assignedNodes assignedElements assign]
2121
1426
  def __js_call__(method, args)
2122
1427
  case method
2123
1428
  when "assignedNodes"
@@ -2168,27 +1473,9 @@ module Dommy
2168
1473
  # `selectedIndex`, and dispatches change events. Minimal compared to
2169
1474
  # happy-dom's full HTMLSelectElement, but covers common test cases.
2170
1475
  class HTMLSelectElement < HTMLElement
1476
+ reflect_string :name
1477
+ reflect_boolean :multiple
2171
1478
  # Own __js_call__ methods, on top of Element's.
2172
- JS_METHOD_NAMES = %w[item add checkValidity reportValidity setCustomValidity].freeze
2173
- def __js_method_names__
2174
- super + JS_METHOD_NAMES
2175
- end
2176
-
2177
- def name
2178
- reflected_string("name")
2179
- end
2180
-
2181
- def name=(v)
2182
- set_reflected_string("name", v)
2183
- end
2184
-
2185
- def multiple
2186
- reflected_boolean("multiple")
2187
- end
2188
-
2189
- def multiple=(v)
2190
- set_reflected_boolean("multiple", v)
2191
- end
2192
1479
 
2193
1480
  def size
2194
1481
  @__node__["size"].to_s.to_i
@@ -2340,10 +1627,6 @@ module Dommy
2340
1627
  length
2341
1628
  when "value"
2342
1629
  value
2343
- when "name"
2344
- name
2345
- when "multiple"
2346
- multiple
2347
1630
  when "size"
2348
1631
  size
2349
1632
  when "selectedIndex"
@@ -2369,10 +1652,6 @@ module Dommy
2369
1652
  case key
2370
1653
  when "value"
2371
1654
  self.value = val
2372
- when "name"
2373
- set_reflected_string("name", val)
2374
- when "multiple"
2375
- set_reflected_boolean("multiple", val)
2376
1655
  when "selectedIndex"
2377
1656
  self.selected_index = val
2378
1657
  else
@@ -2380,6 +1659,7 @@ module Dommy
2380
1659
  end
2381
1660
  end
2382
1661
 
1662
+ js_methods %w[item add checkValidity reportValidity setCustomValidity]
2383
1663
  def __js_call__(method, args)
2384
1664
  case method
2385
1665
  when "item"
@@ -2402,19 +1682,8 @@ module Dommy
2402
1682
  # `close(returnValue?)`. Dommy has no modal stack, so showModal is
2403
1683
  # functionally identical to show (no backdrop, no escape-to-close).
2404
1684
  class HTMLDialogElement < HTMLElement
1685
+ reflect_boolean :open
2405
1686
  # Own __js_call__ methods, on top of Element's.
2406
- JS_METHOD_NAMES = %w[show showModal close].freeze
2407
- def __js_method_names__
2408
- super + JS_METHOD_NAMES
2409
- end
2410
-
2411
- def open
2412
- reflected_boolean("open")
2413
- end
2414
-
2415
- def open=(v)
2416
- set_reflected_boolean("open", v)
2417
- end
2418
1687
 
2419
1688
  def return_value
2420
1689
  @return_value ||= ""
@@ -2443,8 +1712,6 @@ module Dommy
2443
1712
 
2444
1713
  def __js_get__(key)
2445
1714
  case key
2446
- when "open"
2447
- open
2448
1715
  when "returnValue"
2449
1716
  return_value
2450
1717
  else
@@ -2454,8 +1721,6 @@ module Dommy
2454
1721
 
2455
1722
  def __js_set__(key, value)
2456
1723
  case key
2457
- when "open"
2458
- self.open = value
2459
1724
  when "returnValue"
2460
1725
  self.return_value = value
2461
1726
  else
@@ -2463,6 +1728,7 @@ module Dommy
2463
1728
  end
2464
1729
  end
2465
1730
 
1731
+ js_methods %w[show showModal close]
2466
1732
  def __js_call__(method, args)
2467
1733
  case method
2468
1734
  when "show"
@@ -2689,6 +1955,7 @@ module Dommy
2689
1955
  # `<td>` / `<th>` — single table cell. `cellIndex` is the
2690
1956
  # position within the parent row's cells collection.
2691
1957
  class HTMLTableCellElement < HTMLElement
1958
+ reflect_string :headers, :scope, :abbr
2692
1959
  def cell_index
2693
1960
  row = closest("tr")
2694
1961
  return -1 unless row
@@ -2712,31 +1979,8 @@ module Dommy
2712
1979
  set_reflected_string("rowspan", v.to_s)
2713
1980
  end
2714
1981
 
2715
- def headers
2716
- reflected_string("headers")
2717
- end
2718
-
2719
- def headers=(v)
2720
- set_reflected_string("headers", v)
2721
- end
2722
-
2723
1982
  # `scope` / `abbr` are only meaningful on `<th>`, but the IDL
2724
1983
  # exposes them on the cell element either way.
2725
- def scope
2726
- reflected_string("scope")
2727
- end
2728
-
2729
- def scope=(v)
2730
- set_reflected_string("scope", v)
2731
- end
2732
-
2733
- def abbr
2734
- reflected_string("abbr")
2735
- end
2736
-
2737
- def abbr=(v)
2738
- set_reflected_string("abbr", v)
2739
- end
2740
1984
 
2741
1985
  def __js_get__(key)
2742
1986
  case key
@@ -2746,12 +1990,6 @@ module Dommy
2746
1990
  col_span
2747
1991
  when "rowSpan"
2748
1992
  row_span
2749
- when "headers"
2750
- headers
2751
- when "scope"
2752
- scope
2753
- when "abbr"
2754
- abbr
2755
1993
  else
2756
1994
  super
2757
1995
  end
@@ -2763,12 +2001,6 @@ module Dommy
2763
2001
  self.col_span = value
2764
2002
  when "rowSpan"
2765
2003
  self.row_span = value
2766
- when "headers"
2767
- self.headers = value
2768
- when "scope"
2769
- self.scope = value
2770
- when "abbr"
2771
- self.abbr = value
2772
2004
  else
2773
2005
  super
2774
2006
  end
@@ -2780,11 +2012,6 @@ module Dommy
2780
2012
  # the enclosing thead/tbody/tfoot.
2781
2013
  class HTMLTableRowElement < HTMLElement
2782
2014
  # Own __js_call__ methods, on top of Element's.
2783
- JS_METHOD_NAMES = %w[insertCell deleteCell].freeze
2784
- def __js_method_names__
2785
- super + JS_METHOD_NAMES
2786
- end
2787
-
2788
2015
  def cells
2789
2016
  el = self
2790
2017
  HTMLCollection.new do
@@ -2844,6 +2071,7 @@ module Dommy
2844
2071
  end
2845
2072
  end
2846
2073
 
2074
+ js_methods %w[insertCell deleteCell]
2847
2075
  def __js_call__(method, args)
2848
2076
  case method
2849
2077
  when "insertCell"
@@ -2860,11 +2088,6 @@ module Dommy
2860
2088
  # collection + insertRow / deleteRow.
2861
2089
  class HTMLTableSectionElement < HTMLElement
2862
2090
  # Own __js_call__ methods, on top of Element's.
2863
- JS_METHOD_NAMES = %w[insertRow deleteRow].freeze
2864
- def __js_method_names__
2865
- super + JS_METHOD_NAMES
2866
- end
2867
-
2868
2091
  def rows
2869
2092
  el = self
2870
2093
  HTMLCollection.new do
@@ -2898,6 +2121,7 @@ module Dommy
2898
2121
  key == "rows" ? rows : super
2899
2122
  end
2900
2123
 
2124
+ js_methods %w[insertRow deleteRow]
2901
2125
  def __js_call__(method, args)
2902
2126
  case method
2903
2127
  when "insertRow"
@@ -2920,14 +2144,6 @@ module Dommy
2920
2144
  # creates one); `deleteRow` works against the merged `rows` list.
2921
2145
  class HTMLTableElement < HTMLElement
2922
2146
  # Own __js_call__ methods, on top of Element's.
2923
- JS_METHOD_NAMES = %w[
2924
- insertRow deleteRow createCaption deleteCaption createTHead deleteTHead
2925
- createTFoot deleteTFoot createTBody
2926
- ].freeze
2927
- def __js_method_names__
2928
- super + JS_METHOD_NAMES
2929
- end
2930
-
2931
2147
  def caption
2932
2148
  @__node__.element_children.find { |n| n.name == "caption" }&.then { |n| @document.wrap_node(n) }
2933
2149
  end
@@ -3098,6 +2314,10 @@ module Dommy
3098
2314
  end
3099
2315
  end
3100
2316
 
2317
+ js_methods %w[
2318
+ insertRow deleteRow createCaption deleteCaption createTHead deleteTHead createTFoot
2319
+ deleteTFoot createTBody
2320
+ ]
3101
2321
  def __js_call__(method, args)
3102
2322
  case method
3103
2323
  when "insertRow"
@@ -3128,12 +2348,9 @@ module Dommy
3128
2348
  # absent in Dommy — getters return inert values, `play()` returns
3129
2349
  # a resolved Promise, and `pause()` flips `paused` back to true.
3130
2350
  class HTMLMediaElement < HTMLElement
2351
+ reflect_string :src, :preload, crossorigin: { js: "crossOrigin" }
2352
+ reflect_boolean :autoplay, :controls, loop_: { attr: "loop", js: "loop" }, default_muted: "muted"
3131
2353
  # Own __js_call__ methods, on top of Element's.
3132
- JS_METHOD_NAMES = %w[play pause load canPlayType].freeze
3133
- def __js_method_names__
3134
- super + JS_METHOD_NAMES
3135
- end
3136
-
3137
2354
  NETWORK_EMPTY = 0
3138
2355
  NETWORK_IDLE = 1
3139
2356
  NETWORK_LOADING = 2
@@ -3145,54 +2362,10 @@ module Dommy
3145
2362
  HAVE_FUTURE_DATA = 3
3146
2363
  HAVE_ENOUGH_DATA = 4
3147
2364
 
3148
- def src
3149
- reflected_string("src")
3150
- end
3151
-
3152
- def src=(v)
3153
- set_reflected_string("src", v)
3154
- end
3155
-
3156
2365
  def current_src
3157
2366
  src
3158
2367
  end
3159
2368
 
3160
- def preload
3161
- reflected_string("preload")
3162
- end
3163
-
3164
- def preload=(v)
3165
- set_reflected_string("preload", v)
3166
- end
3167
-
3168
- def crossorigin
3169
- reflected_string("crossorigin")
3170
- end
3171
-
3172
- def autoplay
3173
- reflected_boolean("autoplay")
3174
- end
3175
-
3176
- def autoplay=(v)
3177
- set_reflected_boolean("autoplay", v)
3178
- end
3179
-
3180
- def loop_
3181
- reflected_boolean("loop")
3182
- end
3183
-
3184
- def loop_=(v)
3185
- set_reflected_boolean("loop", v)
3186
- end
3187
-
3188
- def controls
3189
- reflected_boolean("controls")
3190
- end
3191
-
3192
- def controls=(v)
3193
- set_reflected_boolean("controls", v)
3194
- end
3195
-
3196
2369
  def muted
3197
2370
  @__muted == true || reflected_boolean("muted")
3198
2371
  end
@@ -3201,14 +2374,6 @@ module Dommy
3201
2374
  @__muted = !!v
3202
2375
  end
3203
2376
 
3204
- def default_muted
3205
- reflected_boolean("muted")
3206
- end
3207
-
3208
- def default_muted=(v)
3209
- set_reflected_boolean("muted", v)
3210
- end
3211
-
3212
2377
  def paused
3213
2378
  @__paused.nil? ? true : @__paused
3214
2379
  end
@@ -3288,24 +2453,10 @@ module Dommy
3288
2453
 
3289
2454
  def __js_get__(key)
3290
2455
  case key
3291
- when "src"
3292
- src
3293
2456
  when "currentSrc"
3294
2457
  current_src
3295
- when "preload"
3296
- preload
3297
- when "crossOrigin"
3298
- crossorigin
3299
- when "autoplay"
3300
- autoplay
3301
- when "loop"
3302
- loop_
3303
- when "controls"
3304
- controls
3305
2458
  when "muted"
3306
2459
  muted
3307
- when "defaultMuted"
3308
- default_muted
3309
2460
  when "paused"
3310
2461
  paused
3311
2462
  when "ended"
@@ -3351,20 +2502,8 @@ module Dommy
3351
2502
 
3352
2503
  def __js_set__(key, value)
3353
2504
  case key
3354
- when "src"
3355
- self.src = value
3356
- when "preload"
3357
- self.preload = value
3358
- when "autoplay"
3359
- self.autoplay = value
3360
- when "loop"
3361
- self.loop_ = value
3362
- when "controls"
3363
- self.controls = value
3364
2505
  when "muted"
3365
2506
  self.muted = value
3366
- when "defaultMuted"
3367
- self.default_muted = value
3368
2507
  when "volume"
3369
2508
  self.volume = value
3370
2509
  when "playbackRate"
@@ -3378,6 +2517,7 @@ module Dommy
3378
2517
  end
3379
2518
  end
3380
2519
 
2520
+ js_methods %w[play pause load canPlayType]
3381
2521
  def __js_call__(method, args)
3382
2522
  case method
3383
2523
  when "play"
@@ -3398,14 +2538,8 @@ module Dommy
3398
2538
  end
3399
2539
 
3400
2540
  class HTMLVideoElement < HTMLMediaElement
3401
- def poster
3402
- reflected_string("poster")
3403
- end
3404
-
3405
- def poster=(v)
3406
- set_reflected_string("poster", v)
3407
- end
3408
-
2541
+ reflect_string :poster
2542
+ reflect_boolean plays_inline: "playsinline"
3409
2543
  def width
3410
2544
  @__node__["width"].to_s.to_i
3411
2545
  end
@@ -3430,18 +2564,8 @@ module Dommy
3430
2564
  height
3431
2565
  end
3432
2566
 
3433
- def plays_inline
3434
- reflected_boolean("playsinline")
3435
- end
3436
-
3437
- def plays_inline=(v)
3438
- set_reflected_boolean("playsinline", v)
3439
- end
3440
-
3441
2567
  def __js_get__(key)
3442
2568
  case key
3443
- when "poster"
3444
- poster
3445
2569
  when "width"
3446
2570
  width
3447
2571
  when "height"
@@ -3450,8 +2574,6 @@ module Dommy
3450
2574
  video_width
3451
2575
  when "videoHeight"
3452
2576
  video_height
3453
- when "playsInline"
3454
- plays_inline
3455
2577
  else
3456
2578
  super
3457
2579
  end
@@ -3459,14 +2581,10 @@ module Dommy
3459
2581
 
3460
2582
  def __js_set__(key, value)
3461
2583
  case key
3462
- when "poster"
3463
- self.poster = value
3464
2584
  when "width"
3465
2585
  self.width = value
3466
2586
  when "height"
3467
2587
  self.height = value
3468
- when "playsInline"
3469
- self.plays_inline = value
3470
2588
  else
3471
2589
  super
3472
2590
  end
@@ -3474,46 +2592,7 @@ module Dommy
3474
2592
  end
3475
2593
 
3476
2594
  class HTMLSourceElement < HTMLElement
3477
- def src
3478
- reflected_string("src")
3479
- end
3480
-
3481
- def src=(v)
3482
- set_reflected_string("src", v)
3483
- end
3484
-
3485
- def type
3486
- reflected_string("type")
3487
- end
3488
-
3489
- def type=(v)
3490
- set_reflected_string("type", v)
3491
- end
3492
-
3493
- def media
3494
- reflected_string("media")
3495
- end
3496
-
3497
- def media=(v)
3498
- set_reflected_string("media", v)
3499
- end
3500
-
3501
- def srcset
3502
- reflected_string("srcset")
3503
- end
3504
-
3505
- def srcset=(v)
3506
- set_reflected_string("srcset", v)
3507
- end
3508
-
3509
- def sizes
3510
- reflected_string("sizes")
3511
- end
3512
-
3513
- def sizes=(v)
3514
- set_reflected_string("sizes", v)
3515
- end
3516
-
2595
+ reflect_string :src, :type, :media, :srcset, :sizes
3517
2596
  def width
3518
2597
  @__node__["width"].to_s.to_i
3519
2598
  end
@@ -3532,16 +2611,6 @@ module Dommy
3532
2611
 
3533
2612
  def __js_get__(key)
3534
2613
  case key
3535
- when "src"
3536
- src
3537
- when "type"
3538
- type
3539
- when "media"
3540
- media
3541
- when "srcset"
3542
- srcset
3543
- when "sizes"
3544
- sizes
3545
2614
  when "width"
3546
2615
  width
3547
2616
  when "height"
@@ -3553,8 +2622,6 @@ module Dommy
3553
2622
 
3554
2623
  def __js_set__(key, value)
3555
2624
  case key
3556
- when "src", "type", "media", "srcset", "sizes"
3557
- set_reflected_string(key, value)
3558
2625
  when "width"
3559
2626
  self.width = value
3560
2627
  when "height"
@@ -3566,151 +2633,30 @@ module Dommy
3566
2633
  end
3567
2634
 
3568
2635
  class HTMLTrackElement < HTMLElement
2636
+ reflect_string :kind, :src, :srclang, :label
2637
+ reflect_boolean default_: { attr: "default", js: "default" }
3569
2638
  NONE = 0
3570
2639
  LOADING = 1
3571
2640
  LOADED = 2
3572
2641
  ERROR = 3
3573
2642
 
3574
- def kind
3575
- reflected_string("kind")
3576
- end
3577
-
3578
- def kind=(v)
3579
- set_reflected_string("kind", v)
3580
- end
3581
-
3582
- def src
3583
- reflected_string("src")
3584
- end
3585
-
3586
- def src=(v)
3587
- set_reflected_string("src", v)
3588
- end
3589
-
3590
- def srclang
3591
- reflected_string("srclang")
3592
- end
3593
-
3594
- def srclang=(v)
3595
- set_reflected_string("srclang", v)
3596
- end
3597
-
3598
- def label
3599
- reflected_string("label")
3600
- end
3601
-
3602
- def label=(v)
3603
- set_reflected_string("label", v)
3604
- end
3605
-
3606
- def default_
3607
- reflected_boolean("default")
3608
- end
3609
-
3610
- def default_=(v)
3611
- set_reflected_boolean("default", v)
3612
- end
3613
-
3614
2643
  def ready_state
3615
2644
  NONE
3616
2645
  end
3617
2646
 
3618
2647
  def __js_get__(key)
3619
2648
  case key
3620
- when "kind"
3621
- kind
3622
- when "src"
3623
- src
3624
- when "srclang"
3625
- srclang
3626
- when "label"
3627
- label
3628
- when "default"
3629
- default_
3630
2649
  when "readyState"
3631
2650
  ready_state
3632
2651
  else
3633
2652
  super
3634
2653
  end
3635
2654
  end
3636
-
3637
- def __js_set__(key, value)
3638
- case key
3639
- when "kind", "src", "srclang", "label"
3640
- set_reflected_string(key, value)
3641
- when "default"
3642
- self.default_ = value
3643
- else
3644
- super
3645
- end
3646
- end
3647
2655
  end
3648
2656
 
3649
2657
  class HTMLIFrameElement < HTMLElement
3650
- def src
3651
- reflected_string("src")
3652
- end
3653
-
3654
- def src=(v)
3655
- set_reflected_string("src", v)
3656
- end
3657
-
3658
- def srcdoc
3659
- reflected_string("srcdoc")
3660
- end
3661
-
3662
- def srcdoc=(v)
3663
- set_reflected_string("srcdoc", v)
3664
- end
3665
-
3666
- def name
3667
- reflected_string("name")
3668
- end
3669
-
3670
- def name=(v)
3671
- set_reflected_string("name", v)
3672
- end
3673
-
3674
- def sandbox
3675
- reflected_string("sandbox")
3676
- end
3677
-
3678
- def sandbox=(v)
3679
- set_reflected_string("sandbox", v)
3680
- end
3681
-
3682
- def allow
3683
- reflected_string("allow")
3684
- end
3685
-
3686
- def allow=(v)
3687
- set_reflected_string("allow", v)
3688
- end
3689
-
3690
- def allow_fullscreen
3691
- reflected_boolean("allowfullscreen")
3692
- end
3693
-
3694
- def allow_fullscreen=(v)
3695
- set_reflected_boolean("allowfullscreen", v)
3696
- end
3697
-
3698
- def referrer_policy
3699
- reflected_string("referrerpolicy")
3700
- end
3701
-
3702
- def referrer_policy=(v)
3703
- set_reflected_string("referrerpolicy", v)
3704
- end
3705
-
3706
- def loading
3707
- reflected_string("loading")
3708
- end
3709
-
3710
- def loading=(v)
3711
- set_reflected_string("loading", v)
3712
- end
3713
-
2658
+ reflect_string :src, :srcdoc, :name, :sandbox, :allow, :loading, referrer_policy: "referrerpolicy"
2659
+ reflect_boolean allow_fullscreen: "allowfullscreen"
3714
2660
  def width
3715
2661
  @__node__["width"].to_s
3716
2662
  end
@@ -3727,32 +2673,23 @@ module Dommy
3727
2673
  set_reflected_string("height", v.to_s)
3728
2674
  end
3729
2675
 
2676
+ # Dommy doesn't navigate iframes itself, but an integration/test layer can
2677
+ # populate the nested browsing context's document (e.g. parsing the `src`
2678
+ # resource) via `__internal_set_content_document__`.
3730
2679
  def content_document
3731
- nil
2680
+ @content_document
2681
+ end
2682
+
2683
+ def __internal_set_content_document__(doc)
2684
+ @content_document = doc
3732
2685
  end
3733
2686
 
3734
2687
  def content_window
3735
- nil
2688
+ @content_document&.default_view
3736
2689
  end
3737
2690
 
3738
2691
  def __js_get__(key)
3739
2692
  case key
3740
- when "src"
3741
- src
3742
- when "srcdoc"
3743
- srcdoc
3744
- when "name"
3745
- name
3746
- when "sandbox"
3747
- sandbox
3748
- when "allow"
3749
- allow
3750
- when "allowFullscreen"
3751
- allow_fullscreen
3752
- when "referrerPolicy"
3753
- referrer_policy
3754
- when "loading"
3755
- loading
3756
2693
  when "width"
3757
2694
  width
3758
2695
  when "height"
@@ -3761,6 +2698,11 @@ module Dommy
3761
2698
  content_document
3762
2699
  when "contentWindow"
3763
2700
  content_window
2701
+ when "sandbox"
2702
+ # JS-side `iframe.sandbox` is a DOMTokenList (the Ruby `#sandbox` string
2703
+ # accessor from reflect_string is kept for internal use). Non-iframe
2704
+ # frame elements get undefined via the element/namespace check.
2705
+ reflected_token_list("sandbox", "sandbox")
3764
2706
  else
3765
2707
  super
3766
2708
  end
@@ -3768,12 +2710,6 @@ module Dommy
3768
2710
 
3769
2711
  def __js_set__(key, value)
3770
2712
  case key
3771
- when "src", "srcdoc", "name", "sandbox", "allow", "loading"
3772
- set_reflected_string(key, value)
3773
- when "allowFullscreen"
3774
- self.allow_fullscreen = value
3775
- when "referrerPolicy"
3776
- set_reflected_string("referrerpolicy", value)
3777
2713
  when "width"
3778
2714
  self.width = value
3779
2715
  when "height"
@@ -3788,6 +2724,8 @@ module Dommy
3788
2724
  end
3789
2725
 
3790
2726
  class HTMLOListElement < HTMLElement
2727
+ reflect_string :type
2728
+ reflect_boolean :reversed
3791
2729
  def start
3792
2730
  (@__node__["start"] || "1").to_i
3793
2731
  end
@@ -3796,30 +2734,10 @@ module Dommy
3796
2734
  set_reflected_string("start", v.to_s)
3797
2735
  end
3798
2736
 
3799
- def reversed
3800
- reflected_boolean("reversed")
3801
- end
3802
-
3803
- def reversed=(v)
3804
- set_reflected_boolean("reversed", v)
3805
- end
3806
-
3807
- def type
3808
- reflected_string("type")
3809
- end
3810
-
3811
- def type=(v)
3812
- set_reflected_string("type", v)
3813
- end
3814
-
3815
2737
  def __js_get__(key)
3816
2738
  case key
3817
2739
  when "start"
3818
2740
  start
3819
- when "reversed"
3820
- reversed
3821
- when "type"
3822
- type
3823
2741
  else
3824
2742
  super
3825
2743
  end
@@ -3829,10 +2747,6 @@ module Dommy
3829
2747
  case key
3830
2748
  when "start"
3831
2749
  self.start = value
3832
- when "reversed"
3833
- self.reversed = value
3834
- when "type"
3835
- self.type = value
3836
2750
  else
3837
2751
  super
3838
2752
  end
@@ -3861,128 +2775,19 @@ module Dommy
3861
2775
  end
3862
2776
 
3863
2777
  class HTMLTimeElement < HTMLElement
3864
- def date_time
3865
- reflected_string("datetime")
3866
- end
3867
-
3868
- def date_time=(v)
3869
- set_reflected_string("datetime", v)
3870
- end
3871
-
3872
- def __js_get__(key)
3873
- key == "dateTime" ? date_time : super
3874
- end
3875
-
3876
- def __js_set__(key, value)
3877
- key == "dateTime" ? (self.date_time = value) : super
3878
- end
2778
+ reflect_string date_time: "datetime"
3879
2779
  end
3880
2780
 
3881
2781
  class HTMLDataElement < HTMLElement
3882
- def value
3883
- reflected_string("value")
3884
- end
3885
-
3886
- def value=(v)
3887
- set_reflected_string("value", v)
3888
- end
3889
-
3890
- def __js_get__(key)
3891
- key == "value" ? value : super
3892
- end
3893
-
3894
- def __js_set__(key, value)
3895
- key == "value" ? (self.value = value) : super
3896
- end
2782
+ reflect_string :value
3897
2783
  end
3898
2784
 
3899
2785
  class HTMLAreaElement < HTMLElement
3900
- def alt
3901
- reflected_string("alt")
3902
- end
3903
-
3904
- def alt=(v)
3905
- set_reflected_string("alt", v)
3906
- end
3907
-
3908
- def coords
3909
- reflected_string("coords")
3910
- end
3911
-
3912
- def coords=(v)
3913
- set_reflected_string("coords", v)
3914
- end
3915
-
3916
- def shape
3917
- reflected_string("shape")
3918
- end
3919
-
3920
- def shape=(v)
3921
- set_reflected_string("shape", v)
3922
- end
3923
-
3924
- def href
3925
- reflected_string("href")
3926
- end
3927
-
3928
- def href=(v)
3929
- set_reflected_string("href", v)
3930
- end
3931
-
3932
- def target
3933
- reflected_string("target")
3934
- end
3935
-
3936
- def target=(v)
3937
- set_reflected_string("target", v)
3938
- end
3939
-
3940
- def rel
3941
- reflected_string("rel")
3942
- end
3943
-
3944
- def rel=(v)
3945
- set_reflected_string("rel", v)
3946
- end
3947
-
3948
- def __js_get__(key)
3949
- case key
3950
- when "alt"
3951
- alt
3952
- when "coords"
3953
- coords
3954
- when "shape"
3955
- shape
3956
- when "href"
3957
- href
3958
- when "target"
3959
- target
3960
- when "rel"
3961
- rel
3962
- else
3963
- super
3964
- end
3965
- end
3966
-
3967
- def __js_set__(key, value)
3968
- case key
3969
- when "alt", "coords", "shape", "href", "target", "rel"
3970
- set_reflected_string(key, value)
3971
- else
3972
- super
3973
- end
3974
- end
2786
+ reflect_string :alt, :coords, :shape, :href, :target, :rel
3975
2787
  end
3976
2788
 
3977
2789
  class HTMLMapElement < HTMLElement
3978
- def name
3979
- reflected_string("name")
3980
- end
3981
-
3982
- def name=(v)
3983
- set_reflected_string("name", v)
3984
- end
3985
-
2790
+ reflect_string :name
3986
2791
  def areas
3987
2792
  HTMLCollection.new do
3988
2793
  @__node__.css("area").map { |n| @document.wrap_node(n) }.compact
@@ -3991,8 +2796,6 @@ module Dommy
3991
2796
 
3992
2797
  def __js_get__(key)
3993
2798
  case key
3994
- when "name"
3995
- name
3996
2799
  when "areas"
3997
2800
  areas
3998
2801
  else
@@ -4006,38 +2809,7 @@ module Dommy
4006
2809
  end
4007
2810
 
4008
2811
  class HTMLObjectElement < HTMLElement
4009
- def data
4010
- reflected_string("data")
4011
- end
4012
-
4013
- def data=(v)
4014
- set_reflected_string("data", v)
4015
- end
4016
-
4017
- def type
4018
- reflected_string("type")
4019
- end
4020
-
4021
- def type=(v)
4022
- set_reflected_string("type", v)
4023
- end
4024
-
4025
- def name
4026
- reflected_string("name")
4027
- end
4028
-
4029
- def name=(v)
4030
- set_reflected_string("name", v)
4031
- end
4032
-
4033
- def use_map
4034
- reflected_string("usemap")
4035
- end
4036
-
4037
- def use_map=(v)
4038
- set_reflected_string("usemap", v)
4039
- end
4040
-
2812
+ reflect_string :data, :type, :name, use_map: "usemap"
4041
2813
  def width
4042
2814
  @__node__["width"].to_s
4043
2815
  end
@@ -4064,14 +2836,6 @@ module Dommy
4064
2836
 
4065
2837
  def __js_get__(key)
4066
2838
  case key
4067
- when "data"
4068
- data
4069
- when "type"
4070
- type
4071
- when "name"
4072
- name
4073
- when "useMap"
4074
- use_map
4075
2839
  when "width"
4076
2840
  width
4077
2841
  when "height"
@@ -4080,6 +2844,11 @@ module Dommy
4080
2844
  content_document
4081
2845
  when "contentWindow"
4082
2846
  content_window
2847
+ when "sandbox"
2848
+ # JS-side `iframe.sandbox` is a DOMTokenList (the Ruby `#sandbox` string
2849
+ # accessor from reflect_string is kept for internal use). Non-iframe
2850
+ # frame elements get undefined via the element/namespace check.
2851
+ reflected_token_list("sandbox", "sandbox")
4083
2852
  else
4084
2853
  super
4085
2854
  end
@@ -4087,10 +2856,6 @@ module Dommy
4087
2856
 
4088
2857
  def __js_set__(key, value)
4089
2858
  case key
4090
- when "data", "type", "name"
4091
- set_reflected_string(key, value)
4092
- when "useMap"
4093
- set_reflected_string("usemap", value)
4094
2859
  when "width"
4095
2860
  self.width = value
4096
2861
  when "height"
@@ -4102,22 +2867,7 @@ module Dommy
4102
2867
  end
4103
2868
 
4104
2869
  class HTMLEmbedElement < HTMLElement
4105
- def src
4106
- reflected_string("src")
4107
- end
4108
-
4109
- def src=(v)
4110
- set_reflected_string("src", v)
4111
- end
4112
-
4113
- def type
4114
- reflected_string("type")
4115
- end
4116
-
4117
- def type=(v)
4118
- set_reflected_string("type", v)
4119
- end
4120
-
2870
+ reflect_string :src, :type
4121
2871
  def width
4122
2872
  @__node__["width"].to_s
4123
2873
  end
@@ -4136,10 +2886,6 @@ module Dommy
4136
2886
 
4137
2887
  def __js_get__(key)
4138
2888
  case key
4139
- when "src"
4140
- src
4141
- when "type"
4142
- type
4143
2889
  when "width"
4144
2890
  width
4145
2891
  when "height"
@@ -4151,8 +2897,6 @@ module Dommy
4151
2897
 
4152
2898
  def __js_set__(key, value)
4153
2899
  case key
4154
- when "src", "type"
4155
- set_reflected_string(key, value)
4156
2900
  when "width"
4157
2901
  self.width = value
4158
2902
  when "height"
@@ -4164,120 +2908,15 @@ module Dommy
4164
2908
  end
4165
2909
 
4166
2910
  class HTMLBaseElement < HTMLElement
4167
- def href
4168
- reflected_string("href")
4169
- end
4170
-
4171
- def href=(v)
4172
- set_reflected_string("href", v)
4173
- end
4174
-
4175
- def target
4176
- reflected_string("target")
4177
- end
4178
-
4179
- def target=(v)
4180
- set_reflected_string("target", v)
4181
- end
4182
-
4183
- def __js_get__(key)
4184
- case key
4185
- when "href"
4186
- href
4187
- when "target"
4188
- target
4189
- else
4190
- super
4191
- end
4192
- end
4193
-
4194
- def __js_set__(key, value)
4195
- case key
4196
- when "href", "target"
4197
- set_reflected_string(key, value)
4198
- else
4199
- super
4200
- end
4201
- end
2911
+ reflect_string :href, :target
4202
2912
  end
4203
2913
 
4204
2914
  class HTMLMetaElement < HTMLElement
4205
- def name
4206
- reflected_string("name")
4207
- end
4208
-
4209
- def name=(v)
4210
- set_reflected_string("name", v)
4211
- end
4212
-
4213
- def content
4214
- reflected_string("content")
4215
- end
4216
-
4217
- def content=(v)
4218
- set_reflected_string("content", v)
4219
- end
4220
-
4221
- def charset
4222
- reflected_string("charset")
4223
- end
4224
-
4225
- def charset=(v)
4226
- set_reflected_string("charset", v)
4227
- end
4228
-
4229
- def http_equiv
4230
- reflected_string("http-equiv")
4231
- end
4232
-
4233
- def http_equiv=(v)
4234
- set_reflected_string("http-equiv", v)
4235
- end
4236
-
4237
- def __js_get__(key)
4238
- case key
4239
- when "name"
4240
- name
4241
- when "content"
4242
- content
4243
- when "charset"
4244
- charset
4245
- when "httpEquiv"
4246
- http_equiv
4247
- else
4248
- super
4249
- end
4250
- end
4251
-
4252
- def __js_set__(key, value)
4253
- case key
4254
- when "name", "content", "charset"
4255
- set_reflected_string(key, value)
4256
- when "httpEquiv"
4257
- set_reflected_string("http-equiv", value)
4258
- else
4259
- super
4260
- end
4261
- end
2915
+ reflect_string :name, :content, :charset, http_equiv: "http-equiv"
4262
2916
  end
4263
2917
 
4264
2918
  class HTMLStyleElement < HTMLElement
4265
- def type
4266
- reflected_string("type")
4267
- end
4268
-
4269
- def type=(v)
4270
- set_reflected_string("type", v)
4271
- end
4272
-
4273
- def media
4274
- reflected_string("media")
4275
- end
4276
-
4277
- def media=(v)
4278
- set_reflected_string("media", v)
4279
- end
4280
-
2919
+ reflect_string :type, :media
4281
2920
  def disabled
4282
2921
  @__disabled == true
4283
2922
  end
@@ -4300,10 +2939,6 @@ module Dommy
4300
2939
 
4301
2940
  def __js_get__(key)
4302
2941
  case key
4303
- when "type"
4304
- type
4305
- when "media"
4306
- media
4307
2942
  when "disabled"
4308
2943
  disabled
4309
2944
  when "sheet"
@@ -4315,8 +2950,6 @@ module Dommy
4315
2950
 
4316
2951
  def __js_set__(key, value)
4317
2952
  case key
4318
- when "type", "media"
4319
- set_reflected_string(key, value)
4320
2953
  when "disabled"
4321
2954
  self.disabled = value
4322
2955
  else
@@ -4344,61 +2977,11 @@ module Dommy
4344
2977
  end
4345
2978
 
4346
2979
  class HTMLQuoteElement < HTMLElement
4347
- def cite
4348
- reflected_string("cite")
4349
- end
4350
-
4351
- def cite=(v)
4352
- set_reflected_string("cite", v)
4353
- end
4354
-
4355
- def __js_get__(key)
4356
- key == "cite" ? cite : super
4357
- end
4358
-
4359
- def __js_set__(key, value)
4360
- key == "cite" ? (self.cite = value) : super
4361
- end
2980
+ reflect_string :cite
4362
2981
  end
4363
2982
 
4364
2983
  class HTMLModElement < HTMLElement
4365
- def cite
4366
- reflected_string("cite")
4367
- end
4368
-
4369
- def cite=(v)
4370
- set_reflected_string("cite", v)
4371
- end
4372
-
4373
- def date_time
4374
- reflected_string("datetime")
4375
- end
4376
-
4377
- def date_time=(v)
4378
- set_reflected_string("datetime", v)
4379
- end
4380
-
4381
- def __js_get__(key)
4382
- case key
4383
- when "cite"
4384
- cite
4385
- when "dateTime"
4386
- date_time
4387
- else
4388
- super
4389
- end
4390
- end
4391
-
4392
- def __js_set__(key, value)
4393
- case key
4394
- when "cite"
4395
- self.cite = value
4396
- when "dateTime"
4397
- self.date_time = value
4398
- else
4399
- super
4400
- end
4401
- end
2984
+ reflect_string :cite, date_time: "datetime"
4402
2985
  end
4403
2986
 
4404
2987
  # Identity-only subclasses — useful for `instanceof` / `is_a?` checks