Skip to content

Commit f5e4f20

Browse files
committed
LibWeb: Add NavigateEvent.sourceElement
Corresponds to: - whatwg/html#10898 - whatwg/html#10971 I've also updated the imported WPT test as it's been recently changed to account for 10898 being merged.
1 parent 8dfd382 commit f5e4f20

File tree

8 files changed

+44
-25
lines changed

8 files changed

+44
-25
lines changed

Libraries/LibWeb/HTML/Navigable.cpp

+13-9
Original file line numberDiff line numberDiff line change
@@ -1327,7 +1327,8 @@ WebIDL::ExceptionOr<void> Navigable::populate_session_history_entry_document(
13271327
// an optional serialized state-or-null navigationAPIState (default null),
13281328
// an optional entry list or null formDataEntryList (default null),
13291329
// an optional referrer policy referrerPolicy (default the empty string),
1330-
// and an optional user navigation involvement userInvolvement (default "none"):
1330+
// an optional user navigation involvement userInvolvement (default "none"),
1331+
// and an optional Element sourceElement (default null):
13311332

13321333
// https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate
13331334
WebIDL::ExceptionOr<void> Navigable::navigate(NavigateParams params)
@@ -1346,6 +1347,7 @@ WebIDL::ExceptionOr<void> Navigable::navigate(NavigateParams params)
13461347
auto const& form_data_entry_list = params.form_data_entry_list;
13471348
auto referrer_policy = params.referrer_policy;
13481349
auto user_involvement = params.user_involvement;
1350+
auto source_element = params.source_element;
13491351
auto& active_document = *this->active_document();
13501352
auto& realm = active_document.realm();
13511353
auto& vm = this->vm();
@@ -1429,8 +1431,8 @@ WebIDL::ExceptionOr<void> Navigable::navigate(NavigateParams params)
14291431
&& !response
14301432
&& url.equals(active_session_history_entry()->url(), URL::ExcludeFragment::Yes)
14311433
&& url.fragment().has_value()) {
1432-
// 1. Navigate to a fragment given navigable, url, historyHandling, userInvolvement, navigationAPIState, and navigationId.
1433-
TRY(navigate_to_a_fragment(url, to_history_handling_behavior(history_handling), user_involvement, navigation_api_state, navigation_id));
1434+
// 1. Navigate to a fragment given navigable, url, historyHandling, userInvolvement, sourceElement, navigationAPIState, and navigationId.
1435+
TRY(navigate_to_a_fragment(url, to_history_handling_behavior(history_handling), user_involvement, source_element, navigation_api_state, navigation_id));
14341436

14351437
// 2. Return.
14361438
return {};
@@ -1492,7 +1494,8 @@ WebIDL::ExceptionOr<void> Navigable::navigate(NavigateParams params)
14921494

14931495
// 4. Let continue be the result of firing a push/replace/reload navigate event at navigation
14941496
// with navigationType set to historyHandling, isSameDocument set to false, userInvolvement set to userInvolvement,
1495-
// formDataEntryList set to entryListForFiring, destinationURL set to url, and navigationAPIState set to navigationAPIStateForFiring.
1497+
// sourceElement set to sourceElement, formDataEntryList set to entryListForFiring, destinationURL set to url,
1498+
// and navigationAPIState set to navigationAPIStateForFiring.
14961499
auto navigation_type = [](Bindings::NavigationHistoryBehavior history_handling) {
14971500
switch (history_handling) {
14981501
case Bindings::NavigationHistoryBehavior::Push:
@@ -1504,7 +1507,7 @@ WebIDL::ExceptionOr<void> Navigable::navigate(NavigateParams params)
15041507
VERIFY_NOT_REACHED();
15051508
}
15061509
}(history_handling);
1507-
auto continue_ = navigation->fire_a_push_replace_reload_navigate_event(navigation_type, url, false, user_involvement, entry_list_for_firing, navigation_api_state_for_firing);
1510+
auto continue_ = navigation->fire_a_push_replace_reload_navigate_event(navigation_type, url, false, user_involvement, source_element, entry_list_for_firing, navigation_api_state_for_firing);
15081511

15091512
// 5. If continue is false, then return.
15101513
if (!continue_)
@@ -1611,7 +1614,7 @@ WebIDL::ExceptionOr<void> Navigable::navigate(NavigateParams params)
16111614
}
16121615

16131616
// https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate-fragid
1614-
WebIDL::ExceptionOr<void> Navigable::navigate_to_a_fragment(URL::URL const& url, HistoryHandlingBehavior history_handling, UserNavigationInvolvement user_involvement, Optional<SerializationRecord> navigation_api_state, String navigation_id)
1617+
WebIDL::ExceptionOr<void> Navigable::navigate_to_a_fragment(URL::URL const& url, HistoryHandlingBehavior history_handling, UserNavigationInvolvement user_involvement, GC::Ptr<DOM::Element> source_element, Optional<SerializationRecord> navigation_api_state, String navigation_id)
16151618
{
16161619
(void)navigation_id;
16171620

@@ -1623,10 +1626,11 @@ WebIDL::ExceptionOr<void> Navigable::navigate_to_a_fragment(URL::URL const& url,
16231626
// 3. If navigationAPIState is not null, then set destinationNavigationAPIState to navigationAPIState.
16241627
auto destination_navigation_api_state = navigation_api_state.has_value() ? *navigation_api_state : active_session_history_entry()->navigation_api_state();
16251628

1626-
// 4. Let continue be the result of firing a push/replace/reload navigate event at navigation with navigationType set to historyHandling, isSameDocument set to true,
1627-
// userInvolvement set to userInvolvement, and destinationURL set to url, and navigationAPIState set to destinationNavigationAPIState.
1629+
// 4. Let continue be the result of firing a push/replace/reload navigate event at navigation with navigationType
1630+
// set to historyHandling, isSameDocument set to true, userInvolvement set to userInvolvement, sourceElement set
1631+
// to sourceElement, destinationURL set to url, and navigationAPIState set to destinationNavigationAPIState.
16281632
auto navigation_type = history_handling == HistoryHandlingBehavior::Push ? Bindings::NavigationType::Push : Bindings::NavigationType::Replace;
1629-
bool const continue_ = navigation->fire_a_push_replace_reload_navigate_event(navigation_type, url, true, user_involvement, {}, destination_navigation_api_state);
1633+
bool const continue_ = navigation->fire_a_push_replace_reload_navigate_event(navigation_type, url, true, user_involvement, source_element, {}, destination_navigation_api_state);
16301634

16311635
// 5. If continue is false, then return.
16321636
if (!continue_)

Libraries/LibWeb/HTML/Navigable.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -146,11 +146,12 @@ class Navigable : public JS::Cell {
146146
Optional<Vector<XHR::FormDataEntry>&> form_data_entry_list = {};
147147
ReferrerPolicy::ReferrerPolicy referrer_policy = ReferrerPolicy::ReferrerPolicy::EmptyString;
148148
UserNavigationInvolvement user_involvement = UserNavigationInvolvement::None;
149+
GC::Ptr<DOM::Element> source_element = nullptr;
149150
};
150151

151152
WebIDL::ExceptionOr<void> navigate(NavigateParams);
152153

153-
WebIDL::ExceptionOr<void> navigate_to_a_fragment(URL::URL const&, HistoryHandlingBehavior, UserNavigationInvolvement, Optional<SerializationRecord> navigation_api_state, String navigation_id);
154+
WebIDL::ExceptionOr<void> navigate_to_a_fragment(URL::URL const&, HistoryHandlingBehavior, UserNavigationInvolvement, GC::Ptr<DOM::Element> source_element, Optional<SerializationRecord> navigation_api_state, String navigation_id);
154155

155156
GC::Ptr<DOM::Document> evaluate_javascript_url(URL::URL const&, URL::Origin const& new_document_origin, UserNavigationInvolvement, String navigation_id);
156157
void navigate_to_a_javascript_url(URL::URL const&, HistoryHandlingBehavior, URL::Origin const& initiator_origin, UserNavigationInvolvement, CSPNavigationType csp_navigation_type, String navigation_id);

Libraries/LibWeb/HTML/NavigateEvent.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ NavigateEvent::NavigateEvent(JS::Realm& realm, FlyString const& event_name, Navi
4242
, m_download_request(event_init.download_request)
4343
, m_info(event_init.info.value_or(JS::js_undefined()))
4444
, m_has_ua_visual_transition(event_init.has_ua_visual_transition)
45+
, m_source_element(event_init.source_element)
4546
{
4647
}
4748

@@ -62,6 +63,7 @@ void NavigateEvent::visit_edges(JS::Cell::Visitor& visitor)
6263
visitor.visit(m_signal);
6364
visitor.visit(m_form_data);
6465
visitor.visit(m_info);
66+
visitor.visit(m_source_element);
6567
}
6668

6769
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-navigateevent-intercept

Libraries/LibWeb/HTML/NavigateEvent.h

+7-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
#include <LibWeb/Bindings/NavigateEventPrototype.h>
1010
#include <LibWeb/DOM/Event.h>
1111
#include <LibWeb/HTML/NavigationType.h>
12-
#include <LibWeb/HTML/StructuredSerialize.h>
1312

1413
namespace Web::HTML {
1514

@@ -25,6 +24,7 @@ struct NavigateEventInit : public DOM::EventInit {
2524
Optional<String> download_request = {};
2625
Optional<JS::Value> info;
2726
bool has_ua_visual_transition = false;
27+
GC::Ptr<DOM::Element> source_element = nullptr;
2828
};
2929

3030
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#navigationintercepthandler
@@ -54,8 +54,8 @@ class NavigateEvent : public DOM::Event {
5454

5555
[[nodiscard]] static GC::Ref<NavigateEvent> construct_impl(JS::Realm&, FlyString const& event_name, NavigateEventInit const&);
5656

57-
// The navigationType, destination, canIntercept, userInitiated, hashChange, signal, formData,
58-
// downloadRequest, info, and hasUAVisualTransition attributes must return the values they are initialized to.
57+
// The navigationType, destination, canIntercept, userInitiated, hashChange, signal, formData, downloadRequest,
58+
// info, hasUAVisualTransition, and sourceElement attributes must return the values they are initialized to.
5959
Bindings::NavigationType navigation_type() const { return m_navigation_type; }
6060
GC::Ref<NavigationDestination> destination() const { return m_destination; }
6161
bool can_intercept() const { return m_can_intercept; }
@@ -66,6 +66,7 @@ class NavigateEvent : public DOM::Event {
6666
Optional<String> download_request() const { return m_download_request; }
6767
JS::Value info() const { return m_info; }
6868
bool has_ua_visual_transition() const { return m_has_ua_visual_transition; }
69+
GC::Ptr<DOM::Element> source_element() const { return m_source_element; }
6970

7071
WebIDL::ExceptionOr<void> intercept(NavigationInterceptOptions const&);
7172
WebIDL::ExceptionOr<void> scroll();
@@ -141,6 +142,9 @@ class NavigateEvent : public DOM::Event {
141142

142143
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-navigateevent-hasuavisualtransition
143144
bool m_has_ua_visual_transition { false };
145+
146+
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-navigateevent-sourceelement
147+
GC::Ptr<DOM::Element> m_source_element { nullptr };
144148
};
145149

146150
}

Libraries/LibWeb/HTML/NavigateEvent.idl

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ interface NavigateEvent : Event {
1919
readonly attribute DOMString? downloadRequest;
2020
readonly attribute any info;
2121
readonly attribute boolean hasUAVisualTransition;
22+
readonly attribute Element? sourceElement;
2223

2324
undefined intercept(optional NavigationInterceptOptions options = {});
2425
undefined scroll();
@@ -35,6 +36,7 @@ dictionary NavigateEventInit : EventInit {
3536
DOMString? downloadRequest = null;
3637
any info;
3738
boolean hasUAVisualTransition = false;
39+
Element? sourceElement = null;
3840
};
3941

4042
dictionary NavigationInterceptOptions {

Libraries/LibWeb/HTML/Navigation.cpp

+13-7
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,7 @@ bool Navigation::inner_navigate_event_firing_algorithm(
911911
Bindings::NavigationType navigation_type,
912912
GC::Ref<NavigationDestination> destination,
913913
UserNavigationInvolvement user_involvement,
914+
GC::Ptr<DOM::Element> source_element,
914915
Optional<Vector<XHR::FormDataEntry>&> form_data_entry_list,
915916
Optional<String> download_request_filename,
916917
Optional<SerializationRecord> classic_history_api_state)
@@ -1011,6 +1012,9 @@ bool Navigation::inner_navigate_event_firing_algorithm(
10111012
// of the document's latest entry, was done by the user agent. Otherwise, initialize it to false.
10121013
event_init.has_ua_visual_transition = false;
10131014

1015+
// 18. Initialize event's sourceElement to sourceElement.
1016+
event_init.source_element = source_element;
1017+
10141018
// 18. Set event's abort controller to a new AbortController created in navigation's relevant realm.
10151019
// AD-HOC: Set on the NavigateEvent later after construction
10161020
auto abort_controller = MUST(DOM::AbortController::construct_impl(realm));
@@ -1291,9 +1295,10 @@ bool Navigation::fire_a_traverse_navigate_event(GC::Ref<SessionHistoryEntry> des
12911295
// navigation's relevant global object's associated Document; otherwise false.
12921296
destination->set_is_same_document(destination_she->document() == &as<Window>(relevant_global_object(*this)).associated_document());
12931297

1294-
// 9. Return the result of performing the inner navigate event firing algorithm given navigation, "traverse", event, destination, userInvolvement, null, and null.
1298+
// 9. Return the result of performing the inner navigate event firing algorithm given navigation, "traverse",
1299+
// event, destination, userInvolvement, sourceElement, null, and null.
12951300
// AD-HOC: We don't pass the event, but we do pass the classic_history_api state at the end to be set later
1296-
return inner_navigate_event_firing_algorithm(Bindings::NavigationType::Traverse, destination, user_involvement, {}, {}, {});
1301+
return inner_navigate_event_firing_algorithm(Bindings::NavigationType::Traverse, destination, user_involvement, {}, {}, {}, {});
12971302
}
12981303

12991304
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#fire-a-push/replace/reload-navigate-event
@@ -1302,6 +1307,7 @@ bool Navigation::fire_a_push_replace_reload_navigate_event(
13021307
URL::URL destination_url,
13031308
bool is_same_document,
13041309
UserNavigationInvolvement user_involvement,
1310+
GC::Ptr<DOM::Element> source_element,
13051311
Optional<Vector<XHR::FormDataEntry>&> form_data_entry_list,
13061312
Optional<SerializationRecord> navigation_api_state,
13071313
Optional<SerializationRecord> classic_history_api_state)
@@ -1333,13 +1339,13 @@ bool Navigation::fire_a_push_replace_reload_navigate_event(
13331339
destination->set_is_same_document(is_same_document);
13341340

13351341
// 8. Return the result of performing the inner navigate event firing algorithm given navigation,
1336-
// navigationType, event, destination, userInvolvement, formDataEntryList, and null.
1342+
// navigationType, event, destination, userInvolvement, sourceElement, formDataEntryList, and null.
13371343
// AD-HOC: We don't pass the event, but we do pass the classic_history_api state at the end to be set later
1338-
return inner_navigate_event_firing_algorithm(navigation_type, destination, user_involvement, move(form_data_entry_list), {}, move(classic_history_api_state));
1344+
return inner_navigate_event_firing_algorithm(navigation_type, destination, user_involvement, source_element, move(form_data_entry_list), {}, move(classic_history_api_state));
13391345
}
13401346

13411347
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#fire-a-download-request-navigate-event
1342-
bool Navigation::fire_a_download_request_navigate_event(URL::URL destination_url, UserNavigationInvolvement user_involvement, String filename)
1348+
bool Navigation::fire_a_download_request_navigate_event(URL::URL destination_url, UserNavigationInvolvement user_involvement, GC::Ptr<DOM::Element> source_element, String filename)
13431349
{
13441350
auto& realm = relevant_realm(*this);
13451351
auto& vm = this->vm();
@@ -1364,9 +1370,9 @@ bool Navigation::fire_a_download_request_navigate_event(URL::URL destination_url
13641370
destination->set_is_same_document(false);
13651371

13661372
// 8. Return the result of performing the inner navigate event firing algorithm given navigation,
1367-
// "push", event, destination, userInvolvement, null, and filename.
1373+
// "push", event, destination, userInvolvement, sourceElement, null, and filename.
13681374
// AD-HOC: We don't pass the event, but we do pass the classic_history_api state at the end to be set later
1369-
return inner_navigate_event_firing_algorithm(Bindings::NavigationType::Push, destination, user_involvement, {}, move(filename), {});
1375+
return inner_navigate_event_firing_algorithm(Bindings::NavigationType::Push, destination, user_involvement, source_element, {}, move(filename), {});
13701376
}
13711377

13721378
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#initialize-the-navigation-api-entries-for-a-new-document

Libraries/LibWeb/HTML/Navigation.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,11 @@ class Navigation : public DOM::EventTarget {
116116
URL::URL destination_url,
117117
bool is_same_document,
118118
UserNavigationInvolvement = UserNavigationInvolvement::None,
119+
GC::Ptr<DOM::Element> source_element = {},
119120
Optional<Vector<XHR::FormDataEntry>&> form_data_entry_list = {},
120121
Optional<SerializationRecord> navigation_api_state = {},
121122
Optional<SerializationRecord> classic_history_api_state = {});
122-
bool fire_a_download_request_navigate_event(URL::URL destination_url, UserNavigationInvolvement user_involvement, String filename);
123+
bool fire_a_download_request_navigate_event(URL::URL destination_url, UserNavigationInvolvement user_involvement, GC::Ptr<DOM::Element> source_element, String filename);
123124

124125
void initialize_the_navigation_api_entries_for_a_new_document(Vector<GC::Ref<SessionHistoryEntry>> const& new_shes, GC::Ref<SessionHistoryEntry> initial_she);
125126
void update_the_navigation_api_entries_for_a_same_document_navigation(GC::Ref<SessionHistoryEntry> destination_she, Bindings::NavigationType);
@@ -154,6 +155,7 @@ class Navigation : public DOM::EventTarget {
154155
Bindings::NavigationType,
155156
GC::Ref<NavigationDestination>,
156157
UserNavigationInvolvement,
158+
GC::Ptr<DOM::Element> source_element,
157159
Optional<Vector<XHR::FormDataEntry>&> form_data_entry_list,
158160
Optional<String> download_request_filename,
159161
Optional<SerializationRecord> classic_history_api_state);

Tests/LibWeb/Text/input/wpt-import/navigation-api/navigate-event/event-constructor.html

+2-4
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,7 @@
7878
assert_equals(event.downloadRequest, downloadRequest);
7979
assert_equals(event.info, info);
8080
assert_equals(event.hasUAVisualTransition, hasUAVisualTransition);
81-
// NavigateEvent sourceElement is still in development, so test whether it is available.
82-
if ("sourceElement" in e) assert_equals(event.sourceElement, sourceElement);
81+
assert_equals(event.sourceElement, sourceElement);
8382
});
8483
history.pushState(2, null, "#2");
8584
}, "all properties are reflected back");
@@ -99,8 +98,7 @@
9998
assert_equals(event.formData, null);
10099
assert_equals(event.downloadRequest, null);
101100
assert_equals(event.info, undefined);
102-
// NavigateEvent sourceElement is still in development, so test whether it is available.
103-
if ("sourceElement" in e) assert_equals(event.sourceElement, null);
101+
assert_equals(event.sourceElement, null);
104102
});
105103
history.pushState(3, null, "#3");
106104
}, "defaults are as expected");

0 commit comments

Comments
 (0)