diff --git a/dlls/mshtml/htmldoc3.c b/dlls/mshtml/htmldoc3.c index 8139f7fef6..f5e2f5454f 100644 --- a/dlls/mshtml/htmldoc3.c +++ b/dlls/mshtml/htmldoc3.c @@ -36,7 +36,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(mshtml); -static HRESULT get_doc_elem_by_id(HTMLDocumentNode *doc, const WCHAR *id, HTMLElement **ret) +HRESULT get_doc_elem_by_id(HTMLDocumentNode *doc, const WCHAR *id, HTMLElement **ret) { nsIDOMNodeList *nsnode_list; nsIDOMElement *nselem; diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index eeb4070865..53f8cff705 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -1443,6 +1443,21 @@ HRESULT detach_event(event_target_t *event_target, HTMLDocument *doc, BSTR name, return S_OK; } +void bind_elem_event(HTMLDocumentNode *doc, HTMLElement *elem, const WCHAR *event, IDispatch *disp) +{ + eventid_t eid; + + TRACE("(%p %p %s %p)\n", doc, elem, debugstr_w(event), disp); + + eid = attr_to_eid(event); + if(eid == EVENTID_LAST) { + WARN("Unsupported event %s\n", debugstr_w(event)); + return; + } + + set_event_handler_disp(&elem->node.event_target, elem->node.nsnode, doc, eid, disp); +} + void update_cp_events(HTMLInnerWindow *window, event_target_t **event_target_ptr, cp_static_data_t *cp, nsIDOMNode *nsnode) { event_target_t *event_target; diff --git a/dlls/mshtml/htmlevent.h b/dlls/mshtml/htmlevent.h index 2917dee92a..174d2f79ad 100644 --- a/dlls/mshtml/htmlevent.h +++ b/dlls/mshtml/htmlevent.h @@ -61,6 +61,7 @@ void update_cp_events(HTMLInnerWindow*,event_target_t**,cp_static_data_t*,nsIDOM HRESULT doc_init_events(HTMLDocumentNode*) DECLSPEC_HIDDEN; void detach_events(HTMLDocumentNode *doc) DECLSPEC_HIDDEN; HRESULT create_event_obj(IHTMLEventObj**) DECLSPEC_HIDDEN; +void bind_elem_event(HTMLDocumentNode*,HTMLElement*,const WCHAR*,IDispatch*) DECLSPEC_HIDDEN; void init_nsevents(HTMLDocumentNode*) DECLSPEC_HIDDEN; void release_nsevents(HTMLDocumentNode*) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 9cdc410099..1e07de6960 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -751,6 +751,7 @@ typedef struct { } HTMLScriptElement; HRESULT script_elem_from_nsscript(HTMLDocumentNode*,nsIDOMHTMLScriptElement*,HTMLScriptElement**) DECLSPEC_HIDDEN; +void bind_event_scripts(HTMLDocumentNode*) DECLSPEC_HIDDEN; HRESULT HTMLCurrentStyle_Create(HTMLElement*,IHTMLCurrentStyle**) DECLSPEC_HIDDEN; @@ -923,6 +924,7 @@ BOOL find_global_prop(HTMLInnerWindow*,BSTR,DWORD,ScriptHost**,DISPID*) DECLSPEC IDispatch *get_script_disp(ScriptHost*) DECLSPEC_HIDDEN; HRESULT search_window_props(HTMLInnerWindow*,BSTR,DWORD,DISPID*) DECLSPEC_HIDDEN; HRESULT get_frame_by_name(HTMLOuterWindow*,const WCHAR*,BOOL,HTMLOuterWindow**) DECLSPEC_HIDDEN; +HRESULT get_doc_elem_by_id(HTMLDocumentNode*,const WCHAR*,HTMLElement**) DECLSPEC_HIDDEN; HRESULT wrap_iface(IUnknown*,IUnknown*,IUnknown**) DECLSPEC_HIDDEN; diff --git a/dlls/mshtml/mutation.c b/dlls/mshtml/mutation.c index 7b8bf8970e..d765b02a6b 100644 --- a/dlls/mshtml/mutation.c +++ b/dlls/mshtml/mutation.c @@ -287,6 +287,7 @@ static nsresult run_end_load(HTMLDocumentNode *This, nsISupports *arg1, nsISuppo parse_complete(This->basedoc.doc_obj); } + bind_event_scripts(This); set_ready_state(This->basedoc.window, READYSTATE_INTERACTIVE); return NS_OK; } diff --git a/dlls/mshtml/script.c b/dlls/mshtml/script.c index ceb88d7123..467464a753 100644 --- a/dlls/mshtml/script.c +++ b/dlls/mshtml/script.c @@ -19,6 +19,7 @@ #include "config.h" #include +#include #define COBJMACROS @@ -32,6 +33,8 @@ #include "wine/debug.h" #include "mshtml_private.h" +#include "pluginhost.h" +#include "htmlevent.h" #include "binding.h" WINE_DEFAULT_DEBUG_CHANNEL(mshtml); @@ -60,7 +63,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(mshtml); #endif +static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0}; static const WCHAR windowW[] = {'w','i','n','d','o','w',0}; +static const WCHAR script_endW[] = {'<','/','S','C','R','I','P','T','>',0}; static const WCHAR emptyW[] = {0}; struct ScriptHost { @@ -689,8 +694,6 @@ static void parse_text(ScriptHost *script_host, LPCWSTR text) VARIANT var; HRESULT hres; - static const WCHAR script_endW[] = {'<','/','S','C','R','I','P','T','>',0}; - TRACE("%s\n", debugstr_w(text)); VariantInit(&var); @@ -889,23 +892,29 @@ static ScriptHost *get_script_host(HTMLInnerWindow *window, const GUID *guid) return create_script_host(window, guid); } -void doc_insert_script(HTMLInnerWindow *window, HTMLScriptElement *script_elem) +static ScriptHost *get_elem_script_host(HTMLInnerWindow *window, HTMLScriptElement *script_elem) { - ScriptHost *script_host; GUID guid; if(!get_script_guid(window, script_elem->nsscript, &guid)) { WARN("Could not find script GUID\n"); - return; + return NULL; } if(IsEqualGUID(&CLSID_JScript, &guid) && (!window->base.outer_window || window->base.outer_window->scriptmode != SCRIPTMODE_ACTIVESCRIPT)) { TRACE("Ignoring JScript\n"); - return; + return NULL; } - script_host = get_script_host(window, &guid); + return get_script_host(window, &guid); +} + +void doc_insert_script(HTMLInnerWindow *window, HTMLScriptElement *script_elem) +{ + ScriptHost *script_host; + + script_host = get_elem_script_host(window, script_elem); if(!script_host) return; @@ -1022,6 +1031,195 @@ IDispatch *get_script_disp(ScriptHost *script_host) return disp; } +static HTMLElement *find_event_target(HTMLDocumentNode *doc, HTMLScriptElement *script_elem) +{ + const PRUnichar *target_id; + nsAString target_id_str; + HTMLElement *elem; + nsresult nsres; + HRESULT hres; + + nsAString_Init(&target_id_str, NULL); + nsres = nsIDOMHTMLScriptElement_GetHtmlFor(script_elem->nsscript, &target_id_str); + if(NS_FAILED(nsres)) { + ERR("GetScriptFor failed: %08x\n", nsres); + nsAString_Finish(&target_id_str); + return NULL; + } + + nsAString_GetData(&target_id_str, &target_id); + if(!*target_id || !strcmpW(target_id, documentW) || !strcmpW(target_id, windowW)) { + FIXME("for %s not supported\n", debugstr_w(target_id)); + elem = NULL; + }else { + hres = get_doc_elem_by_id(doc, target_id, &elem); + if(FAILED(hres)) + elem = NULL; + } + nsAString_Finish(&target_id_str); + + return elem; +} + +static BOOL parse_event_str(WCHAR *event, const WCHAR **args) +{ + WCHAR *ptr; + + for(ptr = event; isalnumW(*ptr); ptr++); + if(!*ptr) { + *args = NULL; + return TRUE; + } + + if(*ptr != '(') + return FALSE; + + *ptr++ = 0; + *args = ptr; + while(isalnumW(*ptr) || isspaceW(*ptr) || *ptr == ',') + ptr++; + + if(*ptr++ != ')') + return FALSE; + *ptr++ = 0; + return !*ptr; +} + +static IDispatch *parse_event_elem(HTMLDocumentNode *doc, HTMLScriptElement *script_elem, WCHAR **ret_event) +{ + ScriptHost *script_host; + WCHAR *event = NULL; + const WCHAR *args; + nsAString nsstr; + IDispatch *disp; + nsresult nsres; + HRESULT hres; + + if(script_elem->parsed) + return NULL; + + script_host = get_elem_script_host(doc->window, script_elem); + if(!script_host || !script_host->parse_proc) + return NULL; + + nsAString_Init(&nsstr, NULL); + nsres = nsIDOMHTMLScriptElement_GetEvent(script_elem->nsscript, &nsstr); + if(NS_SUCCEEDED(nsres)) { + const PRUnichar *event_val; + + nsAString_GetData(&nsstr, &event_val); + event = heap_strdupW(event_val); + } + nsAString_Finish(&nsstr); + if(!event) + return NULL; + + if(!parse_event_str(event, &args)) { + WARN("parsing %s failed\n", debugstr_w(event)); + heap_free(event); + return NULL; + } + + nsAString_Init(&nsstr, NULL); + nsres = nsIDOMHTMLScriptElement_GetText(script_elem->nsscript, &nsstr); + if(NS_SUCCEEDED(nsres)) { + const PRUnichar *text; + + nsAString_GetData(&nsstr, &text); + hres = IActiveScriptParseProcedure_ParseProcedureText(script_host->parse_proc, text, args, + emptyW, NULL, NULL, script_endW, 0, 0, + SCRIPTPROC_HOSTMANAGESSOURCE|SCRIPTPROC_IMPLICIT_THIS|SCRIPTPROC_IMPLICIT_PARENTS, &disp); + if(FAILED(hres)) + disp = NULL; + }else { + ERR("GetText failed: %08x\n", nsres); + disp = NULL; + } + nsAString_Finish(&nsstr); + if(!disp) { + heap_free(event); + return NULL; + } + + *ret_event = event; + return disp; +} + +void bind_event_scripts(HTMLDocumentNode *doc) +{ + HTMLPluginContainer *plugin_container; + nsIDOMHTMLScriptElement *nsscript; + HTMLScriptElement *script_elem; + HTMLElement *event_target; + nsIDOMNodeList *node_list; + nsIDOMNode *script_node; + nsAString selector_str; + IDispatch *event_disp; + PRUint32 length, i; + WCHAR *event; + nsresult nsres; + HRESULT hres; + + static const PRUnichar selectorW[] = {'s','c','r','i','p','t','[','e','v','e','n','t',']',0}; + + TRACE("%p\n", doc); + + if(!doc->nsdoc) + return; + + nsAString_InitDepend(&selector_str, selectorW); + nsres = nsIDOMNodeSelector_QuerySelectorAll(doc->nsnode_selector, &selector_str, &node_list); + nsAString_Finish(&selector_str); + if(NS_FAILED(nsres)) { + ERR("QuerySelectorAll failed: %08x\n", nsres); + return; + } + + if(!node_list) + return; + + nsres = nsIDOMNodeList_GetLength(node_list, &length); + assert(nsres == NS_OK); + + for(i=0; i < length; i++) { + nsres = nsIDOMNodeList_Item(node_list, i, &script_node); + if(NS_FAILED(nsres) || !script_node) { + ERR("Item(%d) failed: %08x\n", i, nsres); + continue; + } + + nsres = nsIDOMNode_QueryInterface(script_node, &IID_nsIDOMHTMLScriptElement, (void**)&nsscript); + assert(nsres == NS_OK); + nsIDOMNode_Release(script_node); + + hres = script_elem_from_nsscript(doc, nsscript, &script_elem); + if(FAILED(hres)) + continue; + + event_disp = parse_event_elem(doc, script_elem, &event); + if(event_disp) { + event_target = find_event_target(doc, script_elem); + if(event_target) { + IHTMLElement_QueryInterface(&event_target->IHTMLElement_iface, &IID_HTMLPluginContainer, (void**)&plugin_container); + + if(plugin_container) + FIXME("ActiveX events not supported\n"); + else + bind_elem_event(doc, event_target, event, event_disp); + + IHTMLElement_Release(&event_target->IHTMLElement_iface); + } + + heap_free(event); + IDispatch_Release(event_disp); + } + + IHTMLScriptElement_Release(&script_elem->IHTMLScriptElement_iface); + } + + nsIDOMNodeList_Release(node_list); +} + BOOL find_global_prop(HTMLInnerWindow *window, BSTR name, DWORD flags, ScriptHost **ret_host, DISPID *ret_id) { IDispatchEx *dispex;