diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index 7b82d823bd9..01a385130b1 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -184,6 +184,8 @@ static const event_info_t event_info[] = { EVENT_FIXME}, {L"msthumbnailclick", EVENT_TYPE_MOUSE, DISPID_EVPROP_ONMSTHUMBNAILCLICK, EVENT_FIXME}, + {L"pagehide", EVENT_TYPE_PAGETRANSITION, DISPID_EVPROP_ONPAGEHIDE, + 0}, {L"pageshow", EVENT_TYPE_PAGETRANSITION, DISPID_EVPROP_ONPAGESHOW, 0}, {L"paste", EVENT_TYPE_CLIPBOARD, DISPID_EVMETH_ONPASTE, diff --git a/dlls/mshtml/htmlevent.h b/dlls/mshtml/htmlevent.h index e49c47d6988..a6d1f734a40 100644 --- a/dlls/mshtml/htmlevent.h +++ b/dlls/mshtml/htmlevent.h @@ -51,6 +51,7 @@ typedef enum { EVENTID_MOUSEUP, EVENTID_MOUSEWHEEL, EVENTID_MSTHUMBNAILCLICK, + EVENTID_PAGEHIDE, EVENTID_PAGESHOW, EVENTID_PASTE, EVENTID_PROGRESS, diff --git a/dlls/mshtml/nsevents.c b/dlls/mshtml/nsevents.c index edc90563dd9..0248737b012 100644 --- a/dlls/mshtml/nsevents.c +++ b/dlls/mshtml/nsevents.c @@ -57,6 +57,7 @@ static nsresult NSAPI handle_blur(nsIDOMEventListener*,nsIDOMEvent*); 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_pagehide(nsIDOMEventListener*,nsIDOMEvent*); static nsresult NSAPI handle_load(nsIDOMEventListener*,nsIDOMEvent*); static nsresult NSAPI handle_beforeunload(nsIDOMEventListener*,nsIDOMEvent*); static nsresult NSAPI handle_unload(nsIDOMEventListener*,nsIDOMEvent*); @@ -75,6 +76,7 @@ static const struct { { EVENTID_FOCUS, 0, EVENTLISTENER_VTBL(handle_focus) }, { EVENTID_KEYPRESS, BUBBLES, EVENTLISTENER_VTBL(handle_keypress) }, { EVENTID_PAGESHOW, OVERRIDE, EVENTLISTENER_VTBL(handle_pageshow), }, + { EVENTID_PAGEHIDE, OVERRIDE, EVENTLISTENER_VTBL(handle_pagehide), }, { EVENTID_LOAD, OVERRIDE, EVENTLISTENER_VTBL(handle_load), }, { EVENTID_BEFOREUNLOAD, OVERRIDE, EVENTLISTENER_VTBL(handle_beforeunload), }, { EVENTID_UNLOAD, OVERRIDE, EVENTLISTENER_VTBL(handle_unload) }, @@ -234,6 +236,26 @@ static nsresult NSAPI handle_pageshow(nsIDOMEventListener *iface, nsIDOMEvent *n return NS_OK; } +static nsresult NSAPI handle_pagehide(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->dom_document || doc->document_mode < COMPAT_MODE_IE11 || doc->unload_sent) + return NS_OK; + + hres = create_document_event(doc, EVENTID_PAGEHIDE, &event); + if(SUCCEEDED(hres)) { + dispatch_event(&window->event_target, event); + IDOMEvent_Release(&event->IDOMEvent_iface); + } + + return NS_OK; +} + static void handle_docobj_load(HTMLDocumentObj *doc) { IOleCommandTarget *olecmd = NULL; diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 0669073771c..33d60f7e835 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -19,12 +19,16 @@ var compat_version; var tests = []; -var pageshow_fired = false; +var pageshow_fired = false, pagehide_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(document.documentMode < 11) + ok(pagehide_fired === false, "pagehide fired before unload"); + else + ok(pagehide_fired === true, "pagehide not fired before unload"); }; if(window.addEventListener) { @@ -38,6 +42,16 @@ if(window.addEventListener) { ok(document.readyState === "complete", "pageshow readyState = " + document.readyState); }, true); + window.addEventListener("pagehide", function(e) { + pagehide_fired = true; + ok(document.documentMode >= 11, "pagehide fired"); + + var r = Object.prototype.toString.call(e); + todo_wine. + ok(r === "[object PageTransitionEvent]", "pagehide toString = " + r); + ok("persisted" in e, "'persisted' not in pagehide event"); + }, true); + 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"); }); @@ -51,6 +65,7 @@ sync_test("page transition events", function() { ok(pageshow_fired === false, "pageshow fired"); else ok(pageshow_fired === true, "pageshow not fired"); + ok(pagehide_fired === false, "pagehide fired"); if(document.body.addEventListener) document.body.addEventListener("unload", function() { ok(false, "unload fired on document.body"); }); diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index 4e7238e119c..643993bc475 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -101,7 +101,9 @@ DEFINE_EXPECT(visibilitychange); DEFINE_EXPECT(onbeforeunload); DEFINE_EXPECT(iframe_onbeforeunload); DEFINE_EXPECT(onunload); +DEFINE_EXPECT(pagehide); DEFINE_EXPECT(iframe_onunload); +DEFINE_EXPECT(iframe_pagehide); DEFINE_EXPECT(doc1_onstorage); DEFINE_EXPECT(doc1_onstoragecommit); DEFINE_EXPECT(window1_onstorage); @@ -1458,6 +1460,17 @@ static HRESULT WINAPI iframe_onbeforeunload(IDispatchEx *iface, DISPID id, LCID EVENT_HANDLER_FUNC_OBJ(iframe_onbeforeunload); +static HRESULT WINAPI pagehide(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + CHECK_EXPECT(pagehide); + ok(!called_onunload, "unload fired before pagehide\n"); + test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller); + return S_OK; +} + +EVENT_HANDLER_FUNC_OBJ(pagehide); + static HRESULT WINAPI onunload(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) { @@ -1465,18 +1478,34 @@ static HRESULT WINAPI onunload(IDispatchEx *iface, DISPID id, LCID lcid, WORD wF 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"); - } + ok(called_pagehide, "pagehide not fired before unload\n"); + }else + ok(!called_pagehide, "pagehide fired before unload in quirks mode\n"); test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller); return S_OK; } EVENT_HANDLER_FUNC_OBJ(onunload); +static HRESULT WINAPI iframe_pagehide(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + CHECK_EXPECT(iframe_pagehide); + ok(called_pagehide, "pagehide not fired on parent window before iframe\n"); + ok(called_onunload, "unload not fired on parent window before pagehide on iframe\n"); + ok(!called_iframe_onunload, "unload fired before pagehide on iframe\n"); + test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller); + return S_OK; +} + +EVENT_HANDLER_FUNC_OBJ(iframe_pagehide); + 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"); + ok(called_iframe_pagehide, "pagehide not fired before unload on iframe\n"); test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller); return S_OK; } @@ -2585,6 +2614,8 @@ static void test_unload_event(IHTMLDocument2 *doc) 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*)window, L"pagehide", (IDispatch*)&pagehide_obj, VARIANT_TRUE); + add_event_listener((IUnknown*)child, L"pagehide", (IDispatch*)&iframe_pagehide_obj, VARIANT_TRUE); 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); @@ -2595,9 +2626,13 @@ static void test_unload_event(IHTMLDocument2 *doc) SET_EXPECT(onbeforeunload); SET_EXPECT(iframe_onbeforeunload); SET_EXPECT(onunload); + SET_EXPECT(pagehide); SET_EXPECT(iframe_onunload); + SET_EXPECT(iframe_pagehide); navigate(doc, L"blank.html"); + CHECK_CALLED(iframe_pagehide); CHECK_CALLED(iframe_onunload); + CHECK_CALLED(pagehide); CHECK_CALLED(onunload); CHECK_CALLED(iframe_onbeforeunload); CHECK_CALLED(onbeforeunload); diff --git a/dlls/mshtml/view.c b/dlls/mshtml/view.c index 3fca80a1b37..063f7afab9d 100644 --- a/dlls/mshtml/view.c +++ b/dlls/mshtml/view.c @@ -420,6 +420,16 @@ static void send_unload_events_impl(HTMLInnerWindow *window) if(window->doc && !window->doc->unload_sent) { window->doc->unload_sent = TRUE; + /* Native sends pagehide events prior to unload on the same window + before it moves on to the next window, so they're interleaved. */ + if(window->doc->document_mode >= COMPAT_MODE_IE11) { + hres = create_document_event(window->doc, EVENTID_PAGEHIDE, &event); + if(SUCCEEDED(hres)) { + dispatch_event(&window->event_target, event); + IDOMEvent_Release(&event->IDOMEvent_iface); + } + } + hres = create_document_event(window->doc, EVENTID_UNLOAD, &event); if(SUCCEEDED(hres)) { dispatch_event(&window->event_target, event);