Module: wine Branch: master Commit: 144056bce0f1195ab8f4bdd8b2c40bf5b39e9d50 URL: http://source.winehq.org/git/wine.git/?a=commit;h=144056bce0f1195ab8f4bdd8b2...
Author: Jacek Caban jacek@codeweavers.com Date: Tue Mar 10 18:27:31 2015 +0100
mshtml: Allow setting event handlers to strings.
---
dlls/mshtml/htmlevent.c | 62 +++++++++++++++++++++++++++++++++---------- dlls/mshtml/htmlevent.h | 8 +++--- dlls/mshtml/htmlwindow.c | 5 ++-- dlls/mshtml/tests/events.c | 2 +- dlls/mshtml/tests/events.html | 19 +++++++++++++ 5 files changed, 75 insertions(+), 21 deletions(-)
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index e1ece61..a14ce72 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -1367,23 +1367,29 @@ void detach_events(HTMLDocumentNode *doc) }
-static HRESULT remove_event_handler(event_target_t **event_target, eventid_t eid) +static void remove_event_handler(DispatchEx *dispex, event_target_t **event_target, eventid_t eid) { + VARIANT *store; + HRESULT hres; + + hres = dispex_get_dprop_ref(dispex, event_info[eid].attr_name, FALSE, &store); + if(SUCCEEDED(hres)) + VariantClear(store); + if(*event_target && (*event_target)->event_table[eid] && (*event_target)->event_table[eid]->handler_prop) { IDispatch_Release((*event_target)->event_table[eid]->handler_prop); (*event_target)->event_table[eid]->handler_prop = NULL; } - - return S_OK; }
-static HRESULT set_event_handler_disp(event_target_t **event_target_ptr, HTMLDocumentNode *doc, +static HRESULT set_event_handler_disp(DispatchEx *dispex, event_target_t **event_target_ptr, HTMLDocumentNode *doc, eventid_t eid, IDispatch *disp) { event_target_t *event_target;
+ remove_event_handler(dispex, event_target_ptr, eid); if(!disp) - return remove_event_handler(event_target_ptr, eid); + return S_OK;
event_target = get_event_target(event_target_ptr); if(!event_target) @@ -1392,23 +1398,44 @@ static HRESULT set_event_handler_disp(event_target_t **event_target_ptr, HTMLDoc if(!alloc_handler_vector(event_target, eid, 0)) return E_OUTOFMEMORY;
- if(event_target->event_table[eid]->handler_prop) - IDispatch_Release(event_target->event_table[eid]->handler_prop); - event_target->event_table[eid]->handler_prop = disp; IDispatch_AddRef(disp);
return ensure_nsevent_handler(doc, event_target, eid); }
-HRESULT set_event_handler(event_target_t **event_target, HTMLDocumentNode *doc, eventid_t eid, VARIANT *var) +HRESULT set_event_handler(DispatchEx *dispex, event_target_t **event_target, HTMLDocumentNode *doc, eventid_t eid, VARIANT *var) { switch(V_VT(var)) { case VT_NULL: - return remove_event_handler(event_target, eid); + remove_event_handler(dispex, event_target, eid); + return S_OK;
case VT_DISPATCH: - return set_event_handler_disp(event_target, doc, eid, V_DISPATCH(var)); + return set_event_handler_disp(dispex, event_target, doc, eid, V_DISPATCH(var)); + + case VT_BSTR: { + VARIANT *v; + HRESULT hres; + + /* + * Setting event handler to string is a rare case and we don't want to + * complicate nor increase memory of event_target_t for that. Instead, + * we store the value in DispatchEx, which can already handle custom + * properties. + */ + remove_event_handler(dispex, event_target, eid); + + hres = dispex_get_dprop_ref(dispex, event_info[eid].attr_name, TRUE, &v); + if(FAILED(hres)) + return hres; + + V_BSTR(v) = SysAllocString(V_BSTR(var)); + if(!V_BSTR(v)) + return E_OUTOFMEMORY; + V_VT(v) = VT_BSTR; + return S_OK; + }
default: FIXME("not handler %s\n", debugstr_variant(var)); @@ -1420,8 +1447,15 @@ HRESULT set_event_handler(event_target_t **event_target, HTMLDocumentNode *doc, return S_OK; }
-HRESULT get_event_handler(event_target_t **event_target, eventid_t eid, VARIANT *var) +HRESULT get_event_handler(DispatchEx *dispex, event_target_t **event_target, eventid_t eid, VARIANT *var) { + VARIANT *v; + HRESULT hres; + + hres = dispex_get_dprop_ref(dispex, event_info[eid].attr_name, FALSE, &v); + if(SUCCEEDED(hres) && V_VT(v) != VT_EMPTY) + return VariantCopy(var, v); + if(*event_target && (*event_target)->event_table[eid] && (*event_target)->event_table[eid]->handler_prop) { V_VT(var) = VT_DISPATCH; V_DISPATCH(var) = (*event_target)->event_table[eid]->handler_prop; @@ -1507,7 +1541,7 @@ void bind_node_event(HTMLDocumentNode *doc, event_target_t **event_target, HTMLD return; }
- set_event_handler_disp(event_target, doc, eid, disp); + set_event_handler_disp(&node->dispex, event_target, doc, eid, disp); }
void update_cp_events(HTMLInnerWindow *window, event_target_t **event_target_ptr, cp_static_data_t *cp) @@ -1547,7 +1581,7 @@ void check_event_attr(HTMLDocumentNode *doc, nsIDOMHTMLElement *nselem) if(disp) { hres = get_node(doc, (nsIDOMNode*)nselem, TRUE, &node); if(SUCCEEDED(hres)) { - set_event_handler_disp(get_node_event_target(node), node->doc, i, disp); + set_event_handler_disp(&node->dispex, get_node_event_target(node), node->doc, i, disp); node_release(node); } IDispatch_Release(disp); diff --git a/dlls/mshtml/htmlevent.h b/dlls/mshtml/htmlevent.h index e312a9c..0517834 100644 --- a/dlls/mshtml/htmlevent.h +++ b/dlls/mshtml/htmlevent.h @@ -54,8 +54,8 @@ eventid_t str_to_eid(LPCWSTR) DECLSPEC_HIDDEN; void check_event_attr(HTMLDocumentNode*,nsIDOMHTMLElement*) DECLSPEC_HIDDEN; void release_event_target(event_target_t*) DECLSPEC_HIDDEN; void fire_event(HTMLDocumentNode*,eventid_t,BOOL,nsIDOMNode*,nsIDOMEvent*,IDispatch*) DECLSPEC_HIDDEN; -HRESULT set_event_handler(event_target_t**,HTMLDocumentNode*,eventid_t,VARIANT*) DECLSPEC_HIDDEN; -HRESULT get_event_handler(event_target_t**,eventid_t,VARIANT*) DECLSPEC_HIDDEN; +HRESULT set_event_handler(DispatchEx*,event_target_t**,HTMLDocumentNode*,eventid_t,VARIANT*) DECLSPEC_HIDDEN; +HRESULT get_event_handler(DispatchEx*,event_target_t**,eventid_t,VARIANT*) DECLSPEC_HIDDEN; HRESULT attach_event(event_target_t**,HTMLDocument*,BSTR,IDispatch*,VARIANT_BOOL*) DECLSPEC_HIDDEN; HRESULT detach_event(event_target_t*,HTMLDocument*,BSTR,IDispatch*) DECLSPEC_HIDDEN; HRESULT dispatch_event(HTMLDOMNode*,const WCHAR*,VARIANT*,VARIANT_BOOL*) DECLSPEC_HIDDEN; @@ -78,12 +78,12 @@ static inline event_target_t **get_node_event_target(HTMLDOMNode *node)
static inline HRESULT set_node_event(HTMLDOMNode *node, eventid_t eid, VARIANT *var) { - return set_event_handler(get_node_event_target(node), node->doc, eid, var); + return set_event_handler(&node->dispex, get_node_event_target(node), node->doc, eid, var); }
static inline HRESULT get_node_event(HTMLDOMNode *node, eventid_t eid, VARIANT *var) { - return get_event_handler(get_node_event_target(node), eid, var); + return get_event_handler(&node->dispex, get_node_event_target(node), eid, var); }
static inline HRESULT set_doc_event(HTMLDocument *doc, eventid_t eid, VARIANT *var) diff --git a/dlls/mshtml/htmlwindow.c b/dlls/mshtml/htmlwindow.c index 6f3cbd4..3a31301 100644 --- a/dlls/mshtml/htmlwindow.c +++ b/dlls/mshtml/htmlwindow.c @@ -95,7 +95,8 @@ static inline HRESULT set_window_event(HTMLWindow *window, eventid_t eid, VARIAN return E_FAIL; }
- return set_event_handler(&window->inner_window->doc->body_event_target, window->inner_window->doc, eid, var); + return set_event_handler(&window->inner_window->dispex, &window->inner_window->doc->body_event_target, + window->inner_window->doc, eid, var); }
static inline HRESULT get_window_event(HTMLWindow *window, eventid_t eid, VARIANT *var) @@ -105,7 +106,7 @@ static inline HRESULT get_window_event(HTMLWindow *window, eventid_t eid, VARIAN return E_FAIL; }
- return get_event_handler(&window->inner_window->doc->body_event_target, eid, var); + return get_event_handler(&window->inner_window->dispex, &window->inner_window->doc->body_event_target, eid, var); }
static void detach_inner_window(HTMLInnerWindow *window) diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index 8f4e15e..e3e7f72 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -1571,7 +1571,7 @@ static void test_onclick(IHTMLDocument2 *doc) V_VT(&v) = VT_BSTR; V_BSTR(&v) = a2bstr("function();"); hres = IHTMLElement_put_onclick(div, v); - todo_wine ok(hres == S_OK, "put_onclick failed: %08x\n", hres); + ok(hres == S_OK, "put_onclick failed: %08x\n", hres);
if(hres == S_OK) { V_VT(&v) = VT_EMPTY; diff --git a/dlls/mshtml/tests/events.html b/dlls/mshtml/tests/events.html index ae83ebe..5a0bbfb 100644 --- a/dlls/mshtml/tests/events.html +++ b/dlls/mshtml/tests/events.html @@ -139,6 +139,24 @@ function test_insert_script() { readystatechange_log = "append"; }
+var string_handler_called = false; + +function test_string_event_handler() { + var e = document.createElement("div"); + var event_str = "string_handler_called = true;"; + + document.body.appendChild(e); + e.onclick = event_str; + ok(e.onclick === event_str, "e.onclick = " + e.onclick); + e.click(); + ok(string_handler_called === false, "string handler called"); + + e.setAttribute("onclick", event_str); + ok(e.onclick === event_str, "e.onclick = " + e.onclick); + e.click(); + ok(string_handler_called === false, "string handler called"); +} + window.onload = function() { try { ok(inlscr_complete_called, "onreadystatechange not fired"); @@ -159,6 +177,7 @@ window.onload = function() { ondataavailable_test(); test_handler_this(); test_insert_script(); + test_string_event_handler(); }catch(e) { ok(false, "Got an exception: " + e.message); }