diff --git a/Tests/LibWeb/Text/expected/HTML/Window-named-properties-elements.txt b/Tests/LibWeb/Text/expected/HTML/Window-named-properties-elements.txt new file mode 100644 index 00000000000..f6d3e3948c7 --- /dev/null +++ b/Tests/LibWeb/Text/expected/HTML/Window-named-properties-elements.txt @@ -0,0 +1,6 @@ + george true +true +true +true +true +true \ No newline at end of file diff --git a/Tests/LibWeb/Text/input/HTML/Window-named-properties-elements.html b/Tests/LibWeb/Text/input/HTML/Window-named-properties-elements.html new file mode 100644 index 00000000000..4428576c3a3 --- /dev/null +++ b/Tests/LibWeb/Text/input/HTML/Window-named-properties-elements.html @@ -0,0 +1,46 @@ + + + +
+ +
+
+
+
+ diff --git a/Userland/Libraries/LibWeb/HTML/Window.cpp b/Userland/Libraries/LibWeb/HTML/Window.cpp index 35dd0768af2..8432e5c93b9 100644 --- a/Userland/Libraries/LibWeb/HTML/Window.cpp +++ b/Userland/Libraries/LibWeb/HTML/Window.cpp @@ -28,14 +28,20 @@ #include #include #include +#include #include #include +#include #include #include #include #include #include #include +#include +#include +#include +#include #include #include #include @@ -1440,13 +1446,111 @@ OrderedHashMap> Window::document_tree_child_ // https://html.spec.whatwg.org/#named-access-on-the-window-object Vector Window::supported_property_names() { - return {}; + // The Window object supports named properties. + // The supported property names of a Window object window at any moment consist of the following, + // in tree order according to the element that contributed them, ignoring later duplicates: + + HashTable property_names; + + // - window's document-tree child navigable target name property set; + auto child_navigable_property_set = document_tree_child_navigable_target_name_property_set(); + for (auto& entry : child_navigable_property_set) + property_names.set(entry.key, AK::HashSetExistingEntryBehavior::Keep); + + // - the value of the name content attribute for all embed, form, img, and object elements + // that have a non-empty name content attribute and are in a document tree with window's associated Document as their root; and + // - the value of the id content attribute for all HTML elements that have a non-empty id content attribute + // and are in a document tree with window's associated Document as their root. + associated_document().for_each_in_subtree_of_type([&property_names](auto& element) -> IterationDecision { + if (is(element) || is(element) || is(element) || is(element)) { + if (auto const& name = element.attribute(AttributeNames::name); name.has_value()) + property_names.set(name.value(), AK::HashSetExistingEntryBehavior::Keep); + } + if (auto const& name = element.attribute(AttributeNames::id); name.has_value()) + property_names.set(name.value(), AK::HashSetExistingEntryBehavior::Keep); + return IterationDecision::Continue; + }); + + // FIXME: Many copies here. Would be nice to be able to return Vector + Vector names; + names.ensure_capacity(property_names.size()); + for (auto const& name : property_names) { + names.append(name.to_deprecated_string()); + } + return names; } // https://html.spec.whatwg.org/#named-access-on-the-window-object WebIDL::ExceptionOr Window::named_item_value(DeprecatedFlyString const& name) { - return JS::js_undefined(); + // To determine the value of a named property name in a Window object window, the user agent must return the value obtained using the following steps: + + // 1. Let objects be the list of named objects of window with the name name. + // NOTE: There will be at least one such object, since the algorithm would otherwise not have been invoked by Web IDL. + auto objects = named_objects(name); + + // 2. If objects contains a navigable, then: + if (!objects.navigables.is_empty()) { + // 1. Let container be the first navigable container in window's associated Document's descendants whose content navigable is in objects. + JS::GCPtr container = nullptr; + associated_document().for_each_in_subtree_of_type([&](HTML::NavigableContainer& navigable_container) { + if (!navigable_container.content_navigable()) + return IterationDecision::Continue; + if (objects.navigables.contains_slow(JS::NonnullGCPtr { *navigable_container.content_navigable() })) { + container = navigable_container; + return IterationDecision::Break; + } + return IterationDecision::Continue; + }); + // 2. Return container's content navigable's active WindowProxy. + VERIFY(container); + return container->content_navigable()->active_window_proxy(); + } + + // 3. Otherwise, if objects has only one element, return that element. + if (objects.elements.size() == 1) + return objects.elements[0]; + + // 4. Otherwise return an HTMLCollection rooted at window's associated Document, + // whose filter matches only named objects of window with the name name. (By definition, these will all be elements.) + return DOM::HTMLCollection::create(associated_document(), DOM::HTMLCollection::Scope::Descendants, [name](auto& element) -> bool { + if ((is(element) || is(element) || is(element) || is(element)) + && (element.attribute(AttributeNames::name) == name.view())) + return true; + return element.attribute(AttributeNames::id) == name.view(); + }); +} + +// https://html.spec.whatwg.org/#dom-window-nameditem-filter +Window::NamedObjects Window::named_objects(StringView name) +{ + // NOTE: Since the Window interface has the [Global] extended attribute, its named properties + // follow the rules for named properties objects rather than legacy platform objects. + + // Named objects of Window object window with the name name, for the purposes of the above algorithm, consist of the following: + NamedObjects objects; + + // document-tree child navigables of window's associated Document whose target name is name; + auto children = associated_document().document_tree_child_navigables(); + for (auto& navigable : children) { + if (navigable->target_name() == name) { + objects.navigables.append(*navigable); + } + } + + // embed, form, img, or object elements that have a name content attribute whose value is name + // and are in a document tree with window's associated Document as their root; and + // HTML elements that have an id content attribute whose value is name and are in a document tree with window's associated Document as their root. + associated_document().for_each_in_subtree_of_type([&objects, &name](auto& element) -> IterationDecision { + if ((is(element) || is(element) || is(element) || is(element)) + && (element.attribute(AttributeNames::name) == name)) + objects.elements.append(element); + else if (element.attribute(AttributeNames::id) == name) + objects.elements.append(element); + return IterationDecision::Continue; + }); + + return objects; } } diff --git a/Userland/Libraries/LibWeb/HTML/Window.h b/Userland/Libraries/LibWeb/HTML/Window.h index c67e02a9d39..5ce5347e0f9 100644 --- a/Userland/Libraries/LibWeb/HTML/Window.h +++ b/Userland/Libraries/LibWeb/HTML/Window.h @@ -209,6 +209,12 @@ private: void invoke_idle_callbacks(); + struct [[nodiscard]] NamedObjects { + Vector> navigables; + Vector> elements; + }; + NamedObjects named_objects(StringView name); + // https://html.spec.whatwg.org/multipage/window-object.html#concept-document-window JS::GCPtr m_associated_document;