|  | Sky Event Model | 
|  | =============== | 
|  |  | 
|  | ```javascript | 
|  | // 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? | 
|  | } | 
|  |  | 
|  | // TODO(ianh): decide if we're using this generic Event class and | 
|  | // allowing any arbitrary properties to be set on it, or if we're | 
|  | // going to use subclasses (and drop "type"). If we use subclasses | 
|  | // then how will declarative event handling work in frameworks? | 
|  | // (consider that multiple modules can each have their own FooEvent | 
|  | // class with the same name...) | 
|  | // | 
|  | // The advantage of this would be the ability to enforce (or at | 
|  | // least better catch) incorrect uses of the API, e.g. to make sure | 
|  | // people don't stop on themselves in 'pointer-down' capture. | 
|  |  | 
|  | 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() | 
|  | } | 
|  | ``` |