Просмотр исходного кода

LibWeb: Implement and use "scroll to the fragment" algorithm

This will eventually be used by Navigable but for now, it's just when
traversing the history.
Sam Atkins 2 лет назад
Родитель
Сommit
8bd3b74e3a

+ 59 - 0
Userland/Libraries/LibWeb/DOM/Document.cpp

@@ -49,6 +49,7 @@
 #include <LibWeb/HTML/DocumentState.h>
 #include <LibWeb/HTML/EventLoop/EventLoop.h>
 #include <LibWeb/HTML/EventNames.h>
+#include <LibWeb/HTML/Focus.h>
 #include <LibWeb/HTML/HTMLAnchorElement.h>
 #include <LibWeb/HTML/HTMLAreaElement.h>
 #include <LibWeb/HTML/HTMLBaseElement.h>
@@ -1796,6 +1797,64 @@ Element* Document::find_a_potential_indicated_element(DeprecatedString fragment)
     return nullptr;
 }
 
+// https://html.spec.whatwg.org/multipage/browsing-the-web.html#scroll-to-the-fragment-identifier
+void Document::scroll_to_the_fragment()
+{
+    // To scroll to the fragment given a Document document:
+
+    // 1. If document's indicated part is null, then set document's target element to null.
+    auto indicated_part = determine_the_indicated_part();
+    if (indicated_part.has<Element*>() && indicated_part.get<Element*>() == nullptr) {
+        set_target_element(nullptr);
+    }
+
+    // 2. Otherwise, if document's indicated part is top of the document, then:
+    else if (indicated_part.has<TopOfTheDocument>()) {
+        // 1. Set document's target element to null.
+        set_target_element(nullptr);
+
+        // 2. Scroll to the beginning of the document for document. [CSSOMVIEW]
+        scroll_to_the_beginning_of_the_document();
+
+        // 3. Return.
+        return;
+    }
+
+    // 3. Otherwise:
+    else {
+        // 1. Assert: document's indicated part is an element.
+        VERIFY(indicated_part.has<Element*>());
+
+        // 2. Let target be document's indicated part.
+        auto target = indicated_part.get<Element*>();
+
+        // 3. Set document's target element to target.
+        set_target_element(target);
+
+        // FIXME: 4. Run the ancestor details revealing algorithm on target.
+
+        // FIXME: 5. Run the ancestor hidden-until-found revealing algorithm on target.
+
+        // 6. Scroll target into view, with behavior set to "auto", block set to "start", and inline set to "nearest". [CSSOMVIEW]
+        // FIXME: Do this properly!
+        (void)target->scroll_into_view();
+
+        // 7. Run the focusing steps for target, with the Document's viewport as the fallback target.
+        // FIXME: Pass the Document's viewport somehow.
+        HTML::run_focusing_steps(target);
+
+        // FIXME: 8. Move the sequential focus navigation starting point to target.
+    }
+}
+
+// https://drafts.csswg.org/cssom-view-1/#scroll-to-the-beginning-of-the-document
+void Document::scroll_to_the_beginning_of_the_document()
+{
+    // FIXME: Actually implement this algorithm
+    if (auto browsing_context = this->browsing_context())
+        browsing_context->scroll_to({ 0, 0 });
+}
+
 DeprecatedString Document::ready_state() const
 {
     switch (m_readiness) {

+ 3 - 0
Userland/Libraries/LibWeb/DOM/Document.h

@@ -298,6 +298,9 @@ public:
     Element const* target_element() const { return m_target_element.ptr(); }
     void set_target_element(Element*);
 
+    void scroll_to_the_fragment();
+    void scroll_to_the_beginning_of_the_document();
+
     bool created_for_appropriate_template_contents() const { return m_created_for_appropriate_template_contents; }
 
     JS::NonnullGCPtr<Document> appropriate_template_contents_owner_document();

+ 2 - 5
Userland/Libraries/LibWeb/HTML/BrowsingContext.cpp

@@ -1407,11 +1407,8 @@ WebIDL::ExceptionOr<void> BrowsingContext::traverse_the_history(size_t entry_ind
     }
 
     // 10. If entry's persisted user state is null, and its URL's fragment is non-null, then scroll to the fragment.
-    if (!entry->url.fragment().is_null()) {
-        // FIXME: Implement the full "scroll to the fragment" algorithm:
-        // https://html.spec.whatwg.org/multipage/browsing-the-web.html#scroll-to-the-fragment-identifier
-        scroll_to_anchor(entry->url.fragment());
-    }
+    if (!entry->url.fragment().is_null())
+        active_document()->scroll_to_the_fragment();
 
     // 11. Set the current entry to entry.
     m_session_history_index = entry_index;