mshtml: Register load, error and abort events directly in event target.
Signed-off-by: Jacek Caban <jacek@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
9550556f3c
commit
d7c94cc7d8
|
@ -5048,7 +5048,7 @@ static nsISupports *HTMLDocumentNode_get_gecko_target(DispatchEx *dispex)
|
|||
static void HTMLDocumentNode_bind_event(DispatchEx *dispex, eventid_t eid)
|
||||
{
|
||||
HTMLDocumentNode *This = impl_from_DispatchEx(dispex);
|
||||
ensure_doc_nsevent_handler(This, eid);
|
||||
ensure_doc_nsevent_handler(This, This->node.nsnode, eid);
|
||||
}
|
||||
|
||||
static EventTarget *HTMLDocumentNode_get_parent_event_target(DispatchEx *dispex)
|
||||
|
|
|
@ -5439,16 +5439,7 @@ static nsISupports *HTMLElement_get_gecko_target(DispatchEx *dispex)
|
|||
static void HTMLElement_bind_event(DispatchEx *dispex, eventid_t eid)
|
||||
{
|
||||
HTMLElement *This = impl_from_DispatchEx(dispex);
|
||||
|
||||
static const WCHAR loadW[] = {'l','o','a','d',0};
|
||||
|
||||
switch(eid) {
|
||||
case EVENTID_LOAD:
|
||||
add_nsevent_listener(This->node.doc, This->node.nsnode, loadW);
|
||||
return;
|
||||
default:
|
||||
ensure_doc_nsevent_handler(This->node.doc, eid);
|
||||
}
|
||||
ensure_doc_nsevent_handler(This->node.doc, This->node.nsnode, eid);
|
||||
}
|
||||
|
||||
static HRESULT HTMLElement_handle_event_default(DispatchEx *dispex, eventid_t eid, nsIDOMEvent *nsevent, BOOL *prevent_default)
|
||||
|
|
|
@ -131,11 +131,17 @@ typedef struct {
|
|||
DWORD flags;
|
||||
} event_info_t;
|
||||
|
||||
/* Use Gecko default listener (it's registered on window object for DOM nodes). */
|
||||
#define EVENT_DEFAULTLISTENER 0x0001
|
||||
#define EVENT_BUBBLES 0x0002
|
||||
#define EVENT_BIND_TO_BODY 0x0008
|
||||
#define EVENT_CANCELABLE 0x0010
|
||||
/* Register Gecko listener on target itself (unlike EVENT_DEFAULTLISTENER). */
|
||||
#define EVENT_BIND_TO_TARGET 0x0002
|
||||
/* Event bubbles by default (unless explicitly specified otherwise). */
|
||||
#define EVENT_BUBBLES 0x0004
|
||||
/* Event is cancelable by default (unless explicitly specified otherwise). */
|
||||
#define EVENT_CANCELABLE 0x0008
|
||||
/* Event may have default handler (so we always have to register Gecko listener). */
|
||||
#define EVENT_HASDEFAULTHANDLERS 0x0020
|
||||
/* Ecent is not supported properly, print FIXME message when it's used. */
|
||||
#define EVENT_FIXME 0x0040
|
||||
|
||||
/* mouse event flags for fromElement and toElement implementation */
|
||||
|
@ -144,7 +150,7 @@ typedef struct {
|
|||
|
||||
static const event_info_t event_info[] = {
|
||||
{abortW, EVENT_TYPE_EVENT, DISPID_EVMETH_ONABORT,
|
||||
EVENT_BIND_TO_BODY},
|
||||
EVENT_BIND_TO_TARGET},
|
||||
{beforeactivateW, EVENT_TYPE_EVENT, DISPID_EVMETH_ONBEFOREACTIVATE,
|
||||
EVENT_FIXME | EVENT_BUBBLES | EVENT_CANCELABLE},
|
||||
{beforeunloadW, EVENT_TYPE_EVENT, DISPID_EVMETH_ONBEFOREUNLOAD,
|
||||
|
@ -168,7 +174,7 @@ static const event_info_t event_info[] = {
|
|||
{dragstartW, EVENT_TYPE_DRAG, DISPID_EVMETH_ONDRAGSTART,
|
||||
EVENT_FIXME | EVENT_BUBBLES | EVENT_CANCELABLE},
|
||||
{errorW, EVENT_TYPE_EVENT, DISPID_EVMETH_ONERROR,
|
||||
EVENT_BIND_TO_BODY},
|
||||
EVENT_BIND_TO_TARGET},
|
||||
{focusW, EVENT_TYPE_FOCUS, DISPID_EVMETH_ONFOCUS,
|
||||
EVENT_DEFAULTLISTENER},
|
||||
{focusinW, EVENT_TYPE_FOCUS, DISPID_EVMETH_ONFOCUSIN,
|
||||
|
@ -184,7 +190,7 @@ static const event_info_t event_info[] = {
|
|||
{keyupW, EVENT_TYPE_KEYBOARD, DISPID_EVMETH_ONKEYUP,
|
||||
EVENT_DEFAULTLISTENER | EVENT_BUBBLES | EVENT_CANCELABLE},
|
||||
{loadW, EVENT_TYPE_UIEVENT, DISPID_EVMETH_ONLOAD,
|
||||
EVENT_BIND_TO_BODY},
|
||||
EVENT_BIND_TO_TARGET},
|
||||
{messageW, EVENT_TYPE_MESSAGE, DISPID_EVMETH_ONMESSAGE,
|
||||
0},
|
||||
{mousedownW, EVENT_TYPE_MOUSE, DISPID_EVMETH_ONMOUSEDOWN,
|
||||
|
@ -2618,6 +2624,14 @@ static HRESULT dispatch_event_object(EventTarget *event_target, DOMEvent *event,
|
|||
void dispatch_event(EventTarget *event_target, DOMEvent *event)
|
||||
{
|
||||
dispatch_event_object(event_target, event, DISPATCH_BOTH, NULL);
|
||||
|
||||
/*
|
||||
* We may have registered multiple Gecko listeners for the same event type,
|
||||
* but we already dispatched event to all relevant targets. Stop event
|
||||
* propagation here to avoid events being dispatched multiple times.
|
||||
*/
|
||||
if(event->event_id != EVENTID_LAST && (event_info[event->event_id].flags & EVENT_BIND_TO_TARGET))
|
||||
nsIDOMEvent_StopPropagation(event->nsevent);
|
||||
}
|
||||
|
||||
HRESULT fire_event(HTMLDOMNode *node, const WCHAR *event_name, VARIANT *event_var, VARIANT_BOOL *cancelled)
|
||||
|
@ -2679,10 +2693,8 @@ HRESULT fire_event(HTMLDOMNode *node, const WCHAR *event_name, VARIANT *event_va
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT ensure_doc_nsevent_handler(HTMLDocumentNode *doc, eventid_t eid)
|
||||
HRESULT ensure_doc_nsevent_handler(HTMLDocumentNode *doc, nsIDOMNode *nsnode, eventid_t eid)
|
||||
{
|
||||
nsIDOMNode *nsnode = NULL;
|
||||
|
||||
TRACE("%s\n", debugstr_w(event_info[eid].name));
|
||||
|
||||
if(!doc->nsdoc)
|
||||
|
@ -2701,19 +2713,22 @@ HRESULT ensure_doc_nsevent_handler(HTMLDocumentNode *doc, eventid_t eid)
|
|||
break;
|
||||
}
|
||||
|
||||
if(doc->event_vector[eid] || !(event_info[eid].flags & (EVENT_DEFAULTLISTENER|EVENT_BIND_TO_BODY)))
|
||||
if(event_info[eid].flags & EVENT_DEFAULTLISTENER) {
|
||||
nsnode = NULL;
|
||||
}else if(event_info[eid].flags & EVENT_BIND_TO_TARGET) {
|
||||
if(!nsnode)
|
||||
nsnode = doc->node.nsnode;
|
||||
}else {
|
||||
return S_OK;
|
||||
|
||||
if(event_info[eid].flags & EVENT_BIND_TO_BODY) {
|
||||
nsnode = doc->node.nsnode;
|
||||
nsIDOMNode_AddRef(nsnode);
|
||||
}
|
||||
|
||||
doc->event_vector[eid] = TRUE;
|
||||
add_nsevent_listener(doc, nsnode, event_info[eid].name);
|
||||
if(!nsnode || nsnode == doc->node.nsnode) {
|
||||
if(doc->event_vector[eid])
|
||||
return S_OK;
|
||||
doc->event_vector[eid] = TRUE;
|
||||
}
|
||||
|
||||
if(nsnode)
|
||||
nsIDOMNode_Release(nsnode);
|
||||
add_nsevent_listener(doc, nsnode, event_info[eid].name);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -2949,7 +2964,7 @@ void update_doc_cp_events(HTMLDocumentNode *doc, cp_static_data_t *cp)
|
|||
|
||||
for(i=0; i < EVENTID_LAST; i++) {
|
||||
if((event_info[i].flags & EVENT_DEFAULTLISTENER) && is_cp_event(cp, event_info[i].dispid))
|
||||
ensure_doc_nsevent_handler(doc, i);
|
||||
ensure_doc_nsevent_handler(doc, NULL, i);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3046,7 +3061,7 @@ HRESULT doc_init_events(HTMLDocumentNode *doc)
|
|||
|
||||
for(i=0; i < EVENTID_LAST; i++) {
|
||||
if(event_info[i].flags & EVENT_HASDEFAULTHANDLERS) {
|
||||
hres = ensure_doc_nsevent_handler(doc, i);
|
||||
hres = ensure_doc_nsevent_handler(doc, NULL, i);
|
||||
if(FAILED(hres))
|
||||
return hres;
|
||||
}
|
||||
|
|
|
@ -98,7 +98,7 @@ HRESULT doc_init_events(HTMLDocumentNode*) DECLSPEC_HIDDEN;
|
|||
void detach_events(HTMLDocumentNode *doc) DECLSPEC_HIDDEN;
|
||||
HRESULT create_event_obj(IHTMLEventObj**) DECLSPEC_HIDDEN;
|
||||
void bind_target_event(HTMLDocumentNode*,EventTarget*,const WCHAR*,IDispatch*) DECLSPEC_HIDDEN;
|
||||
HRESULT ensure_doc_nsevent_handler(HTMLDocumentNode*,eventid_t) DECLSPEC_HIDDEN;
|
||||
HRESULT ensure_doc_nsevent_handler(HTMLDocumentNode*,nsIDOMNode*,eventid_t) DECLSPEC_HIDDEN;
|
||||
|
||||
void dispatch_event(EventTarget*,DOMEvent*) DECLSPEC_HIDDEN;
|
||||
|
||||
|
|
|
@ -3033,7 +3033,7 @@ static nsISupports *HTMLWindow_get_gecko_target(DispatchEx *dispex)
|
|||
static void HTMLWindow_bind_event(DispatchEx *dispex, eventid_t eid)
|
||||
{
|
||||
HTMLInnerWindow *This = impl_from_DispatchEx(dispex);
|
||||
ensure_doc_nsevent_handler(This->doc, eid);
|
||||
ensure_doc_nsevent_handler(This->doc, NULL, eid);
|
||||
}
|
||||
|
||||
static void HTMLWindow_init_dispex_info(dispex_data_t *info, compat_mode_t compat_mode)
|
||||
|
|
|
@ -743,6 +743,44 @@ function test_keyboard_event() {
|
|||
next_test();
|
||||
}
|
||||
|
||||
function test_error_event() {
|
||||
document.body.innerHTML = '<div><img></img></div>';
|
||||
var div = document.body.firstChild;
|
||||
var img = div.firstChild;
|
||||
var calls = "";
|
||||
|
||||
function record_call(msg) {
|
||||
return function() { calls += msg + "," };
|
||||
}
|
||||
var win_onerror = record_call("window.onerror");
|
||||
var doc_onerror = record_call("doc.onerror");
|
||||
var body_onerror = record_call("body.onerror");
|
||||
|
||||
window.addEventListener("error", win_onerror, true);
|
||||
document.addEventListener("error", doc_onerror, true);
|
||||
document.body.addEventListener("error", body_onerror, true);
|
||||
div.addEventListener("error", record_call("div.onerror"), true);
|
||||
|
||||
div.addEventListener("error", function() {
|
||||
ok(calls === "window.onerror,doc.onerror,body.onerror,div.onerror,", "calls = " + calls);
|
||||
|
||||
window.removeEventListener("error", win_onerror, true);
|
||||
document.removeEventListener("error", doc_onerror, true);
|
||||
document.body.removeEventListener("error", body_onerror, true);
|
||||
next_test();
|
||||
}, true);
|
||||
|
||||
img.src = "about:blank";
|
||||
}
|
||||
|
||||
function test_detached_img_error_event() {
|
||||
var img = new Image();
|
||||
img.onerror = function() {
|
||||
next_test();
|
||||
}
|
||||
img.src = "about:blank";
|
||||
}
|
||||
|
||||
var tests = [
|
||||
test_content_loaded,
|
||||
test_add_remove_listener,
|
||||
|
@ -758,6 +796,8 @@ var tests = [
|
|||
test_ui_event,
|
||||
test_mouse_event,
|
||||
test_keyboard_event,
|
||||
test_error_event,
|
||||
test_detached_img_error_event,
|
||||
test_time_stamp,
|
||||
test_listener_order
|
||||
];
|
||||
|
|
Loading…
Reference in New Issue