From 5549371b5239c82b1c9d30a88da2b6a3586bef90 Mon Sep 17 00:00:00 2001 From: Andrew Kaster Date: Fri, 22 Sep 2023 19:10:23 -0600 Subject: [PATCH] LibWeb: Implement fire a traverse navigate event on Navigation --- Userland/Libraries/LibWeb/HTML/Navigation.cpp | 50 +++++++++++++++++++ Userland/Libraries/LibWeb/HTML/Navigation.h | 1 + 2 files changed, 51 insertions(+) diff --git a/Userland/Libraries/LibWeb/HTML/Navigation.cpp b/Userland/Libraries/LibWeb/HTML/Navigation.cpp index 0e1366fc66..942cbb8b26 100644 --- a/Userland/Libraries/LibWeb/HTML/Navigation.cpp +++ b/Userland/Libraries/LibWeb/HTML/Navigation.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -1202,4 +1203,53 @@ bool Navigation::inner_navigate_event_firing_algorithm( return event->interception_state() == NavigateEvent::InterceptionState::None; } +// https://html.spec.whatwg.org/multipage/nav-history-apis.html#fire-a-traverse-navigate-event +bool Navigation::fire_a_traverse_navigate_event(JS::NonnullGCPtr destination_she, UserNavigationInvolvement user_involvement) +{ + auto& realm = relevant_realm(*this); + auto& vm = this->vm(); + + // 1. Let event be the result of creating an event given NavigateEvent, in navigation's relevant realm. + // 2. Set event's classic history API state to null. + // AD-HOC: These are handled in the inner algorithm + + // 3. Let destination be a new NavigationDestination created in navigation's relevant realm. + auto destination = NavigationDestination::create(realm); + + // 4. Set destination's URL to destinationSHE's URL. + destination->set_url(destination_she->url); + + // 5. Let destinationNHE be the NavigationHistoryEntry in navigation's entry list whose session history entry is destinationSHE, + // or null if no such NavigationHistoryEntry exists. + auto destination_nhe = m_entry_list.find_if([destination_she](auto& nhe) { + return &nhe->session_history_entry() == destination_she; + }); + + // 6. If destinationNHE is non-null, then: + if (destination_nhe != m_entry_list.end()) { + // 1. Set destination's entry to destinationNHE. + destination->set_entry(*destination_nhe); + + // 2. Set destination's state to destinationSHE's navigation API state. + destination->set_state(destination_she->navigation_api_state); + } + + // 7. Otherwise: + else { + // 1. Set destination's entry to null. + destination->set_entry(nullptr); + + // 2. Set destination's state to StructuredSerializeForStorage(null). + destination->set_state(MUST(structured_serialize_for_storage(vm, JS::js_null()))); + } + + // 8. Set destination's is same document to true if destinationSHE's document is equal to + // navigation's relevant global object's associated Document; otherwise false. + destination->set_is_same_document(destination_she->document_state->document() == &verify_cast(relevant_global_object(*this)).associated_document()); + + // 9. Return the result of performing the inner navigate event firing algorithm given navigation, "traverse", event, destination, userInvolvement, null, and null. + // AD-HOC: We don't pass the event, but we do pass the classic_history_api state at the end to be set later + return inner_navigate_event_firing_algorithm(Bindings::NavigationType::Traverse, destination, user_involvement, {}, {}, {}); +} + } diff --git a/Userland/Libraries/LibWeb/HTML/Navigation.h b/Userland/Libraries/LibWeb/HTML/Navigation.h index 1f403c6e01..709ac53c14 100644 --- a/Userland/Libraries/LibWeb/HTML/Navigation.h +++ b/Userland/Libraries/LibWeb/HTML/Navigation.h @@ -109,6 +109,7 @@ public: bool has_entries_and_events_disabled() const; i64 get_the_navigation_api_entry_index(SessionHistoryEntry const&) const; void abort_the_ongoing_navigation(Optional> error = {}); + bool fire_a_traverse_navigate_event(JS::NonnullGCPtr destination_she, UserNavigationInvolvement = UserNavigationInvolvement::None); virtual ~Navigation() override;