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();