diff --git a/dlls/mshtml/Makefile.in b/dlls/mshtml/Makefile.in
index 97ae6f133a5..9af9a50b9fd 100644
--- a/dlls/mshtml/Makefile.in
+++ b/dlls/mshtml/Makefile.in
@@ -20,6 +20,7 @@ C_SRCS = \
htmldoc5.c \
htmlelem.c \
htmlelem2.c \
+ htmlevent.c \
htmlinput.c \
htmllocation.c \
htmlnode.c \
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c
new file mode 100644
index 00000000000..fcb5c7ca5df
--- /dev/null
+++ b/dlls/mshtml/htmlevent.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2008 Jacek Caban for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include
+
+#define COBJMACROS
+
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "ole2.h"
+
+#include "mshtml_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
+
+typedef enum {
+ EVENTID_LOAD,
+ EVENTID_LAST
+} eventid;
+
+struct event_target_t {
+ IDispatch *event_table[EVENTID_LAST];
+};
+
+static const WCHAR loadW[] = {'l','o','a','d',0};
+static const WCHAR onloadW[] = {'o','n','l','o','a','d',0};
+
+typedef struct {
+ LPCWSTR name;
+ LPCWSTR attr_name;
+} event_info_t;
+
+static const event_info_t event_info[] = {
+ {loadW, onloadW}
+};
+
+void check_event_attr(HTMLDocument *doc, nsIDOMElement *nselem)
+{
+ const PRUnichar *attr_value;
+ nsAString attr_name_str, attr_value_str;
+ IDispatch *disp;
+ HTMLDOMNode *node;
+ int i;
+ nsresult nsres;
+
+ nsAString_Init(&attr_value_str, NULL);
+ nsAString_Init(&attr_name_str, NULL);
+
+ for(i=0; i < EVENTID_LAST; i++) {
+ nsAString_SetData(&attr_name_str, event_info[i].attr_name);
+ nsres = nsIDOMElement_GetAttribute(nselem, &attr_name_str, &attr_value_str);
+ if(NS_SUCCEEDED(nsres)) {
+ nsAString_GetData(&attr_value_str, &attr_value);
+ if(!*attr_value)
+ continue;
+
+ TRACE("%p.%s = %s\n", nselem, debugstr_w(event_info[i].attr_name), debugstr_w(attr_value));
+
+ disp = script_parse_event(doc, attr_value);
+ if(disp) {
+ node = get_node(doc, (nsIDOMNode*)nselem, TRUE);
+ if(!node->event_target)
+ node->event_target = heap_alloc_zero(sizeof(event_target_t));
+ node->event_target->event_table[i] = disp;
+ }
+ }
+ }
+
+ nsAString_Finish(&attr_value_str);
+ nsAString_Finish(&attr_name_str);
+}
+
+void release_event_target(event_target_t *event_target)
+{
+ int i;
+
+ for(i=0; i < EVENTID_LAST; i++) {
+ if(event_target->event_table[i])
+ IDispatch_Release(event_target->event_table[i]);
+ }
+
+ heap_free(event_target);
+}
diff --git a/dlls/mshtml/htmlnode.c b/dlls/mshtml/htmlnode.c
index a5df57590f9..64cabe46da7 100644
--- a/dlls/mshtml/htmlnode.c
+++ b/dlls/mshtml/htmlnode.c
@@ -331,6 +331,8 @@ void HTMLDOMNode_destructor(HTMLDOMNode *This)
{
if(This->nsnode)
nsIDOMNode_Release(This->nsnode);
+ if(This->event_target)
+ release_event_target(This->event_target);
}
static const NodeImplVtbl HTMLDOMNodeImplVtbl = {
@@ -357,6 +359,7 @@ static HTMLDOMNode *create_node(HTMLDocument *doc, nsIDOMNode *nsnode)
ret->lpHTMLDOMNodeVtbl = &HTMLDOMNodeVtbl;
ret->ref = 1;
ret->doc = doc;
+ ret->event_target = NULL;
nsIDOMNode_AddRef(nsnode);
ret->nsnode = nsnode;
diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h
index ce75611682c..e9277f7b769 100644
--- a/dlls/mshtml/mshtml_private.h
+++ b/dlls/mshtml/mshtml_private.h
@@ -56,6 +56,7 @@ typedef struct HTMLDOMNode HTMLDOMNode;
typedef struct ConnectionPoint ConnectionPoint;
typedef struct BSCallback BSCallback;
typedef struct nsChannelBSC nsChannelBSC;
+typedef struct event_target_t event_target_t;
/* NOTE: make sure to keep in sync with dispex.c */
typedef enum {
@@ -274,6 +275,7 @@ struct HTMLDOMNode {
nsIDOMNode *nsnode;
HTMLDocument *doc;
+ event_target_t *event_target;
HTMLDOMNode *next;
};
@@ -426,6 +428,9 @@ void get_editor_controller(NSContainer*);
void init_nsevents(NSContainer*);
nsresult get_nsinterface(nsISupports*,REFIID,void**);
+void check_event_attr(HTMLDocument*,nsIDOMElement*);
+void release_event_target(event_target_t*);
+
void set_document_bscallback(HTMLDocument*,nsChannelBSC*);
void set_current_mon(HTMLDocument*,IMoniker*);
HRESULT start_binding(HTMLDocument*,BSCallback*,IBindCtx*);
@@ -472,6 +477,7 @@ void release_nodes(HTMLDocument*);
void release_script_hosts(HTMLDocument*);
void connect_scripts(HTMLDocument*);
void doc_insert_script(HTMLDocument*,nsIDOMHTMLScriptElement*);
+IDispatch *script_parse_event(HTMLDocument*,LPCWSTR);
IHTMLElementCollection *create_all_collection(HTMLDOMNode*);
diff --git a/dlls/mshtml/nsevents.c b/dlls/mshtml/nsevents.c
index 7e428ce52fe..12e299eabe8 100644
--- a/dlls/mshtml/nsevents.c
+++ b/dlls/mshtml/nsevents.c
@@ -167,6 +167,7 @@ static nsresult NSAPI handle_node_insert(nsIDOMEventListener *iface, nsIDOMEvent
NSContainer *This = NSEVENTLIST_THIS(iface)->This;
nsIDOMHTMLScriptElement *script;
nsIDOMEventTarget *target;
+ nsIDOMElement *elem;
nsresult nsres;
TRACE("(%p %p)\n", This, event);
@@ -174,16 +175,23 @@ static nsresult NSAPI handle_node_insert(nsIDOMEventListener *iface, nsIDOMEvent
nsres = nsIDOMEvent_GetTarget(event, &target);
if(NS_FAILED(nsres)) {
ERR("GetTarget failed: %08x\n", nsres);
- return nsres;
+ return NS_OK;
}
- nsres = nsISupports_QueryInterface(target, &IID_nsIDOMHTMLScriptElement, (void**)&script);
+ nsres = nsIDOMEventTarget_QueryInterface(target, &IID_nsIDOMElement, (void**)&elem);
+ nsIDOMEventTarget_Release(target);
+ if(NS_FAILED(nsres))
+ return NS_OK;
+
+ nsres = nsIDOMElement_QueryInterface(elem, &IID_nsIDOMHTMLScriptElement, (void**)&script);
if(SUCCEEDED(nsres)) {
doc_insert_script(This->doc, script);
nsIDOMHTMLScriptElement_Release(script);
}
- nsIDOMEventTarget_Release(target);
+ check_event_attr(This->doc, elem);
+
+ nsIDOMNode_Release(elem);
return NS_OK;
}
diff --git a/dlls/mshtml/script.c b/dlls/mshtml/script.c
index 41572961828..3424d904fbf 100644
--- a/dlls/mshtml/script.c
+++ b/dlls/mshtml/script.c
@@ -37,6 +37,7 @@
WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
static const WCHAR windowW[] = {'w','i','n','d','o','w',0};
+static const WCHAR emptyW[] = {0};
static const CLSID CLSID_JScript =
{0xf414c260,0x6ac0,0x11cf,{0xb6,0xd1,0x00,0xaa,0x00,0xbb,0xbb,0x58}};
@@ -507,7 +508,7 @@ static const IActiveScriptSiteDebug32Vtbl ActiveScriptSiteDebug32Vtbl = {
ActiveScriptSiteDebug32_OnScriptErrorDebug
};
-static ScriptHost *create_script_host(HTMLDocument *doc, GUID *guid)
+static ScriptHost *create_script_host(HTMLDocument *doc, const GUID *guid)
{
ScriptHost *ret;
HRESULT hres;
@@ -705,15 +706,9 @@ static BOOL get_script_guid(nsIDOMHTMLScriptElement *nsscript, GUID *guid)
return ret;
}
-static ScriptHost *get_script_host(HTMLDocument *doc, nsIDOMHTMLScriptElement *nsscript)
+static ScriptHost *get_script_host(HTMLDocument *doc, const GUID *guid)
{
ScriptHost *iter;
- GUID guid;
-
- if(!get_script_guid(nsscript, &guid)) {
- WARN("Could not find script GUID\n");
- return NULL;
- }
if(IsEqualGUID(&CLSID_JScript, &guid)) {
FIXME("Ignoring JScript\n");
@@ -721,18 +716,24 @@ static ScriptHost *get_script_host(HTMLDocument *doc, nsIDOMHTMLScriptElement *n
}
LIST_FOR_EACH_ENTRY(iter, &doc->script_hosts, ScriptHost, entry) {
- if(IsEqualGUID(&guid, &iter->guid))
+ if(IsEqualGUID(guid, &iter->guid))
return iter;
}
- return create_script_host(doc, &guid);
+ return create_script_host(doc, guid);
}
void doc_insert_script(HTMLDocument *doc, nsIDOMHTMLScriptElement *nsscript)
{
ScriptHost *script_host;
+ GUID guid;
- script_host = get_script_host(doc, nsscript);
+ if(!get_script_guid(nsscript, &guid)) {
+ WARN("Could not find script GUID\n");
+ return;
+ }
+
+ script_host = get_script_host(doc, &guid);
if(!script_host)
return;
@@ -740,6 +741,55 @@ void doc_insert_script(HTMLDocument *doc, nsIDOMHTMLScriptElement *nsscript)
parse_script_elem(script_host, nsscript);
}
+IDispatch *script_parse_event(HTMLDocument *doc, LPCWSTR text)
+{
+ ScriptHost *script_host;
+ GUID guid = CLSID_JScript;
+ const WCHAR *ptr;
+ IDispatch *disp;
+ HRESULT hres;
+
+ static const WCHAR delimiterW[] = {'\"',0};
+
+ for(ptr = text; isalnumW(*ptr); ptr++);
+ if(*ptr == ':') {
+ LPWSTR language;
+ BOOL b;
+
+ language = heap_alloc((ptr-text+1)*sizeof(WCHAR));
+ memcpy(language, text, (ptr-text)*sizeof(WCHAR));
+ language[ptr-text] = 0;
+
+ b = get_guid_from_language(language, &guid);
+
+ heap_free(language);
+
+ if(!b) {
+ WARN("Could not find language\n");
+ return NULL;
+ }
+
+ ptr++;
+ }else {
+ ptr = text;
+ }
+
+ script_host = get_script_host(doc, &guid);
+ if(!script_host || !script_host->parse_proc)
+ return NULL;
+
+ hres = IActiveScriptParseProcedure_ParseProcedureText(script_host->parse_proc, ptr, NULL, emptyW,
+ NULL, NULL, delimiterW, 0 /* FIXME */, 0,
+ SCRIPTPROC_HOSTMANAGESSOURCE|SCRIPTPROC_IMPLICIT_THIS|SCRIPTPROC_IMPLICIT_PARENTS, &disp);
+ if(FAILED(hres)) {
+ WARN("ParseProcedureText failed: %08x\n", hres);
+ return NULL;
+ }
+
+ TRACE("ret %p\n", disp);
+ return disp;
+}
+
void release_script_hosts(HTMLDocument *doc)
{
ScriptHost *iter;