final boolean ie = getBrowserVersion().isIE();
final Window window = (Window) page.getEnclosingWindow().getScriptObject();
final Object[] args = new Object[] {event};
event.startFire();
ScriptResult result = null;
final Event previousEvent = window.getCurrentEvent();
window.setCurrentEvent(event);
try {
// window's listeners
final EventListenersContainer windowsListeners = getWindow().getEventListenersContainer();
// capturing phase
event.setEventPhase(Event.CAPTURING_PHASE);
result = windowsListeners.executeCapturingListeners(event, args);
if (event.isPropagationStopped()) {
return result;
}
final List<DomNode> parents = new ArrayList<DomNode>();
DomNode node = getDomNodeOrDie();
while (node != null) {
parents.add(node);
node = node.getParentNode();
}
for (int i = parents.size() - 1; i >= 0; i--) {
final DomNode curNode = parents.get(i);
final Node jsNode = (Node) curNode.getScriptObject();
final EventListenersContainer elc = jsNode.eventListenersContainer_;
if (elc != null) {
final ScriptResult r = elc.executeCapturingListeners(event, args);
result = ScriptResult.combine(r, result, ie);
if (event.isPropagationStopped()) {
return result;
}
}
}
// handlers declared as property on a node don't receive the event as argument for IE
final Object[] propHandlerArgs;
if (ie) {
propHandlerArgs = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
else {
propHandlerArgs = args;
}
// bubbling phase
event.setEventPhase(Event.AT_TARGET);
node = getDomNodeOrDie();
while (node != null) {
final Node jsNode = (Node) node.getScriptObject();
final EventListenersContainer elc = jsNode.eventListenersContainer_;
if (elc != null) {
final ScriptResult r = elc.executeBubblingListeners(event, args, propHandlerArgs);
result = ScriptResult.combine(r, result, ie);
if (event.isPropagationStopped()) {
return result;
}
}
node = node.getParentNode();
event.setEventPhase(Event.BUBBLING_PHASE);
}
final ScriptResult r = windowsListeners.executeBubblingListeners(event, args, propHandlerArgs);
result = ScriptResult.combine(r, result, ie);
}
finally {
event.endFire();
window.setCurrentEvent(previousEvent); // reset event