From f6c4304e893007a28d1b6b13af78e1e22c013b41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Mu=C3=B1oz=20Mazur?= Date: Tue, 21 Jan 2025 09:55:53 -0300 Subject: [PATCH] LibWeb: Check if event is not "beforeunload" before cancelling --- Libraries/LibWeb/DOM/EventTarget.cpp | 10 +- .../beforeunload-canceling.txt | 27 +++ .../beforeunload-canceling.html | 222 ++++++++++++++++++ .../support/beforeunload-canceling-1.html | 35 +++ 4 files changed, 292 insertions(+), 2 deletions(-) create mode 100644 Tests/LibWeb/Text/expected/wpt-import/html/browsers/browsing-the-web/unloading-documents/beforeunload-canceling.txt create mode 100644 Tests/LibWeb/Text/input/wpt-import/html/browsers/browsing-the-web/unloading-documents/beforeunload-canceling.html create mode 100644 Tests/LibWeb/Text/input/wpt-import/html/browsers/browsing-the-web/unloading-documents/support/beforeunload-canceling-1.html diff --git a/Libraries/LibWeb/DOM/EventTarget.cpp b/Libraries/LibWeb/DOM/EventTarget.cpp index 260ca7bd57e..ccbd356f423 100644 --- a/Libraries/LibWeb/DOM/EventTarget.cpp +++ b/Libraries/LibWeb/DOM/EventTarget.cpp @@ -2,6 +2,7 @@ * Copyright (c) 2020-2022, Andreas Kling * Copyright (c) 2022, Luke Wilde * Copyright (c) 2024, Glenn Skrzypczak + * Copyright (c) 2025, Felipe Muñoz Mazur * * SPDX-License-Identifier: BSD-2-Clause */ @@ -716,8 +717,10 @@ JS::ThrowCompletionOr EventTarget::process_event_handler_for_event(FlyStri // FIXME: Ideally, invoke_callback would convert JS::Value to the appropriate return type for us as per the spec, but it doesn't currently. auto return_value = *return_value_or_error.value(); + auto is_beforeunload = event.type() == HTML::EventNames::beforeunload; + // 5. Process return value as follows: - if (is(event) && event.type() == "beforeunload") { + if (is(event) && is_beforeunload) { // -> If event is a BeforeUnloadEvent object and event's type is "beforeunload" // If return value is not null, then: if (!return_value.is_nullish()) { @@ -741,7 +744,10 @@ JS::ThrowCompletionOr EventTarget::process_event_handler_for_event(FlyStri // -> Otherwise // If return value is false, then set event's canceled flag. // NOTE: the return type of EventHandler is `any`, so no coercion happens, meaning we have to check if it's a boolean first. - if (return_value.is_boolean() && !return_value.as_bool()) + // Spec-Note: If we've gotten to this "Otherwise" clause because event's type is "beforeunload" but event is + // not a BeforeUnloadEvent object, then return value will never be false, since in such cases + // return value will have been coerced into either null or a DOMString. + if (return_value.is_boolean() && !return_value.as_bool() && !is_beforeunload) event.set_cancelled(true); } diff --git a/Tests/LibWeb/Text/expected/wpt-import/html/browsers/browsing-the-web/unloading-documents/beforeunload-canceling.txt b/Tests/LibWeb/Text/expected/wpt-import/html/browsers/browsing-the-web/unloading-documents/beforeunload-canceling.txt new file mode 100644 index 00000000000..8e1034003b4 --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/html/browsers/browsing-the-web/unloading-documents/beforeunload-canceling.txt @@ -0,0 +1,27 @@ +Harness status: OK + +Found 22 tests + +22 Pass +Pass Returning a string must not cancel the event: CustomEvent, non-cancelable +Pass Returning a string must not cancel the event: CustomEvent, cancelable +Pass Returning false must not cancel the event, because it's coerced to the DOMString "false" which does not cancel CustomEvents: CustomEvent, cancelable +Pass Returning a string must not cancel the event: BeforeUnloadEvent with type "click", cancelable +Pass Returning null with a real iframe unloading +Pass Returning undefined with a real iframe unloading +Pass Returning with a real iframe unloading +Pass Returning false with a real iframe unloading +Pass Returning true with a real iframe unloading +Pass Returning 0 with a real iframe unloading +Pass Returning null with a real iframe unloading; setting returnValue to foo +Pass Returning undefined with a real iframe unloading; setting returnValue to foo +Pass Returning with a real iframe unloading; setting returnValue to foo +Pass Returning false with a real iframe unloading; setting returnValue to foo +Pass Returning true with a real iframe unloading; setting returnValue to foo +Pass Returning 0 with a real iframe unloading; setting returnValue to foo +Pass Returning undefined with a real iframe unloading; setting returnValue to +Pass Returning undefined with a real iframe unloading; calling preventDefault() +Pass Returning undefined with a real iframe unloading; setting returnValue to foo; calling preventDefault() +Pass Returning foo with a real iframe unloading; calling preventDefault() +Pass Returning foo with a real iframe unloading; setting returnValue to foo; calling preventDefault() +Pass Returning true with a real iframe unloading; setting returnValue to ; calling preventDefault() \ No newline at end of file diff --git a/Tests/LibWeb/Text/input/wpt-import/html/browsers/browsing-the-web/unloading-documents/beforeunload-canceling.html b/Tests/LibWeb/Text/input/wpt-import/html/browsers/browsing-the-web/unloading-documents/beforeunload-canceling.html new file mode 100644 index 00000000000..7c2017db2f3 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/html/browsers/browsing-the-web/unloading-documents/beforeunload-canceling.html @@ -0,0 +1,222 @@ + + +beforeunload return value cancelation behavior + + + + + +
+ + diff --git a/Tests/LibWeb/Text/input/wpt-import/html/browsers/browsing-the-web/unloading-documents/support/beforeunload-canceling-1.html b/Tests/LibWeb/Text/input/wpt-import/html/browsers/browsing-the-web/unloading-documents/support/beforeunload-canceling-1.html new file mode 100644 index 00000000000..6ba1e657400 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/html/browsers/browsing-the-web/unloading-documents/support/beforeunload-canceling-1.html @@ -0,0 +1,35 @@ + + +Support page for beforeunload-canceling.html + +

If this goes away, it navigated

+ +