Sky Event Model

  // EVENTS

  class Event {
    constructor (String type, Boolean bubbles = true, any data = null); // O(1)
    readonly attribute String type; // O(1)
    readonly attribute Boolean bubbles; // O(1)
    attribute any data; // O(1)

    readonly attribute EventTarget target; // O(1)
    attribute Boolean handled; // O(1)
    attribute any result; // O(1)

    // TODO(ianh): do events get blocked at scope boundaries, e.g. focus events when both sides are in the scope?
    // TODO(ianh): do events get retargetted, e.g. focus when leaving a custom element?
  }

  callback EventListener any (Event event);
    // if the return value is not undefined:
    //   assign it to event.result
    //   set event.handled to true

  abstract class EventTarget {
    any dispatchEvent(Event event); // O(N) in total number of listeners for this type in the chain
      // sets event.handled to false and event.result to undefined
      // makes a record of the event target chain by calling getEventDispatchChain()
      // invokes all the handlers on the chain in turn
      // returns event.result
    virtual Array<EventTarget> getEventDispatchChain(); // O(1) // returns []
    void addEventListener(String type, EventListener listener); // O(1)
    void removeEventListener(String type, EventListener listener); // O(N) in event listeners with that type
    private Array<String> getRegisteredEventListenerTypes(); // O(N)
    private Array<EventListener> getRegisteredEventListenersForType(String type); // O(N)
  }

  class CustomEventTarget : EventTarget { // implemented in JS
    constructor (); // O(1)
    attribute EventTarget parentNode; // getter O(1), setter O(N) in height of tree, throws if this would make a loop

    virtual Array<EventTarget> getEventDispatchChain(); // O(N) in height of tree // implements EventTarget.getEventDispatchChain()
      // let result = [];
      // let node = this;
      // while (node) {
      //   result.push(node);
      //   node = node.parentNode;
      // }
      // return result;

    // you can inherit from this to make your object into an event target
    // or you can inherit from EventTarget and implement your own getEventDispatchChain()
  }