mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 09:00:22 +00:00
LibWeb: Make Window.postMessage closer to the spec
The main issues are using Structured{Serialize,Deserailize} instead of Structured{Serialize,Deserialize}WithTransfer and the temporary execution context usage for StructuredDeserialize. Allows Discord to load once again, as it uses a postMessage scheduler to render components, including the main App component. The callback checked the (previously) non-existent source attribute of the MessageEvent and returned if it was not the main window. Fixes the Twitch cookie consent banner saying "failed integrity check" for unknown reasons, but presumably related to the source and origin attributes.
This commit is contained in:
parent
464cc55b16
commit
fc42c75a0c
Notes:
sideshowbarker
2024-07-17 20:22:04 +09:00
Author: https://github.com/Lubrsi Commit: https://github.com/SerenityOS/serenity/commit/fc42c75a0c Pull-request: https://github.com/SerenityOS/serenity/pull/21823 Reviewed-by: https://github.com/ADKaster Reviewed-by: https://github.com/shannonbooth Reviewed-by: https://github.com/trflynn89
5 changed files with 361 additions and 13 deletions
100
Tests/LibWeb/Text/expected/HTML/Window-postMessage.txt
Normal file
100
Tests/LibWeb/Text/expected/HTML/Window-postMessage.txt
Normal file
|
@ -0,0 +1,100 @@
|
|||
originError instanceof DOMException: true
|
||||
originError.name: SyntaxError
|
||||
originError.message: Invalid URL for targetOrigin: 'aaaa'
|
||||
originError.constructor === window.DOMException: true
|
||||
originParsedBeforeSerializeError instanceof DOMException: true
|
||||
originParsedBeforeSerializeError.name: SyntaxError
|
||||
originParsedBeforeSerializeError.message: Invalid URL for targetOrigin: 'aaaa'
|
||||
originParsedBeforeSerializeError.constructor === window.DOMException: true
|
||||
serializeError instanceof DOMException: true
|
||||
serializeError.name: DataCloneError
|
||||
serializeError.message: Unsupported type
|
||||
serializeError.constructor === window.DOMException: true
|
||||
originIframeError instanceof DOMException: false
|
||||
originIframeError instanceof iframe.contentWindow.DOMException: true
|
||||
originIframeError.name: SyntaxError
|
||||
originIframeError.message: Invalid URL for targetOrigin: 'aaaa'
|
||||
originIframeError.constructor === DOMException: false
|
||||
originIframeError.constructor === iframe.contentWindow.DOMException: true
|
||||
originParsedBeforeSerializeIframeError instanceof DOMException: false
|
||||
originParsedBeforeSerializeIframeError instanceof iframe.contentWindow.DOMException: true
|
||||
originParsedBeforeSerializeIframeError.name: SyntaxError
|
||||
originParsedBeforeSerializeIframeError.message: Invalid URL for targetOrigin: 'aaaa'
|
||||
originParsedBeforeSerializeIframeError.constructor === DOMException: false
|
||||
originParsedBeforeSerializeIframeError.constructor === iframe.contentWindow.DOMException: true
|
||||
serializeIframeError instanceof DOMException: false
|
||||
serializeIframeError instanceof iframe.contentWindow.DOMException: true
|
||||
serializeIframeError.name: DataCloneError
|
||||
serializeIframeError.message: Unsupported type
|
||||
serializeIframeError.constructor === DOMException: false
|
||||
serializeIframeError.constructor === iframe.contentWindow.DOMException: true
|
||||
Message 1 data: undefined
|
||||
Message 1 origin: file://
|
||||
Message 1 lastEventId:
|
||||
Message 1 source: [object Window]
|
||||
Message 1 source === window: true
|
||||
Message 1 source === iframe.contentWindow: false
|
||||
Message 1 source === blobIframe.contentWindow: false
|
||||
Message 2 data: null
|
||||
Message 2 origin: file://
|
||||
Message 2 lastEventId:
|
||||
Message 2 source: [object Window]
|
||||
Message 2 source === window: true
|
||||
Message 2 source === iframe.contentWindow: false
|
||||
Message 2 source === blobIframe.contentWindow: false
|
||||
Message 3 data: true
|
||||
Message 3 origin: file://
|
||||
Message 3 lastEventId:
|
||||
Message 3 source: [object Window]
|
||||
Message 3 source === window: true
|
||||
Message 3 source === iframe.contentWindow: false
|
||||
Message 3 source === blobIframe.contentWindow: false
|
||||
Message 4 data: false
|
||||
Message 4 origin: file://
|
||||
Message 4 lastEventId:
|
||||
Message 4 source: [object Window]
|
||||
Message 4 source === window: true
|
||||
Message 4 source === iframe.contentWindow: false
|
||||
Message 4 source === blobIframe.contentWindow: false
|
||||
Message 5 data: 123
|
||||
Message 5 origin: file://
|
||||
Message 5 lastEventId:
|
||||
Message 5 source: [object Window]
|
||||
Message 5 source === window: true
|
||||
Message 5 source === iframe.contentWindow: false
|
||||
Message 5 source === blobIframe.contentWindow: false
|
||||
Message 6 data: 123.456
|
||||
Message 6 origin: file://
|
||||
Message 6 lastEventId:
|
||||
Message 6 source: [object Window]
|
||||
Message 6 source === window: true
|
||||
Message 6 source === iframe.contentWindow: false
|
||||
Message 6 source === blobIframe.contentWindow: false
|
||||
Message 7 data: 9007199254740991
|
||||
Message 7 origin: file://
|
||||
Message 7 lastEventId:
|
||||
Message 7 source: [object Window]
|
||||
Message 7 source === window: true
|
||||
Message 7 source === iframe.contentWindow: false
|
||||
Message 7 source === blobIframe.contentWindow: false
|
||||
Message 8 data: This is a string
|
||||
Message 8 origin: file://
|
||||
Message 8 lastEventId:
|
||||
Message 8 source: [object Window]
|
||||
Message 8 source === window: true
|
||||
Message 8 source === iframe.contentWindow: false
|
||||
Message 8 source === blobIframe.contentWindow: false
|
||||
Message 9 data: I am from another ~planet~ iframe
|
||||
Message 9 origin: file://
|
||||
Message 9 lastEventId:
|
||||
Message 9 source: [object Window]
|
||||
Message 9 source === window: false
|
||||
Message 9 source === iframe.contentWindow: true
|
||||
Message 9 source === blobIframe.contentWindow: false
|
||||
Message 10 data: All done :^)
|
||||
Message 10 origin: file://
|
||||
Message 10 lastEventId:
|
||||
Message 10 source: [object Window]
|
||||
Message 10 source === window: false
|
||||
Message 10 source === iframe.contentWindow: false
|
||||
Message 10 source === blobIframe.contentWindow: true
|
137
Tests/LibWeb/Text/input/HTML/Window-postMessage.html
Normal file
137
Tests/LibWeb/Text/input/HTML/Window-postMessage.html
Normal file
|
@ -0,0 +1,137 @@
|
|||
<body>
|
||||
<iframe style="display: none" id="message-iframe" srcdoc="
|
||||
<body>
|
||||
<script>
|
||||
window.addEventListener('message', (event) => {
|
||||
window.parent.postMessage(event.data, '*');
|
||||
});
|
||||
</script>
|
||||
<body>
|
||||
"></iframe>
|
||||
<script src="../include.js"></script>
|
||||
<script>
|
||||
const iframe = document.getElementById("message-iframe");
|
||||
|
||||
const blobSrcdoc = new Blob([iframe.srcdoc], {
|
||||
type: "text/html",
|
||||
});
|
||||
const iframeSrcdocBlobUrl = URL.createObjectURL(blobSrcdoc);
|
||||
|
||||
const blobIframe = document.createElement("iframe");
|
||||
blobIframe.src = iframeSrcdocBlobUrl;
|
||||
blobIframe.setAttribute("style", "display: none");
|
||||
|
||||
document.body.append(blobIframe);
|
||||
|
||||
let messageCount = 1;
|
||||
window.onmessage = (messageEvent) => {
|
||||
try {
|
||||
println(`Message ${messageCount} data: ${messageEvent.data}`);
|
||||
println(`Message ${messageCount} origin: ${messageEvent.origin}`);
|
||||
println(`Message ${messageCount} lastEventId: ${messageEvent.lastEventId}`);
|
||||
println(`Message ${messageCount} source: ${messageEvent.source}`);
|
||||
println(`Message ${messageCount} source === window: ${messageEvent.source === window}`);
|
||||
println(`Message ${messageCount} source === iframe.contentWindow: ${messageEvent.source === iframe.contentWindow}`);
|
||||
println(`Message ${messageCount} source === blobIframe.contentWindow: ${messageEvent.source === blobIframe.contentWindow}`);
|
||||
} catch (ex) {
|
||||
println(`Accessing attributes of message ${messageCount} threw exception: ${ex}`);
|
||||
}
|
||||
messageCount++;
|
||||
|
||||
if (messageEvent.source === blobIframe.contentWindow && messageEvent.data === "All done :^)")
|
||||
{
|
||||
globalThis.doneCallback();
|
||||
}
|
||||
};
|
||||
|
||||
function performTest() {
|
||||
window.postMessage(undefined, "*");
|
||||
window.postMessage(null, "*");
|
||||
window.postMessage(true, "*");
|
||||
window.postMessage(false, "*");
|
||||
window.postMessage(123, "*");
|
||||
window.postMessage(123.456, "*");
|
||||
window.postMessage(BigInt("0x1fffffffffffff"), "*");
|
||||
window.postMessage("This is a string", "/");
|
||||
window.postMessage("I shouldn't appear, I'm not same origin!", "https://serenityos.org");
|
||||
iframe.contentWindow.postMessage("I am from another ~planet~ iframe", "*");
|
||||
blobIframe.contentWindow.postMessage("All done :^)", iframeSrcdocBlobUrl);
|
||||
|
||||
try {
|
||||
window.postMessage("This is a bad origin string", "aaaa");
|
||||
} catch (originError) {
|
||||
println(`originError instanceof DOMException: ${originError instanceof DOMException}`);
|
||||
println(`originError.name: ${originError.name}`);
|
||||
println(`originError.message: ${originError.message}`);
|
||||
println(`originError.constructor === window.DOMException: ${originError.constructor === window.DOMException}`);
|
||||
}
|
||||
|
||||
try {
|
||||
window.postMessage(document, "aaaa");
|
||||
} catch (originParsedBeforeSerializeError) {
|
||||
println(`originParsedBeforeSerializeError instanceof DOMException: ${originParsedBeforeSerializeError instanceof DOMException}`);
|
||||
println(`originParsedBeforeSerializeError.name: ${originParsedBeforeSerializeError.name}`);
|
||||
println(`originParsedBeforeSerializeError.message: ${originParsedBeforeSerializeError.message}`);
|
||||
println(`originParsedBeforeSerializeError.constructor === window.DOMException: ${originParsedBeforeSerializeError.constructor === window.DOMException}`);
|
||||
}
|
||||
|
||||
try {
|
||||
window.postMessage(document, "*");
|
||||
} catch (serializeError) {
|
||||
println(`serializeError instanceof DOMException: ${serializeError instanceof DOMException}`);
|
||||
println(`serializeError.name: ${serializeError.name}`);
|
||||
println(`serializeError.message: ${serializeError.message}`);
|
||||
println(`serializeError.constructor === window.DOMException: ${serializeError.constructor === window.DOMException}`);
|
||||
}
|
||||
|
||||
try {
|
||||
iframe.contentWindow.postMessage("This is a bad origin string", "aaaa");
|
||||
} catch (originIframeError) {
|
||||
println(`originIframeError instanceof DOMException: ${originIframeError instanceof DOMException}`);
|
||||
println(`originIframeError instanceof iframe.contentWindow.DOMException: ${originIframeError instanceof iframe.contentWindow.DOMException}`);
|
||||
println(`originIframeError.name: ${originIframeError.name}`);
|
||||
println(`originIframeError.message: ${originIframeError.message}`);
|
||||
println(`originIframeError.constructor === DOMException: ${originIframeError.constructor === DOMException}`);
|
||||
println(`originIframeError.constructor === iframe.contentWindow.DOMException: ${originIframeError.constructor === iframe.contentWindow.DOMException}`);
|
||||
}
|
||||
|
||||
try {
|
||||
iframe.contentWindow.postMessage(document, "aaaa");
|
||||
} catch (originParsedBeforeSerializeIframeError) {
|
||||
println(`originParsedBeforeSerializeIframeError instanceof DOMException: ${originParsedBeforeSerializeIframeError instanceof DOMException}`);
|
||||
println(`originParsedBeforeSerializeIframeError instanceof iframe.contentWindow.DOMException: ${originParsedBeforeSerializeIframeError instanceof iframe.contentWindow.DOMException}`);
|
||||
println(`originParsedBeforeSerializeIframeError.name: ${originParsedBeforeSerializeIframeError.name}`);
|
||||
println(`originParsedBeforeSerializeIframeError.message: ${originParsedBeforeSerializeIframeError.message}`);
|
||||
println(`originParsedBeforeSerializeIframeError.constructor === DOMException: ${originParsedBeforeSerializeIframeError.constructor === DOMException}`);
|
||||
println(`originParsedBeforeSerializeIframeError.constructor === iframe.contentWindow.DOMException: ${originParsedBeforeSerializeIframeError.constructor === iframe.contentWindow.DOMException}`);
|
||||
}
|
||||
|
||||
try {
|
||||
iframe.contentWindow.postMessage(document, "*");
|
||||
} catch (serializeIframeError) {
|
||||
println(`serializeIframeError instanceof DOMException: ${serializeIframeError instanceof DOMException}`);
|
||||
println(`serializeIframeError instanceof iframe.contentWindow.DOMException: ${serializeIframeError instanceof iframe.contentWindow.DOMException}`);
|
||||
println(`serializeIframeError.name: ${serializeIframeError.name}`);
|
||||
println(`serializeIframeError.message: ${serializeIframeError.message}`);
|
||||
println(`serializeIframeError.constructor === DOMException: ${serializeIframeError.constructor === DOMException}`);
|
||||
println(`serializeIframeError.constructor === iframe.contentWindow.DOMException: ${serializeIframeError.constructor === iframe.contentWindow.DOMException}`);
|
||||
}
|
||||
}
|
||||
|
||||
asyncTest((done) => {
|
||||
globalThis.doneCallback = done;
|
||||
|
||||
const blobIframeLoadPromise = new Promise(resolve => {
|
||||
blobIframe.onload = () => resolve();
|
||||
});
|
||||
|
||||
const srcdocIframeLoadPromise = new Promise(resolve => {
|
||||
iframe.onload = () => resolve();
|
||||
});
|
||||
|
||||
Promise.all([blobIframeLoadPromise, srcdocIframeLoadPromise]).then(() => {
|
||||
performTest();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
|
@ -50,6 +50,7 @@
|
|||
#include <LibWeb/HTML/PageTransitionEvent.h>
|
||||
#include <LibWeb/HTML/Scripting/Environments.h>
|
||||
#include <LibWeb/HTML/Scripting/ExceptionReporter.h>
|
||||
#include <LibWeb/HTML/Scripting/TemporaryExecutionContext.h>
|
||||
#include <LibWeb/HTML/Storage.h>
|
||||
#include <LibWeb/HTML/TokenizedFeatures.h>
|
||||
#include <LibWeb/HTML/TraversableNavigable.h>
|
||||
|
@ -64,6 +65,7 @@
|
|||
#include <LibWeb/Page/Page.h>
|
||||
#include <LibWeb/RequestIdleCallback/IdleDeadline.h>
|
||||
#include <LibWeb/Selection/Selection.h>
|
||||
#include <LibWeb/URL/URL.h>
|
||||
#include <LibWeb/WebIDL/AbstractOperations.h>
|
||||
|
||||
namespace Web::HTML {
|
||||
|
@ -997,17 +999,115 @@ Optional<String> Window::prompt(Optional<String> const& message, Optional<String
|
|||
return {};
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/web-messaging.html#dom-window-postmessage
|
||||
void Window::post_message(JS::Value message, String const&)
|
||||
// https://html.spec.whatwg.org/multipage/web-messaging.html#window-post-message-steps
|
||||
WebIDL::ExceptionOr<void> Window::window_post_message_steps(JS::Value message, WindowPostMessageOptions const& options)
|
||||
{
|
||||
// FIXME: This is an ad-hoc hack implementation instead, since we don't currently
|
||||
// have serialization and deserialization of messages.
|
||||
queue_global_task(Task::Source::PostedMessage, *this, [this, message] {
|
||||
MessageEventInit event_init {};
|
||||
event_init.data = message;
|
||||
event_init.origin = "<origin>"_string;
|
||||
dispatch_event(MessageEvent::create(realm(), EventNames::message, event_init));
|
||||
// 1. Let targetRealm be targetWindow's realm.
|
||||
auto& target_realm = this->realm();
|
||||
|
||||
// 2. Let incumbentSettings be the incumbent settings object.
|
||||
auto& incumbent_settings = incumbent_settings_object();
|
||||
|
||||
// 3. Let targetOrigin be options["targetOrigin"].
|
||||
Variant<String, Origin> target_origin = options.target_origin;
|
||||
|
||||
// 4. If targetOrigin is a single U+002F SOLIDUS character (/), then set targetOrigin to incumbentSettings's origin.
|
||||
if (options.target_origin == "/"sv) {
|
||||
target_origin = incumbent_settings.origin();
|
||||
}
|
||||
// 5. Otherwise, if targetOrigin is not a single U+002A ASTERISK character (*), then:
|
||||
else if (options.target_origin != "*"sv) {
|
||||
// 1. Let parsedURL be the result of running the URL parser on targetOrigin.
|
||||
auto parsed_url = URL::parse(options.target_origin);
|
||||
|
||||
// 2. If parsedURL is failure, then throw a "SyntaxError" DOMException.
|
||||
if (!parsed_url.is_valid())
|
||||
return WebIDL::SyntaxError::create(target_realm, MUST(String::formatted("Invalid URL for targetOrigin: '{}'", options.target_origin)));
|
||||
|
||||
// 3. Set targetOrigin to parsedURL's origin.
|
||||
target_origin = URL::url_origin(parsed_url);
|
||||
}
|
||||
|
||||
// 6. Let transfer be options["transfer"].
|
||||
// FIXME: This is currently unused.
|
||||
|
||||
// 7. Let serializeWithTransferResult be StructuredSerializeWithTransfer(message, transfer). Rethrow any exceptions.
|
||||
// FIXME: Use StructuredSerializeWithTransfer instead of StructuredSerialize
|
||||
auto serialize_with_transfer_result = TRY(structured_serialize(target_realm.vm(), message));
|
||||
|
||||
// 8. Queue a global task on the posted message task source given targetWindow to run the following steps:
|
||||
queue_global_task(Task::Source::PostedMessage, *this, [this, serialize_with_transfer_result = move(serialize_with_transfer_result), target_origin = move(target_origin), &incumbent_settings, &target_realm]() {
|
||||
// 1. If the targetOrigin argument is not a single literal U+002A ASTERISK character (*) and targetWindow's
|
||||
// associated Document's origin is not same origin with targetOrigin, then return.
|
||||
// NOTE: Due to step 4 and 5 above, the only time it's not '*' is if target_origin contains an Origin.
|
||||
if (!target_origin.has<String>()) {
|
||||
auto const& actual_target_origin = target_origin.get<Origin>();
|
||||
if (!document()->origin().is_same_origin(actual_target_origin))
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Let origin be the serialization of incumbentSettings's origin.
|
||||
auto origin = incumbent_settings.origin().serialize();
|
||||
|
||||
// 3. Let source be the WindowProxy object corresponding to incumbentSettings's global object (a Window object).
|
||||
auto& source = verify_cast<WindowProxy>(incumbent_settings.realm().global_environment().global_this_value());
|
||||
|
||||
// 4. Let deserializeRecord be StructuredDeserializeWithTransfer(serializeWithTransferResult, targetRealm).
|
||||
// FIXME: Use StructuredDeserializeWithTransfer instead of StructuredDeserialize
|
||||
// FIXME: Don't use a temporary execution context here.
|
||||
auto& settings_object = Bindings::host_defined_environment_settings_object(target_realm);
|
||||
auto temporary_execution_context = TemporaryExecutionContext { settings_object };
|
||||
auto deserialize_record_or_error = structured_deserialize(vm(), serialize_with_transfer_result, target_realm, Optional<HTML::SerializationMemory> {});
|
||||
|
||||
// If this throws an exception, catch it, fire an event named messageerror at targetWindow, using MessageEvent,
|
||||
// with the origin attribute initialized to origin and the source attribute initialized to source, and then return.
|
||||
if (deserialize_record_or_error.is_exception()) {
|
||||
MessageEventInit message_event_init {};
|
||||
message_event_init.origin = MUST(String::from_deprecated_string(origin));
|
||||
message_event_init.source = JS::make_handle(source);
|
||||
|
||||
auto message_error_event = MessageEvent::create(target_realm, EventNames::messageerror, message_event_init);
|
||||
dispatch_event(message_error_event);
|
||||
return;
|
||||
}
|
||||
|
||||
// 5. Let messageClone be deserializeRecord.[[Deserialized]].
|
||||
// FIXME: Get this from deserializeRecord.[[Deserialized]] once it uses StructuredDeserializeWithTransfer instead of StructuredDeserialize.
|
||||
auto message_clone = deserialize_record_or_error.release_value();
|
||||
|
||||
// FIXME: 6. Let newPorts be a new frozen array consisting of all MessagePort objects in deserializeRecord.[[TransferredValues]],
|
||||
// if any, maintaining their relative order.
|
||||
|
||||
// 7. Fire an event named message at targetWindow, using MessageEvent, with the origin attribute initialized to origin,
|
||||
// the source attribute initialized to source, the data attribute initialized to messageClone, and the ports attribute
|
||||
// initialized to newPorts.
|
||||
// FIXME: Set the ports attribute to newPorts.
|
||||
MessageEventInit message_event_init {};
|
||||
message_event_init.origin = MUST(String::from_deprecated_string(origin));
|
||||
message_event_init.source = JS::make_handle(source);
|
||||
message_event_init.data = message_clone;
|
||||
|
||||
auto message_event = MessageEvent::create(target_realm, EventNames::message, message_event_init);
|
||||
dispatch_event(message_event);
|
||||
});
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/web-messaging.html#dom-window-postmessage-options
|
||||
WebIDL::ExceptionOr<void> Window::post_message(JS::Value message, WindowPostMessageOptions const& options)
|
||||
{
|
||||
// The Window interface's postMessage(message, options) method steps are to run the window post message steps given
|
||||
// this, message, and options.
|
||||
return window_post_message_steps(message, options);
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/web-messaging.html#dom-window-postmessage
|
||||
WebIDL::ExceptionOr<void> Window::post_message(JS::Value message, String const& target_origin, Vector<JS::Handle<JS::Object>> const& transfer)
|
||||
{
|
||||
// The Window interface's postMessage(message, targetOrigin, transfer) method steps are to run the window post message
|
||||
// steps given this, message, and «[ "targetOrigin" → targetOrigin, "transfer" → transfer ]».
|
||||
return window_post_message_steps(message, WindowPostMessageOptions { { .transfer = transfer }, target_origin });
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#dom-window-event
|
||||
|
|
|
@ -38,6 +38,11 @@ struct ScrollToOptions : public ScrollOptions {
|
|||
Optional<double> top;
|
||||
};
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#windowpostmessageoptions
|
||||
struct WindowPostMessageOptions : public StructuredSerializeOptions {
|
||||
String target_origin { "/"_string };
|
||||
};
|
||||
|
||||
class Window final
|
||||
: public DOM::EventTarget
|
||||
, public GlobalEventHandlers
|
||||
|
@ -146,7 +151,8 @@ public:
|
|||
bool confirm(Optional<String> const& message);
|
||||
Optional<String> prompt(Optional<String> const& message, Optional<String> const& default_);
|
||||
|
||||
void post_message(JS::Value message, String const&);
|
||||
WebIDL::ExceptionOr<void> post_message(JS::Value message, String const&, Vector<JS::Handle<JS::Object>> const&);
|
||||
WebIDL::ExceptionOr<void> post_message(JS::Value message, WindowPostMessageOptions const&);
|
||||
|
||||
Variant<JS::Handle<DOM::Event>, JS::Value> event() const;
|
||||
|
||||
|
@ -215,6 +221,8 @@ private:
|
|||
};
|
||||
NamedObjects named_objects(StringView name);
|
||||
|
||||
WebIDL::ExceptionOr<void> window_post_message_steps(JS::Value, WindowPostMessageOptions const&);
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/window-object.html#concept-document-window
|
||||
JS::GCPtr<DOM::Document> m_associated_document;
|
||||
|
||||
|
|
|
@ -52,9 +52,8 @@ interface Window : EventTarget {
|
|||
boolean confirm(optional DOMString message = "");
|
||||
DOMString? prompt(optional DOMString message = "", optional DOMString default = "");
|
||||
|
||||
undefined postMessage(any message, USVString targetOrigin);
|
||||
// FIXME: undefined postMessage(any message, USVString targetOrigin, optional sequence<object> transfer = []);
|
||||
// FIXME: undefined postMessage(any message, optional WindowPostMessageOptions options = {});
|
||||
undefined postMessage(any message, USVString targetOrigin, optional sequence<object> transfer = []);
|
||||
undefined postMessage(any message, optional WindowPostMessageOptions options = {});
|
||||
|
||||
// https://dom.spec.whatwg.org/#interface-window-extensions
|
||||
[Replaceable] readonly attribute (Event or undefined) event; // legacy
|
||||
|
@ -122,3 +121,7 @@ dictionary ScrollToOptions : ScrollOptions {
|
|||
unrestricted double left;
|
||||
unrestricted double top;
|
||||
};
|
||||
|
||||
dictionary WindowPostMessageOptions : StructuredSerializeOptions {
|
||||
USVString targetOrigin = "/";
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue