mshtml: Dispatch beforeunload event to the window.

Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com>
This commit is contained in:
Gabriel Ivăncescu 2022-11-18 17:20:28 +02:00 committed by Alexandre Julliard
parent e2bb4c1b88
commit 00dbd769b9
5 changed files with 138 additions and 0 deletions

View file

@ -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);

View file

@ -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() {

View file

@ -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);
}

View file

@ -0,0 +1,4 @@
<html>
<head><meta http-equiv="x-ua-compatible" content="IE=11" /></head>
<body><iframe src="about:blank" id="ifr"></iframe></body>
</html>

View file

@ -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 */