Ver código fonte

LibWeb: Handle window.open() when passed a navigable name

Andrew Kaster 1 ano atrás
pai
commit
0104c8d052

+ 30 - 0
Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp

@@ -748,6 +748,36 @@ bool BrowsingContext::is_ancestor_of(BrowsingContext const& other) const
     return false;
 }
 
+// https://html.spec.whatwg.org/multipage/document-sequences.html#familiar-with
+bool BrowsingContext::is_familiar_with(BrowsingContext const& other) const
+{
+    // A browsing context A is familiar with a second browsing context B if the following algorithm returns true:
+    auto const& A = *this;
+    auto const& B = other;
+
+    // 1. If A's active document's origin is same origin with B's active document's origin, then return true.
+    if (A.active_document()->origin().is_same_origin(B.active_document()->origin()))
+        return true;
+
+    // 2. If A's top-level browsing context is B, then return true.
+    if (A.top_level_browsing_context() == &B)
+        return true;
+
+    // 3. If B is an auxiliary browsing context and A is familiar with B's opener browsing context, then return true.
+    if (B.opener_browsing_context() != nullptr && A.is_familiar_with(*B.opener_browsing_context()))
+        return true;
+
+    // 4. If there exists an ancestor browsing context of B whose active document has the same origin as the active document of A, then return true.
+    // NOTE: This includes the case where A is an ancestor browsing context of B.
+    for (auto ancestor = B.parent(); ancestor; ancestor = ancestor->parent()) {
+        if (ancestor->active_document()->origin().is_same_origin(A.active_document()->origin()))
+            return true;
+    }
+
+    // 5. Return false.
+    return false;
+}
+
 // https://html.spec.whatwg.org/multipage/browsing-the-web.html#snapshotting-target-snapshot-params
 SandboxingFlagSet determine_the_creation_sandboxing_flags(BrowsingContext const&, JS::GCPtr<DOM::Element>)
 {

+ 1 - 0
Userland/Libraries/LibWeb/HTML/BrowsingContext.h

@@ -55,6 +55,7 @@ public:
     JS::GCPtr<BrowsingContext> next_sibling() const;
 
     bool is_ancestor_of(BrowsingContext const&) const;
+    bool is_familiar_with(BrowsingContext const&) const;
 
     template<typename Callback>
     IterationDecision for_each_in_inclusive_subtree(Callback callback) const

+ 16 - 1
Userland/Libraries/LibWeb/HTML/Navigable.cpp

@@ -304,6 +304,16 @@ void Navigable::set_ongoing_navigation(Variant<Empty, Traversal, String> ongoing
 // https://html.spec.whatwg.org/multipage/document-sequences.html#the-rules-for-choosing-a-navigable
 Navigable::ChosenNavigable Navigable::choose_a_navigable(StringView name, TokenizedFeature::NoOpener no_opener, ActivateTab)
 {
+    // NOTE: Implementation for step 7 here.
+    JS::GCPtr<Navigable> same_name_navigable = nullptr;
+    if (!Infra::is_ascii_case_insensitive_match(name, "_blank"sv)) {
+        for (auto& n : all_navigables()) {
+            if (n->target_name() == name) {
+                same_name_navigable = n;
+            }
+        }
+    }
+
     // 1. Let chosen be null.
     JS::GCPtr<Navigable> chosen = nullptr;
 
@@ -333,7 +343,7 @@ Navigable::ChosenNavigable Navigable::choose_a_navigable(StringView name, Tokeni
         chosen = traversable_navigable();
     }
 
-    //  FIXME: 7. Otherwise, if name is not an ASCII case-insensitive match for "_blank",
+    //  7. Otherwise, if name is not an ASCII case-insensitive match for "_blank",
     //     there exists a navigable whose target name is the same as name, currentNavigable's
     //     active browsing context is familiar with that navigable's active browsing context,
     //     and the user agent determines that the two browsing contexts are related enough that
@@ -341,6 +351,11 @@ Navigable::ChosenNavigable Navigable::choose_a_navigable(StringView name, Tokeni
     //     matching navigables, the user agent should pick one in some arbitrary consistent manner,
     //     such as the most recently opened, most recently focused, or more closely related, and set
     //     chosen to it.
+    else if (same_name_navigable != nullptr && (active_browsing_context()->is_familiar_with(*same_name_navigable->active_browsing_context()))) {
+        // FIXME: Handle multiple name-match case
+        // FIXME: When are these contexts 'not related enough' ?
+        chosen = same_name_navigable;
+    }
 
     // 8. Otherwise, a new top-level traversable is being requested, and what happens depends on the
     // user agent's configuration and abilities — it is determined by the rules given for the first