Commit 570e6b20 authored by Gabriel Ivăncescu's avatar Gabriel Ivăncescu Committed by Alexandre Julliard

mshtml: Implement unload event.

parent 00dbd769
......@@ -209,7 +209,7 @@ static const event_info_t event_info[] = {
{L"timeout", EVENT_TYPE_PROGRESS, DISPID_EVPROP_TIMEOUT,
EVENT_BIND_TO_TARGET},
{L"unload", EVENT_TYPE_UIEVENT, DISPID_EVMETH_ONUNLOAD,
EVENT_FIXME},
EVENT_BIND_TO_TARGET},
{L"visibilitychange", EVENT_TYPE_EVENT, DISPID_EVPROP_VISIBILITYCHANGE,
EVENT_FIXME | EVENT_BUBBLES},
......
......@@ -924,7 +924,8 @@ struct HTMLDocumentNode {
nsIDOMDocument *dom_document;
nsIDOMHTMLDocument *html_document;
BOOL content_ready;
BOOL content_ready : 1;
BOOL unload_sent : 1;
IHTMLDOMImplementation *dom_implementation;
IHTMLNamespaceCollection *namespaces;
......
......@@ -59,6 +59,7 @@ static nsresult NSAPI handle_keypress(nsIDOMEventListener*,nsIDOMEvent*);
static nsresult NSAPI handle_pageshow(nsIDOMEventListener*,nsIDOMEvent*);
static nsresult NSAPI handle_load(nsIDOMEventListener*,nsIDOMEvent*);
static nsresult NSAPI handle_beforeunload(nsIDOMEventListener*,nsIDOMEvent*);
static nsresult NSAPI handle_unload(nsIDOMEventListener*,nsIDOMEvent*);
enum doc_event_listener_flags {
BUBBLES = 0x0001,
......@@ -76,6 +77,7 @@ static const struct {
{ EVENTID_PAGESHOW, OVERRIDE, EVENTLISTENER_VTBL(handle_pageshow), },
{ EVENTID_LOAD, OVERRIDE, EVENTLISTENER_VTBL(handle_load), },
{ EVENTID_BEFOREUNLOAD, OVERRIDE, EVENTLISTENER_VTBL(handle_beforeunload), },
{ EVENTID_UNLOAD, OVERRIDE, EVENTLISTENER_VTBL(handle_unload) },
};
struct nsDocumentEventListener {
......@@ -356,6 +358,27 @@ static nsresult NSAPI handle_beforeunload(nsIDOMEventListener *iface, nsIDOMEven
return NS_OK;
}
static nsresult NSAPI handle_unload(nsIDOMEventListener *iface, nsIDOMEvent *nsevent)
{
nsEventListener *This = impl_from_nsIDOMEventListener(iface);
HTMLDocumentNode *doc = This->This->doc;
HTMLInnerWindow *window;
DOMEvent *event;
HRESULT hres;
if(!doc || !(window = doc->window) || doc->unload_sent)
return NS_OK;
doc->unload_sent = TRUE;
hres = create_event_from_nsevent(nsevent, dispex_compat_mode(&doc->node.event_target.dispex), &event);
if(SUCCEEDED(hres)) {
dispatch_event(&window->event_target, event);
IDOMEvent_Release(&event->IDOMEvent_iface);
}
return NS_OK;
}
static nsresult NSAPI handle_htmlevent(nsIDOMEventListener *iface, nsIDOMEvent *nsevent)
{
nsEventListener *This = impl_from_nsIDOMEventListener(iface);
......
......@@ -20,7 +20,12 @@ var compat_version;
var tests = [];
var pageshow_fired = false;
document.doc_unload_events_called = false;
window.onbeforeunload = function() { ok(false, "beforeunload fired"); };
window.onunload = function() {
document.doc_unload_events_called = true;
ok(document.readyState === "complete", "unload readyState = " + document.readyState);
};
if(window.addEventListener) {
window.addEventListener("pageshow", function(e) {
......@@ -35,8 +40,10 @@ if(window.addEventListener) {
document.addEventListener("visibilitychange", function() { ok(false, "visibilitychange fired"); });
document.addEventListener("beforeunload", function() { ok(false, "beforeunload fired on document"); });
document.addEventListener("unload", function() { ok(false, "unload fired on document"); });
}else {
document.attachEvent("onbeforeunload", function() { ok(false, "beforeunload fired on document"); });
document.attachEvent("onunload", function() { ok(false, "unload fired on document"); });
}
sync_test("page transition events", function() {
......@@ -44,6 +51,11 @@ sync_test("page transition events", function() {
ok(pageshow_fired === false, "pageshow fired");
else
ok(pageshow_fired === true, "pageshow not fired");
if(document.body.addEventListener)
document.body.addEventListener("unload", function() { ok(false, "unload fired on document.body"); });
else
document.body.attachEvent("onunload", function() { ok(false, "unload fired on document.body"); });
});
sync_test("builtin_toString", function() {
......
......@@ -100,6 +100,8 @@ DEFINE_EXPECT(iframe_onload);
DEFINE_EXPECT(visibilitychange);
DEFINE_EXPECT(onbeforeunload);
DEFINE_EXPECT(iframe_onbeforeunload);
DEFINE_EXPECT(onunload);
DEFINE_EXPECT(iframe_onunload);
DEFINE_EXPECT(doc1_onstorage);
DEFINE_EXPECT(doc1_onstoragecommit);
DEFINE_EXPECT(window1_onstorage);
......@@ -1448,12 +1450,39 @@ static HRESULT WINAPI iframe_onbeforeunload(IDispatchEx *iface, DISPID id, LCID
{
CHECK_EXPECT(iframe_onbeforeunload);
ok(called_onbeforeunload, "beforeunload not fired on parent window before iframe\n");
ok(!called_onunload, "unload fired on parent window before beforeunload on iframe\n");
ok(!called_iframe_onunload, "unload fired before beforeunload on iframe\n");
test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller);
return S_OK;
}
EVENT_HANDLER_FUNC_OBJ(iframe_onbeforeunload);
static HRESULT WINAPI onunload(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
{
CHECK_EXPECT(onunload);
if(expect_iframe_onunload) {
ok(called_onbeforeunload, "beforeunload not fired before unload\n");
ok(called_iframe_onbeforeunload, "beforeunload not fired on iframe before unload\n");
}
test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller);
return S_OK;
}
EVENT_HANDLER_FUNC_OBJ(onunload);
static HRESULT WINAPI iframe_onunload(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
{
CHECK_EXPECT(iframe_onunload);
ok(called_onunload, "unload not fired on parent window before iframe\n");
test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller);
return S_OK;
}
EVENT_HANDLER_FUNC_OBJ(iframe_onunload);
static HRESULT WINAPI nocall(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp,
VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller)
{
......@@ -2495,6 +2524,17 @@ static void test_unload_event(IHTMLDocument2 *doc)
BSTR bstr;
V_VT(&v) = VT_DISPATCH;
V_DISPATCH(&v) = (IDispatch*)&onunload_obj;
hres = IHTMLWindow2_put_onunload(window, v);
ok(hres == S_OK, "put_onunload failed: %08lx\n", hres);
V_VT(&v) = VT_EMPTY;
hres = IHTMLWindow2_get_onunload(window, &v);
ok(hres == S_OK, "get_onunload failed: %08lx\n", hres);
ok(V_VT(&v) == VT_DISPATCH, "V_VT(onunload) = %d\n", V_VT(&v));
ok(V_DISPATCH(&v) == (IDispatch*)&onunload_obj, "V_DISPATCH(onunload) = %p\n", V_DISPATCH(&v));
V_VT(&v) = VT_DISPATCH;
V_DISPATCH(&v) = (IDispatch*)&onbeforeunload_obj;
hres = IHTMLWindow2_put_onbeforeunload(window, v);
ok(hres == S_OK, "put_onbeforeunload failed: %08lx\n", hres);
......@@ -2524,6 +2564,17 @@ static void test_unload_event(IHTMLDocument2 *doc)
ok(hres == S_OK, "get_document failed: %08lx\n", hres);
V_VT(&v) = VT_DISPATCH;
V_DISPATCH(&v) = (IDispatch*)&iframe_onunload_obj;
hres = IHTMLWindow2_put_onunload(child, v);
ok(hres == S_OK, "put_onunload failed: %08lx\n", hres);
V_VT(&v) = VT_EMPTY;
hres = IHTMLWindow2_get_onunload(child, &v);
ok(hres == S_OK, "get_onunload failed: %08lx\n", hres);
ok(V_VT(&v) == VT_DISPATCH, "V_VT(onunload) = %d\n", V_VT(&v));
ok(V_DISPATCH(&v) == (IDispatch*)&iframe_onunload_obj, "V_DISPATCH(onunload) = %p\n", V_DISPATCH(&v));
V_VT(&v) = VT_DISPATCH;
V_DISPATCH(&v) = (IDispatch*)&iframe_onbeforeunload_obj;
hres = IHTMLWindow2_put_onbeforeunload(child, v);
ok(hres == S_OK, "put_onbeforeunload failed: %08lx\n", hres);
......@@ -2536,12 +2587,18 @@ static void test_unload_event(IHTMLDocument2 *doc)
add_event_listener((IUnknown*)doc, L"beforeunload", (IDispatch*)&nocall_obj, VARIANT_TRUE);
add_event_listener((IUnknown*)child_doc, L"beforeunload", (IDispatch*)&nocall_obj, VARIANT_TRUE);
add_event_listener((IUnknown*)doc, L"unload", (IDispatch*)&nocall_obj, VARIANT_TRUE);
add_event_listener((IUnknown*)child_doc, L"unload", (IDispatch*)&nocall_obj, VARIANT_TRUE);
IHTMLDocument2_Release(child_doc);
IHTMLWindow2_Release(child);
SET_EXPECT(onbeforeunload);
SET_EXPECT(iframe_onbeforeunload);
SET_EXPECT(onunload);
SET_EXPECT(iframe_onunload);
navigate(doc, L"blank.html");
CHECK_CALLED(iframe_onunload);
CHECK_CALLED(onunload);
CHECK_CALLED(iframe_onbeforeunload);
CHECK_CALLED(onbeforeunload);
......@@ -2551,6 +2608,17 @@ static void test_unload_event(IHTMLDocument2 *doc)
ok(V_VT(&v) == VT_NULL, "V_VT(onbeforeunload) = %d\n", V_VT(&v));
V_VT(&v) = VT_DISPATCH;
V_DISPATCH(&v) = (IDispatch*)&onunload_obj;
hres = IHTMLWindow2_put_onunload(window, v);
ok(hres == S_OK, "put_onunload failed: %08lx\n", hres);
V_VT(&v) = VT_EMPTY;
hres = IHTMLWindow2_get_onunload(window, &v);
ok(hres == S_OK, "get_onunload failed: %08lx\n", hres);
ok(V_VT(&v) == VT_DISPATCH, "V_VT(onunload) = %d\n", V_VT(&v));
ok(V_DISPATCH(&v) == (IDispatch*)&onunload_obj, "V_DISPATCH(onunload) = %p\n", V_DISPATCH(&v));
V_VT(&v) = VT_DISPATCH;
V_DISPATCH(&v) = (IDispatch*)&onbeforeunload_obj;
hres = IHTMLWindow2_put_onbeforeunload(window, v);
ok(hres == S_OK, "put_onbeforeunload failed: %08lx\n", hres);
......@@ -2560,6 +2628,16 @@ static void test_unload_event(IHTMLDocument2 *doc)
ok(hres == S_OK, "get_onbeforeunload failed: %08lx\n", hres);
ok(V_VT(&v) == VT_DISPATCH, "V_VT(onbeforeunload) = %d\n", V_VT(&v));
ok(V_DISPATCH(&v) == (IDispatch*)&onbeforeunload_obj, "V_DISPATCH(onbeforeunload) = %p\n", V_DISPATCH(&v));
IOleDocumentView_Show(view, FALSE);
SET_EXPECT(onunload);
IOleDocumentView_CloseView(view, 0);
CHECK_CALLED(onunload);
IOleDocumentView_SetInPlaceSite(view, NULL);
IOleDocumentView_Release(view);
view = NULL;
}
static void test_submit(IHTMLDocument2 *doc)
......
......@@ -3892,8 +3892,10 @@ static void test_simple_script(void)
static void run_from_moniker(IMoniker *mon)
{
DISPID dispid = DISPID_UNKNOWN;
IPersistMoniker *persist;
IHTMLDocument2 *doc;
BSTR bstr;
MSG msg;
HRESULT hres;
......@@ -3921,8 +3923,28 @@ static void run_from_moniker(IMoniker *mon)
CHECK_CALLED(external_success);
/* check prop set by events fired during document unload */
bstr = SysAllocString(L"doc_unload_events_called");
hres = IHTMLDocument2_GetIDsOfNames(doc, &IID_NULL, &bstr, 1, 0, &dispid);
SysFreeString(bstr);
if(hres == DISP_E_UNKNOWNNAME)
dispid = DISPID_UNKNOWN;
else
ok(hres == S_OK, "GetIDsOfNames failed %08lx\n", hres);
free_registered_streams();
set_client_site(doc, FALSE);
if(dispid != DISPID_UNKNOWN) {
DISPPARAMS dp = { 0 };
UINT argerr;
VARIANT v;
hres = IHTMLDocument2_Invoke(doc, dispid, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dp, &v, NULL, &argerr);
ok(hres == S_OK, "Invoke failed %08lx\n", hres);
ok(V_VT(&v) == VT_BOOL, "V_VT(doc_unload_events_called) = %d\n", V_VT(&v));
ok(V_BOOL(&v) == VARIANT_TRUE, "doc_unload_events_called is not true\n");
}
IHTMLDocument2_Release(doc);
}
......
......@@ -31,6 +31,7 @@
#include "wine/debug.h"
#include "mshtml_private.h"
#include "htmlevent.h"
WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
......@@ -407,6 +408,37 @@ HRESULT call_set_active_object(IOleInPlaceUIWindow *window, IOleInPlaceActiveObj
return IOleInPlaceUIWindow_SetActiveObject(window, act_obj, act_obj ? html_documentW : NULL);
}
static void send_unload_events_impl(HTMLInnerWindow *window)
{
HTMLOuterWindow *child;
DOMEvent *event;
HRESULT hres;
if(!window)
return;
if(window->doc && !window->doc->unload_sent) {
window->doc->unload_sent = TRUE;
hres = create_document_event(window->doc, EVENTID_UNLOAD, &event);
if(SUCCEEDED(hres)) {
dispatch_event(&window->event_target, event);
IDOMEvent_Release(&event->IDOMEvent_iface);
}
}
LIST_FOR_EACH_ENTRY(child, &window->children, HTMLOuterWindow, sibling_entry)
send_unload_events_impl(child->base.inner_window);
}
static void send_unload_events(HTMLDocumentObj *doc)
{
if(!doc->doc_node || !doc->window || !doc->doc_node->content_ready)
return;
send_unload_events_impl(doc->window->base.inner_window);
}
/**********************************************************
* IOleDocumentView implementation
*/
......@@ -670,6 +702,7 @@ static HRESULT WINAPI OleDocumentView_CloseView(IOleDocumentView *iface, DWORD d
if(dwReserved)
WARN("dwReserved = %ld\n", dwReserved);
send_unload_events(This);
IOleDocumentView_Show(iface, FALSE);
return S_OK;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment