1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // TODO(rltoscano): Move data/* into print_preview.data namespace
7 <include src="component.js">
8 <include src="print_preview_focus_manager.js">
10 cr.define('print_preview', function() {
14 * Container class for Chromium's print preview.
16 * @extends {print_preview.Component}
18 function PrintPreview() {
19 print_preview.Component.call(this);
22 * Used to communicate with Chromium's print system.
23 * @type {!print_preview.NativeLayer}
26 this.nativeLayer_ = new print_preview.NativeLayer();
29 * Event target that contains information about the logged in user.
30 * @type {!print_preview.UserInfo}
33 this.userInfo_ = new print_preview.UserInfo();
37 * @type {!print_preview.AppState}
40 this.appState_ = new print_preview.AppState();
43 * Data model that holds information about the document to print.
44 * @type {!print_preview.DocumentInfo}
47 this.documentInfo_ = new print_preview.DocumentInfo();
50 * Data store which holds print destinations.
51 * @type {!print_preview.DestinationStore}
54 this.destinationStore_ = new print_preview.DestinationStore(
55 this.nativeLayer_, this.userInfo_, this.appState_);
58 * Data store which holds printer sharing invitations.
59 * @type {!print_preview.InvitationStore}
62 this.invitationStore_ = new print_preview.InvitationStore(this.userInfo_);
65 * Storage of the print ticket used to create the print job.
66 * @type {!print_preview.PrintTicketStore}
69 this.printTicketStore_ = new print_preview.PrintTicketStore(
70 this.destinationStore_, this.appState_, this.documentInfo_);
73 * Holds the print and cancel buttons and renders some document statistics.
74 * @type {!print_preview.PrintHeader}
77 this.printHeader_ = new print_preview.PrintHeader(
78 this.printTicketStore_, this.destinationStore_);
79 this.addChild(this.printHeader_);
82 * Component used to search for print destinations.
83 * @type {!print_preview.DestinationSearch}
86 this.destinationSearch_ = new print_preview.DestinationSearch(
87 this.destinationStore_, this.invitationStore_, this.userInfo_);
88 this.addChild(this.destinationSearch_);
91 * Component that renders the print destination.
92 * @type {!print_preview.DestinationSettings}
95 this.destinationSettings_ = new print_preview.DestinationSettings(
96 this.destinationStore_);
97 this.addChild(this.destinationSettings_);
100 * Component that renders UI for entering in page range.
101 * @type {!print_preview.PageSettings}
104 this.pageSettings_ = new print_preview.PageSettings(
105 this.printTicketStore_.pageRange);
106 this.addChild(this.pageSettings_);
109 * Component that renders the copies settings.
110 * @type {!print_preview.CopiesSettings}
113 this.copiesSettings_ = new print_preview.CopiesSettings(
114 this.printTicketStore_.copies, this.printTicketStore_.collate);
115 this.addChild(this.copiesSettings_);
118 * Component that renders the media size settings.
119 * @type {!print_preview.MediaSizeSettings}
122 this.mediaSizeSettings_ =
123 new print_preview.MediaSizeSettings(this.printTicketStore_.mediaSize);
124 this.addChild(this.mediaSizeSettings_);
127 * Component that renders the layout settings.
128 * @type {!print_preview.LayoutSettings}
131 this.layoutSettings_ =
132 new print_preview.LayoutSettings(this.printTicketStore_.landscape);
133 this.addChild(this.layoutSettings_);
136 * Component that renders the color options.
137 * @type {!print_preview.ColorSettings}
140 this.colorSettings_ =
141 new print_preview.ColorSettings(this.printTicketStore_.color);
142 this.addChild(this.colorSettings_);
145 * Component that renders a select box for choosing margin settings.
146 * @type {!print_preview.MarginSettings}
149 this.marginSettings_ =
150 new print_preview.MarginSettings(this.printTicketStore_.marginsType);
151 this.addChild(this.marginSettings_);
154 * Component that renders the DPI settings.
155 * @type {!print_preview.DpiSettings}
159 new print_preview.DpiSettings(this.printTicketStore_.dpi);
160 this.addChild(this.dpiSettings_);
163 * Component that renders miscellaneous print options.
164 * @type {!print_preview.OtherOptionsSettings}
167 this.otherOptionsSettings_ = new print_preview.OtherOptionsSettings(
168 this.printTicketStore_.duplex,
169 this.printTicketStore_.fitToPage,
170 this.printTicketStore_.cssBackground,
171 this.printTicketStore_.selectionOnly,
172 this.printTicketStore_.headerFooter);
173 this.addChild(this.otherOptionsSettings_);
176 * Component that renders the advanced options button.
177 * @type {!print_preview.AdvancedOptionsSettings}
180 this.advancedOptionsSettings_ = new print_preview.AdvancedOptionsSettings(
181 this.printTicketStore_.vendorItems, this.destinationStore_);
182 this.addChild(this.advancedOptionsSettings_);
185 * Component used to search for print destinations.
186 * @type {!print_preview.AdvancedSettings}
189 this.advancedSettings_ = new print_preview.AdvancedSettings(
190 this.printTicketStore_);
191 this.addChild(this.advancedSettings_);
193 var settingsSections = [
194 this.destinationSettings_,
196 this.copiesSettings_,
197 this.mediaSizeSettings_,
198 this.layoutSettings_,
199 this.marginSettings_,
202 this.otherOptionsSettings_,
203 this.advancedOptionsSettings_];
205 * Component representing more/less settings button.
206 * @type {!print_preview.MoreSettings}
209 this.moreSettings_ = new print_preview.MoreSettings(
210 this.destinationStore_, settingsSections);
211 this.addChild(this.moreSettings_);
214 * Area of the UI that holds the print preview.
215 * @type {!print_preview.PreviewArea}
218 this.previewArea_ = new print_preview.PreviewArea(this.destinationStore_,
219 this.printTicketStore_,
222 this.addChild(this.previewArea_);
225 * Interface to the Google Cloud Print API. Null if Google Cloud Print
226 * integration is disabled.
227 * @type {cloudprint.CloudPrintInterface}
230 this.cloudPrintInterface_ = null;
233 * Whether in kiosk mode where print preview can print automatically without
234 * user intervention. See http://crbug.com/31395. Print will start when
235 * both the print ticket has been initialized, and an initial printer has
240 this.isInKioskAutoPrintMode_ = false;
243 * Whether Print Preview is in App Kiosk mode, basically, use only printers
244 * available for the device.
248 this.isInAppKioskMode_ = false;
251 * Whether Print with System Dialog link should be hidden. Overrides the
252 * default rules for System dialog link visibility.
256 this.hideSystemDialogLink_ = true;
259 * State of the print preview UI.
260 * @type {print_preview.PrintPreview.UiState_}
263 this.uiState_ = PrintPreview.UiState_.INITIALIZING;
266 * Whether document preview generation is in progress.
270 this.isPreviewGenerationInProgress_ = true;
273 * Whether to show system dialog before next printing.
277 this.showSystemDialogBeforeNextPrint_ = false;
281 * States of the print preview.
285 PrintPreview.UiState_ = {
286 INITIALIZING: 'initializing',
288 OPENING_PDF_PREVIEW: 'opening-pdf-preview',
289 OPENING_NATIVE_PRINT_DIALOG: 'opening-native-print-dialog',
290 PRINTING: 'printing',
291 FILE_SELECTION: 'file-selection',
297 * What can happen when print preview tries to print.
301 PrintPreview.PrintAttemptResult_ = {
302 NOT_READY: 'not-ready',
304 READY_WAITING_FOR_PREVIEW: 'ready-waiting-for-preview'
307 PrintPreview.prototype = {
308 __proto__: print_preview.Component.prototype,
310 /** Sets up the page and print preview by getting the printer list. */
311 initialize: function() {
312 this.decorate($('print-preview'));
313 if (!this.previewArea_.hasCompatiblePlugin) {
314 this.setIsEnabled_(false);
316 this.nativeLayer_.startGetInitialSettings();
317 print_preview.PrintPreviewFocusManager.getInstance().initialize();
318 cr.ui.FocusOutlineManager.forDocument(document);
322 enterDocument: function() {
323 // Native layer events.
326 print_preview.NativeLayer.EventType.INITIAL_SETTINGS_SET,
327 this.onInitialSettingsSet_.bind(this));
330 print_preview.NativeLayer.EventType.CLOUD_PRINT_ENABLE,
331 this.onCloudPrintEnable_.bind(this));
334 print_preview.NativeLayer.EventType.PRINT_TO_CLOUD,
335 this.onPrintToCloud_.bind(this));
338 print_preview.NativeLayer.EventType.FILE_SELECTION_CANCEL,
339 this.onFileSelectionCancel_.bind(this));
342 print_preview.NativeLayer.EventType.FILE_SELECTION_COMPLETE,
343 this.onFileSelectionComplete_.bind(this));
346 print_preview.NativeLayer.EventType.SETTINGS_INVALID,
347 this.onSettingsInvalid_.bind(this));
350 print_preview.NativeLayer.EventType.PRINT_PRESET_OPTIONS,
351 this.onPrintPresetOptionsFromDocument_.bind(this));
354 print_preview.NativeLayer.EventType.PRIVET_PRINT_FAILED,
355 this.onPrivetPrintFailed_.bind(this));
358 print_preview.NativeLayer.EventType.MANIPULATE_SETTINGS_FOR_TEST,
359 this.onManipulateSettingsForTest_.bind(this));
361 if ($('system-dialog-link')) {
363 $('system-dialog-link'),
365 this.openSystemPrintDialog_.bind(this));
367 if ($('open-pdf-in-preview-link')) {
369 $('open-pdf-in-preview-link'),
371 this.onOpenPdfInPreviewLinkClick_.bind(this));
376 print_preview.PreviewArea.EventType.PREVIEW_GENERATION_IN_PROGRESS,
377 this.onPreviewGenerationInProgress_.bind(this));
380 print_preview.PreviewArea.EventType.PREVIEW_GENERATION_DONE,
381 this.onPreviewGenerationDone_.bind(this));
384 print_preview.PreviewArea.EventType.PREVIEW_GENERATION_FAIL,
385 this.onPreviewGenerationFail_.bind(this));
388 print_preview.PreviewArea.EventType.OPEN_SYSTEM_DIALOG_CLICK,
389 this.openSystemPrintDialog_.bind(this));
392 this.destinationStore_,
393 print_preview.DestinationStore.EventType.
394 SELECTED_DESTINATION_CAPABILITIES_READY,
395 this.printIfReady_.bind(this));
397 this.destinationStore_,
398 print_preview.DestinationStore.EventType.DESTINATION_SELECT,
399 this.onDestinationSelect_.bind(this));
401 this.destinationStore_,
402 print_preview.DestinationStore.EventType.DESTINATION_SEARCH_DONE,
403 this.onDestinationSearchDone_.bind(this));
407 print_preview.PrintHeader.EventType.PRINT_BUTTON_CLICK,
408 this.onPrintButtonClick_.bind(this));
411 print_preview.PrintHeader.EventType.CANCEL_BUTTON_CLICK,
412 this.onCancelButtonClick_.bind(this));
414 this.tracker.add(window, 'keydown', this.onKeyDown_.bind(this));
415 this.previewArea_.setPluginKeyEventCallback(this.onKeyDown_.bind(this));
418 this.destinationSettings_,
419 print_preview.DestinationSettings.EventType.CHANGE_BUTTON_ACTIVATE,
420 this.onDestinationChangeButtonActivate_.bind(this));
423 this.destinationSearch_,
424 print_preview.DestinationSearch.EventType.MANAGE_CLOUD_DESTINATIONS,
425 this.onManageCloudDestinationsActivated_.bind(this));
427 this.destinationSearch_,
428 print_preview.DestinationSearch.EventType.MANAGE_LOCAL_DESTINATIONS,
429 this.onManageLocalDestinationsActivated_.bind(this));
431 this.destinationSearch_,
432 print_preview.DestinationSearch.EventType.ADD_ACCOUNT,
433 this.onCloudPrintSignInActivated_.bind(this, true /*addAccount*/));
435 this.destinationSearch_,
436 print_preview.DestinationSearch.EventType.SIGN_IN,
437 this.onCloudPrintSignInActivated_.bind(this, false /*addAccount*/));
439 this.destinationSearch_,
440 print_preview.DestinationListItem.EventType.REGISTER_PROMO_CLICKED,
441 this.onCloudPrintRegisterPromoClick_.bind(this));
444 this.advancedOptionsSettings_,
445 print_preview.AdvancedOptionsSettings.EventType.BUTTON_ACTIVATED,
446 this.onAdvancedOptionsButtonActivated_.bind(this));
448 // TODO(rltoscano): Move no-destinations-promo into its own component
449 // instead being part of PrintPreview.
451 this.getChildElement('#no-destinations-promo .close-button'),
453 this.onNoDestinationsPromoClose_.bind(this));
455 this.getChildElement('#no-destinations-promo .not-now-button'),
457 this.onNoDestinationsPromoClose_.bind(this));
459 this.getChildElement('#no-destinations-promo .add-printer-button'),
461 this.onNoDestinationsPromoClick_.bind(this));
465 decorateInternal: function() {
466 this.printHeader_.decorate($('print-header'));
467 this.destinationSearch_.decorate($('destination-search'));
468 this.destinationSettings_.decorate($('destination-settings'));
469 this.pageSettings_.decorate($('page-settings'));
470 this.copiesSettings_.decorate($('copies-settings'));
471 this.mediaSizeSettings_.decorate($('media-size-settings'));
472 this.layoutSettings_.decorate($('layout-settings'));
473 this.colorSettings_.decorate($('color-settings'));
474 this.marginSettings_.decorate($('margin-settings'));
475 this.dpiSettings_.decorate($('dpi-settings'));
476 this.otherOptionsSettings_.decorate($('other-options-settings'));
477 this.advancedOptionsSettings_.decorate($('advanced-options-settings'));
478 this.advancedSettings_.decorate($('advanced-settings'));
479 this.moreSettings_.decorate($('more-settings'));
480 this.previewArea_.decorate($('preview-area'));
484 * Sets whether the controls in the print preview are enabled.
485 * @param {boolean} isEnabled Whether the controls in the print preview are
489 setIsEnabled_: function(isEnabled) {
490 if ($('system-dialog-link'))
491 $('system-dialog-link').classList.toggle('disabled', !isEnabled);
492 if ($('open-pdf-in-preview-link'))
493 $('open-pdf-in-preview-link').classList.toggle('disabled', !isEnabled);
494 this.printHeader_.isEnabled = isEnabled;
495 this.destinationSettings_.isEnabled = isEnabled;
496 this.pageSettings_.isEnabled = isEnabled;
497 this.copiesSettings_.isEnabled = isEnabled;
498 this.mediaSizeSettings_.isEnabled = isEnabled;
499 this.layoutSettings_.isEnabled = isEnabled;
500 this.colorSettings_.isEnabled = isEnabled;
501 this.marginSettings_.isEnabled = isEnabled;
502 this.dpiSettings_.isEnabled = isEnabled;
503 this.otherOptionsSettings_.isEnabled = isEnabled;
504 this.advancedOptionsSettings_.isEnabled = isEnabled;
508 * Prints the document or launches a pdf preview on the local system.
509 * @param {boolean} isPdfPreview Whether to launch the pdf preview.
512 printDocumentOrOpenPdfPreview_: function(isPdfPreview) {
513 assert(this.uiState_ == PrintPreview.UiState_.READY,
514 'Print document request received when not in ready state: ' +
517 this.uiState_ = PrintPreview.UiState_.OPENING_PDF_PREVIEW;
518 } else if (this.destinationStore_.selectedDestination.id ==
519 print_preview.Destination.GooglePromotedId.SAVE_AS_PDF) {
520 this.uiState_ = PrintPreview.UiState_.FILE_SELECTION;
522 this.uiState_ = PrintPreview.UiState_.PRINTING;
524 this.setIsEnabled_(false);
525 this.printHeader_.isCancelButtonEnabled = true;
526 var printAttemptResult = this.printIfReady_();
527 if (printAttemptResult == PrintPreview.PrintAttemptResult_.PRINTED ||
528 printAttemptResult ==
529 PrintPreview.PrintAttemptResult_.READY_WAITING_FOR_PREVIEW) {
530 if ((this.destinationStore_.selectedDestination.isLocal &&
531 !this.destinationStore_.selectedDestination.isPrivet &&
532 !this.destinationStore_.selectedDestination.isExtension &&
533 this.destinationStore_.selectedDestination.id !=
534 print_preview.Destination.GooglePromotedId.SAVE_AS_PDF) ||
535 this.uiState_ == PrintPreview.UiState_.OPENING_PDF_PREVIEW) {
536 // Hide the dialog for now. The actual print command will be issued
537 // when the preview generation is done.
538 this.nativeLayer_.startHideDialog();
544 * Attempts to print if needed and if ready.
545 * @return {PrintPreview.PrintAttemptResult_} Attempt result.
548 printIfReady_: function() {
550 (this.uiState_ == PrintPreview.UiState_.PRINTING ||
551 this.uiState_ == PrintPreview.UiState_.OPENING_PDF_PREVIEW ||
552 this.uiState_ == PrintPreview.UiState_.FILE_SELECTION ||
553 this.isInKioskAutoPrintMode_) &&
554 this.destinationStore_.selectedDestination &&
555 this.destinationStore_.selectedDestination.capabilities;
557 return PrintPreview.PrintAttemptResult_.NOT_READY;
559 if (this.isPreviewGenerationInProgress_) {
560 return PrintPreview.PrintAttemptResult_.READY_WAITING_FOR_PREVIEW;
562 assert(this.printTicketStore_.isTicketValid(),
563 'Trying to print with invalid ticket');
564 if (getIsVisible(this.moreSettings_.getElement())) {
565 new print_preview.PrintSettingsUiMetricsContext().record(
566 this.moreSettings_.isExpanded ?
567 print_preview.Metrics.PrintSettingsUiBucket.
568 PRINT_WITH_SETTINGS_EXPANDED :
569 print_preview.Metrics.PrintSettingsUiBucket.
570 PRINT_WITH_SETTINGS_COLLAPSED);
572 this.nativeLayer_.startPrint(
573 this.destinationStore_.selectedDestination,
574 this.printTicketStore_,
575 this.cloudPrintInterface_,
577 this.uiState_ == PrintPreview.UiState_.OPENING_PDF_PREVIEW,
578 this.showSystemDialogBeforeNextPrint_);
579 this.showSystemDialogBeforeNextPrint_ = false;
580 return PrintPreview.PrintAttemptResult_.PRINTED;
584 * Closes the print preview.
589 this.uiState_ = PrintPreview.UiState_.CLOSING;
590 this.nativeLayer_.startCloseDialog();
594 * Opens the native system print dialog after disabling all controls.
597 openSystemPrintDialog_: function() {
598 if (!this.shouldShowSystemDialogLink_())
600 if ($('system-dialog-link').classList.contains('disabled'))
603 this.showSystemDialogBeforeNextPrint_ = true;
604 this.printDocumentOrOpenPdfPreview_(false /*isPdfPreview*/);
607 setIsVisible(getRequiredElement('system-dialog-throbber'), true);
608 this.setIsEnabled_(false);
609 this.uiState_ = PrintPreview.UiState_.OPENING_NATIVE_PRINT_DIALOG;
610 this.nativeLayer_.startShowSystemDialog();
614 * Called when the native layer has initial settings to set. Sets the
615 * initial settings of the print preview and begins fetching print
617 * @param {Event} event Contains the initial print preview settings
618 * persisted through the session.
621 onInitialSettingsSet_: function(event) {
622 assert(this.uiState_ == PrintPreview.UiState_.INITIALIZING,
623 'Updating initial settings when not in initializing state: ' +
625 this.uiState_ = PrintPreview.UiState_.READY;
627 var settings = event.initialSettings;
628 this.isInKioskAutoPrintMode_ = settings.isInKioskAutoPrintMode;
629 this.isInAppKioskMode_ = settings.isInAppKioskMode;
631 // The following components must be initialized in this order.
633 settings.serializedAppStateStr,
634 settings.systemDefaultDestinationId);
635 this.documentInfo_.init(
636 settings.isDocumentModifiable,
637 settings.documentTitle,
638 settings.documentHasSelection);
639 this.printTicketStore_.init(
640 settings.thousandsDelimeter,
641 settings.decimalDelimeter,
643 settings.selectionOnly);
644 this.destinationStore_.init(settings.isInAppKioskMode);
645 this.appState_.setInitialized();
647 $('document-title').innerText = settings.documentTitle;
648 this.hideSystemDialogLink_ = settings.hidePrintWithSystemDialogLink ||
649 settings.isInAppKioskMode;
650 if ($('system-dialog-link')) {
651 setIsVisible($('system-dialog-link'),
652 this.shouldShowSystemDialogLink_());
657 * Calls when the native layer enables Google Cloud Print integration.
658 * Fetches the user's cloud printers.
659 * @param {Event} event Contains the base URL of the Google Cloud Print
663 onCloudPrintEnable_: function(event) {
664 this.cloudPrintInterface_ = new cloudprint.CloudPrintInterface(
665 event.baseCloudPrintUrl,
670 this.cloudPrintInterface_,
671 cloudprint.CloudPrintInterface.EventType.SUBMIT_DONE,
672 this.onCloudPrintSubmitDone_.bind(this));
674 this.cloudPrintInterface_,
675 cloudprint.CloudPrintInterface.EventType.SEARCH_FAILED,
676 this.onCloudPrintError_.bind(this));
678 this.cloudPrintInterface_,
679 cloudprint.CloudPrintInterface.EventType.SUBMIT_FAILED,
680 this.onCloudPrintError_.bind(this));
682 this.cloudPrintInterface_,
683 cloudprint.CloudPrintInterface.EventType.PRINTER_FAILED,
684 this.onCloudPrintError_.bind(this));
686 this.cloudPrintInterface_,
687 cloudprint.CloudPrintInterface.EventType.
688 UPDATE_PRINTER_TOS_ACCEPTANCE_FAILED,
689 this.onCloudPrintError_.bind(this));
691 this.destinationStore_.setCloudPrintInterface(this.cloudPrintInterface_);
692 this.invitationStore_.setCloudPrintInterface(this.cloudPrintInterface_);
693 if (this.destinationSearch_.getIsVisible()) {
694 this.destinationStore_.startLoadCloudDestinations();
695 this.invitationStore_.startLoadingInvitations();
700 * Called from the native layer when ready to print to Google Cloud Print.
701 * @param {Event} event Contains the body to send in the HTTP request.
704 onPrintToCloud_: function(event) {
705 assert(this.uiState_ == PrintPreview.UiState_.PRINTING,
706 'Document ready to be sent to the cloud when not in printing ' +
707 'state: ' + this.uiState_);
708 assert(this.cloudPrintInterface_ != null,
709 'Google Cloud Print is not enabled');
710 this.cloudPrintInterface_.submit(
711 this.destinationStore_.selectedDestination,
712 this.printTicketStore_,
718 * Called from the native layer when the user cancels the save-to-pdf file
722 onFileSelectionCancel_: function() {
723 assert(this.uiState_ == PrintPreview.UiState_.FILE_SELECTION,
724 'File selection cancelled when not in file-selection state: ' +
726 this.setIsEnabled_(true);
727 this.uiState_ = PrintPreview.UiState_.READY;
731 * Called from the native layer when save-to-pdf file selection is complete.
734 onFileSelectionComplete_: function() {
735 assert(this.uiState_ == PrintPreview.UiState_.FILE_SELECTION,
736 'File selection completed when not in file-selection state: ' +
738 this.previewArea_.showCustomMessage(
739 loadTimeData.getString('printingToPDFInProgress'));
740 this.uiState_ = PrintPreview.UiState_.PRINTING;
744 * Called after successfully submitting a job to Google Cloud Print.
745 * @param {!Event} event Contains the ID of the submitted print job.
748 onCloudPrintSubmitDone_: function(event) {
749 assert(this.uiState_ == PrintPreview.UiState_.PRINTING,
750 'Submited job to Google Cloud Print but not in printing state ' +
752 if (this.destinationStore_.selectedDestination.id ==
753 print_preview.Destination.GooglePromotedId.FEDEX) {
754 this.nativeLayer_.startForceOpenNewTab(
755 'https://www.google.com/cloudprint/fedexcode.html?jobid=' +
762 * Called when there was an error communicating with Google Cloud print.
763 * Displays an error message in the print header.
764 * @param {!Event} event Contains the error message.
767 onCloudPrintError_: function(event) {
768 if (event.status == 403) {
769 if (!this.isInAppKioskMode_) {
770 this.destinationSearch_.showCloudPrintPromo();
772 } else if (event.status == 0) {
773 return; // Ignore, the system does not have internet connectivity.
775 this.printHeader_.setErrorMessage(event.message);
777 if (event.status == 200) {
778 console.error('Google Cloud Print Error: (' + event.errorCode + ') ' +
781 console.error('Google Cloud Print Error: HTTP status ' + event.status);
786 * Called when the preview area's preview generation is in progress.
789 onPreviewGenerationInProgress_: function() {
790 this.isPreviewGenerationInProgress_ = true;
794 * Called when the preview area's preview generation is complete.
797 onPreviewGenerationDone_: function() {
798 this.isPreviewGenerationInProgress_ = false;
799 this.printHeader_.isPrintButtonEnabled = true;
800 this.nativeLayer_.previewReadyForTest();
801 this.printIfReady_();
805 * Called when the preview area's preview failed to load.
808 onPreviewGenerationFail_: function() {
809 this.isPreviewGenerationInProgress_ = false;
810 this.printHeader_.isPrintButtonEnabled = false;
811 if (this.uiState_ == PrintPreview.UiState_.PRINTING)
812 this.nativeLayer_.startCancelPendingPrint();
816 * Called when the 'Open pdf in preview' link is clicked. Launches the pdf
820 onOpenPdfInPreviewLinkClick_: function() {
821 if ($('open-pdf-in-preview-link').classList.contains('disabled'))
823 assert(this.uiState_ == PrintPreview.UiState_.READY,
824 'Trying to open pdf in preview when not in ready state: ' +
826 setIsVisible(getRequiredElement('open-preview-app-throbber'), true);
827 this.previewArea_.showCustomMessage(
828 loadTimeData.getString('openingPDFInPreview'));
829 this.printDocumentOrOpenPdfPreview_(true /*isPdfPreview*/);
833 * Called when the print header's print button is clicked. Prints the
837 onPrintButtonClick_: function() {
838 assert(this.uiState_ == PrintPreview.UiState_.READY,
839 'Trying to print when not in ready state: ' + this.uiState_);
840 this.printDocumentOrOpenPdfPreview_(false /*isPdfPreview*/);
844 * Called when the print header's cancel button is clicked. Closes the
848 onCancelButtonClick_: function() {
853 * Called when the register promo for Cloud Print is clicked.
856 onCloudPrintRegisterPromoClick_: function(e) {
857 var devicesUrl = 'chrome://devices/register?id=' + e.destination.id;
858 this.nativeLayer_.startForceOpenNewTab(devicesUrl);
859 this.destinationStore_.waitForRegister(e.destination.id);
863 * Consume escape key presses and ctrl + shift + p. Delegate everything else
864 * to the preview area.
865 * @param {KeyboardEvent} e The keyboard event.
867 * @suppress {uselessCode}
868 * Current compiler preprocessor leaves all the code inside all the <if>s,
869 * so the compiler claims that code after first return is unreachable.
871 onKeyDown_: function(e) {
872 // Escape key closes the dialog.
873 if (e.keyCode == 27 && !e.shiftKey && !e.ctrlKey && !e.altKey &&
875 // On non-mac with toolkit-views, ESC key is handled by C++-side instead
884 // On Mac, Cmd- should close the print dialog.
885 if (cr.isMac && e.keyCode == 189 && e.metaKey) {
891 // Ctrl + Shift + p / Mac equivalent.
892 if (e.keyCode == 80) {
893 if ((cr.isMac && e.metaKey && e.altKey && !e.shiftKey && !e.ctrlKey) ||
894 (!cr.isMac && e.shiftKey && e.ctrlKey && !e.altKey && !e.metaKey)) {
895 this.openSystemPrintDialog_();
901 if (e.keyCode == 13 /*enter*/ &&
902 !document.querySelector('.overlay:not([hidden])') &&
903 this.destinationStore_.selectedDestination &&
904 this.printTicketStore_.isTicketValid() &&
905 this.printHeader_.isPrintButtonEnabled) {
906 assert(this.uiState_ == PrintPreview.UiState_.READY,
907 'Trying to print when not in ready state: ' + this.uiState_);
908 var activeElementTag = document.activeElement.tagName.toUpperCase();
909 if (activeElementTag != 'BUTTON' && activeElementTag != 'SELECT' &&
910 activeElementTag != 'A') {
911 this.printDocumentOrOpenPdfPreview_(false /*isPdfPreview*/);
917 // Pass certain directional keyboard events to the PDF viewer.
918 this.previewArea_.handleDirectionalKeyEvent(e);
922 * Called when native layer receives invalid settings for a print request.
925 onSettingsInvalid_: function() {
926 this.uiState_ = PrintPreview.UiState_.ERROR;
927 console.error('Invalid settings error reported from native layer');
928 this.previewArea_.showCustomMessage(
929 loadTimeData.getString('invalidPrinterSettings'));
933 * Called when the destination settings' change button is activated.
934 * Displays the destination search component.
937 onDestinationChangeButtonActivate_: function() {
938 this.destinationSearch_.setIsVisible(true);
942 * Called when the destination settings' change button is activated.
943 * Displays the destination search component.
946 onAdvancedOptionsButtonActivated_: function() {
947 this.advancedSettings_.showForDestination(
948 assert(this.destinationStore_.selectedDestination));
952 * Called when the destination search dispatches manage cloud destinations
953 * event. Calls corresponding native layer method.
956 onManageCloudDestinationsActivated_: function() {
957 this.nativeLayer_.startManageCloudDestinations(this.userInfo_.activeUser);
961 * Called when the destination search dispatches manage local destinations
962 * event. Calls corresponding native layer method.
965 onManageLocalDestinationsActivated_: function() {
966 this.nativeLayer_.startManageLocalDestinations();
970 * Called when the user wants to sign in to Google Cloud Print. Calls the
971 * corresponding native layer event.
972 * @param {boolean} addAccount Whether to open an 'add a new account' or
973 * default sign in page.
976 onCloudPrintSignInActivated_: function(addAccount) {
977 this.nativeLayer_.startCloudPrintSignIn(addAccount);
981 * Updates printing options according to source document presets.
982 * @param {Event} event Contains options from source document.
985 onPrintPresetOptionsFromDocument_: function(event) {
986 if (event.optionsFromDocument.disableScaling) {
987 this.printTicketStore_.fitToPage.updateValue(null);
988 this.documentInfo_.updateIsScalingDisabled(true);
991 if (event.optionsFromDocument.copies > 0 &&
992 this.printTicketStore_.copies.isCapabilityAvailable()) {
993 this.printTicketStore_.copies.updateValue(
994 event.optionsFromDocument.copies);
997 if (event.optionsFromDocument.duplex >= 0 &&
998 this.printTicketStore_.duplex.isCapabilityAvailable()) {
999 this.printTicketStore_.duplex.updateValue(
1000 event.optionsFromDocument.duplex);
1005 * Called when privet printing fails.
1006 * @param {Event} event Event object representing the failure.
1009 onPrivetPrintFailed_: function(event) {
1010 console.error('Privet printing failed with error code ' +
1012 this.printHeader_.setErrorMessage(
1013 loadTimeData.getString('couldNotPrint'));
1017 * Called when the print preview settings need to be changed for testing.
1018 * @param {Event} event Event object that contains the option that is to
1019 * be changed and what to set that option.
1022 onManipulateSettingsForTest_: function(event) {
1024 /** @type {print_preview.PreviewSettings} */(event.settings);
1025 if ('selectSaveAsPdfDestination' in settings) {
1026 this.saveAsPdfForTest_(); // No parameters.
1027 } else if ('layoutSettings' in settings) {
1028 this.setLayoutSettingsForTest_(settings.layoutSettings.portrait);
1029 } else if ('pageRange' in settings) {
1030 this.setPageRangeForTest_(settings.pageRange);
1031 } else if ('headersAndFooters' in settings) {
1032 this.setHeadersAndFootersForTest_(settings.headersAndFooters);
1033 } else if ('backgroundColorsAndImages' in settings) {
1034 this.setBackgroundColorsAndImagesForTest_(
1035 settings.backgroundColorsAndImages);
1036 } else if ('margins' in settings) {
1037 this.setMarginsForTest_(settings.margins);
1042 * Called by onManipulateSettingsForTest_(). Sets the print destination
1046 saveAsPdfForTest_: function() {
1047 if (this.destinationStore_.selectedDestination &&
1048 print_preview.Destination.GooglePromotedId.SAVE_AS_PDF ==
1049 this.destinationStore_.selectedDestination.id) {
1050 this.nativeLayer_.previewReadyForTest();
1054 var destinations = this.destinationStore_.destinations();
1055 var pdfDestination = null;
1056 for (var i = 0; i < destinations.length; i++) {
1057 if (destinations[i].id ==
1058 print_preview.Destination.GooglePromotedId.SAVE_AS_PDF) {
1059 pdfDestination = destinations[i];
1065 this.destinationStore_.selectDestination(pdfDestination);
1067 this.nativeLayer_.previewFailedForTest();
1071 * Called by onManipulateSettingsForTest_(). Sets the layout settings to
1072 * either portrait or landscape.
1073 * @param {boolean} portrait Whether to use portrait page layout;
1074 * if false: landscape.
1077 setLayoutSettingsForTest_: function(portrait) {
1078 var combobox = document.querySelector('.layout-settings-select');
1079 if (combobox.value == 'portrait') {
1080 this.nativeLayer_.previewReadyForTest();
1082 combobox.value = 'landscape';
1083 this.layoutSettings_.onSelectChange_();
1088 * Called by onManipulateSettingsForTest_(). Sets the page range for
1089 * for the print preview settings.
1090 * @param {string} pageRange Sets the page range to the desired value(s).
1091 * Ex: "1-5,9" means pages 1 through 5 and page 9 will be printed.
1094 setPageRangeForTest_: function(pageRange) {
1095 var textbox = document.querySelector('.page-settings-custom-input');
1096 if (textbox.value == pageRange) {
1097 this.nativeLayer_.previewReadyForTest();
1099 textbox.value = pageRange;
1100 document.querySelector('.page-settings-custom-radio').click();
1105 * Called by onManipulateSettings_(). Checks or unchecks the headers and
1106 * footers option on print preview.
1107 * @param {boolean} headersAndFooters Whether the "Headers and Footers"
1108 * checkbox should be checked.
1111 setHeadersAndFootersForTest_: function(headersAndFooters) {
1112 var checkbox = document.querySelector('.header-footer-checkbox');
1113 if (headersAndFooters == checkbox.checked)
1114 this.nativeLayer_.previewReadyForTest();
1120 * Called by onManipulateSettings_(). Checks or unchecks the background
1121 * colors and images option on print preview.
1122 * @param {boolean} backgroundColorsAndImages If true, the checkbox should
1123 * be checked. Otherwise it should be unchecked.
1126 setBackgroundColorsAndImagesForTest_: function(backgroundColorsAndImages) {
1127 var checkbox = document.querySelector('.css-background-checkbox');
1128 if (backgroundColorsAndImages == checkbox.checked)
1129 this.nativeLayer_.previewReadyForTest();
1135 * Called by onManipulateSettings_(). Sets the margin settings
1136 * that are desired. Custom margin settings aren't currently supported.
1137 * @param {number} margins The desired margins combobox index. Must be
1138 * a valid index or else the test fails.
1141 setMarginsForTest_: function(margins) {
1142 var combobox = document.querySelector('.margin-settings-select');
1143 if (margins == combobox.selectedIndex) {
1144 this.nativeLayer_.previewReadyForTest();
1145 } else if (margins >= 0 && margins < combobox.length) {
1146 combobox.selectedIndex = margins;
1147 this.marginSettings_.onSelectChange_();
1149 this.nativeLayer_.previewFailedForTest();
1154 * Returns true if "Print using system dialog" link should be shown for
1155 * current destination.
1156 * @return {boolean} Returns true if link should be shown.
1158 shouldShowSystemDialogLink_: function() {
1159 if (cr.isChromeOS || this.hideSystemDialogLink_)
1163 var selectedDest = this.destinationStore_.selectedDestination;
1164 return !!selectedDest &&
1165 selectedDest.origin == print_preview.Destination.Origin.LOCAL &&
1167 print_preview.Destination.GooglePromotedId.SAVE_AS_PDF;
1171 * Called when a print destination is selected. Shows/hides the "Print with
1172 * Cloud Print" link in the navbar.
1175 onDestinationSelect_: function() {
1176 if ($('system-dialog-link')) {
1177 setIsVisible($('system-dialog-link'),
1178 this.shouldShowSystemDialogLink_());
1180 if (this.destinationStore_.selectedDestination &&
1181 this.isInKioskAutoPrintMode_) {
1182 this.onPrintButtonClick_();
1187 * Called when the destination store loads a group of destinations. Shows
1188 * a promo on Chrome OS if the user has no print destinations promoting
1189 * Google Cloud Print.
1192 onDestinationSearchDone_: function() {
1193 var isPromoVisible = cr.isChromeOS &&
1194 this.cloudPrintInterface_ &&
1195 this.userInfo_.activeUser &&
1196 !this.appState_.isGcpPromoDismissed &&
1197 !this.destinationStore_.isLocalDestinationSearchInProgress &&
1198 !this.destinationStore_.isCloudDestinationSearchInProgress &&
1199 this.destinationStore_.hasOnlyDefaultCloudDestinations();
1200 setIsVisible(this.getChildElement('#no-destinations-promo'),
1202 if (isPromoVisible) {
1203 new print_preview.GcpPromoMetricsContext().record(
1204 print_preview.Metrics.GcpPromoBucket.PROMO_SHOWN);
1209 * Called when the close button on the no-destinations-promotion is clicked.
1210 * Hides the promotion.
1213 onNoDestinationsPromoClose_: function() {
1214 new print_preview.GcpPromoMetricsContext().record(
1215 print_preview.Metrics.GcpPromoBucket.PROMO_CLOSED);
1216 setIsVisible(this.getChildElement('#no-destinations-promo'), false);
1217 this.appState_.persistIsGcpPromoDismissed(true);
1221 * Called when the no-destinations promotion link is clicked. Opens the
1222 * Google Cloud Print management page and closes the print preview.
1225 onNoDestinationsPromoClick_: function() {
1226 new print_preview.GcpPromoMetricsContext().record(
1227 print_preview.Metrics.GcpPromoBucket.PROMO_CLICKED);
1228 this.appState_.persistIsGcpPromoDismissed(true);
1229 window.open(this.cloudPrintInterface_.baseUrl + '?user=' +
1230 this.userInfo_.activeUser + '#printers');
1237 PrintPreview: PrintPreview
1241 // Pull in all other scripts in a single shot.
1242 <include src="common/overlay.js">
1243 <include src="common/search_box.js">
1244 <include src="common/search_bubble.js">
1246 <include src="data/page_number_set.js">
1247 <include src="data/destination.js">
1248 <include src="data/local_parsers.js">
1249 <include src="data/cloud_parsers.js">
1250 <include src="data/destination_store.js">
1251 <include src="data/invitation.js">
1252 <include src="data/invitation_store.js">
1253 <include src="data/margins.js">
1254 <include src="data/document_info.js">
1255 <include src="data/printable_area.js">
1256 <include src="data/measurement_system.js">
1257 <include src="data/print_ticket_store.js">
1258 <include src="data/coordinate2d.js">
1259 <include src="data/size.js">
1260 <include src="data/capabilities_holder.js">
1261 <include src="data/user_info.js">
1262 <include src="data/app_state.js">
1264 <include src="data/ticket_items/ticket_item.js">
1266 <include src="data/ticket_items/custom_margins.js">
1267 <include src="data/ticket_items/collate.js">
1268 <include src="data/ticket_items/color.js">
1269 <include src="data/ticket_items/copies.js">
1270 <include src="data/ticket_items/dpi.js">
1271 <include src="data/ticket_items/duplex.js">
1272 <include src="data/ticket_items/header_footer.js">
1273 <include src="data/ticket_items/media_size.js">
1274 <include src="data/ticket_items/landscape.js">
1275 <include src="data/ticket_items/margins_type.js">
1276 <include src="data/ticket_items/page_range.js">
1277 <include src="data/ticket_items/fit_to_page.js">
1278 <include src="data/ticket_items/css_background.js">
1279 <include src="data/ticket_items/selection_only.js">
1280 <include src="data/ticket_items/vendor_items.js">
1282 <include src="native_layer.js">
1283 <include src="print_preview_animations.js">
1284 <include src="cloud_print_interface.js">
1285 <include src="print_preview_utils.js">
1286 <include src="print_header.js">
1287 <include src="metrics.js">
1289 <include src="settings/settings_section.js">
1290 <include src="settings/settings_section_select.js">
1291 <include src="settings/page_settings.js">
1292 <include src="settings/copies_settings.js">
1293 <include src="settings/dpi_settings.js">
1294 <include src="settings/media_size_settings.js">
1295 <include src="settings/layout_settings.js">
1296 <include src="settings/color_settings.js">
1297 <include src="settings/margin_settings.js">
1298 <include src="settings/destination_settings.js">
1299 <include src="settings/other_options_settings.js">
1300 <include src="settings/advanced_options_settings.js">
1301 <include src="settings/advanced_settings/advanced_settings.js">
1302 <include src="settings/advanced_settings/advanced_settings_item.js">
1303 <include src="settings/more_settings.js">
1305 <include src="previewarea/margin_control.js">
1306 <include src="previewarea/margin_control_container.js">
1307 <include src="../pdf/pdf_scripting_api.js">
1308 <include src="previewarea/preview_area.js">
1309 <include src="preview_generator.js">
1311 <include src="search/destination_list.js">
1312 <include src="search/cloud_destination_list.js">
1313 <include src="search/recent_destination_list.js">
1314 <include src="search/destination_list_item.js">
1315 <include src="search/destination_search.js">
1316 <include src="search/fedex_tos.js">
1317 <include src="search/provisional_destination_resolver.js">
1319 window.addEventListener('DOMContentLoaded', function() {
1320 printPreview = new print_preview.PrintPreview();
1321 printPreview.initialize();