diff --git a/dlls/mshtml/nsevents.c b/dlls/mshtml/nsevents.c index 0b76ebec5c3..7002a2cc71d 100644 --- a/dlls/mshtml/nsevents.c +++ b/dlls/mshtml/nsevents.c @@ -58,6 +58,7 @@ static nsresult NSAPI handle_focus(nsIDOMEventListener*,nsIDOMEvent*); 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*); enum doc_event_listener_flags { BUBBLES = 0x0001, @@ -74,6 +75,7 @@ static const struct { { EVENTID_KEYPRESS, BUBBLES, EVENTLISTENER_VTBL(handle_keypress) }, { EVENTID_PAGESHOW, OVERRIDE, EVENTLISTENER_VTBL(handle_pageshow), }, { EVENTID_LOAD, OVERRIDE, EVENTLISTENER_VTBL(handle_load), }, + { EVENTID_BEFOREUNLOAD, OVERRIDE, EVENTLISTENER_VTBL(handle_beforeunload), }, }; struct nsDocumentEventListener { @@ -333,6 +335,27 @@ static nsresult NSAPI handle_load(nsIDOMEventListener *iface, nsIDOMEvent *event return NS_OK; } +static nsresult NSAPI handle_beforeunload(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)) + return NS_OK; + + /* Gecko dispatches this to the document, but IE dispatches it to the window */ + 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); diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index ca942501381..246974fb82e 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -20,6 +20,8 @@ var compat_version; var tests = []; var pageshow_fired = false; +window.onbeforeunload = function() { ok(false, "beforeunload fired"); }; + if(window.addEventListener) { window.addEventListener("pageshow", function(e) { pageshow_fired = true; @@ -32,6 +34,9 @@ if(window.addEventListener) { }, true); document.addEventListener("visibilitychange", function() { ok(false, "visibilitychange fired"); }); + document.addEventListener("beforeunload", function() { ok(false, "beforeunload fired on document"); }); +}else { + document.attachEvent("onbeforeunload", function() { ok(false, "beforeunload fired on document"); }); } sync_test("page transition events", function() { diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index 6d9543db96b..e12f4f666a2 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -98,6 +98,8 @@ DEFINE_EXPECT(submit_onclick_setret); DEFINE_EXPECT(elem2_cp_onclick); DEFINE_EXPECT(iframe_onload); DEFINE_EXPECT(visibilitychange); +DEFINE_EXPECT(onbeforeunload); +DEFINE_EXPECT(iframe_onbeforeunload); DEFINE_EXPECT(doc1_onstorage); DEFINE_EXPECT(doc1_onstoragecommit); DEFINE_EXPECT(window1_onstorage); @@ -1431,6 +1433,27 @@ static HRESULT WINAPI onvisibilitychange(IDispatchEx *iface, DISPID id, LCID lci EVENT_HANDLER_FUNC_OBJ(onvisibilitychange); +static HRESULT WINAPI onbeforeunload(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + CHECK_EXPECT(onbeforeunload); + test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller); + return S_OK; +} + +EVENT_HANDLER_FUNC_OBJ(onbeforeunload); + +static HRESULT WINAPI iframe_onbeforeunload(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + CHECK_EXPECT(iframe_onbeforeunload); + ok(called_onbeforeunload, "beforeunload 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_onbeforeunload); + static HRESULT WINAPI nocall(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) { @@ -2460,6 +2483,85 @@ static void test_visibilitychange(IHTMLDocument2 *doc) } } +static void test_unload_event(IHTMLDocument2 *doc) +{ + IHTMLDocument2 *child_doc; + IHTMLFrameBase2 *iframe; + IHTMLDocument6 *doc6; + IHTMLElement2 *elem; + IHTMLWindow2 *child; + HRESULT hres; + VARIANT v; + BSTR bstr; + + 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); + + V_VT(&v) = VT_EMPTY; + hres = IHTMLWindow2_get_onbeforeunload(window, &v); + 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)); + + hres = IHTMLDocument2_QueryInterface(doc, &IID_IHTMLDocument6, (void**)&doc6); + ok(hres == S_OK, "Could not get IHTMLDocument6 iface: %08lx\n", hres); + bstr = SysAllocString(L"ifr"); + hres = IHTMLDocument6_getElementById(doc6, bstr, &elem); + ok(hres == S_OK, "getElementById failed: %08lx\n", hres); + IHTMLDocument6_Release(doc6); + SysFreeString(bstr); + + hres = IHTMLElement2_QueryInterface(elem, &IID_IHTMLFrameBase2, (void**)&iframe); + ok(hres == S_OK, "Could not get IHTMLFrameBase2 iface: %08lx\n", hres); + IHTMLElement2_Release(elem); + hres = IHTMLFrameBase2_get_contentWindow(iframe, &child); + ok(hres == S_OK, "get_contentWindow failed: %08lx\n", hres); + IHTMLFrameBase2_Release(iframe); + + hres = IHTMLWindow2_get_document(child, &child_doc); + ok(hres == S_OK, "get_document failed: %08lx\n", hres); + + 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); + + V_VT(&v) = VT_EMPTY; + hres = IHTMLWindow2_get_onbeforeunload(child, &v); + 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*)&iframe_onbeforeunload_obj, "V_DISPATCH(onbeforeunload) = %p\n", V_DISPATCH(&v)); + + 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); + IHTMLDocument2_Release(child_doc); + IHTMLWindow2_Release(child); + + SET_EXPECT(onbeforeunload); + SET_EXPECT(iframe_onbeforeunload); + navigate(doc, L"blank.html"); + CHECK_CALLED(iframe_onbeforeunload); + CHECK_CALLED(onbeforeunload); + + V_VT(&v) = VT_EMPTY; + hres = IHTMLWindow2_get_onbeforeunload(window, &v); + ok(hres == S_OK, "get_onbeforeunload failed: %08lx\n", hres); + ok(V_VT(&v) == VT_NULL, "V_VT(onbeforeunload) = %d\n", V_VT(&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); + + V_VT(&v) = VT_EMPTY; + hres = IHTMLWindow2_get_onbeforeunload(window, &v); + 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)); +} + static void test_submit(IHTMLDocument2 *doc) { IHTMLElement *elem, *submit; @@ -5571,6 +5673,7 @@ START_TEST(events) run_test_from_res(L"doc_with_prop_ie9.html", test_doc_obj); run_test_from_res(L"doc_with_prop_ie9.html", test_visibilitychange); run_test_from_res(L"blank_ie10.html", test_visibilitychange); + run_test_from_res(L"iframe.html", test_unload_event); run_test(empty_doc_ie9_str, test_create_event); } diff --git a/dlls/mshtml/tests/iframe.html b/dlls/mshtml/tests/iframe.html new file mode 100644 index 00000000000..ec08a0eb19a --- /dev/null +++ b/dlls/mshtml/tests/iframe.html @@ -0,0 +1,4 @@ + + + + diff --git a/dlls/mshtml/tests/rsrc.rc b/dlls/mshtml/tests/rsrc.rc index 01b2838be8b..e60e37198de 100644 --- a/dlls/mshtml/tests/rsrc.rc +++ b/dlls/mshtml/tests/rsrc.rc @@ -82,6 +82,9 @@ doc_with_prop.html HTML "doc_with_prop.html" /* @makedep: doc_with_prop_ie9.html */ doc_with_prop_ie9.html HTML "doc_with_prop_ie9.html" +/* @makedep: iframe.html */ +iframe.html HTML "iframe.html" + /* For res: protocol test: */ /* @makedep: jstest.html */