diff --git a/Userland/Libraries/LibWeb/HTML/Navigation.cpp b/Userland/Libraries/LibWeb/HTML/Navigation.cpp index b54d1af5fa..568f8cf222 100644 --- a/Userland/Libraries/LibWeb/HTML/Navigation.cpp +++ b/Userland/Libraries/LibWeb/HTML/Navigation.cpp @@ -20,6 +20,7 @@ #include #include #include +#include namespace Web::HTML { @@ -766,4 +767,98 @@ void Navigation::abort_the_ongoing_navigation(Optional destination_key) +{ + // 1. Assert: navigation's ongoing API method tracker is null. + VERIFY(m_ongoing_api_method_tracker == nullptr); + + // 2. If destinationKey is not null, then: + if (destination_key.has_value()) { + // 1. Assert: navigation's upcoming non-traverse API method tracker is null. + VERIFY(m_upcoming_non_traverse_api_method_tracker == nullptr); + + // 2. If navigation's upcoming traverse API method trackers[destinationKey] exists, then: + if (auto tracker = m_upcoming_traverse_api_method_trackers.get(destination_key.value()); tracker.has_value()) { + // 1. Set navigation's ongoing API method tracker to navigation's upcoming traverse API method trackers[destinationKey]. + m_ongoing_api_method_tracker = tracker.value(); + + // 2. Remove navigation's upcoming traverse API method trackers[destinationKey]. + m_upcoming_traverse_api_method_trackers.remove(destination_key.value()); + } + } + + // 3. Otherwise: + else { + VERIFY(m_upcoming_non_traverse_api_method_tracker != nullptr); + + // 1. Set navigation's ongoing API method tracker to navigation's upcoming non-traverse API method tracker. + m_ongoing_api_method_tracker = m_upcoming_non_traverse_api_method_tracker; + + // 2. Set navigation's upcoming non-traverse API method tracker to null. + m_upcoming_non_traverse_api_method_tracker = nullptr; + } +} + +// https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigation-api-method-tracker-clean-up +void Navigation::clean_up(JS::NonnullGCPtr api_method_tracker) +{ + // 1. Let navigation be apiMethodTracker's navigation object. + VERIFY(api_method_tracker->navigation == this); + + // 2. If navigation's ongoing API method tracker is apiMethodTracker, then set navigation's ongoing API method tracker to null. + if (m_ongoing_api_method_tracker == api_method_tracker) { + m_ongoing_api_method_tracker = nullptr; + } + // 3. Otherwise: + else { + // 1. Let key be apiMethodTracker's key. + auto& key = api_method_tracker->key; + + // 2. Assert: key is not null. + VERIFY(key.has_value()); + + // 3. Assert: navigation's upcoming traverse API method trackers[key] exists. + VERIFY(m_upcoming_traverse_api_method_trackers.contains(*key)); + + // 4. Remove navigation's upcoming traverse API method trackers[key]. + m_upcoming_traverse_api_method_trackers.remove(*key); + } +} + +// https://html.spec.whatwg.org/multipage/nav-history-apis.html#resolve-the-finished-promise +void Navigation::resolve_the_finished_promise(JS::NonnullGCPtr api_method_tracker) +{ + auto& realm = this->realm(); + + // 1. Resolve apiMethodTracker's committed promise with its committed-to entry. + // NOTE: Usually, notify about the committed-to entry has previously been called on apiMethodTracker, + // and so this will do nothing. However, in some cases resolve the finished promise is called + // directly, in which case this step is necessary. + WebIDL::resolve_promise(realm, api_method_tracker->committed_promise, api_method_tracker->commited_to_entry); + + // 2. Resolve apiMethodTracker's finished promise with its committed-to entry. + WebIDL::resolve_promise(realm, api_method_tracker->finished_promise, api_method_tracker->commited_to_entry); + + // 3. Clean up apiMethodTracker. + clean_up(api_method_tracker); +} + +// https://html.spec.whatwg.org/multipage/nav-history-apis.html#reject-the-finished-promise +void Navigation::reject_the_finished_promise(JS::NonnullGCPtr api_method_tracker, JS::Value exception) +{ + auto& realm = this->realm(); + + // 1. Reject apiMethodTracker's committed promise with exception. + // NOTE: This will do nothing if apiMethodTracker's committed promise was previously resolved + // via notify about the committed-to entry. + WebIDL::reject_promise(realm, api_method_tracker->committed_promise, exception); + + // 2. Reject apiMethodTracker's finished promise with exception. + WebIDL::reject_promise(realm, api_method_tracker->finished_promise, exception); + + // 3. Clean up apiMethodTracker. + clean_up(api_method_tracker); +} + } diff --git a/Userland/Libraries/LibWeb/HTML/Navigation.h b/Userland/Libraries/LibWeb/HTML/Navigation.h index 2f40c7fab4..b1f144b53d 100644 --- a/Userland/Libraries/LibWeb/HTML/Navigation.h +++ b/Userland/Libraries/LibWeb/HTML/Navigation.h @@ -128,6 +128,10 @@ private: JS::NonnullGCPtr maybe_set_the_upcoming_non_traverse_api_method_tracker(JS::Value info, Optional); JS::NonnullGCPtr add_an_upcoming_traverse_api_method_tracker(String destination_key, JS::Value info); WebIDL::ExceptionOr perform_a_navigation_api_traversal(String key, NavigationOptions const&); + void promote_an_upcoming_api_method_tracker_to_ongoing(Optional destination_key); + void resolve_the_finished_promise(JS::NonnullGCPtr); + void reject_the_finished_promise(JS::NonnullGCPtr, JS::Value exception); + void clean_up(JS::NonnullGCPtr); // https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigation-entry-list // Each Navigation has an associated entry list, a list of NavigationHistoryEntry objects, initially empty.