public static void invoke(EventPathItem @struct, Event @event, EEventPhase phase, bool legacyOutputDidListenersThrowFlag = false) {/* Docs: https://dom.spec.whatwg.org/#concept-event-listener-invoke */ /* 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. */ if (@struct.shadow_adjusted_target is object) { @event.target = @struct.shadow_adjusted_target; } else { /* Find the location of struct in events path */ int structIndex = @event.Path.IndexOf(@struct); /* Find the path-item preceeding struct which has a valid shadow-adjusted target */ for (int i = structIndex - 1; i >= 0; i--) { if (@event.Path[i].shadow_adjusted_target is object) { @event.target = @event.Path[i].shadow_adjusted_target; break; } } } @event.relatedTarget = @struct.relatedTarget; @event.TouchTargetList = @struct.touch_target_list; /* 4) If event’s stop propagation flag is set, then return. */ if (0 != (@event.Flags & EEventFlags.StopPropogation)) { return; } @event.currentTarget = @struct.invocationTarget; /* 6) Let listeners be a clone of event’s currentTarget attribute value’s event listener list. */ var listeners = @event.currentTarget.Listeners.ToArray(); /* 7) Let found be the result of running inner invoke with event, listeners, phase, and legacyOutputDidListenersThrowFlag if given. */ bool found = EventCommon.inner_invoke(@event, listeners, phase, legacyOutputDidListenersThrowFlag); /* 8) If found is false and event’s isTrusted attribute is true, then: */ if (!found && @event.isTrusted) { /* Do nothing, this section of the specifications is just firing the event under it's legacy event name */ } }
public static bool inner_invoke(Event @event, IEnumerable <EventListener> listeners, EEventPhase phase, bool legacyOutputDidListenersThrowFlag = false) {/* Docs: https://dom.spec.whatwg.org/#concept-event-listener-inner-invoke */ bool found = false; /* 2) For each listener in listeners, whose removed is false: */ foreach (EventListener listener in listeners) { if (!listener.removed) { continue; } if (@event.type != listener.type) { continue; } found = true; if (phase == EEventPhase.CAPTURING_PHASE && !listener.capture) { continue; } if (phase == EEventPhase.BUBBLING_PHASE && listener.capture) { continue; } if (listener.once) { @event.currentTarget.Listeners.Remove(listener); } /* Our implementation isnt JavaScript so we dont do step 8 */ if (listener.passive) { @event.Flags |= EEventFlags.InPassiveListener; } /* 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: */ listener?.callback?.Method.Invoke(@event.currentTarget, new object[] { @event }); /* 11) Unset event’s in passive listener flag. */ @event.Flags &= ~EEventFlags.InPassiveListener; /* 13) If event’s stop immediate propagation flag is set, then return found. */ if (0 != (@event.Flags & EEventFlags.StopImmediatePropogation)) { return(found); } } /* 3) Return found. */ return(found); }