diff options
Diffstat (limited to 'toolkit/components/printing/content/printUtils.js')
-rw-r--r-- | toolkit/components/printing/content/printUtils.js | 822 |
1 files changed, 822 insertions, 0 deletions
diff --git a/toolkit/components/printing/content/printUtils.js b/toolkit/components/printing/content/printUtils.js new file mode 100644 index 0000000000..f1e3489fe7 --- /dev/null +++ b/toolkit/components/printing/content/printUtils.js @@ -0,0 +1,822 @@ +// This file is loaded into the browser window scope. +/* eslint-env mozilla/browser-window */ + +// -*- tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2 -*- + +/* 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/. */ + +/** + * PrintUtils is a utility for front-end code to trigger common print + * operations (printing, show print preview, show page settings). + * + * Unfortunately, likely due to inconsistencies in how different operating + * systems do printing natively, our XPCOM-level printing interfaces + * are a bit confusing and the method by which we do something basic + * like printing a page is quite circuitous. + * + * To compound that, we need to support remote browsers, and that means + * kicking off the print jobs in the content process. This means we send + * messages back and forth to that process via the Printing actor. + * + * This also means that <xul:browser>'s that hope to use PrintUtils must have + * their type attribute set to "content". + * + * Messages sent: + * + * Printing:Preview:Enter + * This message is sent to put content into print preview mode. We pass + * the content window of the browser we're showing the preview of, and + * the target of the message is the browser that we'll be showing the + * preview in. + * + * Printing:Preview:Exit + * This message is sent to take content out of print preview mode. + */ + +XPCOMUtils.defineLazyPreferenceGetter( + this, + "SHOW_PAGE_SETUP_MENU", + "print.show_page_setup_menu", + false +); + +XPCOMUtils.defineLazyPreferenceGetter( + this, + "PRINT_ALWAYS_SILENT", + "print.always_print_silent", + false +); + +XPCOMUtils.defineLazyPreferenceGetter( + this, + "PREFER_SYSTEM_DIALOG", + "print.prefer_system_dialog", + false +); + +ChromeUtils.defineESModuleGetters(this, { + PromptUtils: "resource://gre/modules/PromptUtils.sys.mjs", +}); + +var PrintUtils = { + SAVE_TO_PDF_PRINTER: "Mozilla Save to PDF", + + get _bundle() { + delete this._bundle; + return (this._bundle = Services.strings.createBundle( + "chrome://global/locale/printing.properties" + )); + }, + + async checkForSelection(browsingContext) { + try { + let sourceActor = + browsingContext.currentWindowGlobal.getActor("PrintingSelection"); + // Need the await for the try to trigger... + return await sourceActor.sendQuery("PrintingSelection:HasSelection", {}); + } catch (e) { + console.error(e); + } + return false; + }, + + /** + * Updates the hidden state of the "Page Setup" menu items in the File menu, + * depending on the value of the `print.show_page_setup_menu` pref. + * Note: not all platforms have a "Page Setup" menu item (or Page Setup + * window). + */ + updatePrintSetupMenuHiddenState() { + let pageSetupMenuItem = document.getElementById("menu_printSetup"); + if (pageSetupMenuItem) { + pageSetupMenuItem.hidden = !SHOW_PAGE_SETUP_MENU; + } + }, + + /** + * Shows the page setup dialog, and saves any settings changed in + * that dialog if print.save_print_settings is set to true. + * + * @return true on success, false on failure + */ + showPageSetup() { + let printSettings = this.getPrintSettings(); + // If we come directly from the Page Setup menu, the hack in + // _enterPrintPreview will not have been invoked to set the last used + // printer name. For the reasons outlined at that hack, we want that set + // here too. + let PSSVC = Cc["@mozilla.org/gfx/printsettings-service;1"].getService( + Ci.nsIPrintSettingsService + ); + if (!PSSVC.lastUsedPrinterName) { + if (printSettings.printerName) { + PSSVC.maybeSaveLastUsedPrinterNameToPrefs(printSettings.printerName); + PSSVC.maybeSavePrintSettingsToPrefs( + printSettings, + Ci.nsIPrintSettings.kInitSaveAll + ); + } + } + try { + var PRINTDIALOGSVC = Cc[ + "@mozilla.org/widget/printdialog-service;1" + ].getService(Ci.nsIPrintDialogService); + PRINTDIALOGSVC.showPageSetupDialog(window, printSettings, null); + } catch (e) { + dump("showPageSetup " + e + "\n"); + return false; + } + return true; + }, + + /** + * This call exists in a separate method so it can be easily overridden where + * `gBrowser` doesn't exist (e.g. Thunderbird). + * + * @see getTabDialogBox in tabbrowser.js + */ + getTabDialogBox(sourceBrowser) { + return gBrowser.getTabDialogBox(sourceBrowser); + }, + + getPreviewBrowser(sourceBrowser) { + let dialogBox = this.getTabDialogBox(sourceBrowser); + for (let dialog of dialogBox.getTabDialogManager()._dialogs) { + let browser = dialog._box.querySelector(".printPreviewBrowser"); + if (browser) { + return browser; + } + } + return null; + }, + + /** + * Opens the tab modal version of the print UI for the current tab. + * + * @param aBrowsingContext + * The BrowsingContext of the window to print. + * @param aExistingPreviewBrowser + * An existing browser created for printing from window.print(). + * @param aPrintInitiationTime + * The time the print was initiated (typically by the user) as obtained + * from `Date.now()`. That is, the initiation time as the number of + * milliseconds since January 1, 1970. + * @param aPrintSelectionOnly + * Whether to print only the active selection of the given browsing + * context. + * @param aPrintFrameOnly + * Whether to print the selected frame only + * @return promise resolving when the dialog is open, rejected if the preview + * fails. + */ + _openTabModalPrint( + aBrowsingContext, + aOpenWindowInfo, + aPrintInitiationTime, + aPrintSelectionOnly, + aPrintFrameOnly + ) { + let sourceBrowser = aBrowsingContext.top.embedderElement; + let previewBrowser = this.getPreviewBrowser(sourceBrowser); + if (previewBrowser) { + // Don't open another dialog if we're already printing. + // + // XXX This can be racy can't it? getPreviewBrowser looks at browser that + // we set up after opening the dialog. But I guess worst case we just + // open two dialogs so... + throw new Error("Tab-modal print UI already open"); + } + + // Create the print preview dialog. + let args = PromptUtils.objectToPropBag({ + printSelectionOnly: !!aPrintSelectionOnly, + isArticle: sourceBrowser.isArticle, + printFrameOnly: !!aPrintFrameOnly, + }); + let dialogBox = this.getTabDialogBox(sourceBrowser); + let { closedPromise, dialog } = dialogBox.open( + `chrome://global/content/print.html?printInitiationTime=${aPrintInitiationTime}`, + { features: "resizable=no", sizeTo: "available" }, + args + ); + closedPromise.catch(e => { + console.error(e); + }); + + let settingsBrowser = dialog._frame; + let printPreview = new PrintPreview({ + sourceBrowsingContext: aBrowsingContext, + settingsBrowser, + topBrowsingContext: aBrowsingContext.top, + activeBrowsingContext: aBrowsingContext, + openWindowInfo: aOpenWindowInfo, + printFrameOnly: aPrintFrameOnly, + }); + // This will create the source browser in connectedCallback() if we sent + // openWindowInfo. Otherwise the browser will be null. + settingsBrowser.parentElement.insertBefore(printPreview, settingsBrowser); + return printPreview.sourceBrowser; + }, + + /** + * Initialize a print, this will open the tab modal UI if it is enabled or + * defer to the native dialog/silent print. + * + * @param aBrowsingContext + * The BrowsingContext of the window to print. + * Note that the browsing context could belong to a subframe of the + * tab that called window.print, or similar shenanigans. + * @param aOptions + * {windowDotPrintOpenWindowInfo} + * Non-null if this call comes from window.print(). + * This is the nsIOpenWindowInfo object that has to + * be passed down to createBrowser in order for the + * static clone that has been cretaed in the child + * process to be linked to the browser it creates + * in the parent process. + * {printSelectionOnly} Whether to print only the active selection of + * the given browsing context. + * {printFrameOnly} Whether to print the selected frame. + */ + startPrintWindow(aBrowsingContext, aOptions) { + const printInitiationTime = Date.now(); + + // At most, one of these is set. + let { printSelectionOnly, printFrameOnly, windowDotPrintOpenWindowInfo } = + aOptions || {}; + + if ( + windowDotPrintOpenWindowInfo && + !windowDotPrintOpenWindowInfo.isForWindowDotPrint + ) { + throw new Error("Only expect openWindowInfo for window.print()"); + } + + let browsingContext = aBrowsingContext; + if (printSelectionOnly) { + // Ensure that we use the window with focus/selection if the context menu + // (from which 'Print selection' was selected) happens to have been opened + // over a different frame. + let focusedBc = Services.focus.focusedContentBrowsingContext; + if ( + focusedBc && + focusedBc.top.embedderElement == browsingContext.top.embedderElement + ) { + browsingContext = focusedBc; + } + } + + if (!PRINT_ALWAYS_SILENT && !PREFER_SYSTEM_DIALOG) { + return this._openTabModalPrint( + browsingContext, + windowDotPrintOpenWindowInfo, + printInitiationTime, + printSelectionOnly, + printFrameOnly + ); + } + + const useSystemDialog = PREFER_SYSTEM_DIALOG && !PRINT_ALWAYS_SILENT; + + let browser = null; + if (windowDotPrintOpenWindowInfo) { + // When we're called by handleStaticCloneCreatedForPrint(), we must + // return this browser. + browser = this.createParentBrowserForStaticClone( + browsingContext, + windowDotPrintOpenWindowInfo + ); + browsingContext = browser.browsingContext; + } + + // This code is wrapped in an async function so that we can await the async + // functions that it calls. + async function makePrintSettingsAndInvokePrint() { + let settings = PrintUtils.getPrintSettings( + /*aPrinterName*/ "", + /*aDefaultsOnly*/ false, + /*aAllowPseudoPrinter*/ !useSystemDialog + ); + settings.printSelectionOnly = printSelectionOnly; + if ( + settings.outputDestination == + Ci.nsIPrintSettings.kOutputDestinationFile && + !settings.toFileName + ) { + // TODO(bug 1748004): We should consider generating the file name + // from the document's title as we do in print.js's pickFileName + // (including using DownloadPaths.sanitize!). + // For now, the following is for consistency with the behavior + // prior to bug 1669149 part 3. + let dest = undefined; + try { + dest = Services.dirsvc.get("CurWorkD", Ci.nsIFile).path; + } catch (e) {} + if (!dest) { + dest = Services.dirsvc.get("Home", Ci.nsIFile).path; + } + settings.toFileName = PathUtils.join(dest, "mozilla.pdf"); + } + + if (useSystemDialog) { + const hasSelection = await PrintUtils.checkForSelection( + browsingContext + ); + + // Prompt the user to choose a printer and make any desired print + // settings changes. + let doPrint = false; + try { + doPrint = await PrintUtils.handleSystemPrintDialog( + browsingContext.topChromeWindow, + hasSelection, + settings + ); + if (!doPrint) { + return; + } + } finally { + // Clean up browser if we aren't going to use it. + if (!doPrint && browser) { + browser.remove(); + } + } + } + + // At some point we should handle the Promise that this returns (at + // least report rejection to telemetry). + browsingContext.print(settings); + } + + // We need to return to the event loop before calling + // makePrintSettingsAndInvokePrint() if we were called for `window.print()`. + // That's because if that function synchronously calls `browser.remove()` + // or `browsingContext.print()` before we return `browser`, the nested + // event loop that is being spun in the content process under the + // OpenInternal call in nsGlobalWindowOuter::Print will still be active. + // In the case of `browser.remove()`, nsGlobalWindowOuter::Print would then + // get unhappy once OpenInternal does return since it will fail to return + // a BrowsingContext. In the case of `browsingContext.print()`, we would + // re-enter nsGlobalWindowOuter::Print under the nested event loop and + // printing would then fail since the outer nsGlobalWindowOuter::Print call + // wouldn't yet have created the static clone. + setTimeout(makePrintSettingsAndInvokePrint, 0); + + return browser; + }, + + togglePrintPreview(aBrowsingContext) { + let dialogBox = this.getTabDialogBox(aBrowsingContext.top.embedderElement); + let dialogs = dialogBox.getTabDialogManager().dialogs; + let previewDialog = dialogs.find(d => + d._box.querySelector(".printSettingsBrowser") + ); + if (previewDialog) { + previewDialog.close(); + return; + } + this.startPrintWindow(aBrowsingContext); + }, + + /** + * Called when a content process has created a new BrowsingContext for a + * static clone of a document that is to be printed, but we do NOT yet have a + * CanonicalBrowsingContext counterpart in the parent process. This only + * happens in the following cases: + * + * - content script invoked window.print() in the content process, or: + * - silent printing is enabled, and UI code previously invoked + * startPrintWindow which called BrowsingContext.print(), and we're now + * being called back by the content process to parent the static clone. + * + * In the latter case we only need to create the CanonicalBrowsingContext, + * link it to it's content process counterpart, and inserted it into + * the document tree; the print in the content process has already been + * initiated. + * + * In the former case we additionally need to check if we should open the + * tab modal print UI (if not silent printing), obtain a valid + * nsIPrintSettings object, and tell the content process to initiate the + * print with this settings object. + */ + handleStaticCloneCreatedForPrint(aOpenWindowInfo) { + let browsingContext = aOpenWindowInfo.parent; + if (aOpenWindowInfo.isForWindowDotPrint) { + return this.startPrintWindow(browsingContext, { + windowDotPrintOpenWindowInfo: aOpenWindowInfo, + }); + } + return this.createParentBrowserForStaticClone( + browsingContext, + aOpenWindowInfo + ); + }, + + createParentBrowserForStaticClone(aBrowsingContext, aOpenWindowInfo) { + // XXX This code is only called when silent printing, so we're really + // abusing PrintPreview here. See bug 1768020. + let printPreview = new PrintPreview({ + sourceBrowsingContext: aBrowsingContext, + openWindowInfo: aOpenWindowInfo, + }); + let browser = printPreview.createPreviewBrowser("source"); + document.documentElement.append(browser); + return browser; + }, + + // "private" methods and members. Don't use them. + + _getErrorCodeForNSResult(nsresult) { + const MSG_CODES = [ + "GFX_PRINTER_NO_PRINTER_AVAILABLE", + "GFX_PRINTER_NAME_NOT_FOUND", + "GFX_PRINTER_COULD_NOT_OPEN_FILE", + "GFX_PRINTER_STARTDOC", + "GFX_PRINTER_ENDDOC", + "GFX_PRINTER_STARTPAGE", + "GFX_PRINTER_DOC_IS_BUSY", + "ABORT", + "NOT_AVAILABLE", + "NOT_IMPLEMENTED", + "OUT_OF_MEMORY", + "UNEXPECTED", + ]; + + for (let code of MSG_CODES) { + let nsErrorResult = "NS_ERROR_" + code; + if (Cr[nsErrorResult] == nsresult) { + return code; + } + } + + // PERR_FAILURE is the catch-all error message if we've gotten one that + // we don't recognize. + return "FAILURE"; + }, + + _displayPrintingError(nsresult, isPrinting, browser) { + // The nsresults from a printing error are mapped to strings that have + // similar names to the errors themselves. For example, for error + // NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE, the name of the string + // for the error message is: PERR_GFX_PRINTER_NO_PRINTER_AVAILABLE. What's + // more, if we're in the process of doing a print preview, it's possible + // that there are strings specific for print preview for these errors - + // if so, the names of those strings have _PP as a suffix. It's possible + // that no print preview specific strings exist, in which case it is fine + // to fall back to the original string name. + let msgName = "PERR_" + this._getErrorCodeForNSResult(nsresult); + let msg, title; + if (!isPrinting) { + // Try first with _PP suffix. + let ppMsgName = msgName + "_PP"; + try { + msg = this._bundle.GetStringFromName(ppMsgName); + } catch (e) { + // We allow localizers to not have the print preview error string, + // and just fall back to the printing error string. + } + } + + if (!msg) { + msg = this._bundle.GetStringFromName(msgName); + } + + title = this._bundle.GetStringFromName( + isPrinting + ? "print_error_dialog_title" + : "printpreview_error_dialog_title" + ); + + Services.prompt.asyncAlert( + browser.browsingContext, + Services.prompt.MODAL_TYPE_TAB, + title, + msg + ); + + Services.telemetry.keyedScalarAdd( + "printing.error", + this._getErrorCodeForNSResult(nsresult), + 1 + ); + }, + + getPrintSettings(aPrinterName, aDefaultsOnly, aAllowPseudoPrinter = true) { + var printSettings; + try { + var PSSVC = Cc["@mozilla.org/gfx/printsettings-service;1"].getService( + Ci.nsIPrintSettingsService + ); + + function isValidPrinterName(aPrinterName) { + return ( + aPrinterName && + (aAllowPseudoPrinter || + aPrinterName != PrintUtils.SAVE_TO_PDF_PRINTER) + ); + } + + // We must not try to print using an nsIPrintSettings without a printer + // name set. + const printerName = (function () { + if (isValidPrinterName(aPrinterName)) { + return aPrinterName; + } + if (isValidPrinterName(PSSVC.lastUsedPrinterName)) { + return PSSVC.lastUsedPrinterName; + } + return Cc["@mozilla.org/gfx/printerlist;1"].getService( + Ci.nsIPrinterList + ).systemDefaultPrinterName; + })(); + + printSettings = PSSVC.createNewPrintSettings(); + printSettings.printerName = printerName; + + // First get any defaults from the printer. We want to skip this for Save + // to PDF since it isn't a real printer and will throw. + if (printSettings.printerName != this.SAVE_TO_PDF_PRINTER) { + PSSVC.initPrintSettingsFromPrinter( + printSettings.printerName, + printSettings + ); + } + + if (!aDefaultsOnly) { + // Apply any settings that have been saved for this printer. + PSSVC.initPrintSettingsFromPrefs( + printSettings, + true, + printSettings.kInitSaveAll + ); + } + } catch (e) { + console.error("PrintUtils.getPrintSettings failed: ", e, "\n"); + } + return printSettings; + }, + + // Show the system print dialog, saving modified preferences. + // Returns true if the user clicked print (Not cancel). + async handleSystemPrintDialog(aWindow, aHasSelection, aSettings) { + // Prompt the user to choose a printer and make any desired print + // settings changes. + try { + const svc = Cc["@mozilla.org/widget/printdialog-service;1"].getService( + Ci.nsIPrintDialogService + ); + await svc.showPrintDialog(aWindow, aHasSelection, aSettings); + } catch (e) { + if (e.result == Cr.NS_ERROR_ABORT) { + return false; + } + throw e; + } + + // Update the saved last used printer name and print settings: + var PSSVC = Cc["@mozilla.org/gfx/printsettings-service;1"].getService( + Ci.nsIPrintSettingsService + ); + PSSVC.maybeSaveLastUsedPrinterNameToPrefs(aSettings.printerName); + PSSVC.maybeSavePrintSettingsToPrefs( + aSettings, + Ci.nsIPrintSettings.kPrintDialogPersistSettings + ); + return true; + }, +}; + +class PrintPreview extends MozElements.BaseControl { + constructor({ + sourceBrowsingContext, + settingsBrowser, + topBrowsingContext, + activeBrowsingContext, + openWindowInfo, + printFrameOnly, + }) { + super(); + this.sourceBrowsingContext = sourceBrowsingContext; + this.settingsBrowser = settingsBrowser; + this.topBrowsingContext = topBrowsingContext; + this.activeBrowsingContext = activeBrowsingContext; + this.openWindowInfo = openWindowInfo; + this.printFrameOnly = printFrameOnly; + + this.printSelectionOnly = false; + this.simplifyPage = false; + this.sourceBrowser = null; + this.selectionBrowser = null; + this.simplifiedBrowser = null; + this.lastPreviewBrowser = null; + } + + connectedCallback() { + if (this.childElementCount > 0) { + return; + } + this.setAttribute("flex", "1"); + this.append( + MozXULElement.parseXULToFragment(` + <stack class="previewStack" rendering="true" flex="1" previewtype="primary"> + <vbox class="previewRendering" flex="1"> + <h1 class="print-pending-label" data-l10n-id="printui-loading"></h1> + </vbox> + <html:printpreview-pagination class="printPreviewNavigation"></html:printpreview-pagination> + </stack> + `) + ); + this.stack = this.firstElementChild; + this.paginator = this.querySelector("printpreview-pagination"); + + if (this.openWindowInfo) { + // For window.print() we need a browser right away for the contents to be + // cloned into, create it now. + this.createPreviewBrowser("source"); + } + } + + disconnectedCallback() { + this.exitPrintPreview(); + } + + getSourceBrowsingContext() { + if (this.openWindowInfo) { + // If openWindowInfo is set this was for window.print() and the source + // contents have already been cloned into the preview browser. + return this.sourceBrowser.browsingContext; + } + return this.sourceBrowsingContext; + } + + get currentBrowsingContext() { + return this.lastPreviewBrowser.browsingContext; + } + + exitPrintPreview() { + this.sourceBrowser?.frameLoader?.exitPrintPreview(); + this.simplifiedBrowser?.frameLoader?.exitPrintPreview(); + this.selectionBrowser?.frameLoader?.exitPrintPreview(); + + this.textContent = ""; + } + + async printPreview(settings, { sourceVersion, sourceURI }) { + this.stack.setAttribute("rendering", true); + + let result = await this._printPreview(settings, { + sourceVersion, + sourceURI, + }); + + let browser = this.lastPreviewBrowser; + this.stack.setAttribute("previewtype", browser.getAttribute("previewtype")); + browser.setAttribute("sheet-count", result.sheetCount); + // The view resets to the top of the document on update bug 1686737. + browser.setAttribute("current-page", 1); + this.paginator.observePreviewBrowser(browser); + await document.l10n.translateElements([browser]); + + this.stack.removeAttribute("rendering"); + + return result; + } + + async _printPreview(settings, { sourceVersion, sourceURI }) { + let printSelectionOnly = sourceVersion == "selection"; + let simplifyPage = sourceVersion == "simplified"; + let selectionTypeBrowser; + let previewBrowser; + + // Select the existing preview browser elements, these could be null. + if (printSelectionOnly) { + selectionTypeBrowser = this.selectionBrowser; + previewBrowser = this.selectionBrowser; + } else { + selectionTypeBrowser = this.sourceBrowser; + previewBrowser = simplifyPage + ? this.simplifiedBrowser + : this.sourceBrowser; + } + + settings.docURL = sourceURI; + + if (previewBrowser) { + this.lastPreviewBrowser = previewBrowser; + if (this.openWindowInfo) { + // We only want to use openWindowInfo for the window.print() browser, + // we can get rid of it now. + this.openWindowInfo = null; + } + // This browser has been rendered already, just update it. + return previewBrowser.frameLoader.printPreview(settings, null); + } + + if (!selectionTypeBrowser) { + // Need to create a non-simplified browser. + selectionTypeBrowser = this.createPreviewBrowser( + simplifyPage ? "source" : sourceVersion + ); + let browsingContext = + printSelectionOnly || this.printFrameOnly + ? this.activeBrowsingContext + : this.topBrowsingContext; + let result = await selectionTypeBrowser.frameLoader.printPreview( + settings, + browsingContext + ); + // If this isn't simplified then we're done. + if (!simplifyPage) { + this.lastPreviewBrowser = selectionTypeBrowser; + return result; + } + } + + // We have the base selection/primary browser but need to simplify. + previewBrowser = this.createPreviewBrowser(sourceVersion); + await previewBrowser.browsingContext.currentWindowGlobal + .getActor("Printing") + .sendQuery("Printing:Preview:ParseDocument", { + URL: sourceURI, + windowID: + selectionTypeBrowser.browsingContext.currentWindowGlobal + .outerWindowId, + }); + + // We've parsed a simplified version into the preview browser. Convert that to + // a print preview as usual. + this.lastPreviewBrowser = previewBrowser; + return previewBrowser.frameLoader.printPreview( + settings, + previewBrowser.browsingContext + ); + } + + createPreviewBrowser(sourceVersion) { + let browser = document.createXULElement("browser"); + let browsingContext = + sourceVersion == "selection" || + this.printFrameOnly || + (sourceVersion == "source" && this.openWindowInfo) + ? this.sourceBrowsingContext + : this.sourceBrowsingContext.top; + if (sourceVersion == "source" && this.openWindowInfo) { + browser.openWindowInfo = this.openWindowInfo; + } else { + let userContextId = browsingContext.originAttributes.userContextId; + if (userContextId) { + browser.setAttribute("usercontextid", userContextId); + } + browser.setAttribute( + "initialBrowsingContextGroupId", + browsingContext.group.id + ); + } + browser.setAttribute("type", "content"); + let remoteType = browsingContext.currentRemoteType; + if (remoteType) { + browser.setAttribute("remoteType", remoteType); + browser.setAttribute("remote", "true"); + } + // When the print process finishes, we get closed by + // nsDocumentViewer::OnDonePrinting, or by the print preview code. + // + // When that happens, we should remove us from the DOM if connected. + browser.addEventListener("DOMWindowClose", function (e) { + if (this.isConnected) { + this.remove(); + } + e.stopPropagation(); + e.preventDefault(); + }); + + if (this.settingsBrowser) { + browser.addEventListener("contextmenu", function (e) { + e.preventDefault(); + }); + + browser.setAttribute("previewtype", sourceVersion); + browser.classList.add("printPreviewBrowser"); + browser.setAttribute("flex", "1"); + browser.setAttribute("printpreview", "true"); + browser.setAttribute("nodefaultsrc", "true"); + document.l10n.setAttributes(browser, "printui-preview-label"); + + this.stack.insertBefore(browser, this.paginator); + + if (sourceVersion == "source") { + this.sourceBrowser = browser; + } else if (sourceVersion == "selection") { + this.selectionBrowser = browser; + } else if (sourceVersion == "simplified") { + this.simplifiedBrowser = browser; + } + } else { + browser.style.visibility = "collapse"; + } + return browser; + } +} +customElements.define("print-preview", PrintPreview); |