1 // This file is loaded into the browser window scope.
2 /* eslint-env mozilla/browser-window */
4 // -*- tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2 -*-
6 /* This Source Code Form is subject to the terms of the Mozilla Public
7 * License, v. 2.0. If a copy of the MPL was not distributed with this
8 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
11 * PrintUtils is a utility for front-end code to trigger common print
12 * operations (printing, show print preview, show page settings).
14 * Unfortunately, likely due to inconsistencies in how different operating
15 * systems do printing natively, our XPCOM-level printing interfaces
16 * are a bit confusing and the method by which we do something basic
17 * like printing a page is quite circuitous.
19 * To compound that, we need to support remote browsers, and that means
20 * kicking off the print jobs in the content process. This means we send
21 * messages back and forth to that process via the Printing actor.
23 * This also means that <xul:browser>'s that hope to use PrintUtils must have
24 * their type attribute set to "content".
28 * Printing:Preview:Enter
29 * This message is sent to put content into print preview mode. We pass
30 * the content window of the browser we're showing the preview of, and
31 * the target of the message is the browser that we'll be showing the
34 * Printing:Preview:Exit
35 * This message is sent to take content out of print preview mode.
38 XPCOMUtils
.defineLazyPreferenceGetter(
40 "SHOW_PAGE_SETUP_MENU",
41 "print.show_page_setup_menu",
45 XPCOMUtils
.defineLazyPreferenceGetter(
47 "PRINT_ALWAYS_SILENT",
48 "print.always_print_silent",
52 XPCOMUtils
.defineLazyPreferenceGetter(
54 "PREFER_SYSTEM_DIALOG",
55 "print.prefer_system_dialog",
59 ChromeUtils
.defineESModuleGetters(this, {
60 PromptUtils
: "resource://gre/modules/PromptUtils.sys.mjs",
64 SAVE_TO_PDF_PRINTER
: "Mozilla Save to PDF",
68 return (this._bundle
= Services
.strings
.createBundle(
69 "chrome://global/locale/printing.properties"
73 async
checkForSelection(browsingContext
) {
76 browsingContext
.currentWindowGlobal
.getActor("PrintingSelection");
77 // Need the await for the try to trigger...
78 return await sourceActor
.sendQuery("PrintingSelection:HasSelection", {});
86 * Updates the hidden state of the "Page Setup" menu items in the File menu,
87 * depending on the value of the `print.show_page_setup_menu` pref.
88 * Note: not all platforms have a "Page Setup" menu item (or Page Setup
91 updatePrintSetupMenuHiddenState() {
92 let pageSetupMenuItem
= document
.getElementById("menu_printSetup");
93 if (pageSetupMenuItem
) {
94 pageSetupMenuItem
.hidden
= !SHOW_PAGE_SETUP_MENU
;
99 * Shows the page setup dialog, and saves any settings changed in
100 * that dialog if print.save_print_settings is set to true.
102 * @return true on success, false on failure
105 let printSettings
= this.getPrintSettings();
106 // If we come directly from the Page Setup menu, the hack in
107 // _enterPrintPreview will not have been invoked to set the last used
108 // printer name. For the reasons outlined at that hack, we want that set
110 let PSSVC
= Cc
["@mozilla.org/gfx/printsettings-service;1"].getService(
111 Ci
.nsIPrintSettingsService
113 if (!PSSVC
.lastUsedPrinterName
) {
114 if (printSettings
.printerName
) {
115 PSSVC
.maybeSaveLastUsedPrinterNameToPrefs(printSettings
.printerName
);
116 PSSVC
.maybeSavePrintSettingsToPrefs(
118 Ci
.nsIPrintSettings
.kInitSaveAll
123 var PRINTDIALOGSVC
= Cc
[
124 "@mozilla.org/widget/printdialog-service;1"
125 ].getService(Ci
.nsIPrintDialogService
);
126 PRINTDIALOGSVC
.showPageSetupDialog(window
, printSettings
, null);
128 dump("showPageSetup " + e
+ "\n");
135 * This call exists in a separate method so it can be easily overridden where
136 * `gBrowser` doesn't exist (e.g. Thunderbird).
138 * @see getTabDialogBox in tabbrowser.js
140 getTabDialogBox(sourceBrowser
) {
141 return gBrowser
.getTabDialogBox(sourceBrowser
);
144 getPreviewBrowser(sourceBrowser
) {
145 let dialogBox
= this.getTabDialogBox(sourceBrowser
);
146 for (let dialog
of dialogBox
.getTabDialogManager()._dialogs
) {
147 let browser
= dialog
._box
.querySelector(".printPreviewBrowser");
156 * Opens the tab modal version of the print UI for the current tab.
158 * @param aBrowsingContext
159 * The BrowsingContext of the window to print.
160 * @param aExistingPreviewBrowser
161 * An existing browser created for printing from window.print().
162 * @param aPrintSelectionOnly
163 * Whether to print only the active selection of the given browsing
165 * @param aPrintFrameOnly
166 * Whether to print the selected frame only
167 * @return promise resolving when the dialog is open, rejected if the preview
176 let sourceBrowser
= aBrowsingContext
.top
.embedderElement
;
177 let previewBrowser
= this.getPreviewBrowser(sourceBrowser
);
178 if (previewBrowser
) {
179 // Don't open another dialog if we're already printing.
181 // XXX This can be racy can't it? getPreviewBrowser looks at browser that
182 // we set up after opening the dialog. But I guess worst case we just
183 // open two dialogs so...
184 throw new Error("Tab-modal print UI already open");
187 // Create the print preview dialog.
188 let args
= PromptUtils
.objectToPropBag({
189 printSelectionOnly
: !!aPrintSelectionOnly
,
190 isArticle
: sourceBrowser
.isArticle
,
191 printFrameOnly
: !!aPrintFrameOnly
,
193 let dialogBox
= this.getTabDialogBox(sourceBrowser
);
194 let { closedPromise
, dialog
} = dialogBox
.open(
195 `chrome://global/content/print.html`,
196 { features
: "resizable=no", sizeTo
: "available" },
199 closedPromise
.catch(e
=> {
203 let settingsBrowser
= dialog
._frame
;
204 let printPreview
= new PrintPreview({
205 sourceBrowsingContext
: aBrowsingContext
,
207 topBrowsingContext
: aBrowsingContext
.top
,
208 activeBrowsingContext
: aBrowsingContext
,
209 openWindowInfo
: aOpenWindowInfo
,
210 printFrameOnly
: aPrintFrameOnly
,
212 // This will create the source browser in connectedCallback() if we sent
213 // openWindowInfo. Otherwise the browser will be null.
214 settingsBrowser
.parentElement
.insertBefore(printPreview
, settingsBrowser
);
215 return printPreview
.sourceBrowser
;
219 * Initialize a print, this will open the tab modal UI if it is enabled or
220 * defer to the native dialog/silent print.
222 * @param aBrowsingContext
223 * The BrowsingContext of the window to print.
224 * Note that the browsing context could belong to a subframe of the
225 * tab that called window.print, or similar shenanigans.
227 * {windowDotPrintOpenWindowInfo}
228 * Non-null if this call comes from window.print().
229 * This is the nsIOpenWindowInfo object that has to
230 * be passed down to createBrowser in order for the
231 * static clone that has been cretaed in the child
232 * process to be linked to the browser it creates
233 * in the parent process.
234 * {printSelectionOnly} Whether to print only the active selection of
235 * the given browsing context.
236 * {printFrameOnly} Whether to print the selected frame.
238 startPrintWindow(aBrowsingContext
, aOptions
) {
239 // At most, one of these is set.
240 let { printSelectionOnly
, printFrameOnly
, windowDotPrintOpenWindowInfo
} =
244 windowDotPrintOpenWindowInfo
&&
245 !windowDotPrintOpenWindowInfo
.isForWindowDotPrint
247 throw new Error("Only expect openWindowInfo for window.print()");
250 let browsingContext
= aBrowsingContext
;
251 if (printSelectionOnly
) {
252 // Ensure that we use the window with focus/selection if the context menu
253 // (from which 'Print selection' was selected) happens to have been opened
254 // over a different frame.
255 let focusedBc
= Services
.focus
.focusedContentBrowsingContext
;
258 focusedBc
.top
.embedderElement
== browsingContext
.top
.embedderElement
260 browsingContext
= focusedBc
;
264 if (!PRINT_ALWAYS_SILENT
&& !PREFER_SYSTEM_DIALOG
) {
265 return this._openTabModalPrint(
267 windowDotPrintOpenWindowInfo
,
273 const useSystemDialog
= PREFER_SYSTEM_DIALOG
&& !PRINT_ALWAYS_SILENT
;
276 if (windowDotPrintOpenWindowInfo
) {
277 // When we're called by handleStaticCloneCreatedForPrint(), we must
278 // return this browser.
279 browser
= this.createParentBrowserForStaticClone(
281 windowDotPrintOpenWindowInfo
283 browsingContext
= browser
.browsingContext
;
286 // This code is wrapped in an async function so that we can await the async
287 // functions that it calls.
288 async
function makePrintSettingsAndInvokePrint() {
289 let settings
= PrintUtils
.getPrintSettings(
291 /*aDefaultsOnly*/ false,
292 /*aAllowPseudoPrinter*/ !useSystemDialog
294 settings
.printSelectionOnly
= printSelectionOnly
;
296 settings
.outputDestination
==
297 Ci
.nsIPrintSettings
.kOutputDestinationFile
&&
300 // TODO(bug 1748004): We should consider generating the file name
301 // from the document's title as we do in print.js's pickFileName
302 // (including using DownloadPaths.sanitize!).
303 // For now, the following is for consistency with the behavior
304 // prior to bug 1669149 part 3.
305 let dest
= undefined;
307 dest
= Services
.dirsvc
.get("CurWorkD", Ci
.nsIFile
).path
;
310 dest
= Services
.dirsvc
.get("Home", Ci
.nsIFile
).path
;
312 settings
.toFileName
= PathUtils
.join(dest
, "mozilla.pdf");
315 if (useSystemDialog
) {
317 await PrintUtils
.checkForSelection(browsingContext
);
319 // Prompt the user to choose a printer and make any desired print
323 doPrint
= await PrintUtils
.handleSystemPrintDialog(
324 browsingContext
.topChromeWindow
,
332 // Clean up browser if we aren't going to use it.
333 if (!doPrint
&& browser
) {
339 // At some point we should handle the Promise that this returns (at
340 // least report rejection to telemetry).
341 browsingContext
.print(settings
);
344 // We need to return to the event loop before calling
345 // makePrintSettingsAndInvokePrint() if we were called for `window.print()`.
346 // That's because if that function synchronously calls `browser.remove()`
347 // or `browsingContext.print()` before we return `browser`, the nested
348 // event loop that is being spun in the content process under the
349 // OpenInternal call in nsGlobalWindowOuter::Print will still be active.
350 // In the case of `browser.remove()`, nsGlobalWindowOuter::Print would then
351 // get unhappy once OpenInternal does return since it will fail to return
352 // a BrowsingContext. In the case of `browsingContext.print()`, we would
353 // re-enter nsGlobalWindowOuter::Print under the nested event loop and
354 // printing would then fail since the outer nsGlobalWindowOuter::Print call
355 // wouldn't yet have created the static clone.
356 setTimeout(makePrintSettingsAndInvokePrint
, 0);
361 togglePrintPreview(aBrowsingContext
) {
362 let dialogBox
= this.getTabDialogBox(aBrowsingContext
.top
.embedderElement
);
363 let dialogs
= dialogBox
.getTabDialogManager().dialogs
;
364 let previewDialog
= dialogs
.find(d
=>
365 d
._box
.querySelector(".printSettingsBrowser")
368 previewDialog
.close();
371 this.startPrintWindow(aBrowsingContext
);
375 * Called when a content process has created a new BrowsingContext for a
376 * static clone of a document that is to be printed, but we do NOT yet have a
377 * CanonicalBrowsingContext counterpart in the parent process. This only
378 * happens in the following cases:
380 * - content script invoked window.print() in the content process, or:
381 * - silent printing is enabled, and UI code previously invoked
382 * startPrintWindow which called BrowsingContext.print(), and we're now
383 * being called back by the content process to parent the static clone.
385 * In the latter case we only need to create the CanonicalBrowsingContext,
386 * link it to it's content process counterpart, and inserted it into
387 * the document tree; the print in the content process has already been
390 * In the former case we additionally need to check if we should open the
391 * tab modal print UI (if not silent printing), obtain a valid
392 * nsIPrintSettings object, and tell the content process to initiate the
393 * print with this settings object.
395 handleStaticCloneCreatedForPrint(aOpenWindowInfo
) {
396 let browsingContext
= aOpenWindowInfo
.parent
;
397 if (aOpenWindowInfo
.isForWindowDotPrint
) {
398 return this.startPrintWindow(browsingContext
, {
399 windowDotPrintOpenWindowInfo
: aOpenWindowInfo
,
402 return this.createParentBrowserForStaticClone(
408 createParentBrowserForStaticClone(aBrowsingContext
, aOpenWindowInfo
) {
409 // XXX This code is only called when silent printing, so we're really
410 // abusing PrintPreview here. See bug 1768020.
411 let printPreview
= new PrintPreview({
412 sourceBrowsingContext
: aBrowsingContext
,
413 openWindowInfo
: aOpenWindowInfo
,
415 let browser
= printPreview
.createPreviewBrowser("source");
416 document
.documentElement
.append(browser
);
420 // "private" methods and members. Don't use them.
422 _getErrorCodeForNSResult(nsresult
) {
424 "GFX_PRINTER_NO_PRINTER_AVAILABLE",
425 "GFX_PRINTER_NAME_NOT_FOUND",
426 "GFX_PRINTER_COULD_NOT_OPEN_FILE",
427 "GFX_PRINTER_STARTDOC",
428 "GFX_PRINTER_ENDDOC",
429 "GFX_PRINTER_STARTPAGE",
430 "GFX_PRINTER_DOC_IS_BUSY",
438 for (let code
of MSG_CODES
) {
439 let nsErrorResult
= "NS_ERROR_" + code
;
440 if (Cr
[nsErrorResult
] == nsresult
) {
445 // PERR_FAILURE is the catch-all error message if we've gotten one that
446 // we don't recognize.
450 _displayPrintingError(nsresult
, isPrinting
, browser
) {
451 // The nsresults from a printing error are mapped to strings that have
452 // similar names to the errors themselves. For example, for error
453 // NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE, the name of the string
454 // for the error message is: PERR_GFX_PRINTER_NO_PRINTER_AVAILABLE. What's
455 // more, if we're in the process of doing a print preview, it's possible
456 // that there are strings specific for print preview for these errors -
457 // if so, the names of those strings have _PP as a suffix. It's possible
458 // that no print preview specific strings exist, in which case it is fine
459 // to fall back to the original string name.
460 let msgName
= "PERR_" + this._getErrorCodeForNSResult(nsresult
);
463 // Try first with _PP suffix.
464 let ppMsgName
= msgName
+ "_PP";
466 msg
= this._bundle
.GetStringFromName(ppMsgName
);
468 // We allow localizers to not have the print preview error string,
469 // and just fall back to the printing error string.
474 msg
= this._bundle
.GetStringFromName(msgName
);
477 title
= this._bundle
.GetStringFromName(
479 ? "print_error_dialog_title"
480 : "printpreview_error_dialog_title"
483 Services
.prompt
.asyncAlert(
484 browser
.browsingContext
,
485 Services
.prompt
.MODAL_TYPE_TAB
,
490 Glean
.printing
.error
[this._getErrorCodeForNSResult(nsresult
)].add(1);
493 getPrintSettings(aPrinterName
, aDefaultsOnly
, aAllowPseudoPrinter
= true) {
496 var PSSVC
= Cc
["@mozilla.org/gfx/printsettings-service;1"].getService(
497 Ci
.nsIPrintSettingsService
500 function isValidPrinterName(aPrinterName
) {
503 (aAllowPseudoPrinter
||
504 aPrinterName
!= PrintUtils
.SAVE_TO_PDF_PRINTER
)
508 // We must not try to print using an nsIPrintSettings without a printer
510 const printerName
= (function () {
511 if (isValidPrinterName(aPrinterName
)) {
514 if (isValidPrinterName(PSSVC
.lastUsedPrinterName
)) {
515 return PSSVC
.lastUsedPrinterName
;
517 return Cc
["@mozilla.org/gfx/printerlist;1"].getService(
519 ).systemDefaultPrinterName
;
522 printSettings
= PSSVC
.createNewPrintSettings();
523 printSettings
.printerName
= printerName
;
525 // First get any defaults from the printer. We want to skip this for Save
526 // to PDF since it isn't a real printer and will throw.
527 if (printSettings
.printerName
!= this.SAVE_TO_PDF_PRINTER
) {
528 PSSVC
.initPrintSettingsFromPrinter(
529 printSettings
.printerName
,
534 if (!aDefaultsOnly
) {
535 // Apply any settings that have been saved for this printer.
536 PSSVC
.initPrintSettingsFromPrefs(
539 printSettings
.kInitSaveAll
543 console
.error("PrintUtils.getPrintSettings failed:", e
);
545 return printSettings
;
548 // Show the system print dialog, saving modified preferences.
549 // Returns true if the user clicked print (Not cancel).
550 async
handleSystemPrintDialog(aWindow
, aHasSelection
, aSettings
) {
551 // Prompt the user to choose a printer and make any desired print
554 const svc
= Cc
["@mozilla.org/widget/printdialog-service;1"].getService(
555 Ci
.nsIPrintDialogService
557 await svc
.showPrintDialog(aWindow
, aHasSelection
, aSettings
);
559 if (e
.result
== Cr
.NS_ERROR_ABORT
) {
565 // Update the saved last used printer name and print settings:
566 var PSSVC
= Cc
["@mozilla.org/gfx/printsettings-service;1"].getService(
567 Ci
.nsIPrintSettingsService
569 PSSVC
.maybeSaveLastUsedPrinterNameToPrefs(aSettings
.printerName
);
570 PSSVC
.maybeSavePrintSettingsToPrefs(
572 Ci
.nsIPrintSettings
.kPrintDialogPersistSettings
579 * This class implements a custom element that contains a nested <browser>
580 * element. When the user asks to print a document, we create an instance of
581 * this class and ask the platform code to create a static clone of the
582 * document (a snapshot that won't change due to script running, etc.) in the
583 * contained <browser> element.
585 * To display a print preview to the user, an instance of this element is added
586 * to the tab-modal print preview dialog. As the user changes print preview
587 * settings, we may actually end up with multiple instances: one for a preview
588 * of the original document, one for a preview of the focused frame, and one
589 * for the selected text.
591 * To print without displaying a print preview, an instance of this class is
592 * appended, hidden, to the end of the top-level chrome browser's document.
594 class PrintPreview
extends MozElements
.BaseControl
{
596 sourceBrowsingContext
,
599 activeBrowsingContext
,
604 this.sourceBrowsingContext
= sourceBrowsingContext
;
605 this.settingsBrowser
= settingsBrowser
;
606 this.topBrowsingContext
= topBrowsingContext
;
607 this.activeBrowsingContext
= activeBrowsingContext
;
608 this.openWindowInfo
= openWindowInfo
;
609 this.printFrameOnly
= printFrameOnly
;
611 this.printSelectionOnly
= false;
612 this.simplifyPage
= false;
613 this.sourceBrowser
= null;
614 this.selectionBrowser
= null;
615 this.simplifiedBrowser
= null;
616 this.lastPreviewBrowser
= null;
619 connectedCallback() {
620 if (this.childElementCount
> 0) {
623 this.setAttribute("flex", "1");
625 MozXULElement
.parseXULToFragment(`
626 <stack class="previewStack" rendering="true" flex="1" previewtype="primary">
627 <vbox class="previewRendering" flex="1">
628 <h1 class="print-pending-label" data-l10n-id="printui-loading"></h1>
630 <html:printpreview-pagination class="printPreviewNavigation"></html:printpreview-pagination>
632 <html:link rel="stylesheet" href="chrome://global/content/printPreview.css"/>
635 this.stack
= this.firstElementChild
;
636 this.paginator
= this.querySelector("printpreview-pagination");
638 if (this.openWindowInfo
) {
639 // For window.print() we need a browser right away for the contents to be
640 // cloned into, create it now.
641 this.createPreviewBrowser("source");
645 disconnectedCallback() {
646 this.exitPrintPreview();
649 getSourceBrowsingContext() {
650 if (this.openWindowInfo
) {
651 // If openWindowInfo is set this was for window.print() and the source
652 // contents have already been cloned into the preview browser.
653 return this.sourceBrowser
.browsingContext
;
655 return this.sourceBrowsingContext
;
658 get currentBrowsingContext() {
659 return this.lastPreviewBrowser
.browsingContext
;
663 this.sourceBrowser
?.frameLoader
?.exitPrintPreview();
664 this.simplifiedBrowser
?.frameLoader
?.exitPrintPreview();
665 this.selectionBrowser
?.frameLoader
?.exitPrintPreview();
667 this.textContent
= "";
670 async
printPreview(settings
, { sourceVersion
, sourceURI
}) {
671 this.stack
.setAttribute("rendering", true);
673 let result
= await
this._printPreview(settings
, {
678 let browser
= this.lastPreviewBrowser
;
679 this.stack
.setAttribute("previewtype", browser
.getAttribute("previewtype"));
680 browser
.setAttribute("sheet-count", result
.sheetCount
);
681 // The view resets to the top of the document on update bug 1686737.
682 browser
.setAttribute("current-page", 1);
683 this.paginator
.observePreviewBrowser(browser
);
684 await document
.l10n
.translateElements([browser
]);
686 this.stack
.removeAttribute("rendering");
691 async
_printPreview(settings
, { sourceVersion
, sourceURI
}) {
692 let printSelectionOnly
= sourceVersion
== "selection";
693 let simplifyPage
= sourceVersion
== "simplified";
694 let selectionTypeBrowser
;
697 // Select the existing preview browser elements, these could be null.
698 if (printSelectionOnly
) {
699 selectionTypeBrowser
= this.selectionBrowser
;
700 previewBrowser
= this.selectionBrowser
;
702 selectionTypeBrowser
= this.sourceBrowser
;
703 previewBrowser
= simplifyPage
704 ? this.simplifiedBrowser
705 : this.sourceBrowser
;
708 settings
.docURL
= sourceURI
;
710 if (previewBrowser
) {
711 this.lastPreviewBrowser
= previewBrowser
;
712 if (this.openWindowInfo
) {
713 // We only want to use openWindowInfo for the window.print() browser,
714 // we can get rid of it now.
715 this.openWindowInfo
= null;
717 // This browser has been rendered already, just update it.
718 return previewBrowser
.frameLoader
.printPreview(settings
, null);
721 if (!selectionTypeBrowser
) {
722 // Need to create a non-simplified browser.
723 selectionTypeBrowser
= this.createPreviewBrowser(
724 simplifyPage
? "source" : sourceVersion
726 let browsingContext
=
727 printSelectionOnly
|| this.printFrameOnly
728 ? this.activeBrowsingContext
729 : this.topBrowsingContext
;
730 let result
= await selectionTypeBrowser
.frameLoader
.printPreview(
734 // If this isn't simplified then we're done.
736 this.lastPreviewBrowser
= selectionTypeBrowser
;
741 // We have the base selection/primary browser but need to simplify.
742 previewBrowser
= this.createPreviewBrowser(sourceVersion
);
743 await previewBrowser
.browsingContext
.currentWindowGlobal
744 .getActor("Printing")
745 .sendQuery("Printing:Preview:ParseDocument", {
748 selectionTypeBrowser
.browsingContext
.currentWindowGlobal
752 // We've parsed a simplified version into the preview browser. Convert that to
753 // a print preview as usual.
754 this.lastPreviewBrowser
= previewBrowser
;
755 return previewBrowser
.frameLoader
.printPreview(
757 previewBrowser
.browsingContext
761 createPreviewBrowser(sourceVersion
) {
762 let browser
= document
.createXULElement("browser");
763 let browsingContext
=
764 sourceVersion
== "selection" ||
765 this.printFrameOnly
||
766 (sourceVersion
== "source" && this.openWindowInfo
)
767 ? this.sourceBrowsingContext
768 : this.sourceBrowsingContext
.top
;
769 if (sourceVersion
== "source" && this.openWindowInfo
) {
770 browser
.openWindowInfo
= this.openWindowInfo
;
772 let userContextId
= browsingContext
.originAttributes
.userContextId
;
774 browser
.setAttribute("usercontextid", userContextId
);
776 browser
.setAttribute(
777 "initialBrowsingContextGroupId",
778 browsingContext
.group
.id
781 browser
.setAttribute("type", "content");
782 let remoteType
= browsingContext
.currentRemoteType
;
784 browser
.setAttribute("remoteType", remoteType
);
785 browser
.setAttribute("remote", "true");
787 // When the print process finishes, we get closed by
788 // nsDocumentViewer::OnDonePrinting, or by the print preview code.
790 // When that happens, we should remove us from the DOM if connected.
791 browser
.addEventListener("DOMWindowClose", function (e
) {
792 if (this.isConnected
) {
799 if (this.settingsBrowser
) {
800 browser
.addEventListener("contextmenu", function (e
) {
804 browser
.setAttribute("previewtype", sourceVersion
);
805 browser
.classList
.add("printPreviewBrowser");
806 browser
.setAttribute("flex", "1");
807 browser
.setAttribute("printpreview", "true");
808 browser
.setAttribute("nodefaultsrc", "true");
809 document
.l10n
.setAttributes(browser
, "printui-preview-label");
811 this.stack
.insertBefore(browser
, this.paginator
);
813 if (sourceVersion
== "source") {
814 this.sourceBrowser
= browser
;
815 } else if (sourceVersion
== "selection") {
816 this.selectionBrowser
= browser
;
817 } else if (sourceVersion
== "simplified") {
818 this.simplifiedBrowser
= browser
;
821 browser
.style
.visibility
= "collapse";
826 customElements
.define("print-preview", PrintPreview
);