diff --git a/toolkit/mozapps/handling/ContentDispatchChooser.sys.mjs b/toolkit/mozapps/handling/ContentDispatchChooser.sys.mjs index 8228826dfb29..e916fdad4c4c 100644 --- a/toolkit/mozapps/handling/ContentDispatchChooser.sys.mjs +++ b/toolkit/mozapps/handling/ContentDispatchChooser.sys.mjs @@ -321,7 +321,8 @@ export class nsContentDispatchChooser { /** * Opens a dialog as a SubDialog on tab level. - * If we don't have a BrowsingContext we will fallback to a standalone window. + * If we don't have a BrowsingContext or tab level dialogs are not supported, + * we will fallback to a standalone window. * @param {string} aDialogURL - URL of the dialog to open. * @param {Object} aDialogArgs - Arguments passed to the dialog. * @param {BrowsingContext} [aBrowsingContext] - BrowsingContext associated @@ -348,16 +349,20 @@ export class nsContentDispatchChooser { ); } - let tabDialogBox = window.gBrowser.getTabDialogBox(topFrameElement); - return tabDialogBox.open( - aDialogURL, - { - features: resizable, - allowDuplicateDialogs: false, - keepOpenSameOriginNav: true, - }, - aDialogArgs - ).closedPromise; + // If the app does not support window.gBrowser or getTabDialogBox(), + // fallback to the standalone application chooser window. + let getTabDialogBox = window.gBrowser?.getTabDialogBox; + if (getTabDialogBox) { + return getTabDialogBox(topFrameElement).open( + aDialogURL, + { + features: resizable, + allowDuplicateDialogs: false, + keepOpenSameOriginNav: true, + }, + aDialogArgs + ).closedPromise; + } } // If we don't have a BrowsingContext, we need to show a standalone window. diff --git a/uriloader/exthandler/tests/mochitest/browser.toml b/uriloader/exthandler/tests/mochitest/browser.toml index 5c034060174a..2eaf6632ac83 100644 --- a/uriloader/exthandler/tests/mochitest/browser.toml +++ b/uriloader/exthandler/tests/mochitest/browser.toml @@ -145,6 +145,12 @@ support-files = [ "file_txt_attachment_test.txt^headers^", ] +["browser_standalone_application_chooser_window_fallback.js"] +support-files = [ + "FTPprotocolHandler.html", + "blank.html", +] + ["browser_txt_download_save_as.js"] support-files = [ "file_txt_attachment_test.txt", diff --git a/uriloader/exthandler/tests/mochitest/browser_standalone_application_chooser_window_fallback.js b/uriloader/exthandler/tests/mochitest/browser_standalone_application_chooser_window_fallback.js new file mode 100644 index 000000000000..40496fb3b2cf --- /dev/null +++ b/uriloader/exthandler/tests/mochitest/browser_standalone_application_chooser_window_fallback.js @@ -0,0 +1,67 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test the fallback fixed in bug 1875460, if the modern tab dialog box is not +// supported. + +const TEST_URL = + "https://example.com/browser/" + + "uriloader/exthandler/tests/mochitest/FTPprotocolHandler.html"; + +add_task(async function () { + await SpecialPowers.pushPrefEnv({ + set: [["security.external_protocol_requires_permission", false]], + }); + + // Load a page with an FTP link. + let browser = gBrowser.selectedBrowser; + BrowserTestUtils.startLoadingURIString(browser, TEST_URL); + await BrowserTestUtils.browserLoaded(browser, false, TEST_URL); + + // Make sure no handler is set, forcing the dialog to show. + let protoSvc = Cc[ + "@mozilla.org/uriloader/external-protocol-service;1" + ].getService(Ci.nsIExternalProtocolService); + let protoInfo = protoSvc.getProtocolHandlerInfo("ftp"); + ok(!protoInfo.preferredApplicationHandler, "no preferred handler is set"); + let handlers = protoInfo.possibleApplicationHandlers; + is(0, handlers.length, "no handler registered for ftp"); + protoInfo.alwaysAskBeforeHandling = true; + let handlerSvc = Cc["@mozilla.org/uriloader/handler-service;1"].getService( + Ci.nsIHandlerService + ); + handlerSvc.store(protoInfo); + + // Delete getTabDialogBox from gBrowser, to test the fallback to the standalone + // application chooser window. + let _getTabDialogBox = gBrowser.getTabDialogBox; + delete gBrowser.getTabDialogBox; + + let appChooserDialogOpenPromise = BrowserTestUtils.domWindowOpened( + null, + async win => { + await BrowserTestUtils.waitForEvent(win, "load"); + Assert.ok( + win.document.documentURI == + "chrome://mozapps/content/handling/appChooser.xhtml", + "application chooser dialog opened" + ); + return true; + } + ); + let link = "#link"; + await BrowserTestUtils.synthesizeMouseAtCenter(link, {}, browser); + let appChooserDialog = await appChooserDialogOpenPromise; + + let appChooserDialogClosePromise = + BrowserTestUtils.domWindowClosed(appChooserDialog); + let dialog = appChooserDialog.document.getElementsByTagName("dialog")[0]; + let cancelButton = dialog.getButton("cancel"); + cancelButton.click(); + await appChooserDialogClosePromise; + + // Restore the original getTabDialogBox(), to not affect other tests. + gBrowser.getTabDialogBox = _getTabDialogBox; +});