Class: Dommy::Window
Overview
Instance Attribute Summary collapse
-
#custom_elements ⇒ Object
readonly
Returns the value of attribute custom_elements.
-
#document ⇒ Object
readonly
Returns the value of attribute document.
-
#globals ⇒ Object
readonly
Returns the value of attribute globals.
-
#location ⇒ Object
readonly
Returns the value of attribute location.
-
#navigator ⇒ Object
readonly
Returns the value of attribute navigator.
-
#scheduler ⇒ Object
readonly
Returns the value of attribute scheduler.
Instance Method Summary collapse
- #__event_parent__ ⇒ Object
- #__js_call__(method, args) ⇒ Object
-
#__js_get__(key) ⇒ Object
Bridge protocol: respond to a JS-style property read by name.
- #__js_set__(key, value) ⇒ Object
- #fire_hashchange(old_hash, new_hash) ⇒ Object
-
#fire_popstate(state) ⇒ Object
Called by History#go and Location.href= to fire popstate / hashchange events.
-
#initialize(host = nil, nokogiri_doc: nil) ⇒ Window
constructor
A new instance of Window.
Methods included from EventTarget
#__deliver_event__, #add_event_listener, #dispatch_event, #invoke_listener, #remove_event_listener
Constructor Details
#initialize(host = nil, nokogiri_doc: nil) ⇒ Window
Returns a new instance of Window.
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/dommy/world.rb', line 26 def initialize(host = nil, nokogiri_doc: nil) @host = host @scheduler = Scheduler.new @event_ctor = Bridge::Constructor.new { |args| Event.new(args[0], args[1]) } @custom_event_ctor = Bridge::Constructor.new { |args| CustomEvent.new(args[0], args[1]) } @mouse_event_ctor = Bridge::Constructor.new { |args| MouseEvent.new(args[0], args[1]) } @keyboard_event_ctor = Bridge::Constructor.new { |args| KeyboardEvent.new(args[0], args[1]) } @event_target_ctor = Bridge::Constructor.new { |_args| StandaloneEventTarget.new } @error_ctor = Bridge::Constructor.new { |args| ErrorValue.new(args[0]) } @promise_ctor = Bridge::PromiseConstructor.new(self) @mutation_observer_ctor = Bridge::Constructor.new { |args| MutationObserver.new(self, args[0]) } @abort_controller_ctor = Bridge::Constructor.new { |_args| AbortController.new } @blob_ctor = Bridge::Constructor.new { |args| Blob.new(args[0] || [], args[1] || {}) } @file_ctor = Bridge::Constructor.new { |args| File.new(args[0] || [], args[1].to_s, args[2] || {}) } @file_list_ctor = Bridge::Constructor.new { |args| FileList.new(args[0] || []) } @data_transfer_ctor = Bridge::Constructor.new { |args| opts = args[0] || {} DataTransfer.new( files: opts["files"] || opts[:files] || [], data: opts["data"] || opts[:data] || {} ) } @drag_event_ctor = Bridge::Constructor.new { |args| DragEvent.new(args[0], args[1]) } @local_storage = Storage.new @session_storage = Storage.new @location = Location.new(self) @history = History.new(self, @location) @url_ctor = Bridge::Constructor.new { |args| Url.new(args[0], args[1]) } @url_ctor.define_class_method("createObjectURL") { |args| URL.create_object_url(args[0]) } @url_ctor.define_class_method("revokeObjectURL") { |args| URL.revoke_object_url(args[0]) } # `JS.global[:__some_key__] = ...` from user code lands here. # Test code uses this for stub installation (e.g. a custom # `__fetch_stub__`); production code stays on the typed # accessors above. We keep it last in the read fallback to # avoid shadowing intentional getters. @globals = {} @document = Document.new(host, nokogiri_doc: nokogiri_doc) @document.default_view = self @custom_elements = CustomElementRegistry.new(self) @navigator = Navigator.new(self) end |
Instance Attribute Details
#custom_elements ⇒ Object (readonly)
Returns the value of attribute custom_elements.
24 25 26 |
# File 'lib/dommy/world.rb', line 24 def custom_elements @custom_elements end |
#document ⇒ Object (readonly)
Returns the value of attribute document.
24 25 26 |
# File 'lib/dommy/world.rb', line 24 def document @document end |
#globals ⇒ Object (readonly)
Returns the value of attribute globals.
24 25 26 |
# File 'lib/dommy/world.rb', line 24 def globals @globals end |
#location ⇒ Object (readonly)
Returns the value of attribute location.
24 25 26 |
# File 'lib/dommy/world.rb', line 24 def location @location end |
#navigator ⇒ Object (readonly)
Returns the value of attribute navigator.
24 25 26 |
# File 'lib/dommy/world.rb', line 24 def navigator @navigator end |
#scheduler ⇒ Object (readonly)
Returns the value of attribute scheduler.
24 25 26 |
# File 'lib/dommy/world.rb', line 24 def scheduler @scheduler end |
Instance Method Details
#__event_parent__ ⇒ Object
192 193 194 |
# File 'lib/dommy/world.rb', line 192 def __event_parent__ nil end |
#__js_call__(method, args) ⇒ Object
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
# File 'lib/dommy/world.rb', line 154 def __js_call__(method, args) case method when "fetch" FetchFn.new(self).__js_call__("call", args) when "encodeURIComponent" # JS spec encoding: percent-encode anything except # `A-Za-z0-9 - _ . ! ~ * ' ( )`. Ruby's `CGI.escape` uses # `+` for space; ERB::Util.url_encode matches JS behavior. ERB::Util.url_encode(args[0].to_s) when "decodeURIComponent" CGI.unescape(args[0].to_s) when "addEventListener" add_event_listener(args[0], args[1], args[2]) when "removeEventListener" remove_event_listener(args[0], args[1]) when "dispatchEvent" dispatch_event(args[0]) when "setTimeout" @scheduler.set_timeout(args[0], args[1] || 0) when "clearTimeout" @scheduler.clear_timeout(args[0]) when "setInterval" @scheduler.set_interval(args[0], args[1] || 0) when "clearInterval" @scheduler.clear_interval(args[0]) when "requestAnimationFrame" @scheduler.request_animation_frame(args[0]) when "cancelAnimationFrame" @scheduler.cancel_animation_frame(args[0]) when "queueMicrotask" @scheduler.queue_microtask(args[0]) else # Additional window-level methods (fetch, location, history, # Promise, MutationObserver, etc.) arrive in later sessions. nil end end |
#__js_get__(key) ⇒ Object
Bridge protocol: respond to a JS-style property read by name. Returns either a Ruby primitive (Integer / String / true / false / nil), a Hash/Array (for JS object/array literals), or a Dom::* instance for live DOM/BOM objects.
Anything outside the surface we’ve explicitly polyfilled returns nil (= JS undefined). Spec failures here are the signal to widen the surface in a future session.
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/dommy/world.rb', line 76 def __js_get__(key) case key when "document" @document when "Event" @event_ctor when "CustomEvent" @custom_event_ctor when "MouseEvent" @mouse_event_ctor when "KeyboardEvent" @keyboard_event_ctor when "EventTarget" @event_target_ctor when "Error" @error_ctor when "Promise" @promise_ctor when "MutationObserver" @mutation_observer_ctor when "AbortController" @abort_controller_ctor when "Blob" @blob_ctor when "File" @file_ctor when "FileList" @file_list_ctor when "DataTransfer" @data_transfer_ctor when "DragEvent" @drag_event_ctor # handled by Symbol sentinel when "console" :console # likewise when "Object" :object_ctor when "Array" :array_ctor when "JSON" :json_ctor when "performance" {"now" => @scheduler.now_ms.to_f} when "localStorage" @local_storage when "sessionStorage" @session_storage when "location" @location when "history" @history when "URL" @url_ctor when "fetch" FetchFn.new(self) when "customElements" @custom_elements when "navigator" @navigator else @globals[key] end end |
#__js_set__(key, value) ⇒ Object
141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/dommy/world.rb', line 141 def __js_set__(key, value) # Stash arbitrary keys for later reads (e.g. # `JS.global[:__fetchy_stub__] = map`). @globals[key] = value # The Fetchy spec's `install_fetch_stub` resets `__fetch_count__` # to 0 inside its JS installer (`globalThis.__fetch_count__ = 0; # globalThis.fetch = ...`). Our polyfill ignores raw JS, so we # piggy-back on the stub assignment to perform the same reset # — without it the count accumulates across tests in one VM run. @globals["__fetch_count__"] = 0 if %w[__fetchy_stub__ __resource_fetch_stub__ __inject_fetch_stub__].include?(key) nil end |
#fire_hashchange(old_hash, new_hash) ⇒ Object
204 205 206 207 |
# File 'lib/dommy/world.rb', line 204 def fire_hashchange(old_hash, new_hash) event = CustomEvent.new("hashchange", "detail" => {"oldURL" => old_hash, "newURL" => new_hash}) dispatch_event(event) end |
#fire_popstate(state) ⇒ Object
Called by History#go and Location.href= to fire popstate / hashchange events. Listeners registered on the Window via ‘addEventListener(“popstate”|“hashchange”, cb)` receive them.
199 200 201 202 |
# File 'lib/dommy/world.rb', line 199 def fire_popstate(state) event = CustomEvent.new("popstate", "detail" => state) dispatch_event(event) end |