diff --git a/Tests/LibWeb/Text/expected/HTML/Window-opener.txt b/Tests/LibWeb/Text/expected/HTML/Window-opener.txt new file mode 100644 index 0000000000..588c4b7669 --- /dev/null +++ b/Tests/LibWeb/Text/expected/HTML/Window-opener.txt @@ -0,0 +1,5 @@ + window.opener initial value: null +window.opener after setting to "test": test +iframe contentWindow.opener initial value is the current window object: true +iframe contentWindow.opener after setting to null: null +iframe contentWindow.opener after setting to "test": test diff --git a/Tests/LibWeb/Text/input/HTML/Window-opener.html b/Tests/LibWeb/Text/input/HTML/Window-opener.html new file mode 100644 index 0000000000..f47b6262b9 --- /dev/null +++ b/Tests/LibWeb/Text/input/HTML/Window-opener.html @@ -0,0 +1,20 @@ + + + + diff --git a/Userland/Libraries/LibWeb/HTML/Window.cpp b/Userland/Libraries/LibWeb/HTML/Window.cpp index 657aa7fccf..c80f5affb3 100644 --- a/Userland/Libraries/LibWeb/HTML/Window.cpp +++ b/Userland/Libraries/LibWeb/HTML/Window.cpp @@ -946,6 +946,41 @@ JS::GCPtr Window::top() const return navigable->top_level_traversable()->active_window_proxy(); } +// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-opener +JS::GCPtr Window::opener() const +{ + // 1. Let current be this's browsing context. + auto const* current = browsing_context(); + + // 2. If current is null, then return null. + if (!current) + return {}; + + // 3. If current's opener browsing context is null, then return null. + auto opener_browsing_context = current->opener_browsing_context(); + if (!opener_browsing_context) + return {}; + + // 4. Return current's opener browsing context's WindowProxy object. + return opener_browsing_context->window_proxy(); +} + +WebIDL::ExceptionOr Window::set_opener(JS::Value value) +{ + // 1. If the given value is null and this's browsing context is non-null, then set this's browsing context's opener browsing context to null. + auto* browsing_context = this->browsing_context(); + if (value.is_null() && browsing_context) + browsing_context->set_opener_browsing_context(nullptr); + + // 2. If the given value is non-null, then perform ? DefinePropertyOrThrow(this, "opener", { [[Value]]: the given value, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true }). + if (!value.is_null()) { + static JS::PropertyKey opener_property_key { "opener", JS::PropertyKey::StringMayBeNumber::No }; + TRY(define_property_or_throw(opener_property_key, { .value = value, .writable = true, .enumerable = true, .configurable = true })); + } + + return {}; +} + // https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-parent JS::GCPtr Window::parent() const { diff --git a/Userland/Libraries/LibWeb/HTML/Window.h b/Userland/Libraries/LibWeb/HTML/Window.h index 9fae9fb118..6f44b4a2e7 100644 --- a/Userland/Libraries/LibWeb/HTML/Window.h +++ b/Userland/Libraries/LibWeb/HTML/Window.h @@ -144,6 +144,8 @@ public: JS::NonnullGCPtr frames() const; u32 length(); JS::GCPtr top() const; + JS::GCPtr opener() const; + WebIDL::ExceptionOr set_opener(JS::Value); JS::GCPtr parent() const; JS::GCPtr frame_element() const; WebIDL::ExceptionOr> open(Optional const& url, Optional const& target, Optional const& features); diff --git a/Userland/Libraries/LibWeb/HTML/Window.idl b/Userland/Libraries/LibWeb/HTML/Window.idl index a78bb54cca..48d8969648 100644 --- a/Userland/Libraries/LibWeb/HTML/Window.idl +++ b/Userland/Libraries/LibWeb/HTML/Window.idl @@ -35,6 +35,7 @@ interface Window : EventTarget { [Replaceable] readonly attribute WindowProxy frames; [Replaceable] readonly attribute unsigned long length; [LegacyUnforgeable] readonly attribute WindowProxy? top; + attribute any opener; [Replaceable] readonly attribute WindowProxy? parent; readonly attribute Element? frameElement; WindowProxy? open(optional USVString url = "", optional DOMString target = "_blank", optional [LegacyNullToEmptyString] DOMString features = "");