1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
| bool EventTargetNode::dispatchGenericEvent(PassRefPtr<Event> e, ExceptionCode&, bool tempEvent)
{
RefPtr<Event> evt(e);
ASSERT(!eventDispatchForbidden());
ASSERT(evt->target());
ASSERT(!evt->type().isNull()); // JavaScript code could create an event with an 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 not 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 some work prior
// to the DOM event handlers getting a crack.
void* data = preDispatchEventHandler(evt.get());
// trigger any capturing event handlers on our way down
evt->setEventPhase(Event::CAPTURING_PHASE);
it.toFirst();
// Handle window events for capture phase, except load events, this quirk is needed
// 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 to be 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 will be called)
// ### recalculate the node chain here? (e.g. if target node moved in document by previous 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 tree during event processing,
// event flow will proceed based on the initial state of the tree.
//
// 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, this quirk is needed
// because Mozilla used to never propagate load events at 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 is correct, the spec does not seem to say
// anything about the 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 is internal to khtml)
it.toLast();
if (evt->bubbles())
for (; it.current() && !evt->defaultPrevented() && !evt->defaultHandled(); --it)
EventTargetNodeCast(it.current())->defaultEventHandler(evt.get());
else if (!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 that the DOM implementation
// will not be storing a reference to the event, i.e. there is no
// way to retrieve it from javascript if a script does not already
// have a reference to it in a variable. So there 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 before dispatchEvent?
} |