/src/serenity/Userland/Libraries/LibWeb/HTML/Navigation.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2023, Andrew Kaster <akaster@serenityos.org> |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #pragma once |
8 | | |
9 | | #include <LibJS/Runtime/Promise.h> |
10 | | #include <LibWeb/Bindings/NavigationPrototype.h> |
11 | | #include <LibWeb/DOM/EventTarget.h> |
12 | | #include <LibWeb/HTML/HistoryHandlingBehavior.h> |
13 | | #include <LibWeb/HTML/Navigable.h> |
14 | | #include <LibWeb/HTML/NavigationType.h> |
15 | | #include <LibWeb/HTML/StructuredSerialize.h> |
16 | | |
17 | | namespace Web::HTML { |
18 | | |
19 | | // https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigationupdatecurrententryoptions |
20 | | struct NavigationUpdateCurrentEntryOptions { |
21 | | JS::Value state; |
22 | | }; |
23 | | |
24 | | // https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigationoptions |
25 | | struct NavigationOptions { |
26 | | Optional<JS::Value> info; |
27 | | }; |
28 | | |
29 | | // https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigationnavigateoptions |
30 | | struct NavigationNavigateOptions : public NavigationOptions { |
31 | | Optional<JS::Value> state; |
32 | | Bindings::NavigationHistoryBehavior history = Bindings::NavigationHistoryBehavior::Auto; |
33 | | }; |
34 | | |
35 | | // https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigationreloadoptions |
36 | | struct NavigationReloadOptions : public NavigationOptions { |
37 | | Optional<JS::Value> state; |
38 | | }; |
39 | | |
40 | | // https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigationresult |
41 | | struct NavigationResult { |
42 | | // FIXME: Are we supposed to return a PromiseCapability (WebIDL::Promise) here? |
43 | | JS::NonnullGCPtr<JS::Object> committed; |
44 | | JS::NonnullGCPtr<JS::Object> finished; |
45 | | }; |
46 | | |
47 | | // https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigation-api-method-tracker |
48 | | struct NavigationAPIMethodTracker final : public JS::Cell { |
49 | | JS_CELL(NavigationAPIMethodTracker, JS::Cell); |
50 | | JS_DECLARE_ALLOCATOR(NavigationAPIMethodTracker); |
51 | | |
52 | | NavigationAPIMethodTracker(JS::NonnullGCPtr<Navigation> navigation, |
53 | | Optional<String> key, |
54 | | JS::Value info, |
55 | | Optional<SerializationRecord> serialized_state, |
56 | | JS::GCPtr<NavigationHistoryEntry> commited_to_entry, |
57 | | JS::NonnullGCPtr<WebIDL::Promise> committed_promise, |
58 | | JS::NonnullGCPtr<WebIDL::Promise> finished_promise); |
59 | | |
60 | | virtual void visit_edges(Cell::Visitor&) override; |
61 | | |
62 | | JS::NonnullGCPtr<Navigation> navigation; |
63 | | Optional<String> key; |
64 | | JS::Value info; |
65 | | Optional<SerializationRecord> serialized_state; |
66 | | JS::GCPtr<NavigationHistoryEntry> commited_to_entry; |
67 | | JS::NonnullGCPtr<WebIDL::Promise> committed_promise; |
68 | | JS::NonnullGCPtr<WebIDL::Promise> finished_promise; |
69 | | }; |
70 | | |
71 | | // https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigation-interface |
72 | | class Navigation : public DOM::EventTarget { |
73 | | WEB_PLATFORM_OBJECT(Navigation, DOM::EventTarget); |
74 | | JS_DECLARE_ALLOCATOR(Navigation); |
75 | | |
76 | | public: |
77 | | [[nodiscard]] static JS::NonnullGCPtr<Navigation> create(JS::Realm&); |
78 | | |
79 | | // IDL properties and methods |
80 | | Vector<JS::NonnullGCPtr<NavigationHistoryEntry>> entries() const; |
81 | | JS::GCPtr<NavigationHistoryEntry> current_entry() const; |
82 | | WebIDL::ExceptionOr<void> update_current_entry(NavigationUpdateCurrentEntryOptions); |
83 | | |
84 | | // https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-navigation-transition |
85 | 0 | JS::GCPtr<NavigationTransition> transition() const { return m_transition; } |
86 | | |
87 | | bool can_go_back() const; |
88 | | bool can_go_forward() const; |
89 | | |
90 | | WebIDL::ExceptionOr<NavigationResult> navigate(String url, NavigationNavigateOptions const&); |
91 | | WebIDL::ExceptionOr<NavigationResult> reload(NavigationReloadOptions const&); |
92 | | |
93 | | WebIDL::ExceptionOr<NavigationResult> traverse_to(String key, NavigationOptions const&); |
94 | | WebIDL::ExceptionOr<NavigationResult> back(NavigationOptions const&); |
95 | | WebIDL::ExceptionOr<NavigationResult> forward(NavigationOptions const&); |
96 | | |
97 | | // Event Handlers |
98 | | void set_onnavigate(WebIDL::CallbackType*); |
99 | | WebIDL::CallbackType* onnavigate(); |
100 | | |
101 | | void set_onnavigatesuccess(WebIDL::CallbackType*); |
102 | | WebIDL::CallbackType* onnavigatesuccess(); |
103 | | |
104 | | void set_onnavigateerror(WebIDL::CallbackType*); |
105 | | WebIDL::CallbackType* onnavigateerror(); |
106 | | |
107 | | void set_oncurrententrychange(WebIDL::CallbackType*); |
108 | | WebIDL::CallbackType* oncurrententrychange(); |
109 | | |
110 | | // Abstract Operations |
111 | | bool has_entries_and_events_disabled() const; |
112 | | i64 get_the_navigation_api_entry_index(SessionHistoryEntry const&) const; |
113 | | void abort_the_ongoing_navigation(JS::GCPtr<WebIDL::DOMException> error = {}); |
114 | | bool fire_a_traverse_navigate_event(JS::NonnullGCPtr<SessionHistoryEntry> destination_she, UserNavigationInvolvement = UserNavigationInvolvement::None); |
115 | | bool fire_a_push_replace_reload_navigate_event( |
116 | | Bindings::NavigationType, |
117 | | URL::URL destination_url, |
118 | | bool is_same_document, |
119 | | UserNavigationInvolvement = UserNavigationInvolvement::None, |
120 | | Optional<Vector<XHR::FormDataEntry>&> form_data_entry_list = {}, |
121 | | Optional<SerializationRecord> navigation_api_state = {}, |
122 | | Optional<SerializationRecord> classic_history_api_state = {}); |
123 | | bool fire_a_download_request_navigate_event(URL::URL destination_url, UserNavigationInvolvement user_involvement, String filename); |
124 | | |
125 | | void initialize_the_navigation_api_entries_for_a_new_document(Vector<JS::NonnullGCPtr<SessionHistoryEntry>> const& new_shes, JS::NonnullGCPtr<SessionHistoryEntry> initial_she); |
126 | | void update_the_navigation_api_entries_for_a_same_document_navigation(JS::NonnullGCPtr<SessionHistoryEntry> destination_she, Bindings::NavigationType); |
127 | | |
128 | | virtual ~Navigation() override; |
129 | | |
130 | | // Internal Getters/Setters |
131 | 0 | JS::GCPtr<NavigateEvent> ongoing_navigate_event() const { return m_ongoing_navigate_event; } |
132 | | |
133 | 0 | bool focus_changed_during_ongoing_navigation() const { return m_focus_changed_during_ongoing_navigation; } |
134 | 0 | void set_focus_changed_during_ongoing_navigation(bool b) { m_focus_changed_during_ongoing_navigation = b; } |
135 | | |
136 | | private: |
137 | | explicit Navigation(JS::Realm&); |
138 | | |
139 | | virtual void initialize(JS::Realm&) override; |
140 | | virtual void visit_edges(Visitor&) override; |
141 | | |
142 | | using AnyException = decltype(declval<WebIDL::ExceptionOr<void>>().exception()); |
143 | | NavigationResult early_error_result(AnyException); |
144 | | |
145 | | JS::NonnullGCPtr<NavigationAPIMethodTracker> maybe_set_the_upcoming_non_traverse_api_method_tracker(JS::Value info, Optional<SerializationRecord>); |
146 | | JS::NonnullGCPtr<NavigationAPIMethodTracker> add_an_upcoming_traverse_api_method_tracker(String destination_key, JS::Value info); |
147 | | WebIDL::ExceptionOr<NavigationResult> perform_a_navigation_api_traversal(String key, NavigationOptions const&); |
148 | | void promote_an_upcoming_api_method_tracker_to_ongoing(Optional<String> destination_key); |
149 | | void resolve_the_finished_promise(JS::NonnullGCPtr<NavigationAPIMethodTracker>); |
150 | | void reject_the_finished_promise(JS::NonnullGCPtr<NavigationAPIMethodTracker>, JS::Value exception); |
151 | | void clean_up(JS::NonnullGCPtr<NavigationAPIMethodTracker>); |
152 | | void notify_about_the_committed_to_entry(JS::NonnullGCPtr<NavigationAPIMethodTracker>, JS::NonnullGCPtr<NavigationHistoryEntry>); |
153 | | |
154 | | bool inner_navigate_event_firing_algorithm( |
155 | | Bindings::NavigationType, |
156 | | JS::NonnullGCPtr<NavigationDestination>, |
157 | | UserNavigationInvolvement, |
158 | | Optional<Vector<XHR::FormDataEntry>&> form_data_entry_list, |
159 | | Optional<String> download_request_filename, |
160 | | Optional<SerializationRecord> classic_history_api_state); |
161 | | |
162 | | // https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigation-entry-list |
163 | | // Each Navigation has an associated entry list, a list of NavigationHistoryEntry objects, initially empty. |
164 | | Vector<JS::NonnullGCPtr<NavigationHistoryEntry>> m_entry_list; |
165 | | |
166 | | // https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigation-current-entry-index |
167 | | // Each Navigation has an associated current entry index, an integer, initially −1. |
168 | | i64 m_current_entry_index { -1 }; |
169 | | |
170 | | // https://html.spec.whatwg.org/multipage/nav-history-apis.html#concept-navigation-transition |
171 | | // Each Navigation has a transition, which is a NavigationTransition or null, initially null. |
172 | | JS::GCPtr<NavigationTransition> m_transition { nullptr }; |
173 | | |
174 | | // https://html.spec.whatwg.org/multipage/nav-history-apis.html#ongoing-navigate-event |
175 | | JS::GCPtr<NavigateEvent> m_ongoing_navigate_event { nullptr }; |
176 | | |
177 | | // https://html.spec.whatwg.org/multipage/nav-history-apis.html#focus-changed-during-ongoing-navigation |
178 | | bool m_focus_changed_during_ongoing_navigation { false }; |
179 | | |
180 | | // https://html.spec.whatwg.org/multipage/nav-history-apis.html#suppress-normal-scroll-restoration-during-ongoing-navigation |
181 | | bool m_suppress_scroll_restoration_during_ongoing_navigation { false }; |
182 | | |
183 | | // https://html.spec.whatwg.org/multipage/nav-history-apis.html#ongoing-api-method-tracker |
184 | | JS::GCPtr<NavigationAPIMethodTracker> m_ongoing_api_method_tracker = nullptr; |
185 | | |
186 | | // https://html.spec.whatwg.org/multipage/nav-history-apis.html#upcoming-non-traverse-api-method-tracker |
187 | | JS::GCPtr<NavigationAPIMethodTracker> m_upcoming_non_traverse_api_method_tracker = nullptr; |
188 | | |
189 | | // https://html.spec.whatwg.org/multipage/nav-history-apis.html#upcoming-non-traverse-api-method-tracker |
190 | | HashMap<String, JS::NonnullGCPtr<NavigationAPIMethodTracker>> m_upcoming_traverse_api_method_trackers; |
191 | | }; |
192 | | |
193 | | HistoryHandlingBehavior to_history_handling_behavior(Bindings::NavigationHistoryBehavior); |
194 | | Bindings::NavigationHistoryBehavior to_navigation_history_behavior(HistoryHandlingBehavior); |
195 | | |
196 | | } |