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.printTicketStore_.distillPage);
174 this.addChild(this.otherOptionsSettings_);
177 * Component that renders the advanced options button.
178 * @type {!print_preview.AdvancedOptionsSettings}
181 this.advancedOptionsSettings_ = new print_preview.AdvancedOptionsSettings(
182 this.printTicketStore_.vendorItems, this.destinationStore_);
183 this.addChild(this.advancedOptionsSettings_);
186 * Component used to search for print destinations.
187 * @type {!print_preview.AdvancedSettings}
190 this.advancedSettings_ = new print_preview.AdvancedSettings(
191 this.printTicketStore_);
192 this.addChild(this.advancedSettings_);
194 var settingsSections = [
195 this.destinationSettings_,
197 this.copiesSettings_,
198 this.mediaSizeSettings_,
199 this.layoutSettings_,
200 this.marginSettings_,
203 this.otherOptionsSettings_,
204 this.advancedOptionsSettings_];
206 * Component representing more/less settings button.
207 * @type {!print_preview.MoreSettings}
210 this.moreSettings_ = new print_preview.MoreSettings(
211 this.destinationStore_, settingsSections);
212 this.addChild(this.moreSettings_);
215 * Area of the UI that holds the print preview.
216 * @type {!print_preview.PreviewArea}
219 this.previewArea_ = new print_preview.PreviewArea(this.destinationStore_,
220 this.printTicketStore_,
223 this.addChild(this.previewArea_);
226 * Interface to the Google Cloud Print API. Null if Google Cloud Print
227 * integration is disabled.
228 * @type {cloudprint.CloudPrintInterface}
231 this.cloudPrintInterface_ = null;
234 * Whether in kiosk mode where print preview can print automatically without
235 * user intervention. See http://crbug.com/31395. Print will start when
236 * both the print ticket has been initialized, and an initial printer has
241 this.isInKioskAutoPrintMode_ = false;
244 * Whether Print Preview is in App Kiosk mode, basically, use only printers
245 * available for the device.
249 this.isInAppKioskMode_ = false;
252 * Whether Print with System Dialog link should be hidden. Overrides the
253 * default rules for System dialog link visibility.
257 this.hideSystemDialogLink_ = true;
260 * State of the print preview UI.
261 * @type {print_preview.PrintPreview.UiState_}
264 this.uiState_ = PrintPreview.UiState_.INITIALIZING;
267 * Whether document preview generation is in progress.
271 this.isPreviewGenerationInProgress_ = true;
274 * Whether to show system dialog before next printing.
278 this.showSystemDialogBeforeNextPrint_ = false;
282 * States of the print preview.
286 PrintPreview.UiState_ = {
287 INITIALIZING: 'initializing',
289 OPENING_PDF_PREVIEW: 'opening-pdf-preview',
290 OPENING_NATIVE_PRINT_DIALOG: 'opening-native-print-dialog',
291 PRINTING: 'printing',
292 FILE_SELECTION: 'file-selection',
298 * What can happen when print preview tries to print.
302 PrintPreview.PrintAttemptResult_ = {
303 NOT_READY: 'not-ready',
305 READY_WAITING_FOR_PREVIEW: 'ready-waiting-for-preview'
308 PrintPreview.prototype = {
309 __proto__: print_preview.Component.prototype,
311 /** Sets up the page and print preview by getting the printer list. */
312 initialize: function() {
313 this.decorate($('print-preview'));
314 if (!this.previewArea_.hasCompatiblePlugin) {
315 this.setIsEnabled_(false);
317 this.nativeLayer_.startGetInitialSettings();
318 print_preview.PrintPreviewFocusManager.getInstance().initialize();
319 cr.ui.FocusOutlineManager.forDocument(document);
323 enterDocument: function() {
324 // Native layer events.
327 print_preview.NativeLayer.EventType.INITIAL_SETTINGS_SET,
328 this.onInitialSettingsSet_.bind(this));
331 print_preview.NativeLayer.EventType.CLOUD_PRINT_ENABLE,
332 this.onCloudPrintEnable_.bind(this));
335 print_preview.NativeLayer.EventType.PRINT_TO_CLOUD,
336 this.onPrintToCloud_.bind(this));
339 print_preview.NativeLayer.EventType.FILE_SELECTION_CANCEL,
340 this.onFileSelectionCancel_.bind(this));
343 print_preview.NativeLayer.EventType.FILE_SELECTION_COMPLETE,
344 this.onFileSelectionComplete_.bind(this));
347 print_preview.NativeLayer.EventType.SETTINGS_INVALID,
348 this.onSettingsInvalid_.bind(this));
351 print_preview.NativeLayer.EventType.PRINT_PRESET_OPTIONS,
352 this.onPrintPresetOptionsFromDocument_.bind(this));
355 print_preview.NativeLayer.EventType.PRIVET_PRINT_FAILED,
356 this.onPrivetPrintFailed_.bind(this));
359 print_preview.NativeLayer.EventType.MANIPULATE_SETTINGS_FOR_TEST,
360 this.onManipulateSettingsForTest_.bind(this));
363 print_preview.NativeLayer.EventType.ALLOW_DISTILL_PAGE,
364 this.onAllowDistillPage_.bind(this));
366 if ($('system-dialog-link')) {
368 $('system-dialog-link'),
370 this.openSystemPrintDialog_.bind(this));
372 if ($('open-pdf-in-preview-link')) {
374 $('open-pdf-in-preview-link'),
376 this.onOpenPdfInPreviewLinkClick_.bind(this));
381 print_preview.PreviewArea.EventType.PREVIEW_GENERATION_IN_PROGRESS,
382 this.onPreviewGenerationInProgress_.bind(this));
385 print_preview.PreviewArea.EventType.PREVIEW_GENERATION_DONE,
386 this.onPreviewGenerationDone_.bind(this));
389 print_preview.PreviewArea.EventType.PREVIEW_GENERATION_FAIL,
390 this.onPreviewGenerationFail_.bind(this));
393 print_preview.PreviewArea.EventType.OPEN_SYSTEM_DIALOG_CLICK,
394 this.openSystemPrintDialog_.bind(this));
397 this.destinationStore_,
398 print_preview.DestinationStore.EventType.
399 SELECTED_DESTINATION_CAPABILITIES_READY,
400 this.printIfReady_.bind(this));
402 this.destinationStore_,
403 print_preview.DestinationStore.EventType.DESTINATION_SELECT,
404 this.onDestinationSelect_.bind(this));
406 this.destinationStore_,
407 print_preview.DestinationStore.EventType.DESTINATION_SEARCH_DONE,
408 this.onDestinationSearchDone_.bind(this));
412 print_preview.PrintHeader.EventType.PRINT_BUTTON_CLICK,
413 this.onPrintButtonClick_.bind(this));
416 print_preview.PrintHeader.EventType.CANCEL_BUTTON_CLICK,
417 this.onCancelButtonClick_.bind(this));
419 this.tracker.add(window, 'keydown', this.onKeyDown_.bind(this));
420 this.previewArea_.setPluginKeyEventCallback(this.onKeyDown_.bind(this));
423 this.destinationSettings_,
424 print_preview.DestinationSettings.EventType.CHANGE_BUTTON_ACTIVATE,
425 this.onDestinationChangeButtonActivate_.bind(this));
428 this.destinationSearch_,
429 print_preview.DestinationSearch.EventType.MANAGE_CLOUD_DESTINATIONS,
430 this.onManageCloudDestinationsActivated_.bind(this));
432 this.destinationSearch_,
433 print_preview.DestinationSearch.EventType.MANAGE_LOCAL_DESTINATIONS,
434 this.onManageLocalDestinationsActivated_.bind(this));
436 this.destinationSearch_,
437 print_preview.DestinationSearch.EventType.ADD_ACCOUNT,
438 this.onCloudPrintSignInActivated_.bind(this, true /*addAccount*/));
440 this.destinationSearch_,
441 print_preview.DestinationSearch.EventType.SIGN_IN,
442 this.onCloudPrintSignInActivated_.bind(this, false /*addAccount*/));
444 this.destinationSearch_,
445 print_preview.DestinationListItem.EventType.REGISTER_PROMO_CLICKED,
446 this.onCloudPrintRegisterPromoClick_.bind(this));
449 this.advancedOptionsSettings_,
450 print_preview.AdvancedOptionsSettings.EventType.BUTTON_ACTIVATED,
451 this.onAdvancedOptionsButtonActivated_.bind(this));
453 // TODO(rltoscano): Move no-destinations-promo into its own component
454 // instead being part of PrintPreview.
456 this.getChildElement('#no-destinations-promo .close-button'),
458 this.onNoDestinationsPromoClose_.bind(this));
460 this.getChildElement('#no-destinations-promo .not-now-button'),
462 this.onNoDestinationsPromoClose_.bind(this));
464 this.getChildElement('#no-destinations-promo .add-printer-button'),
466 this.onNoDestinationsPromoClick_.bind(this));
470 decorateInternal: function() {
471 this.printHeader_.decorate($('print-header'));
472 this.destinationSearch_.decorate($('destination-search'));
473 this.destinationSettings_.decorate($('destination-settings'));
474 this.pageSettings_.decorate($('page-settings'));
475 this.copiesSettings_.decorate($('copies-settings'));
476 this.mediaSizeSettings_.decorate($('media-size-settings'));
477 this.layoutSettings_.decorate($('layout-settings'));
478 this.colorSettings_.decorate($('color-settings'));
479 this.marginSettings_.decorate($('margin-settings'));
480 this.dpiSettings_.decorate($('dpi-settings'));
481 this.otherOptionsSettings_.decorate($('other-options-settings'));
482 this.advancedOptionsSettings_.decorate($('advanced-options-settings'));
483 this.advancedSettings_.decorate($('advanced-settings'));
484 this.moreSettings_.decorate($('more-settings'));
485 this.previewArea_.decorate($('preview-area'));
489 * Sets whether the controls in the print preview are enabled.
490 * @param {boolean} isEnabled Whether the controls in the print preview are
494 setIsEnabled_: function(isEnabled) {
495 if ($('system-dialog-link'))
496 $('system-dialog-link').classList.toggle('disabled', !isEnabled);
497 if ($('open-pdf-in-preview-link'))
498 $('open-pdf-in-preview-link').classList.toggle('disabled', !isEnabled);
499 this.printHeader_.isEnabled = isEnabled;
500 this.destinationSettings_.isEnabled = isEnabled;
501 this.pageSettings_.isEnabled = isEnabled;
502 this.copiesSettings_.isEnabled = isEnabled;
503 this.mediaSizeSettings_.isEnabled = isEnabled;
504 this.layoutSettings_.isEnabled = isEnabled;
505 this.colorSettings_.isEnabled = isEnabled;
506 this.marginSettings_.isEnabled = isEnabled;
507 this.dpiSettings_.isEnabled = isEnabled;
508 this.otherOptionsSettings_.isEnabled = isEnabled;
509 this.advancedOptionsSettings_.isEnabled = isEnabled;
513 * Prints the document or launches a pdf preview on the local system.
514 * @param {boolean} isPdfPreview Whether to launch the pdf preview.
517 printDocumentOrOpenPdfPreview_: function(isPdfPreview) {
518 assert(this.uiState_ == PrintPreview.UiState_.READY,
519 'Print document request received when not in ready state: ' +
522 this.uiState_ = PrintPreview.UiState_.OPENING_PDF_PREVIEW;
523 } else if (this.destinationStore_.selectedDestination.id ==
524 print_preview.Destination.GooglePromotedId.SAVE_AS_PDF) {
525 this.uiState_ = PrintPreview.UiState_.FILE_SELECTION;
527 this.uiState_ = PrintPreview.UiState_.PRINTING;
529 this.setIsEnabled_(false);
530 this.printHeader_.isCancelButtonEnabled = true;
531 var printAttemptResult = this.printIfReady_();
532 if (printAttemptResult == PrintPreview.PrintAttemptResult_.PRINTED ||
533 printAttemptResult ==
534 PrintPreview.PrintAttemptResult_.READY_WAITING_FOR_PREVIEW) {
535 if ((this.destinationStore_.selectedDestination.isLocal &&
536 !this.destinationStore_.selectedDestination.isPrivet &&
537 !this.destinationStore_.selectedDestination.isExtension &&
538 this.destinationStore_.selectedDestination.id !=
539 print_preview.Destination.GooglePromotedId.SAVE_AS_PDF) ||
540 this.uiState_ == PrintPreview.UiState_.OPENING_PDF_PREVIEW) {
541 // Hide the dialog for now. The actual print command will be issued
542 // when the preview generation is done.
543 this.nativeLayer_.startHideDialog();
549 * Attempts to print if needed and if ready.
550 * @return {PrintPreview.PrintAttemptResult_} Attempt result.
553 printIfReady_: function() {
555 (this.uiState_ == PrintPreview.UiState_.PRINTING ||
556 this.uiState_ == PrintPreview.UiState_.OPENING_PDF_PREVIEW ||
557 this.uiState_ == PrintPreview.UiState_.FILE_SELECTION ||
558 this.isInKioskAutoPrintMode_) &&
559 this.destinationStore_.selectedDestination &&
560 this.destinationStore_.selectedDestination.capabilities;
562 return PrintPreview.PrintAttemptResult_.NOT_READY;
564 if (this.isPreviewGenerationInProgress_) {
565 return PrintPreview.PrintAttemptResult_.READY_WAITING_FOR_PREVIEW;
567 assert(this.printTicketStore_.isTicketValid(),
568 'Trying to print with invalid ticket');
569 if (getIsVisible(this.moreSettings_.getElement())) {
570 new print_preview.PrintSettingsUiMetricsContext().record(
571 this.moreSettings_.isExpanded ?
572 print_preview.Metrics.PrintSettingsUiBucket.
573 PRINT_WITH_SETTINGS_EXPANDED :
574 print_preview.Metrics.PrintSettingsUiBucket.
575 PRINT_WITH_SETTINGS_COLLAPSED);
577 this.nativeLayer_.startPrint(
578 this.destinationStore_.selectedDestination,
579 this.printTicketStore_,
580 this.cloudPrintInterface_,
582 this.uiState_ == PrintPreview.UiState_.OPENING_PDF_PREVIEW,
583 this.showSystemDialogBeforeNextPrint_);
584 this.showSystemDialogBeforeNextPrint_ = false;
585 return PrintPreview.PrintAttemptResult_.PRINTED;
589 * Closes the print preview.
594 this.uiState_ = PrintPreview.UiState_.CLOSING;
595 this.nativeLayer_.startCloseDialog();
599 * Opens the native system print dialog after disabling all controls.
602 openSystemPrintDialog_: function() {
603 if (!this.shouldShowSystemDialogLink_())
605 if ($('system-dialog-link').classList.contains('disabled'))
608 this.showSystemDialogBeforeNextPrint_ = true;
609 this.printDocumentOrOpenPdfPreview_(false /*isPdfPreview*/);
612 setIsVisible(getRequiredElement('system-dialog-throbber'), true);
613 this.setIsEnabled_(false);
614 this.uiState_ = PrintPreview.UiState_.OPENING_NATIVE_PRINT_DIALOG;
615 this.nativeLayer_.startShowSystemDialog();
619 * Called when the native layer has initial settings to set. Sets the
620 * initial settings of the print preview and begins fetching print
622 * @param {Event} event Contains the initial print preview settings
623 * persisted through the session.
626 onInitialSettingsSet_: function(event) {
627 assert(this.uiState_ == PrintPreview.UiState_.INITIALIZING,
628 'Updating initial settings when not in initializing state: ' +
630 this.uiState_ = PrintPreview.UiState_.READY;
632 var settings = event.initialSettings;
633 this.isInKioskAutoPrintMode_ = settings.isInKioskAutoPrintMode;
634 this.isInAppKioskMode_ = settings.isInAppKioskMode;
636 // The following components must be initialized in this order.
638 settings.serializedAppStateStr,
639 settings.systemDefaultDestinationId);
640 this.documentInfo_.init(
641 settings.isDocumentModifiable,
642 settings.documentTitle,
643 settings.documentHasSelection);
644 this.printTicketStore_.init(
645 settings.thousandsDelimeter,
646 settings.decimalDelimeter,
648 settings.selectionOnly);
649 this.destinationStore_.init(settings.isInAppKioskMode);
650 this.appState_.setInitialized();
652 $('document-title').innerText = settings.documentTitle;
653 this.hideSystemDialogLink_ = settings.hidePrintWithSystemDialogLink ||
654 settings.isInAppKioskMode;
655 if ($('system-dialog-link')) {
656 setIsVisible($('system-dialog-link'),
657 this.shouldShowSystemDialogLink_());
662 * Calls when the native layer enables Google Cloud Print integration.
663 * Fetches the user's cloud printers.
664 * @param {Event} event Contains the base URL of the Google Cloud Print
668 onCloudPrintEnable_: function(event) {
669 this.cloudPrintInterface_ = new cloudprint.CloudPrintInterface(
670 event.baseCloudPrintUrl,
675 this.cloudPrintInterface_,
676 cloudprint.CloudPrintInterface.EventType.SUBMIT_DONE,
677 this.onCloudPrintSubmitDone_.bind(this));
679 this.cloudPrintInterface_,
680 cloudprint.CloudPrintInterface.EventType.SEARCH_FAILED,
681 this.onCloudPrintError_.bind(this));
683 this.cloudPrintInterface_,
684 cloudprint.CloudPrintInterface.EventType.SUBMIT_FAILED,
685 this.onCloudPrintError_.bind(this));
687 this.cloudPrintInterface_,
688 cloudprint.CloudPrintInterface.EventType.PRINTER_FAILED,
689 this.onCloudPrintError_.bind(this));
691 this.cloudPrintInterface_,
692 cloudprint.CloudPrintInterface.EventType.
693 UPDATE_PRINTER_TOS_ACCEPTANCE_FAILED,
694 this.onCloudPrintError_.bind(this));
696 this.destinationStore_.setCloudPrintInterface(this.cloudPrintInterface_);
697 this.invitationStore_.setCloudPrintInterface(this.cloudPrintInterface_);
698 if (this.destinationSearch_.getIsVisible()) {
699 this.destinationStore_.startLoadCloudDestinations();
700 this.invitationStore_.startLoadingInvitations();
705 * Called from the native layer when ready to print to Google Cloud Print.
706 * @param {Event} event Contains the body to send in the HTTP request.
709 onPrintToCloud_: function(event) {
710 assert(this.uiState_ == PrintPreview.UiState_.PRINTING,
711 'Document ready to be sent to the cloud when not in printing ' +
712 'state: ' + this.uiState_);
713 assert(this.cloudPrintInterface_ != null,
714 'Google Cloud Print is not enabled');
715 this.cloudPrintInterface_.submit(
716 this.destinationStore_.selectedDestination,
717 this.printTicketStore_,
723 * Called from the native layer when the user cancels the save-to-pdf file
727 onFileSelectionCancel_: function() {
728 assert(this.uiState_ == PrintPreview.UiState_.FILE_SELECTION,
729 'File selection cancelled when not in file-selection state: ' +
731 this.setIsEnabled_(true);
732 this.uiState_ = PrintPreview.UiState_.READY;
736 * Called from the native layer when save-to-pdf file selection is complete.
739 onFileSelectionComplete_: function() {
740 assert(this.uiState_ == PrintPreview.UiState_.FILE_SELECTION,
741 'File selection completed when not in file-selection state: ' +
743 this.previewArea_.showCustomMessage(
744 loadTimeData.getString('printingToPDFInProgress'));
745 this.uiState_ = PrintPreview.UiState_.PRINTING;
749 * Called after successfully submitting a job to Google Cloud Print.
750 * @param {!Event} event Contains the ID of the submitted print job.
753 onCloudPrintSubmitDone_: function(event) {
754 assert(this.uiState_ == PrintPreview.UiState_.PRINTING,
755 'Submited job to Google Cloud Print but not in printing state ' +
757 if (this.destinationStore_.selectedDestination.id ==
758 print_preview.Destination.GooglePromotedId.FEDEX) {
759 this.nativeLayer_.startForceOpenNewTab(
760 'https://www.google.com/cloudprint/fedexcode.html?jobid=' +
767 * Called when there was an error communicating with Google Cloud print.
768 * Displays an error message in the print header.
769 * @param {!Event} event Contains the error message.
772 onCloudPrintError_: function(event) {
773 if (event.status == 403) {
774 if (!this.isInAppKioskMode_) {
775 this.destinationSearch_.showCloudPrintPromo();
777 } else if (event.status == 0) {
778 return; // Ignore, the system does not have internet connectivity.
780 this.printHeader_.setErrorMessage(event.message);
782 if (event.status == 200) {
783 console.error('Google Cloud Print Error: (' + event.errorCode + ') ' +
786 console.error('Google Cloud Print Error: HTTP status ' + event.status);
791 * Called when the preview area's preview generation is in progress.
794 onPreviewGenerationInProgress_: function() {
795 this.isPreviewGenerationInProgress_ = true;
799 * Called when the preview area's preview generation is complete.
802 onPreviewGenerationDone_: function() {
803 this.isPreviewGenerationInProgress_ = false;
804 this.printHeader_.isPrintButtonEnabled = true;
805 this.nativeLayer_.previewReadyForTest();
806 this.printIfReady_();
810 * Called when the preview area's preview failed to load.
813 onPreviewGenerationFail_: function() {
814 this.isPreviewGenerationInProgress_ = false;
815 this.printHeader_.isPrintButtonEnabled = false;
816 if (this.uiState_ == PrintPreview.UiState_.PRINTING)
817 this.nativeLayer_.startCancelPendingPrint();
821 * Called when the 'Open pdf in preview' link is clicked. Launches the pdf
825 onOpenPdfInPreviewLinkClick_: function() {
826 if ($('open-pdf-in-preview-link').classList.contains('disabled'))
828 assert(this.uiState_ == PrintPreview.UiState_.READY,
829 'Trying to open pdf in preview when not in ready state: ' +
831 setIsVisible(getRequiredElement('open-preview-app-throbber'), true);
832 this.previewArea_.showCustomMessage(
833 loadTimeData.getString('openingPDFInPreview'));
834 this.printDocumentOrOpenPdfPreview_(true /*isPdfPreview*/);
838 * Called when the print header's print button is clicked. Prints the
842 onPrintButtonClick_: function() {
843 assert(this.uiState_ == PrintPreview.UiState_.READY,
844 'Trying to print when not in ready state: ' + this.uiState_);
845 this.printDocumentOrOpenPdfPreview_(false /*isPdfPreview*/);
849 * Called when the print header's cancel button is clicked. Closes the
853 onCancelButtonClick_: function() {
858 * Called when the register promo for Cloud Print is clicked.
861 onCloudPrintRegisterPromoClick_: function(e) {
862 var devicesUrl = 'chrome://devices/register?id=' + e.destination.id;
863 this.nativeLayer_.startForceOpenNewTab(devicesUrl);
864 this.destinationStore_.waitForRegister(e.destination.id);
868 * Consume escape key presses and ctrl + shift + p. Delegate everything else
869 * to the preview area.
870 * @param {KeyboardEvent} e The keyboard event.
872 * @suppress {uselessCode}
873 * Current compiler preprocessor leaves all the code inside all the <if>s,
874 * so the compiler claims that code after first return is unreachable.
876 onKeyDown_: function(e) {
877 // Escape key closes the dialog.
878 if (e.keyCode == 27 && !e.shiftKey && !e.ctrlKey && !e.altKey &&
880 // On non-mac with toolkit-views, ESC key is handled by C++-side instead
889 // On Mac, Cmd- should close the print dialog.
890 if (cr.isMac && e.keyCode == 189 && e.metaKey) {
896 // Ctrl + Shift + p / Mac equivalent.
897 if (e.keyCode == 80) {
898 if ((cr.isMac && e.metaKey && e.altKey && !e.shiftKey && !e.ctrlKey) ||
899 (!cr.isMac && e.shiftKey && e.ctrlKey && !e.altKey && !e.metaKey)) {
900 this.openSystemPrintDialog_();
906 if (e.keyCode == 13 /*enter*/ &&
907 !document.querySelector('.overlay:not([hidden])') &&
908 this.destinationStore_.selectedDestination &&
909 this.printTicketStore_.isTicketValid() &&
910 this.printHeader_.isPrintButtonEnabled) {
911 assert(this.uiState_ == PrintPreview.UiState_.READY,
912 'Trying to print when not in ready state: ' + this.uiState_);
913 var activeElementTag = document.activeElement.tagName.toUpperCase();
914 if (activeElementTag != 'BUTTON' && activeElementTag != 'SELECT' &&
915 activeElementTag != 'A') {
916 this.printDocumentOrOpenPdfPreview_(false /*isPdfPreview*/);
922 // Pass certain directional keyboard events to the PDF viewer.
923 this.previewArea_.handleDirectionalKeyEvent(e);
927 * Called when native layer receives invalid settings for a print request.
930 onSettingsInvalid_: function() {
931 this.uiState_ = PrintPreview.UiState_.ERROR;
932 console.error('Invalid settings error reported from native layer');
933 this.previewArea_.showCustomMessage(
934 loadTimeData.getString('invalidPrinterSettings'));
938 * Called when the destination settings' change button is activated.
939 * Displays the destination search component.
942 onDestinationChangeButtonActivate_: function() {
943 this.destinationSearch_.setIsVisible(true);
947 * Called when the destination settings' change button is activated.
948 * Displays the destination search component.
951 onAdvancedOptionsButtonActivated_: function() {
952 this.advancedSettings_.showForDestination(
953 assert(this.destinationStore_.selectedDestination));
957 * Called when the destination search dispatches manage cloud destinations
958 * event. Calls corresponding native layer method.
961 onManageCloudDestinationsActivated_: function() {
962 this.nativeLayer_.startManageCloudDestinations(this.userInfo_.activeUser);
966 * Called when the destination search dispatches manage local destinations
967 * event. Calls corresponding native layer method.
970 onManageLocalDestinationsActivated_: function() {
971 this.nativeLayer_.startManageLocalDestinations();
975 * Called when the user wants to sign in to Google Cloud Print. Calls the
976 * corresponding native layer event.
977 * @param {boolean} addAccount Whether to open an 'add a new account' or
978 * default sign in page.
981 onCloudPrintSignInActivated_: function(addAccount) {
982 this.nativeLayer_.startCloudPrintSignIn(addAccount);
986 * Updates printing options according to source document presets.
987 * @param {Event} event Contains options from source document.
990 onPrintPresetOptionsFromDocument_: function(event) {
991 if (event.optionsFromDocument.disableScaling) {
992 this.printTicketStore_.fitToPage.updateValue(null);
993 this.documentInfo_.updateIsScalingDisabled(true);
996 if (event.optionsFromDocument.copies > 0 &&
997 this.printTicketStore_.copies.isCapabilityAvailable()) {
998 this.printTicketStore_.copies.updateValue(
999 event.optionsFromDocument.copies);
1002 if (event.optionsFromDocument.duplex >= 0 &&
1003 this.printTicketStore_.duplex.isCapabilityAvailable()) {
1004 this.printTicketStore_.duplex.updateValue(
1005 event.optionsFromDocument.duplex);
1010 * Called when privet printing fails.
1011 * @param {Event} event Event object representing the failure.
1014 onPrivetPrintFailed_: function(event) {
1015 console.error('Privet printing failed with error code ' +
1017 this.printHeader_.setErrorMessage(
1018 loadTimeData.getString('couldNotPrint'));
1022 * Called when the native layer has detected that the "Distill page"
1023 * option should be allowed.
1026 onAllowDistillPage_: function(event) {
1027 this.printTicketStore_.distillPage.setIsCapabilityAvailable(true);
1031 * Called when the print preview settings need to be changed for testing.
1032 * @param {Event} event Event object that contains the option that is to
1033 * be changed and what to set that option.
1036 onManipulateSettingsForTest_: function(event) {
1038 /** @type {print_preview.PreviewSettings} */(event.settings);
1039 if ('selectSaveAsPdfDestination' in settings) {
1040 this.saveAsPdfForTest_(); // No parameters.
1041 } else if ('layoutSettings' in settings) {
1042 this.setLayoutSettingsForTest_(settings.layoutSettings.portrait);
1043 } else if ('pageRange' in settings) {
1044 this.setPageRangeForTest_(settings.pageRange);
1045 } else if ('headersAndFooters' in settings) {
1046 this.setHeadersAndFootersForTest_(settings.headersAndFooters);
1047 } else if ('backgroundColorsAndImages' in settings) {
1048 this.setBackgroundColorsAndImagesForTest_(
1049 settings.backgroundColorsAndImages);
1050 } else if ('margins' in settings) {
1051 this.setMarginsForTest_(settings.margins);
1056 * Called by onManipulateSettingsForTest_(). Sets the print destination
1060 saveAsPdfForTest_: function() {
1061 if (this.destinationStore_.selectedDestination &&
1062 print_preview.Destination.GooglePromotedId.SAVE_AS_PDF ==
1063 this.destinationStore_.selectedDestination.id) {
1064 this.nativeLayer_.previewReadyForTest();
1068 var destinations = this.destinationStore_.destinations();
1069 var pdfDestination = null;
1070 for (var i = 0; i < destinations.length; i++) {
1071 if (destinations[i].id ==
1072 print_preview.Destination.GooglePromotedId.SAVE_AS_PDF) {
1073 pdfDestination = destinations[i];
1079 this.destinationStore_.selectDestination(pdfDestination);
1081 this.nativeLayer_.previewFailedForTest();
1085 * Called by onManipulateSettingsForTest_(). Sets the layout settings to
1086 * either portrait or landscape.
1087 * @param {boolean} portrait Whether to use portrait page layout;
1088 * if false: landscape.
1091 setLayoutSettingsForTest_: function(portrait) {
1092 var combobox = document.querySelector('.layout-settings-select');
1093 if (combobox.value == 'portrait') {
1094 this.nativeLayer_.previewReadyForTest();
1096 combobox.value = 'landscape';
1097 this.layoutSettings_.onSelectChange_();
1102 * Called by onManipulateSettingsForTest_(). Sets the page range for
1103 * for the print preview settings.
1104 * @param {string} pageRange Sets the page range to the desired value(s).
1105 * Ex: "1-5,9" means pages 1 through 5 and page 9 will be printed.
1108 setPageRangeForTest_: function(pageRange) {
1109 var textbox = document.querySelector('.page-settings-custom-input');
1110 if (textbox.value == pageRange) {
1111 this.nativeLayer_.previewReadyForTest();
1113 textbox.value = pageRange;
1114 document.querySelector('.page-settings-custom-radio').click();
1119 * Called by onManipulateSettings_(). Checks or unchecks the headers and
1120 * footers option on print preview.
1121 * @param {boolean} headersAndFooters Whether the "Headers and Footers"
1122 * checkbox should be checked.
1125 setHeadersAndFootersForTest_: function(headersAndFooters) {
1126 var checkbox = document.querySelector('.header-footer-checkbox');
1127 if (headersAndFooters == checkbox.checked)
1128 this.nativeLayer_.previewReadyForTest();
1134 * Called by onManipulateSettings_(). Checks or unchecks the background
1135 * colors and images option on print preview.
1136 * @param {boolean} backgroundColorsAndImages If true, the checkbox should
1137 * be checked. Otherwise it should be unchecked.
1140 setBackgroundColorsAndImagesForTest_: function(backgroundColorsAndImages) {
1141 var checkbox = document.querySelector('.css-background-checkbox');
1142 if (backgroundColorsAndImages == checkbox.checked)
1143 this.nativeLayer_.previewReadyForTest();
1149 * Called by onManipulateSettings_(). Sets the margin settings
1150 * that are desired. Custom margin settings aren't currently supported.
1151 * @param {number} margins The desired margins combobox index. Must be
1152 * a valid index or else the test fails.
1155 setMarginsForTest_: function(margins) {
1156 var combobox = document.querySelector('.margin-settings-select');
1157 if (margins == combobox.selectedIndex) {
1158 this.nativeLayer_.previewReadyForTest();
1159 } else if (margins >= 0 && margins < combobox.length) {
1160 combobox.selectedIndex = margins;
1161 this.marginSettings_.onSelectChange_();
1163 this.nativeLayer_.previewFailedForTest();
1168 * Returns true if "Print using system dialog" link should be shown for
1169 * current destination.
1170 * @return {boolean} Returns true if link should be shown.
1172 shouldShowSystemDialogLink_: function() {
1173 if (cr.isChromeOS || this.hideSystemDialogLink_)
1177 var selectedDest = this.destinationStore_.selectedDestination;
1178 return !!selectedDest &&
1179 selectedDest.origin == print_preview.Destination.Origin.LOCAL &&
1181 print_preview.Destination.GooglePromotedId.SAVE_AS_PDF;
1185 * Called when a print destination is selected. Shows/hides the "Print with
1186 * Cloud Print" link in the navbar.
1189 onDestinationSelect_: function() {
1190 if ($('system-dialog-link')) {
1191 setIsVisible($('system-dialog-link'),
1192 this.shouldShowSystemDialogLink_());
1194 if (this.destinationStore_.selectedDestination &&
1195 this.isInKioskAutoPrintMode_) {
1196 this.onPrintButtonClick_();
1201 * Called when the destination store loads a group of destinations. Shows
1202 * a promo on Chrome OS if the user has no print destinations promoting
1203 * Google Cloud Print.
1206 onDestinationSearchDone_: function() {
1207 var isPromoVisible = cr.isChromeOS &&
1208 this.cloudPrintInterface_ &&
1209 this.userInfo_.activeUser &&
1210 !this.appState_.isGcpPromoDismissed &&
1211 !this.destinationStore_.isLocalDestinationSearchInProgress &&
1212 !this.destinationStore_.isCloudDestinationSearchInProgress &&
1213 this.destinationStore_.hasOnlyDefaultCloudDestinations();
1214 setIsVisible(this.getChildElement('#no-destinations-promo'),
1216 if (isPromoVisible) {
1217 new print_preview.GcpPromoMetricsContext().record(
1218 print_preview.Metrics.GcpPromoBucket.PROMO_SHOWN);
1223 * Called when the close button on the no-destinations-promotion is clicked.
1224 * Hides the promotion.
1227 onNoDestinationsPromoClose_: function() {
1228 new print_preview.GcpPromoMetricsContext().record(
1229 print_preview.Metrics.GcpPromoBucket.PROMO_CLOSED);
1230 setIsVisible(this.getChildElement('#no-destinations-promo'), false);
1231 this.appState_.persistIsGcpPromoDismissed(true);
1235 * Called when the no-destinations promotion link is clicked. Opens the
1236 * Google Cloud Print management page and closes the print preview.
1239 onNoDestinationsPromoClick_: function() {
1240 new print_preview.GcpPromoMetricsContext().record(
1241 print_preview.Metrics.GcpPromoBucket.PROMO_CLICKED);
1242 this.appState_.persistIsGcpPromoDismissed(true);
1243 window.open(this.cloudPrintInterface_.baseUrl + '?user=' +
1244 this.userInfo_.activeUser + '#printers');
1251 PrintPreview: PrintPreview
1255 // Pull in all other scripts in a single shot.
1256 <include src="common/overlay.js">
1257 <include src="common/search_box.js">
1258 <include src="common/search_bubble.js">
1260 <include src="data/page_number_set.js">
1261 <include src="data/destination.js">
1262 <include src="data/local_parsers.js">
1263 <include src="data/cloud_parsers.js">
1264 <include src="data/destination_store.js">
1265 <include src="data/invitation.js">
1266 <include src="data/invitation_store.js">
1267 <include src="data/margins.js">
1268 <include src="data/document_info.js">
1269 <include src="data/printable_area.js">
1270 <include src="data/measurement_system.js">
1271 <include src="data/print_ticket_store.js">
1272 <include src="data/coordinate2d.js">
1273 <include src="data/size.js">
1274 <include src="data/capabilities_holder.js">
1275 <include src="data/user_info.js">
1276 <include src="data/app_state.js">
1278 <include src="data/ticket_items/ticket_item.js">
1280 <include src="data/ticket_items/custom_margins.js">
1281 <include src="data/ticket_items/collate.js">
1282 <include src="data/ticket_items/color.js">
1283 <include src="data/ticket_items/copies.js">
1284 <include src="data/ticket_items/dpi.js">
1285 <include src="data/ticket_items/duplex.js">
1286 <include src="data/ticket_items/header_footer.js">
1287 <include src="data/ticket_items/distill_page.js">
1288 <include src="data/ticket_items/media_size.js">
1289 <include src="data/ticket_items/landscape.js">
1290 <include src="data/ticket_items/margins_type.js">
1291 <include src="data/ticket_items/page_range.js">
1292 <include src="data/ticket_items/fit_to_page.js">
1293 <include src="data/ticket_items/css_background.js">
1294 <include src="data/ticket_items/selection_only.js">
1295 <include src="data/ticket_items/vendor_items.js">
1297 <include src="native_layer.js">
1298 <include src="print_preview_animations.js">
1299 <include src="cloud_print_interface.js">
1300 <include src="print_preview_utils.js">
1301 <include src="print_header.js">
1302 <include src="metrics.js">
1304 <include src="settings/settings_section.js">
1305 <include src="settings/settings_section_select.js">
1306 <include src="settings/page_settings.js">
1307 <include src="settings/copies_settings.js">
1308 <include src="settings/dpi_settings.js">
1309 <include src="settings/media_size_settings.js">
1310 <include src="settings/layout_settings.js">
1311 <include src="settings/color_settings.js">
1312 <include src="settings/margin_settings.js">
1313 <include src="settings/destination_settings.js">
1314 <include src="settings/other_options_settings.js">
1315 <include src="settings/advanced_options_settings.js">
1316 <include src="settings/advanced_settings/advanced_settings.js">
1317 <include src="settings/advanced_settings/advanced_settings_item.js">
1318 <include src="settings/more_settings.js">
1320 <include src="previewarea/margin_control.js">
1321 <include src="previewarea/margin_control_container.js">
1322 <include src="../pdf/pdf_scripting_api.js">
1323 <include src="previewarea/preview_area.js">
1324 <include src="preview_generator.js">
1326 <include src="search/destination_list.js">
1327 <include src="search/cloud_destination_list.js">
1328 <include src="search/recent_destination_list.js">
1329 <include src="search/destination_list_item.js">
1330 <include src="search/destination_search.js">
1331 <include src="search/fedex_tos.js">
1332 <include src="search/provisional_destination_resolver.js">
1334 window.addEventListener('DOMContentLoaded', function() {
1335 printPreview = new print_preview.PrintPreview();
1336 printPreview.initialize();