Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LibWeb: Add NavigateEvent.sourceElement #3409

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions Libraries/LibWeb/HTML/Navigable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1327,7 +1327,8 @@ WebIDL::ExceptionOr<void> Navigable::populate_session_history_entry_document(
// an optional serialized state-or-null navigationAPIState (default null),
// an optional entry list or null formDataEntryList (default null),
// an optional referrer policy referrerPolicy (default the empty string),
// and an optional user navigation involvement userInvolvement (default "none"):
// an optional user navigation involvement userInvolvement (default "none"),
// and an optional Element sourceElement (default null):

// https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate
WebIDL::ExceptionOr<void> Navigable::navigate(NavigateParams params)
Expand All @@ -1346,6 +1347,7 @@ WebIDL::ExceptionOr<void> Navigable::navigate(NavigateParams params)
auto const& form_data_entry_list = params.form_data_entry_list;
auto referrer_policy = params.referrer_policy;
auto user_involvement = params.user_involvement;
auto source_element = params.source_element;
auto& active_document = *this->active_document();
auto& realm = active_document.realm();
auto& vm = this->vm();
Expand Down Expand Up @@ -1429,8 +1431,8 @@ WebIDL::ExceptionOr<void> Navigable::navigate(NavigateParams params)
&& !response
&& url.equals(active_session_history_entry()->url(), URL::ExcludeFragment::Yes)
&& url.fragment().has_value()) {
// 1. Navigate to a fragment given navigable, url, historyHandling, userInvolvement, navigationAPIState, and navigationId.
TRY(navigate_to_a_fragment(url, to_history_handling_behavior(history_handling), user_involvement, navigation_api_state, navigation_id));
// 1. Navigate to a fragment given navigable, url, historyHandling, userInvolvement, sourceElement, navigationAPIState, and navigationId.
TRY(navigate_to_a_fragment(url, to_history_handling_behavior(history_handling), user_involvement, source_element, navigation_api_state, navigation_id));

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

// 4. Let continue be the result of firing a push/replace/reload navigate event at navigation
// with navigationType set to historyHandling, isSameDocument set to false, userInvolvement set to userInvolvement,
// formDataEntryList set to entryListForFiring, destinationURL set to url, and navigationAPIState set to navigationAPIStateForFiring.
// sourceElement set to sourceElement, formDataEntryList set to entryListForFiring, destinationURL set to url,
// and navigationAPIState set to navigationAPIStateForFiring.
auto navigation_type = [](Bindings::NavigationHistoryBehavior history_handling) {
switch (history_handling) {
case Bindings::NavigationHistoryBehavior::Push:
Expand All @@ -1504,7 +1507,7 @@ WebIDL::ExceptionOr<void> Navigable::navigate(NavigateParams params)
VERIFY_NOT_REACHED();
}
}(history_handling);
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);
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);

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

// https://html.spec.whatwg.org/multipage/browsing-the-web.html#navigate-fragid
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)
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)
{
(void)navigation_id;

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

// 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,
// userInvolvement set to userInvolvement, and destinationURL set to url, and navigationAPIState set to destinationNavigationAPIState.
// 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, userInvolvement set to userInvolvement, sourceElement set
// to sourceElement, destinationURL set to url, and navigationAPIState set to destinationNavigationAPIState.
auto navigation_type = history_handling == HistoryHandlingBehavior::Push ? Bindings::NavigationType::Push : Bindings::NavigationType::Replace;
bool const continue_ = navigation->fire_a_push_replace_reload_navigate_event(navigation_type, url, true, user_involvement, {}, destination_navigation_api_state);
bool const continue_ = navigation->fire_a_push_replace_reload_navigate_event(navigation_type, url, true, user_involvement, source_element, {}, destination_navigation_api_state);

// 5. If continue is false, then return.
if (!continue_)
Expand Down
3 changes: 2 additions & 1 deletion Libraries/LibWeb/HTML/Navigable.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,12 @@ class Navigable : public JS::Cell {
Optional<Vector<XHR::FormDataEntry>&> form_data_entry_list = {};
ReferrerPolicy::ReferrerPolicy referrer_policy = ReferrerPolicy::ReferrerPolicy::EmptyString;
UserNavigationInvolvement user_involvement = UserNavigationInvolvement::None;
GC::Ptr<DOM::Element> source_element = nullptr;
};

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

WebIDL::ExceptionOr<void> navigate_to_a_fragment(URL::URL const&, HistoryHandlingBehavior, UserNavigationInvolvement, Optional<SerializationRecord> navigation_api_state, String navigation_id);
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);

GC::Ptr<DOM::Document> evaluate_javascript_url(URL::URL const&, URL::Origin const& new_document_origin, UserNavigationInvolvement, String navigation_id);
void navigate_to_a_javascript_url(URL::URL const&, HistoryHandlingBehavior, URL::Origin const& initiator_origin, UserNavigationInvolvement, CSPNavigationType csp_navigation_type, String navigation_id);
Expand Down
2 changes: 2 additions & 0 deletions Libraries/LibWeb/HTML/NavigateEvent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ NavigateEvent::NavigateEvent(JS::Realm& realm, FlyString const& event_name, Navi
, m_download_request(event_init.download_request)
, m_info(event_init.info.value_or(JS::js_undefined()))
, m_has_ua_visual_transition(event_init.has_ua_visual_transition)
, m_source_element(event_init.source_element)
{
}

Expand All @@ -62,6 +63,7 @@ void NavigateEvent::visit_edges(JS::Cell::Visitor& visitor)
visitor.visit(m_signal);
visitor.visit(m_form_data);
visitor.visit(m_info);
visitor.visit(m_source_element);
}

// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-navigateevent-intercept
Expand Down
10 changes: 7 additions & 3 deletions Libraries/LibWeb/HTML/NavigateEvent.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
#include <LibWeb/Bindings/NavigateEventPrototype.h>
#include <LibWeb/DOM/Event.h>
#include <LibWeb/HTML/NavigationType.h>
#include <LibWeb/HTML/StructuredSerialize.h>

namespace Web::HTML {

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

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

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

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

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

// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-navigateevent-hasuavisualtransition
bool m_has_ua_visual_transition { false };

// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-navigateevent-sourceelement
GC::Ptr<DOM::Element> m_source_element { nullptr };
};

}
Expand Down
2 changes: 2 additions & 0 deletions Libraries/LibWeb/HTML/NavigateEvent.idl
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ interface NavigateEvent : Event {
readonly attribute DOMString? downloadRequest;
readonly attribute any info;
readonly attribute boolean hasUAVisualTransition;
readonly attribute Element? sourceElement;

undefined intercept(optional NavigationInterceptOptions options = {});
undefined scroll();
Expand All @@ -35,6 +36,7 @@ dictionary NavigateEventInit : EventInit {
DOMString? downloadRequest = null;
any info;
boolean hasUAVisualTransition = false;
Element? sourceElement = null;
};

dictionary NavigationInterceptOptions {
Expand Down
20 changes: 13 additions & 7 deletions Libraries/LibWeb/HTML/Navigation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -911,6 +911,7 @@ bool Navigation::inner_navigate_event_firing_algorithm(
Bindings::NavigationType navigation_type,
GC::Ref<NavigationDestination> destination,
UserNavigationInvolvement user_involvement,
GC::Ptr<DOM::Element> source_element,
Optional<Vector<XHR::FormDataEntry>&> form_data_entry_list,
Optional<String> download_request_filename,
Optional<SerializationRecord> classic_history_api_state)
Expand Down Expand Up @@ -1011,6 +1012,9 @@ bool Navigation::inner_navigate_event_firing_algorithm(
// of the document's latest entry, was done by the user agent. Otherwise, initialize it to false.
event_init.has_ua_visual_transition = false;

// 18. Initialize event's sourceElement to sourceElement.
event_init.source_element = source_element;

// 18. Set event's abort controller to a new AbortController created in navigation's relevant realm.
// AD-HOC: Set on the NavigateEvent later after construction
auto abort_controller = MUST(DOM::AbortController::construct_impl(realm));
Expand Down Expand Up @@ -1291,9 +1295,10 @@ bool Navigation::fire_a_traverse_navigate_event(GC::Ref<SessionHistoryEntry> des
// navigation's relevant global object's associated Document; otherwise false.
destination->set_is_same_document(destination_she->document() == &as<Window>(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.
// 9. Return the result of performing the inner navigate event firing algorithm given navigation, "traverse",
// event, destination, userInvolvement, sourceElement, 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, {}, {}, {});
return inner_navigate_event_firing_algorithm(Bindings::NavigationType::Traverse, destination, user_involvement, {}, {}, {}, {});
}

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

// 8. Return the result of performing the inner navigate event firing algorithm given navigation,
// navigationType, event, destination, userInvolvement, formDataEntryList, and null.
// navigationType, event, destination, userInvolvement, sourceElement, formDataEntryList, 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(navigation_type, destination, user_involvement, move(form_data_entry_list), {}, move(classic_history_api_state));
return inner_navigate_event_firing_algorithm(navigation_type, destination, user_involvement, source_element, move(form_data_entry_list), {}, move(classic_history_api_state));
}

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

// 8. Return the result of performing the inner navigate event firing algorithm given navigation,
// "push", event, destination, userInvolvement, null, and filename.
// "push", event, destination, userInvolvement, sourceElement, null, and filename.
// 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::Push, destination, user_involvement, {}, move(filename), {});
return inner_navigate_event_firing_algorithm(Bindings::NavigationType::Push, destination, user_involvement, source_element, {}, move(filename), {});
}

// https://html.spec.whatwg.org/multipage/nav-history-apis.html#initialize-the-navigation-api-entries-for-a-new-document
Expand Down
4 changes: 3 additions & 1 deletion Libraries/LibWeb/HTML/Navigation.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,11 @@ class Navigation : public DOM::EventTarget {
URL::URL destination_url,
bool is_same_document,
UserNavigationInvolvement = UserNavigationInvolvement::None,
GC::Ptr<DOM::Element> source_element = {},
Optional<Vector<XHR::FormDataEntry>&> form_data_entry_list = {},
Optional<SerializationRecord> navigation_api_state = {},
Optional<SerializationRecord> classic_history_api_state = {});
bool fire_a_download_request_navigate_event(URL::URL destination_url, UserNavigationInvolvement user_involvement, String filename);
bool fire_a_download_request_navigate_event(URL::URL destination_url, UserNavigationInvolvement user_involvement, GC::Ptr<DOM::Element> source_element, String filename);

void initialize_the_navigation_api_entries_for_a_new_document(Vector<GC::Ref<SessionHistoryEntry>> const& new_shes, GC::Ref<SessionHistoryEntry> initial_she);
void update_the_navigation_api_entries_for_a_same_document_navigation(GC::Ref<SessionHistoryEntry> destination_she, Bindings::NavigationType);
Expand Down Expand Up @@ -154,6 +155,7 @@ class Navigation : public DOM::EventTarget {
Bindings::NavigationType,
GC::Ref<NavigationDestination>,
UserNavigationInvolvement,
GC::Ptr<DOM::Element> source_element,
Optional<Vector<XHR::FormDataEntry>&> form_data_entry_list,
Optional<String> download_request_filename,
Optional<SerializationRecord> classic_history_api_state);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,7 @@
assert_equals(event.downloadRequest, downloadRequest);
assert_equals(event.info, info);
assert_equals(event.hasUAVisualTransition, hasUAVisualTransition);
// NavigateEvent sourceElement is still in development, so test whether it is available.
if ("sourceElement" in e) assert_equals(event.sourceElement, sourceElement);
assert_equals(event.sourceElement, sourceElement);
});
history.pushState(2, null, "#2");
}, "all properties are reflected back");
Expand All @@ -99,8 +98,7 @@
assert_equals(event.formData, null);
assert_equals(event.downloadRequest, null);
assert_equals(event.info, undefined);
// NavigateEvent sourceElement is still in development, so test whether it is available.
if ("sourceElement" in e) assert_equals(event.sourceElement, null);
assert_equals(event.sourceElement, null);
});
history.pushState(3, null, "#3");
}, "defaults are as expected");
Expand Down
Loading