diff --git a/Userland/Libraries/LibWeb/Bindings/WindowProxy.cpp b/Userland/Libraries/LibWeb/Bindings/WindowProxy.cpp index c93bb37cbf19c4..8b535cff14e31b 100644 --- a/Userland/Libraries/LibWeb/Bindings/WindowProxy.cpp +++ b/Userland/Libraries/LibWeb/Bindings/WindowProxy.cpp @@ -72,8 +72,8 @@ JS::ThrowCompletionOr> WindowProxy::internal_ge // 1. Let index be ! ToUint32(P). auto index = property_key.as_number(); - // FIXME: 2. Let maxProperties be the number of document-tree child browsing contexts of W. - size_t max_properties = 0; + // 2. Let maxProperties be the number of document-tree child browsing contexts of W. + auto max_properties = TRY(m_window->document_tree_child_browsing_context_count()); // 3. Let value be undefined. Optional value; @@ -227,8 +227,8 @@ JS::ThrowCompletionOr> WindowProxy::internal_own_pro // 2. Let keys be a new empty List. auto keys = JS::MarkedVector { vm.heap() }; - // FIXME: 3. Let maxProperties be the number of document-tree child browsing contexts of W. - size_t max_properties = 0; + // 3. Let maxProperties be the number of document-tree child browsing contexts of W. + auto max_properties = TRY(m_window->document_tree_child_browsing_context_count()); // 4. Let index be 0. // 5. Repeat while index < maxProperties, diff --git a/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp b/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp index d92e1532e36fcc..bc2ae9bc8fbb60 100644 --- a/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp +++ b/Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp @@ -742,6 +742,28 @@ BrowsingContext* BrowsingContext::choose_a_browsing_context(StringView name, boo return chosen; } +// https://html.spec.whatwg.org/multipage/browsers.html#document-tree-child-browsing-context +size_t BrowsingContext::document_tree_child_browsing_context_count() const +{ + size_t count = 0; + + // A browsing context child is a document-tree child browsing context of parent if child is a child browsing context and child's container is in a document tree. + for_each_child([this, &count](BrowsingContext const& child) { + if (child.is_child_of(*this) && child.container()->in_a_document_tree()) + ++count; + }); + + return count; +} + +// https://html.spec.whatwg.org/multipage/browsers.html#child-browsing-context +bool BrowsingContext::is_child_of(BrowsingContext const& parent) const +{ + // A browsing context child is said to be a child browsing context of another browsing context parent, + // if child's container document is non-null and child's container document's browsing context is parent. + return container_document() && container_document()->browsing_context() == &parent; +} + // https://html.spec.whatwg.org/multipage/dom.html#still-on-its-initial-about:blank-document bool BrowsingContext::still_on_its_initial_about_blank_document() const { diff --git a/Userland/Libraries/LibWeb/HTML/BrowsingContext.h b/Userland/Libraries/LibWeb/HTML/BrowsingContext.h index ddcd870ea197d5..81bfabf7555afb 100644 --- a/Userland/Libraries/LibWeb/HTML/BrowsingContext.h +++ b/Userland/Libraries/LibWeb/HTML/BrowsingContext.h @@ -80,6 +80,10 @@ class BrowsingContext : public TreeNode { BrowsingContext* choose_a_browsing_context(StringView name, bool noopener); + size_t document_tree_child_browsing_context_count() const; + + bool is_child_of(BrowsingContext const&) const; + HTML::BrowsingContextContainer* container() { return m_container; } HTML::BrowsingContextContainer const* container() const { return m_container; } diff --git a/Userland/Libraries/LibWeb/HTML/Window.cpp b/Userland/Libraries/LibWeb/HTML/Window.cpp index db68182a714769..5cd97faf811109 100644 --- a/Userland/Libraries/LibWeb/HTML/Window.cpp +++ b/Userland/Libraries/LibWeb/HTML/Window.cpp @@ -794,6 +794,7 @@ void Window::initialize(JS::Realm& realm) define_native_accessor(realm, "pageXOffset", scroll_x_getter, {}, attr); define_native_accessor(realm, "scrollY", scroll_y_getter, {}, attr); define_native_accessor(realm, "pageYOffset", scroll_y_getter, {}, attr); + define_native_accessor(realm, "length", length_getter, {}, attr); define_native_function(realm, "scroll", scroll, 2, attr); define_native_function(realm, "scrollTo", scroll, 2, attr); @@ -1074,6 +1075,29 @@ JS_DEFINE_NATIVE_FUNCTION(Window::btoa) return JS::js_string(vm, move(encoded)); } +// https://html.spec.whatwg.org/multipage/window-object.html#number-of-document-tree-child-browsing-contexts +JS::ThrowCompletionOr Window::document_tree_child_browsing_context_count() const +{ + auto* impl = TRY(impl_from(vm())); + + // 1. If W's browsing context is null, then return 0. + auto* this_browsing_context = impl->associated_document().browsing_context(); + if (!this_browsing_context) + return 0; + + // 2. Return the number of document-tree child browsing contexts of W's browsing context. + return this_browsing_context->document_tree_child_browsing_context_count(); +} + +// https://html.spec.whatwg.org/multipage/window-object.html#dom-length +JS_DEFINE_NATIVE_FUNCTION(Window::length_getter) +{ + auto* impl = TRY(impl_from(vm)); + + // The length getter steps are to return the number of document-tree child browsing contexts of this. + return TRY(impl->document_tree_child_browsing_context_count()); +} + // https://html.spec.whatwg.org/multipage/browsers.html#dom-top JS_DEFINE_NATIVE_FUNCTION(Window::top_getter) { diff --git a/Userland/Libraries/LibWeb/HTML/Window.h b/Userland/Libraries/LibWeb/HTML/Window.h index e1ce9e953b5620..3d58ce73b48a50 100644 --- a/Userland/Libraries/LibWeb/HTML/Window.h +++ b/Userland/Libraries/LibWeb/HTML/Window.h @@ -50,6 +50,8 @@ class Window final HTML::BrowsingContext const* browsing_context() const; HTML::BrowsingContext* browsing_context(); + JS::ThrowCompletionOr document_tree_child_browsing_context_count() const; + void alert_impl(String const&); bool confirm_impl(String const&); String prompt_impl(String const&, String const&); @@ -199,6 +201,7 @@ class Window final Bindings::CrossOriginPropertyDescriptorMap& cross_origin_property_descriptor_map() { return m_cross_origin_property_descriptor_map; } private: + JS_DECLARE_NATIVE_FUNCTION(length_getter); JS_DECLARE_NATIVE_FUNCTION(top_getter); JS_DECLARE_NATIVE_FUNCTION(document_getter);