/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ const lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { SelectableProfileService: "resource:///modules/profiles/SelectableProfileService.sys.mjs", }); /** * Implements nsIPromptCollection * * @class PromptCollection */ export class PromptCollection { confirmRepost(browsingContext) { let brandName; try { brandName = this.stringBundles.brand.GetStringFromName("brandShortName"); } catch (exception) { // That's ok, we'll use a generic version of the prompt } let message; let resendLabel; try { if (brandName) { message = this.stringBundles.app.formatStringFromName( "confirmRepostPrompt", [brandName] ); } else { // Use a generic version of this prompt. message = this.stringBundles.app.GetStringFromName( "confirmRepostPrompt" ); } resendLabel = this.stringBundles.app.GetStringFromName("resendButton.label"); } catch (exception) { console.error("Failed to get strings from appstrings.properties"); return false; } let docViewer = browsingContext?.docShell?.docViewer; let modalType = docViewer?.isTabModalPromptAllowed ? Ci.nsIPromptService.MODAL_TYPE_CONTENT : Ci.nsIPromptService.MODAL_TYPE_WINDOW; let buttonFlags = (Ci.nsIPromptService.BUTTON_TITLE_IS_STRING * Ci.nsIPromptService.BUTTON_POS_0) | (Ci.nsIPromptService.BUTTON_TITLE_CANCEL * Ci.nsIPromptService.BUTTON_POS_1); let buttonPressed = Services.prompt.confirmExBC( browsingContext, modalType, null, message, buttonFlags, resendLabel, null, null, null, {} ); return buttonPressed === 0; } async asyncBeforeUnloadCheck(browsingContext) { const docViewer = browsingContext?.docShell?.docViewer; if ( (docViewer && !docViewer.isTabModalPromptAllowed) || !browsingContext.ancestorsAreCurrent ) { console.error("Can't prompt from inactive content viewer"); return true; } let originNoSuffix = browsingContext.embedderElement?.contentPrincipal.originNoSuffix; const isPDFjs = originNoSuffix === "resource://pdf.js"; const isProfilePage = originNoSuffix === "about:newprofile" || originNoSuffix === "about:editprofile"; let title, message, leaveLabel, stayLabel, buttonFlags; let args = { // Tell the prompt service that this is a permit unload prompt // so that it can set the appropriate flag on the detail object // of the events it dispatches. inPermitUnload: true, }; try { if (isPDFjs) { title = this.stringBundles.dom.GetStringFromName( "OnBeforeUnloadPDFjsTitle" ); message = this.stringBundles.dom.GetStringFromName( "OnBeforeUnloadPDFjsMessage" ); buttonFlags = Ci.nsIPromptService.BUTTON_POS_0_DEFAULT | (Ci.nsIPrompt.BUTTON_TITLE_SAVE * Ci.nsIPrompt.BUTTON_POS_0) | (Ci.nsIPrompt.BUTTON_TITLE_CANCEL * Ci.nsIPrompt.BUTTON_POS_1) | (Ci.nsIPrompt.BUTTON_TITLE_DONT_SAVE * Ci.nsIPrompt.BUTTON_POS_2); args.useTitle = true; args.headerIconCSSValue = "url('chrome://branding/content/document_pdf.svg')"; } else if (isProfilePage) { title = this.stringBundles.dom.GetStringFromName( "OnBeforeUnloadAboutNewProfileTitle" ); let defaultName = lazy.SelectableProfileService.currentProfile.name; message = this.stringBundles.dom.formatStringFromName( "OnBeforeUnloadAboutNewProfileMessage", [defaultName] ); leaveLabel = this.stringBundles.dom.GetStringFromName( "OnBeforeUnloadAboutNewProfileLeaveButton" ); stayLabel = this.stringBundles.dom.GetStringFromName( "OnBeforeUnloadAboutNewProfileStayButton" ); buttonFlags = Ci.nsIPromptService.BUTTON_POS_0_DEFAULT | (Ci.nsIPromptService.BUTTON_TITLE_IS_STRING * Ci.nsIPromptService.BUTTON_POS_0) | (Ci.nsIPromptService.BUTTON_TITLE_IS_STRING * Ci.nsIPromptService.BUTTON_POS_1); args.useTitle = true; } else { title = this.stringBundles.dom.GetStringFromName("OnBeforeUnloadTitle"); message = this.stringBundles.dom.GetStringFromName( "OnBeforeUnloadMessage2" ); leaveLabel = this.stringBundles.dom.GetStringFromName( "OnBeforeUnloadLeaveButton" ); stayLabel = this.stringBundles.dom.GetStringFromName( "OnBeforeUnloadStayButton" ); buttonFlags = Ci.nsIPromptService.BUTTON_POS_0_DEFAULT | (Ci.nsIPromptService.BUTTON_TITLE_IS_STRING * Ci.nsIPromptService.BUTTON_POS_0) | (Ci.nsIPromptService.BUTTON_TITLE_IS_STRING * Ci.nsIPromptService.BUTTON_POS_1); } } catch (exception) { console.error("Failed to get strings from dom.properties"); return false; } const result = await Services.prompt.asyncConfirmEx( browsingContext, Services.prompt.MODAL_TYPE_CONTENT, title, message, buttonFlags, leaveLabel, stayLabel, null, null, false, args ); const buttonNumClicked = result .QueryInterface(Ci.nsIPropertyBag2) .get("buttonNumClicked"); if (isPDFjs) { if (buttonNumClicked === 0) { const savePdfPromise = new Promise(resolve => { Services.obs.addObserver( { observe(_aSubject, aTopic) { if (aTopic === "pdfjs:saveComplete") { Services.obs.removeObserver(this, aTopic); resolve(); } }, }, "pdfjs:saveComplete" ); }); const actor = browsingContext.currentWindowGlobal.getActor("Pdfjs"); actor.sendAsyncMessage("PDFJS:Save"); await savePdfPromise; } return buttonNumClicked !== 1; } else if (isProfilePage) { if (buttonNumClicked === 0) { Services.prefs.setBoolPref( "browser.profiles.profile-name.updated", true ); } let gleanFn = originNoSuffix === "about:newprofile" ? "profilesNew" : "profilesExisting"; let value = buttonNumClicked === 0 ? "leave" : "cancel"; Glean[gleanFn].alert.record({ value }); return buttonNumClicked !== 1; } return buttonNumClicked === 0; } confirmFolderUpload(browsingContext, directoryName) { let title; let message; let acceptLabel; try { title = this.stringBundles.dom.GetStringFromName( "FolderUploadPrompt.title" ); message = this.stringBundles.dom.formatStringFromName( "FolderUploadPrompt.message", [directoryName] ); acceptLabel = this.stringBundles.dom.GetStringFromName( "FolderUploadPrompt.acceptButtonLabel" ); } catch (exception) { console.error("Failed to get strings from dom.properties"); return false; } let buttonFlags = Services.prompt.BUTTON_TITLE_IS_STRING * Services.prompt.BUTTON_POS_0 + Services.prompt.BUTTON_TITLE_CANCEL * Services.prompt.BUTTON_POS_1 + Services.prompt.BUTTON_POS_1_DEFAULT; return ( Services.prompt.confirmExBC( browsingContext, Services.prompt.MODAL_TYPE_TAB, title, message, buttonFlags | Ci.nsIPrompt.BUTTON_DELAY_ENABLE, acceptLabel, null, null, null, {} ) === 0 ); } } const BUNDLES = { dom: "chrome://global/locale/dom/dom.properties", app: "chrome://global/locale/appstrings.properties", brand: "chrome://branding/locale/brand.properties", }; PromptCollection.prototype.stringBundles = {}; for (const [bundleName, bundleUrl] of Object.entries(BUNDLES)) { ChromeUtils.defineLazyGetter( PromptCollection.prototype.stringBundles, bundleName, function () { let bundle = Services.strings.createBundle(bundleUrl); if (!bundle) { throw new Error("String bundle for dom not present!"); } return bundle; } ); } PromptCollection.prototype.QueryInterface = ChromeUtils.generateQI([ "nsIPromptCollection", ]);