From f4be4817f628daa01ad4c69093cbb313d9a1dafb Mon Sep 17 00:00:00 2001 From: keithamus Date: Thu, 17 Oct 2024 15:38:42 +0000 Subject: [PATCH] Guard dialog toggle events from remove/showmodal Differential Revision: https://phabricator.services.mozilla.com/D225949 bugzilla-url: https://bugzilla.mozilla.org/show_bug.cgi?id=1925252 gecko-commit: fe15a02a83f2dec2a89cc294523ea2a250ea1985 gecko-reviewers: smaug --- .../toggle-events.tentative.html | 77 ++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/html/semantics/interactive-elements/the-dialog-element/toggle-events.tentative.html b/html/semantics/interactive-elements/the-dialog-element/toggle-events.tentative.html index e8c5fb1b4cfe70..555dc03b019e62 100644 --- a/html/semantics/interactive-elements/the-dialog-element/toggle-events.tentative.html +++ b/html/semantics/interactive-elements/the-dialog-element/toggle-events.tentative.html @@ -1,6 +1,6 @@ - + @@ -288,5 +288,80 @@ mo.takeRecords(); assert_equals(attributeChanges, 1, "Should have removed open once"); }, `dialog.${methodName}() should not double-set open/close if beforetoggle re-opens`); + + promise_test(async (t) => { + const abortController = new AbortController(); + const signal = abortController.signal; + const mydialog = document.getElementById("mydialog"); + t.add_cleanup(() => { + abortController.abort(); + mydialog.close(); + document.body.prepend(mydialog); + }); + mydialog.addEventListener("beforetoggle", () => { + mydialog.remove(); + }, { once: true }); + let toggleEventCounter = 0; + mydialog.addEventListener( + "toggle", + (event) => { + toggleEventCounter += 1; + }, + { signal } + ); + + mydialog[methodName](); + assert_false(mydialog.isConnected, "Dialog is not connected"); + if (methodName == 'show') { + assert_true(mydialog.open, "Dialog did open"); + } else { + assert_false(mydialog.open, "Dialog did not open"); + assert_false(mydialog.matches(':modal'), "Dialog is not modal"); + } + await waitForTick(); + if (methodName == 'show') { + assert_equals(toggleEventCounter, 1, "toggle event was fired"); + } else { + assert_equals(toggleEventCounter, 0, "toggle event not fired"); + } + }, `dialog.${methodName}() should not open if beforetoggle removes`); + + promise_test(async (t) => { + const abortController = new AbortController(); + const signal = abortController.signal; + t.add_cleanup(async () => { + try { mydialog.hidePopover(); } catch {} + try { mydialog.close(); } catch {} + mydialog.removeAttribute('popover'); + abortController.abort(); + await waitForTick(); + }); + mydialog.setAttribute('popover', ''); + mydialog.addEventListener("beforetoggle", () => { + mydialog.showPopover(); + }, { once: true }); + let toggleEventCounter = 0; + mydialog.addEventListener( + "toggle", + (event) => { + toggleEventCounter += 1; + }, + { signal } + ); + + mydialog[methodName](); + if (methodName == 'show') { + assert_true(mydialog.open, "Dialog did open"); + } else { + assert_false(mydialog.open, "Dialog did not open"); + assert_false(mydialog.matches(':modal'), "Dialog is not modal"); + } + await waitForTick(); + if (methodName == 'show') { + assert_equals(toggleEventCounter, 2, "toggle event was fired for show+showPopover"); + } else { + assert_equals(toggleEventCounter, 1, "toggle event was fired for showPopover"); + } + }, `dialog.${methodName}() should not open if beforetoggle calls showPopover`); });