DOM Event Specification
DOM Event primarily defines three types of interfaces:
Eventtarget, all DOM nodes and XMLHttpRequest implement Eventtarget interfaces
Class Eventtarget {
void AddEventListener (in domstring Type,ineventlistener Listener, in Boolean usecapture);
void RemoveEventListener (in domstring type,in EventListener Listener, in Boolean usecapture);
Boolean dispatchevent (in event event)};
This class is a pure virtual base class, so it is an interface class
1. Add and remove listener, these are virtual functions that can be implemented in subclasses
2. Distribution event, there is a virtual function, and a function, this kind of class can have their own personality
3. Add, delete, and get Properties listener
4.fire Trigger listener function, this function does not need to have subclass implementation
EventListener, the user implements this interface, and registers on a eventtarget, uses AddEventListener to complete the registration;
void Handleevent (in Event evt);
Eventlistener::type {
Jseventlistenertype,
Imageeventlistenertype,
Inspectordomagenttype,
Inspectordomstorageresourcetype,
Objceventlistenertype,
Cppeventlistenertype,
Conditioneventlistenertype,
Gobjecteventlistenertype,
Nativeeventlistenertype
};
Event provides contextual information to Eventhandle
readonly attribute domstring type;
readonly attribute Eventtarget target;
readonly attribute Eventtarget Currenttarget;
ReadOnly attribute unsigned short eventphase;
ReadOnly attribute Boolean bubbles;
ReadOnly attribute Boolean cancelable;
readonly attribute Domtimestamp TimeStamp;
void Stoppropagation ();
void Preventdefault ();
[OLDSTYLEOBJC] void initevent (in Domstringeventtypearg,
In Boolean Canbubblearg,
in Boolean cancelablearg);
DOM Level 3 additions.
ReadOnly attribute Boolean defaultprevented;
void Stopimmediatepropagation ();
IE Extensions
readonly attribute Eventtarget srcelement;
Attribute Boolean returnvalue;
Attribute Boolean cancelbubble;
#if defined (language_javascript) &&language_javascript
readonly attribute [Custom] Clipboard clipboarddata;
#endif
Event Flow Basic event Flow
Each event corresponds to an event target (Eventtarget) (also a node) that is specified by the target attribute of the Eventtarget event. Each event target is registered with several event listeners (Eventlisterner), which are activated after the event arrives, and the order of activation is not defined in the DOM specification. If no event capture or bubbling is defined, the event is processed after all event listeners on the event target have completed the response. Event capture
Event capture occurs when an event listener registers on an ancestor node of an event's target node, and when that event occurs, the ancestor node's event listener first catches and processes it, and then passes the event down to the target node, before it reaches the target node. Event bubbling
The initial phase of event bubbling is the same as the basic event stream, however, after all event listeners have responded to the target node of the event, they will be uploaded along the node to their ancestors, until the document point, which will escalate all event listeners registered on the encountered node (except for the capture event). Event cancellation
Some events can be set to be canceled, and these events typically should have a default action. When such an event occurs, it is first passed to the event listener on the target node, and the event listener can choose whether to cancel the default action of the event.
The following two diagram is an event flow diagram:
WebKit DOM Event class diagram
WebKit Implementation Logic
Implementation logic (for example, mouse events): Mouse events occur according to the location of mouse events, find the corresponding Eventtarget node in the Eventtarget dispatchgenericevent function, get to all the parent node, save to the list; Enter the event-capture phase to trigger the current Eventtarget current event Eventlisten into the events bubbling phase
BOOL Eventtargetnode::d ispatchgenericevent (Passrefptr<event>e, exceptioncode&, bool tempEvent)
{
REFPTR<EVENT>EVT (e);
ASSERT (!eventdispatchforbidden ());
ASSERT (Evt->target ());
ASSERT (!evt->type (). IsNull ()); JavaScript code could create anevent with a empty name
Work out what nodes to send event to
Deprecatedptrlist<node> Nodechain;
if (Indocument ()) {
for (node* n = this; n; n = n->eventparentnode ()) {
N->ref ();
Nodechain.prepend (n);
}
}else {
If node is isn't in the document just send event to itself
Ref ();
Nodechain.prepend (this);
}
Deprecatedptrlistiterator<node> it (nodechain);
Before we begin dispatching events, give the target node a chance to do somework prior
To the DOM event handlers getting a crack.
Void*data = Predispatcheventhandler (Evt.get ());
Trigger any capturing event handlers on we way down
Evt->seteventphase (event::capturing_phase);
It.tofirst ();
Handle window events for capture phase, except load events, this quirk isneeded
Because Mozilla used to never propagate load events to the Window object
if (Evt->type ()!= loadevent && it.current ()->isdocumentnode () &&!evt->propagationstopped () )
Static_cast<document*> (It.current ())->handlewindowevent (Evt.get (), true);
for (; It.current () && it.current ()!= this &&!evt->propagationstopped (); ++it) {
Evt->setcurrenttarget (Eventtargetnodecast (It.current ()));
Eventtargetnodecast (It.current ())->handlelocalevents (Evt.get (), true);
}
Dispatch to the actual target node
It.tolast ();
if (!evt->propagationstopped ()) {
Evt->seteventphase (Event::at_target);
Evt->setcurrenttarget (Eventtargetnodecast (It.current ()));
We do want capturing event listeners for invoked here, even though
That violates the specification since Mozilla does it.
Eventtargetnodecast (It.current ())->handlelocalevents (Evt.get (), true);
Eventtargetnodecast (It.current ())->handlelocalevents (Evt.get (), false);
}
--it;
OK, now bubble up again (only non-capturing event handlers'll be called)
### recalculate the node chain here? (e.g. if target node moved in document Byprevious event handlers)
No. The DOM specs says:
The chain of Eventtargets from the event target to the "top" of the tree
is determined before the initial dispatch of the event.
If modifications occur to the during event processing,
Event flow would proceed based on the initial state.
//
Since the initial dispatch is before the capturing phase,
There ' s no need to recalculate the node chain.
(Tobias)
if (Evt->bubbles ()) {
Evt->seteventphase (event::bubbling_phase);
for (; It.current () &&!evt->propagationstopped () &&!evt->cancelbubble ();--it) {
Evt->setcurrenttarget (Eventtargetnodecast (It.current ()));
Eventtargetnodecast (It.current ())->handlelocalevents (Evt.get (), false);
}
Handle window events for bubbling phase, except load events, Thisquirk is needed
Because Mozilla used to never propagate load events in all
It.tofirst ();
if (Evt->type ()!= loadevent && it.current ()->isdocumentnode () &&!evt->propagationstopped () &&!evt->cancelbubble ()) {
Evt->setcurrenttarget (Eventtargetnodecast (It.current ()));
Static_cast<document*> (It.current ())->handlewindowevent (Evt.get (), false);
}
}
Evt->setcurrenttarget (0);
Evt->seteventphase (0); I guess this are correct, the spec does notseem to say
Anything aboutthe default event handler phase.
Now call the Post Dispatch.
Postdispatcheventhandler (Evt.get (), data);
Now we call all default event handlers (this is not part of dom-it isinternal to khtml)
It.tolast ();
if (Evt->bubbles ())
for (; It.current () &&!evt->defaultprevented () &&!evt->defaulthandled ();--it)
Eventtargetnodecast (It.current ())->defaulteventhandler (Evt.get ());
ElseIf (!evt->defaultprevented () &&!evt->defaulthandled ())
Eventtargetnodecast (It.current ())->defaulteventhandler (Evt.get ());
Deref all nodes in chain
It.tofirst ();
for (; It.current (); ++it)
It.current ()->deref (); This may delete us
Document::updatedocumentsrendering ();
If Tempevent is true, this means the DOM implementation
Won't is storing a reference to the event, i.e. There is no
Way to retrieve it out JavaScript if a script does not already
Have a reference to it in a variable. Sothere is no need for
The interpreter to keep the event in it ' s cache
Frame *frame = document ()->frame ();
if (tempevent && frame && frame->scriptproxy ())
Frame->scriptproxy ()->finishedwithevent (Evt.get ());
Return!evt->defaultprevented (); ### What if defaultprevented was called beforedispatchevent? }
Event::type {
Abort
Beforecopy
Beforecut
Beforeload
Beforepaste
Beforeprocess
Beforeunload
Blocked
Blur
Cached
Change
Checking
Click
Close
Complete
Compositionend
Compositionstart
Compositionupdate
Connect
ContextMenu
Copy
Cut-and
DblClick
Devicemotion
Deviceorientation
Display
Downloading
Drag
Dragend
DragEnter
DragLeave
DragOver
DragStart
Drop
Error
Focus
Focusin
Focusout
Hashchange
Input
Invalid
KeyDown
KeyPress
KeyUp
Load
Loadstart
Message
MouseDown
MouseMove
Mouseout
MouseOver
MouseUp
MouseWheel
Noupdate
Obsolete
Offline
Online
Open
Overflowchanged
Pagehide
Pageshow
Paste
Popstate
ReadyStateChange
Reset
Resize
Scroll
Search
Select
Selectstart
SelectionChange
Storage
Submit
TextInput
Unload
Updateready
Versionchange
Write
Writeend
Writestart
Zoom
Domactivate