Event
Represents an event argument.
using AngleSharp.Attributes;
using AngleSharp.Html;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
namespace AngleSharp.Dom.Events
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
[DomName("Event")]
public class Event : EventArgs
{
[System.Runtime.CompilerServices.NullableContext(2)]
[System.Runtime.CompilerServices.Nullable(0)]
private struct EventPathItem
{
[System.Runtime.CompilerServices.Nullable(1)]
public EventTarget InvocationTarget;
public bool IsInvocationTargetInShadowTree;
public bool IsRootOfClosedTree;
public bool IsSlotInClosedTree;
public EventTarget ShadowAdjustedTarget;
public EventTarget RelatedTarget;
}
private EventFlags _flags;
private EventPhase _phase;
[System.Runtime.CompilerServices.Nullable(2)]
private IEventTarget _current;
[System.Runtime.CompilerServices.Nullable(2)]
private IEventTarget _target;
private bool _bubbles;
private bool _cancelable;
private bool _composed;
[System.Runtime.CompilerServices.Nullable(2)]
private string _type;
private DateTime _time;
[System.Runtime.CompilerServices.Nullable(2)]
private List<EventPathItem> _currentPath;
internal EventFlags Flags => _flags;
[DomName("type")]
public string Type {
get {
return _type;
}
}
[System.Runtime.CompilerServices.Nullable(2)]
[DomName("target")]
public IEventTarget OriginalTarget {
[System.Runtime.CompilerServices.NullableContext(2)]
get { get; }
}
[System.Runtime.CompilerServices.Nullable(2)]
[DomName("currentTarget")]
public IEventTarget CurrentTarget {
[System.Runtime.CompilerServices.NullableContext(2)]
get {
return _current;
}
}
[DomName("eventPhase")]
public EventPhase Phase {
get {
return _phase;
}
}
[DomName("composed")]
public bool IsComposed {
get {
return _composed;
}
}
[DomName("bubbles")]
public bool IsBubbling {
get {
return _bubbles;
}
}
[DomName("cancelable")]
public bool IsCancelable {
get {
return _cancelable;
}
}
[DomName("defaultPrevented")]
public bool IsDefaultPrevented {
get {
return (_flags & EventFlags.Canceled) == EventFlags.Canceled;
}
}
[DomName("isTrusted")]
public bool IsTrusted { get; set; }
[DomName("timeStamp")]
public DateTime Time {
get {
return _time;
}
}
public Event()
{
_flags = EventFlags.None;
_phase = EventPhase.None;
_time = DateTime.Now;
_composed = false;
}
public Event(string type)
: this(type, false, false)
{
}
public Event(string type, bool bubbles = false, bool cancelable = false)
: this(type, bubbles, cancelable, false)
{
}
[DomConstructor]
[DomInitDict(1, true)]
public Event(string type, bool bubbles = false, bool cancelable = false, bool composed = false)
: this()
{
Init(type, bubbles, cancelable);
_composed = composed;
}
[DomName("composedPath")]
public IEnumerable<IEventTarget> GetComposedPath()
{
List<IEventTarget> list = new List<IEventTarget>();
if (_currentPath != null && _currentPath.Count > 0) {
list.Add(_current);
int num = 0;
int num2 = 0;
int count = _currentPath.Count;
for (int num3 = count - 1; num3 >= 0; num3--) {
EventPathItem eventPathItem = _currentPath[num3];
if (eventPathItem.IsRootOfClosedTree)
num2++;
if (eventPathItem.InvocationTarget == _current) {
num = num3;
break;
}
if (eventPathItem.IsSlotInClosedTree)
num2--;
}
int num4 = num2;
int num5 = num2;
for (int num6 = num - 1; num6 >= 0; num6--) {
EventPathItem eventPathItem2 = _currentPath[num6];
if (eventPathItem2.IsRootOfClosedTree)
num4++;
if (num4 <= num5)
list.Insert(0, eventPathItem2.InvocationTarget);
if (eventPathItem2.IsSlotInClosedTree) {
num4--;
if (num4 < num5)
num5 = num4;
}
}
num4 = num2;
num5 = num2;
for (int i = num + 1; i < count; i++) {
EventPathItem eventPathItem3 = _currentPath[i];
if (eventPathItem3.IsRootOfClosedTree)
num4++;
if (num4 <= num5)
list.Add(eventPathItem3.InvocationTarget);
if (eventPathItem3.IsSlotInClosedTree) {
num4--;
if (num4 < num5)
num5 = num4;
}
}
}
return list;
}
[DomName("stopPropagation")]
public void Stop()
{
_flags |= EventFlags.StopPropagation;
}
[DomName("stopImmediatePropagation")]
public void StopImmediately()
{
_flags |= EventFlags.StopImmediatePropagation;
}
[DomName("preventDefault")]
public void Cancel()
{
if (_cancelable)
_flags |= EventFlags.Canceled;
}
[DomName("initEvent")]
public void Init(string type, bool bubbles, bool cancelable)
{
_flags |= EventFlags.Initialized;
if ((_flags & EventFlags.Dispatch) != EventFlags.Dispatch) {
_flags &= ~(EventFlags.StopPropagation | EventFlags.StopImmediatePropagation | EventFlags.Canceled);
IsTrusted = false;
_target = null;
_type = type;
_bubbles = bubbles;
_cancelable = cancelable;
}
}
internal bool Dispatch(IEventTarget target)
{
_flags |= EventFlags.Dispatch;
_target = target;
List<EventPathItem> list = new List<EventPathItem>();
Node node = target as Node;
if (node != null) {
while ((node = node.Parent) != null) {
bool isRootOfClosedTree = false;
bool isSlotInClosedTree = false;
bool isInvocationTargetInShadowTree = false;
IElement element = node as IElement;
if (element != null) {
IShadowRoot shadowRoot = element.GetRoot() as IShadowRoot;
if (shadowRoot != null) {
isInvocationTargetInShadowTree = true;
if (element.AssignedSlot != null && shadowRoot.Mode == ShadowRootMode.Closed)
isSlotInClosedTree = true;
}
}
IShadowRoot shadowRoot2 = node as IShadowRoot;
if (shadowRoot2 != null && shadowRoot2.Mode == ShadowRootMode.Closed)
isRootOfClosedTree = true;
list.Add(new EventPathItem {
InvocationTarget = node,
IsInvocationTargetInShadowTree = isInvocationTargetInShadowTree,
IsSlotInClosedTree = isSlotInClosedTree,
IsRootOfClosedTree = isRootOfClosedTree,
RelatedTarget = null,
ShadowAdjustedTarget = null
});
}
}
_currentPath = list;
_phase = EventPhase.Capturing;
DispatchAt(Enumerable.Reverse(list));
_phase = EventPhase.AtTarget;
if ((_flags & EventFlags.StopPropagation) != EventFlags.StopPropagation)
CallListeners(target);
if (_bubbles) {
_phase = EventPhase.Bubbling;
DispatchAt(list);
}
_flags &= ~EventFlags.Dispatch;
_phase = EventPhase.None;
_current = null;
return (_flags & EventFlags.Canceled) == EventFlags.Canceled;
}
private void CallListeners(IEventTarget target)
{
_current = target;
target.InvokeEventListener(this);
}
private void DispatchAt(IEnumerable<EventPathItem> path)
{
foreach (EventPathItem item in path) {
CallListeners(item.InvocationTarget);
if ((_flags & EventFlags.StopPropagation) == EventFlags.StopPropagation)
break;
}
}
}
}