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;