2020-09-06 14:28:41 +02:00
/*
2022-02-16 20:43:24 +01:00
* Copyright ( c ) 2020 - 2022 , Andreas Kling < kling @ serenityos . org >
2020-09-06 14:28:41 +02:00
*
2021-04-22 01:24:48 -07:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-09-06 14:28:41 +02:00
*/
2020-11-21 18:32:39 +00:00
# include <AK/Assertions.h>
# include <AK/TypeCasts.h>
2022-01-23 02:12:26 -07:00
# include <LibJS/Runtime/AbstractOperations.h>
2021-06-27 21:48:34 +02:00
# include <LibJS/Runtime/FunctionObject.h>
2020-09-06 14:28:41 +02:00
# include <LibWeb/Bindings/EventTargetWrapper.h>
# include <LibWeb/Bindings/EventTargetWrapperFactory.h>
2020-10-15 20:02:28 +02:00
# include <LibWeb/Bindings/EventWrapper.h>
# include <LibWeb/Bindings/EventWrapperFactory.h>
2021-10-14 18:03:08 +01:00
# include <LibWeb/Bindings/IDLAbstractOperations.h>
2020-11-21 18:32:39 +00:00
# include <LibWeb/Bindings/WindowObject.h>
2022-02-16 20:43:24 +01:00
# include <LibWeb/DOM/AbortSignal.h>
2020-11-21 18:32:39 +00:00
# include <LibWeb/DOM/Document.h>
2020-09-06 14:28:41 +02:00
# include <LibWeb/DOM/Event.h>
# include <LibWeb/DOM/EventDispatcher.h>
# include <LibWeb/DOM/EventTarget.h>
2022-02-16 20:43:24 +01:00
# include <LibWeb/DOM/IDLEventListener.h>
2020-11-21 18:32:39 +00:00
# include <LibWeb/DOM/Node.h>
# include <LibWeb/DOM/ShadowRoot.h>
2020-11-21 19:15:57 +00:00
# include <LibWeb/HTML/EventNames.h>
2022-02-07 15:12:41 +01:00
# include <LibWeb/HTML/Scripting/ExceptionReporter.h>
2022-03-07 23:08:26 +01:00
# include <LibWeb/HTML/Window.h>
2020-11-21 18:32:39 +00:00
# include <LibWeb/UIEvents/MouseEvent.h>
2020-09-06 14:28:41 +02:00
namespace Web : : DOM {
2020-11-21 18:32:39 +00:00
// FIXME: This shouldn't be here, as retargeting is not only used by the event dispatcher.
// When moving this function, it needs to be generalized. https://dom.spec.whatwg.org/#retarget
2021-09-02 02:17:43 +01:00
static EventTarget * retarget ( EventTarget * left , EventTarget * right )
2020-09-06 14:28:41 +02:00
{
2022-04-19 23:56:38 +02:00
// To retarget an object A against an object B, repeat these steps until they return an object:
2020-11-21 18:32:39 +00:00
for ( ; ; ) {
2022-04-19 23:56:38 +02:00
// 1. If one of the following is true then return A.
2022-04-20 19:48:48 +02:00
// - A is not a node
2020-11-21 18:32:39 +00:00
if ( ! is < Node > ( left ) )
return left ;
2022-04-20 19:48:48 +02:00
// - A’ s root is not a shadow root
2021-06-24 19:53:42 +02:00
auto * left_node = verify_cast < Node > ( left ) ;
2021-09-02 19:27:42 +01:00
auto & left_root = left_node - > root ( ) ;
2021-01-01 18:12:33 +01:00
if ( ! is < ShadowRoot > ( left_root ) )
2020-11-21 18:32:39 +00:00
return left ;
2022-04-20 19:48:48 +02:00
// - B is a node and A’ s root is a shadow-including inclusive ancestor of B
2021-09-02 19:27:42 +01:00
if ( is < Node > ( right ) & & left_root . is_shadow_including_inclusive_ancestor_of ( verify_cast < Node > ( * right ) ) )
2021-09-02 02:17:43 +01:00
return left ;
2020-11-21 18:32:39 +00:00
2022-04-19 23:56:38 +02:00
// 2. Set A to A’ s root’ s host.
2021-09-02 19:27:42 +01:00
auto & left_shadow_root = verify_cast < ShadowRoot > ( left_root ) ;
left = left_shadow_root . host ( ) ;
2020-11-21 18:32:39 +00:00
}
}
// https://dom.spec.whatwg.org/#concept-event-listener-inner-invoke
2022-02-16 20:43:24 +01:00
bool EventDispatcher : : inner_invoke ( Event & event , Vector < NonnullRefPtr < DOM : : DOMEventListener > > & listeners , Event : : Phase phase , bool invocation_target_in_shadow_tree )
2020-11-21 18:32:39 +00:00
{
2021-10-14 18:03:08 +01:00
// 1. Let found be false.
2020-11-21 18:32:39 +00:00
bool found = false ;
2021-10-14 18:03:08 +01:00
// 2. For each listener in listeners, whose removed is false:
2020-09-06 14:28:41 +02:00
for ( auto & listener : listeners ) {
2022-02-16 20:43:24 +01:00
if ( listener - > removed )
2020-11-21 18:32:39 +00:00
continue ;
2021-10-14 18:03:08 +01:00
// 1. If event’ s type attribute value is not listener’ s type, then continue.
2022-02-16 20:43:24 +01:00
if ( event . type ( ) ! = listener - > type )
2020-09-06 14:28:41 +02:00
continue ;
2020-11-21 18:32:39 +00:00
2021-10-14 18:03:08 +01:00
// 2. Set found to true.
2020-11-21 18:32:39 +00:00
found = true ;
2021-10-14 18:03:08 +01:00
// 3. If phase is "capturing" and listener’ s capture is false, then continue.
2022-02-16 20:43:24 +01:00
if ( phase = = Event : : Phase : : CapturingPhase & & ! listener - > capture )
2020-11-21 18:32:39 +00:00
continue ;
2021-10-14 18:03:08 +01:00
// 4. If phase is "bubbling" and listener’ s capture is true, then continue.
2022-02-16 20:43:24 +01:00
if ( phase = = Event : : Phase : : BubblingPhase & & listener - > capture )
2020-11-21 18:32:39 +00:00
continue ;
2021-10-14 18:03:08 +01:00
// 5. If listener’ s once is true, then remove listener from event’ s currentTarget attribute value’ s event listener list.
2022-02-16 20:43:24 +01:00
if ( listener - > once )
event . current_target ( ) - > remove_from_event_listener_list ( listener ) ;
2020-11-21 18:32:39 +00:00
2021-10-14 18:03:08 +01:00
// 6. Let global be listener callback’ s associated Realm’ s global object.
2022-02-16 20:43:24 +01:00
auto & callback = listener - > callback - > callback ( ) ;
2021-10-14 18:03:08 +01:00
auto & global = callback . callback . cell ( ) - > global_object ( ) ;
2020-11-21 18:32:39 +00:00
2021-10-14 18:03:08 +01:00
// 7. Let currentEvent be undefined.
2020-11-21 18:32:39 +00:00
RefPtr < Event > current_event ;
2021-10-14 18:03:08 +01:00
// 8. If global is a Window object, then:
2020-11-21 18:32:39 +00:00
if ( is < Bindings : : WindowObject > ( global ) ) {
2021-06-24 19:53:42 +02:00
auto & bindings_window_global = verify_cast < Bindings : : WindowObject > ( global ) ;
2020-11-21 18:32:39 +00:00
auto & window_impl = bindings_window_global . impl ( ) ;
2021-10-14 18:03:08 +01:00
// 1. Set currentEvent to global’ s current event.
2020-11-21 18:32:39 +00:00
current_event = window_impl . current_event ( ) ;
2021-10-14 18:03:08 +01:00
// 2. If invocationTargetInShadowTree is false, then set global’ s current event to event.
2020-11-21 18:32:39 +00:00
if ( ! invocation_target_in_shadow_tree )
window_impl . set_current_event ( & event ) ;
}
2021-10-14 18:03:08 +01:00
// 9. If listener’ s passive is true, then set event’ s in passive listener flag.
2022-02-16 20:43:24 +01:00
if ( listener - > passive )
2020-11-21 18:32:39 +00:00
event . set_in_passive_listener ( true ) ;
2020-09-20 19:22:44 +02:00
2021-10-14 18:03:08 +01:00
// 10. Call a user object’ s operation with listener’ s callback, "handleEvent", « event », and event’ s currentTarget attribute value. If this throws an exception, then:
// FIXME: These should be wrapped for us in call_user_object_operation, but it currently doesn't do that.
2020-11-21 18:32:39 +00:00
auto * this_value = Bindings : : wrap ( global , * event . current_target ( ) ) ;
auto * wrapped_event = Bindings : : wrap ( global , event ) ;
2021-10-14 18:03:08 +01:00
auto result = Bindings : : IDL : : call_user_object_operation ( callback , " handleEvent " , this_value , wrapped_event ) ;
2022-02-07 15:12:41 +01:00
// If this throws an exception, then:
if ( result . is_error ( ) ) {
// 1. Report the exception.
2021-10-14 18:03:08 +01:00
HTML : : report_exception ( result ) ;
2022-02-07 15:12:41 +01:00
// FIXME: 2. Set legacyOutputDidListenersThrowFlag if given. (Only used by IndexedDB currently)
2020-11-21 18:32:39 +00:00
}
2021-10-14 18:03:08 +01:00
// 11. Unset event’ s in passive listener flag.
2020-11-21 18:32:39 +00:00
event . set_in_passive_listener ( false ) ;
2021-10-14 18:03:08 +01:00
// 12. If global is a Window object, then set global’ s current event to currentEvent.
2020-11-21 18:32:39 +00:00
if ( is < Bindings : : WindowObject > ( global ) ) {
2021-06-24 19:53:42 +02:00
auto & bindings_window_global = verify_cast < Bindings : : WindowObject > ( global ) ;
2020-11-21 18:32:39 +00:00
auto & window_impl = bindings_window_global . impl ( ) ;
window_impl . set_current_event ( current_event ) ;
}
2021-10-14 18:03:08 +01:00
// 13. If event’ s stop immediate propagation flag is set, then return found.
2020-11-21 18:32:39 +00:00
if ( event . should_stop_immediate_propagation ( ) )
return found ;
}
2021-10-14 18:03:08 +01:00
// 3. Return found.
2020-11-21 18:32:39 +00:00
return found ;
}
// https://dom.spec.whatwg.org/#concept-event-listener-invoke
void EventDispatcher : : invoke ( Event : : PathEntry & struct_ , Event & event , Event : : Phase phase )
{
auto last_valid_shadow_adjusted_target = event . path ( ) . last_matching ( [ & struct_ ] ( auto & entry ) {
return entry . index < = struct_ . index & & ! entry . shadow_adjusted_target . is_null ( ) ;
} ) ;
2021-02-23 20:42:32 +01:00
VERIFY ( last_valid_shadow_adjusted_target . has_value ( ) ) ;
2020-11-21 18:32:39 +00:00
2022-04-19 23:56:38 +02:00
// 1. Set event’ s target to the shadow-adjusted target of the last struct in event’ s path,
// that is either struct or preceding struct, whose shadow-adjusted target is non-null.
2020-11-21 18:32:39 +00:00
event . set_target ( last_valid_shadow_adjusted_target . value ( ) . shadow_adjusted_target ) ;
2022-04-19 23:56:38 +02:00
// 2. Set event’ s relatedTarget to struct’ s relatedTarget.
2020-11-21 18:32:39 +00:00
event . set_related_target ( struct_ . related_target ) ;
2022-04-19 23:56:38 +02:00
// 3. Set event’ s touch target list to struct’ s touch target list.
2020-11-21 18:32:39 +00:00
event . set_touch_target_list ( struct_ . touch_target_list ) ;
2022-04-19 23:56:38 +02:00
// 4. If event’ s stop propagation flag is set, then return.
2020-11-21 18:32:39 +00:00
if ( event . should_stop_propagation ( ) )
return ;
2022-04-19 23:56:38 +02:00
// 5. Initialize event’ s currentTarget attribute to struct’ s invocation target.
2020-11-21 18:32:39 +00:00
event . set_current_target ( struct_ . invocation_target ) ;
2022-04-19 23:56:38 +02:00
// 6. Let listeners be a clone of event’ s currentTarget attribute value’ s event listener list.
// NOTE: This avoids event listeners added after this point from being run. Note that removal still has an effect due to the removed field.
2022-02-16 20:43:24 +01:00
auto listeners = event . current_target ( ) - > event_listener_list ( ) ;
2022-04-19 23:56:38 +02:00
// 7. Let invocationTargetInShadowTree be struct’ s invocation-target-in-shadow-tree.
2020-11-21 18:32:39 +00:00
bool invocation_target_in_shadow_tree = struct_ . invocation_target_in_shadow_tree ;
2022-04-19 23:56:38 +02:00
// 8. Let found be the result of running inner invoke with event, listeners, phase, invocationTargetInShadowTree, and legacyOutputDidListenersThrowFlag if given.
2020-11-21 18:32:39 +00:00
bool found = inner_invoke ( event , listeners , phase , invocation_target_in_shadow_tree ) ;
2022-04-19 23:56:38 +02:00
// 9. If found is false and event’ s isTrusted attribute is true, then:
2020-11-21 18:32:39 +00:00
if ( ! found & & event . is_trusted ( ) ) {
2022-04-20 19:48:48 +02:00
// 1. Let originalEventType be event’ s type attribute value.
2020-11-21 18:32:39 +00:00
auto original_event_type = event . type ( ) ;
2022-04-20 19:48:48 +02:00
// 2. If event’ s type attribute value is a match for any of the strings in the first column in the following table,
// set event’ s type attribute value to the string in the second column on the same row as the matching string, and return otherwise.
2020-11-21 18:32:39 +00:00
if ( event . type ( ) = = " animationend " )
event . set_type ( " webkitAnimationEnd " ) ;
else if ( event . type ( ) = = " animationiteration " )
event . set_type ( " webkitAnimationIteration " ) ;
else if ( event . type ( ) = = " animationstart " )
event . set_type ( " webkitAnimationStart " ) ;
else if ( event . type ( ) = = " transitionend " )
event . set_type ( " webkitTransitionEnd " ) ;
else
return ;
2022-04-20 19:48:48 +02:00
// 3. Inner invoke with event, listeners, phase, invocationTargetInShadowTree, and legacyOutputDidListenersThrowFlag if given.
2020-11-21 18:32:39 +00:00
inner_invoke ( event , listeners , phase , invocation_target_in_shadow_tree ) ;
2022-04-19 23:56:38 +02:00
2022-04-20 19:48:48 +02:00
// 4. Set event’ s type attribute value to originalEventType.
2020-11-21 18:32:39 +00:00
event . set_type ( original_event_type ) ;
2020-09-06 14:28:41 +02:00
}
}
2020-11-21 18:32:39 +00:00
// https://dom.spec.whatwg.org/#concept-event-dispatch
bool EventDispatcher : : dispatch ( NonnullRefPtr < EventTarget > target , NonnullRefPtr < Event > event , bool legacy_target_override )
{
2022-04-19 23:56:38 +02:00
// 1. Set event’ s dispatch flag.
2020-11-21 18:32:39 +00:00
event - > set_dispatched ( true ) ;
2022-04-19 23:56:38 +02:00
// 2. Let targetOverride be target, if legacy target override flag is not given, and target’ s associated Document otherwise. [HTML]
// NOTE: legacy target override flag is only used by HTML and only when target is a Window object.
RefPtr < EventTarget > target_override ;
2020-11-21 18:32:39 +00:00
if ( ! legacy_target_override ) {
target_override = target ;
} else {
2022-03-07 23:08:26 +01:00
target_override = verify_cast < HTML : : Window > ( * target ) . associated_document ( ) ;
2020-11-21 18:32:39 +00:00
}
2022-04-19 23:56:38 +02:00
// 3. Let activationTarget be null.
2020-11-21 18:32:39 +00:00
RefPtr < EventTarget > activation_target ;
2022-04-19 23:56:38 +02:00
// 4. Let relatedTarget be the result of retargeting event’ s relatedTarget against target.
2020-11-21 18:32:39 +00:00
RefPtr < EventTarget > related_target = retarget ( event - > related_target ( ) , target ) ;
bool clear_targets = false ;
2022-04-19 23:56:38 +02:00
// 5. If target is not relatedTarget or target is event’ s relatedTarget, then:
2020-11-21 18:32:39 +00:00
if ( related_target ! = target | | event - > related_target ( ) = = target ) {
2022-04-20 19:48:48 +02:00
// 1. Let touchTargets be a new list.
2020-11-21 18:32:39 +00:00
Event : : TouchTargetList touch_targets ;
2022-04-20 19:48:48 +02:00
// 2. For each touchTarget of event’ s touch target list, append the result of retargeting touchTarget against target to touchTargets.
2020-11-21 18:32:39 +00:00
for ( auto & touch_target : event - > touch_target_list ( ) ) {
touch_targets . append ( retarget ( touch_target , target ) ) ;
}
2022-04-20 19:48:48 +02:00
// 3. Append to an event path with event, target, targetOverride, relatedTarget, touchTargets, and false.
2020-11-21 18:32:39 +00:00
event - > append_to_path ( * target , target_override , related_target , touch_targets , false ) ;
2022-04-20 19:48:48 +02:00
// 4. Let isActivationEvent be true, if event is a MouseEvent object and event’ s type attribute is "click"; otherwise false.
2020-11-21 19:15:57 +00:00
bool is_activation_event = is < UIEvents : : MouseEvent > ( * event ) & & event - > type ( ) = = HTML : : EventNames : : click ;
2020-11-21 18:32:39 +00:00
2022-04-20 19:48:48 +02:00
// 5. If isActivationEvent is true and target has activation behavior, then set activationTarget to target.
2021-09-07 12:56:50 +02:00
if ( is_activation_event & & target - > activation_behavior )
2020-11-21 18:32:39 +00:00
activation_target = target ;
2022-04-20 19:48:48 +02:00
// FIXME: 6. Let slottable be target, if target is a slottable and is assigned, and null otherwise.
2020-11-21 18:32:39 +00:00
2022-04-20 19:48:48 +02:00
// 7. Let slot-in-closed-tree be false
2020-11-21 18:32:39 +00:00
bool slot_in_closed_tree = false ;
2022-04-19 23:56:38 +02:00
2022-04-20 19:48:48 +02:00
// 8. Let parent be the result of invoking target’ s get the parent with event.
2020-11-21 18:32:39 +00:00
auto * parent = target - > get_parent ( event ) ;
2022-04-20 19:48:48 +02:00
// 9. While parent is non-null:
2020-11-21 18:32:39 +00:00
while ( parent ) {
2022-04-20 19:48:48 +02:00
// FIXME: 1. If slottable is non-null:
// 1. Assert: parent is a slot.
// 2. Set slottable to null.
// 3. If parent’ s root is a shadow root whose mode is "closed", then set slot-in-closed-tree to true.
// FIXME: 2. If parent is a slottable and is assigned, then set slottable to parent.
// 3. Let relatedTarget be the result of retargeting event’ s relatedTarget against parent.
2020-11-21 18:32:39 +00:00
related_target = retarget ( event - > related_target ( ) , parent ) ;
2022-04-19 23:56:38 +02:00
2022-04-20 19:48:48 +02:00
// 4. Let touchTargets be a new list.
2020-11-21 18:32:39 +00:00
touch_targets . clear ( ) ;
2022-04-20 19:48:48 +02:00
// 5. For each touchTarget of event’ s touch target list, append the result of retargeting touchTarget against parent to touchTargets.
2020-11-21 18:32:39 +00:00
for ( auto & touch_target : event - > touch_target_list ( ) ) {
touch_targets . append ( retarget ( touch_target , parent ) ) ;
}
2022-04-20 19:48:48 +02:00
// 6. If parent is a Window object, or parent is a node and target’ s root is a shadow-including inclusive ancestor of parent, then:
2022-03-07 23:08:26 +01:00
if ( is < HTML : : Window > ( parent )
2021-09-02 19:33:01 +01:00
| | ( is < Node > ( parent ) & & verify_cast < Node > ( * target ) . root ( ) . is_shadow_including_inclusive_ancestor_of ( verify_cast < Node > ( * parent ) ) ) ) {
2022-04-20 19:48:48 +02:00
// 1. If isActivationEvent is true, event’ s bubbles attribute is true, activationTarget is null, and parent has activation behavior, then set activationTarget to parent.
2021-09-07 12:56:50 +02:00
if ( is_activation_event & & event - > bubbles ( ) & & ! activation_target & & parent - > activation_behavior )
2020-11-21 18:32:39 +00:00
activation_target = parent ;
2022-04-20 19:48:48 +02:00
// 2. Append to an event path with event, parent, null, relatedTarget, touchTargets, and slot-in-closed-tree.
2020-11-21 18:32:39 +00:00
event - > append_to_path ( * parent , nullptr , related_target , touch_targets , slot_in_closed_tree ) ;
2022-04-19 23:56:38 +02:00
2022-04-20 19:48:48 +02:00
}
// 7. Otherwise, if parent is relatedTarget, then set parent to null.
else if ( related_target = = parent ) {
2020-11-21 18:32:39 +00:00
parent = nullptr ;
2022-04-20 19:48:48 +02:00
}
// 8. Otherwise, set target to parent and then:
else {
2020-11-21 18:32:39 +00:00
target = * parent ;
2022-04-20 19:48:48 +02:00
// 1. If isActivationEvent is true, activationTarget is null, and target has activation behavior, then set activationTarget to target.
2021-09-07 12:56:50 +02:00
if ( is_activation_event & & ! activation_target & & target - > activation_behavior )
2020-11-21 18:32:39 +00:00
activation_target = target ;
2022-04-20 19:48:48 +02:00
// 2. Append to an event path with event, parent, target, relatedTarget, touchTargets, and slot-in-closed-tree.
2020-11-21 18:32:39 +00:00
event - > append_to_path ( * parent , target , related_target , touch_targets , slot_in_closed_tree ) ;
}
2022-04-20 19:48:48 +02:00
// 9. If parent is non-null, then set parent to the result of invoking parent’ s get the parent with event.
2020-11-21 18:32:39 +00:00
if ( parent ) {
parent = parent - > get_parent ( event ) ;
}
2022-04-20 19:48:48 +02:00
// 10. Set slot-in-closed-tree to false.
2020-11-21 18:32:39 +00:00
slot_in_closed_tree = false ;
}
2022-04-20 19:48:48 +02:00
// 10. Let clearTargetsStruct be the last struct in event’ s path whose shadow-adjusted target is non-null.
2020-11-21 18:32:39 +00:00
auto clear_targets_struct = event - > path ( ) . last_matching ( [ ] ( auto & entry ) {
return ! entry . shadow_adjusted_target . is_null ( ) ;
} ) ;
2021-02-23 20:42:32 +01:00
VERIFY ( clear_targets_struct . has_value ( ) ) ;
2020-11-21 18:32:39 +00:00
2022-04-20 19:48:48 +02:00
// 11. Let clearTargets be true if clearTargetsStruct’ s shadow-adjusted target, clearTargetsStruct’ s relatedTarget,
// or an EventTarget object in clearTargetsStruct’ s touch target list is a node and its root is a shadow root; otherwise false.
2020-11-21 18:32:39 +00:00
if ( is < Node > ( clear_targets_struct . value ( ) . shadow_adjusted_target . ptr ( ) ) ) {
2021-06-24 19:53:42 +02:00
auto & shadow_adjusted_target_node = verify_cast < Node > ( * clear_targets_struct . value ( ) . shadow_adjusted_target ) ;
2020-11-21 18:32:39 +00:00
if ( is < ShadowRoot > ( shadow_adjusted_target_node . root ( ) ) )
clear_targets = true ;
}
if ( ! clear_targets & & is < Node > ( clear_targets_struct . value ( ) . related_target . ptr ( ) ) ) {
2021-06-24 19:53:42 +02:00
auto & related_target_node = verify_cast < Node > ( * clear_targets_struct . value ( ) . related_target ) ;
2020-11-21 18:32:39 +00:00
if ( is < ShadowRoot > ( related_target_node . root ( ) ) )
clear_targets = true ;
}
if ( ! clear_targets ) {
for ( auto touch_target : clear_targets_struct . value ( ) . touch_target_list ) {
if ( is < Node > ( * touch_target . ptr ( ) ) ) {
2021-06-24 19:53:42 +02:00
auto & touch_target_node = verify_cast < Node > ( * touch_target . ptr ( ) ) ;
2020-11-21 18:32:39 +00:00
if ( is < ShadowRoot > ( touch_target_node . root ( ) ) ) {
clear_targets = true ;
break ;
}
}
}
}
2022-04-20 19:48:48 +02:00
// 12. If activationTarget is non-null and activationTarget has legacy-pre-activation behavior, then run activationTarget’ s legacy-pre-activation behavior.
2022-02-18 20:40:12 +01:00
if ( activation_target )
2021-09-07 12:56:50 +02:00
activation_target - > legacy_pre_activation_behavior ( ) ;
2020-11-21 18:32:39 +00:00
2022-04-20 19:48:48 +02:00
// 13. For each struct in event’ s path, in reverse order:
2022-04-13 19:42:47 +02:00
for ( auto & entry : event - > path ( ) . in_reverse ( ) ) {
2022-04-20 19:48:48 +02:00
// 1. If struct’ s shadow-adjusted target is non-null, then set event’ s eventPhase attribute to AT_TARGET.
2020-11-21 18:32:39 +00:00
if ( entry . shadow_adjusted_target )
event - > set_phase ( Event : : Phase : : AtTarget ) ;
2022-04-20 19:48:48 +02:00
// 2. Otherwise, set event’ s eventPhase attribute to CAPTURING_PHASE.
2020-11-21 18:32:39 +00:00
else
event - > set_phase ( Event : : Phase : : CapturingPhase ) ;
2022-04-20 19:48:48 +02:00
// 3. Invoke with struct, event, "capturing", and legacyOutputDidListenersThrowFlag if given.
2020-11-21 18:32:39 +00:00
invoke ( entry , event , Event : : Phase : : CapturingPhase ) ;
}
2022-04-20 19:48:48 +02:00
// 14. For each struct in event’ s path:
2020-11-21 18:32:39 +00:00
for ( auto & entry : event - > path ( ) ) {
2022-04-20 19:48:48 +02:00
// 1. If struct’ s shadow-adjusted target is non-null, then set event’ s eventPhase attribute to AT_TARGET.
2020-11-21 18:32:39 +00:00
if ( entry . shadow_adjusted_target ) {
event - > set_phase ( Event : : Phase : : AtTarget ) ;
2022-04-20 19:48:48 +02:00
}
// 2. Otherwise:
else {
// 1. If event’ s bubbles attribute is false, then continue.
2020-11-21 18:32:39 +00:00
if ( ! event - > bubbles ( ) )
continue ;
2022-04-20 19:48:48 +02:00
// 2. Set event’ s eventPhase attribute to BUBBLING_PHASE.
2020-11-21 18:32:39 +00:00
event - > set_phase ( Event : : Phase : : BubblingPhase ) ;
}
2022-04-20 19:48:48 +02:00
// 3. Invoke with struct, event, "bubbling", and legacyOutputDidListenersThrowFlag if given.
2020-11-21 18:32:39 +00:00
invoke ( entry , event , Event : : Phase : : BubblingPhase ) ;
}
}
2022-04-19 23:56:38 +02:00
// 6. Set event’ s eventPhase attribute to NONE.
2020-11-21 18:32:39 +00:00
event - > set_phase ( Event : : Phase : : None ) ;
2022-04-19 23:56:38 +02:00
// 7. Set event’ s currentTarget attribute to null.
2020-11-21 18:32:39 +00:00
event - > set_current_target ( nullptr ) ;
2022-04-19 23:56:38 +02:00
// 8. Set event’ s path to the empty list.
2020-11-21 18:32:39 +00:00
event - > clear_path ( ) ;
2022-04-19 23:56:38 +02:00
// 9. Unset event’ s dispatch flag, stop propagation flag, and stop immediate propagation flag.
2020-11-21 18:32:39 +00:00
event - > set_dispatched ( false ) ;
event - > set_stop_propagation ( false ) ;
event - > set_stop_immediate_propagation ( false ) ;
2022-04-19 23:56:38 +02:00
// 10. If clearTargets, then:
2020-11-21 18:32:39 +00:00
if ( clear_targets ) {
2022-04-20 19:48:48 +02:00
// 1. Set event’ s target to null.
2020-11-21 18:32:39 +00:00
event - > set_target ( nullptr ) ;
2022-04-19 23:56:38 +02:00
2022-04-20 19:48:48 +02:00
// 2. Set event’ s relatedTarget to null.
2020-11-21 18:32:39 +00:00
event - > set_related_target ( nullptr ) ;
2022-04-19 23:56:38 +02:00
2022-04-20 19:48:48 +02:00
// 3. Set event’ s touch target list to the empty list.
2020-11-21 18:32:39 +00:00
event - > clear_touch_target_list ( ) ;
}
2022-04-19 23:56:38 +02:00
// 11. If activationTarget is non-null, then:
2020-11-21 18:32:39 +00:00
if ( activation_target ) {
2022-04-20 19:48:48 +02:00
// 1. If event’ s canceled flag is unset, then run activationTarget’ s activation behavior with event.
2020-11-21 18:32:39 +00:00
if ( ! event - > cancelled ( ) ) {
2021-09-07 12:56:50 +02:00
activation_target - > activation_behavior ( event ) ;
2022-03-14 23:05:55 +00:00
activation_target - > legacy_cancelled_activation_behavior_was_not_called ( ) ;
2022-04-20 19:48:48 +02:00
}
// 2. Otherwise, if activationTarget has legacy-canceled-activation behavior, then run activationTarget’ s legacy-canceled-activation behavior.
else {
2022-02-18 20:40:12 +01:00
activation_target - > legacy_cancelled_activation_behavior ( ) ;
2020-11-21 18:32:39 +00:00
}
}
2022-04-19 23:56:38 +02:00
// 12. Return false if event’ s canceled flag is set; otherwise true.
2020-11-21 18:32:39 +00:00
return ! event - > cancelled ( ) ;
}
2020-09-06 14:28:41 +02:00
}