/// <summary>The deep path of this event. (Unclear working draft spec; subject to change). /// http://w3c.github.io/webcomponents/spec/shadow/#widl-Event-deepPath-sequence-EventTarget</summary> public EventTarget[] deepPath() { if (eventPhase == NONE) { // Not been dispatched or isn't currently being dispatched - empty set: return(new EventTarget[0]); } // Create the set: EventTarget[] set = new EventTarget[EventTarget.dispatchStackRef.Size]; // Copy the dispatch stack: Array.Copy(EventTarget.dispatchStackRef.Stack, 0, set, 0, set.Length); // Ok! return(set); }
/// <summary>Runs an event of the given name.</summary> public bool dispatchEvent(Event e) { e.target = this; // First we must go all the way to the bottom of the DOM. // As we go, we'll build up a stack of the elements that we went past. // We'll store that stack in a DispatchStack object (which are pooled): DispatchStack stackNode = PooledStack; if (stackNode == null) { stackNode = new DispatchStack(); } else { // Pop from the pool: PooledStack = stackNode.Next; } int stackPointer = 0; EventTarget[] stack = stackNode.Stack; int stackSize = stack.Length; EventTarget current = eventTargetParentNode; while (current != null) { // Resize required? if (stackPointer == stackSize) { stackNode.Resize(); stack = stackNode.Stack; stackSize = stack.Length; } // Push to stack: stack[stackPointer++] = current; // Up a level: current = current.eventTargetParentNode; } // Stack size (Both are for the Event API): stackNode.Size = stackPointer; CurrentStack_ = stackNode; // Ok we've now got all the elements that we'll be attempting to trigger the event on. // Time for the event phases to begin! try{ // Step 1 - Capture phase. e.eventPhase = Event.CAPTURING_PHASE; for (int i = stackPointer - 1; i >= 0; i--) { // The current one: EventTarget currentTarget = stack[i]; // Update currentTarget: e.currentTarget = currentTarget; // Run and test if it's been halted: if (currentTarget.HandleLocalEvent(e, false)) { // Halt! e.eventPhase = Event.NONE; return(!e._Cancelled); } } // Step 2 - Target phase (bubble events). e.eventPhase = Event.AT_TARGET; e.currentTarget = this; // Handle e.g. onclick attributes: if (HandleLocalEvent(e, true)) { // It quit us return(!e._Cancelled); } // Test if it's been halted: if (e.cancelBubble) { // Halt! e.eventPhase = Event.NONE; return(!e._Cancelled); } // Step 3 - Bubble phase. e.eventPhase = Event.BUBBLING_PHASE; for (int i = 0; i < stackPointer; i++) { // The current one: EventTarget currentTarget = stack[i]; // Update currentTarget: e.currentTarget = currentTarget; // Run: if (currentTarget.HandleLocalEvent(e, true)) { // Halt! e.eventPhase = Event.NONE; return(!e._Cancelled); } } }catch (Exception ex) { // Handler errored. Log.Add(ex); } // Pool the stack: stackNode.Next = PooledStack; PooledStack = stackNode; // Done! e.eventPhase = Event.NONE; return(!e._Cancelled); }
/// <summary>Doubles the size of the dispatch stack.</summary> internal void Resize() { EventTarget[] newStack = new EventTarget[Stack.Length * 2]; Array.Copy(Stack, 0, newStack, 0, Stack.Length); Stack = newStack; }