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;