[sql] Remove _HAS_EXCEPTIONS=0 from build info.
[chromium-blink-merge.git] / chrome / browser / resources / print_preview / print_preview.js
blob96336e85c6eddb2790f0b579cd45c2df9f335193
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() {
11 'use strict';
13 /**
14 * Container class for Chromium's print preview.
15 * @constructor
16 * @extends {print_preview.Component}
18 function PrintPreview() {
19 print_preview.Component.call(this);
21 /**
22 * Used to communicate with Chromium's print system.
23 * @type {!print_preview.NativeLayer}
24 * @private
26 this.nativeLayer_ = new print_preview.NativeLayer();
28 /**
29 * Event target that contains information about the logged in user.
30 * @type {!print_preview.UserInfo}
31 * @private
33 this.userInfo_ = new print_preview.UserInfo();
35 /**
36 * Application state.
37 * @type {!print_preview.AppState}
38 * @private
40 this.appState_ = new print_preview.AppState();
42 /**
43 * Data model that holds information about the document to print.
44 * @type {!print_preview.DocumentInfo}
45 * @private
47 this.documentInfo_ = new print_preview.DocumentInfo();
49 /**
50 * Data store which holds print destinations.
51 * @type {!print_preview.DestinationStore}
52 * @private
54 this.destinationStore_ = new print_preview.DestinationStore(
55 this.nativeLayer_, this.userInfo_, this.appState_);
57 /**
58 * Data store which holds printer sharing invitations.
59 * @type {!print_preview.InvitationStore}
60 * @private
62 this.invitationStore_ = new print_preview.InvitationStore(this.userInfo_);
64 /**
65 * Storage of the print ticket used to create the print job.
66 * @type {!print_preview.PrintTicketStore}
67 * @private
69 this.printTicketStore_ = new print_preview.PrintTicketStore(
70 this.destinationStore_, this.appState_, this.documentInfo_);
72 /**
73 * Holds the print and cancel buttons and renders some document statistics.
74 * @type {!print_preview.PrintHeader}
75 * @private
77 this.printHeader_ = new print_preview.PrintHeader(
78 this.printTicketStore_, this.destinationStore_);
79 this.addChild(this.printHeader_);
81 /**
82 * Component used to search for print destinations.
83 * @type {!print_preview.DestinationSearch}
84 * @private
86 this.destinationSearch_ = new print_preview.DestinationSearch(
87 this.destinationStore_, this.invitationStore_, this.userInfo_);
88 this.addChild(this.destinationSearch_);
90 /**
91 * Component that renders the print destination.
92 * @type {!print_preview.DestinationSettings}
93 * @private
95 this.destinationSettings_ = new print_preview.DestinationSettings(
96 this.destinationStore_);
97 this.addChild(this.destinationSettings_);
99 /**
100 * Component that renders UI for entering in page range.
101 * @type {!print_preview.PageSettings}
102 * @private
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}
111 * @private
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}
120 * @private
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}
129 * @private
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}
138 * @private
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}
147 * @private
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}
156 * @private
158 this.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}
165 * @private
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}
178 * @private
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}
187 * @private
189 this.advancedSettings_ = new print_preview.AdvancedSettings(
190 this.printTicketStore_);
191 this.addChild(this.advancedSettings_);
193 var settingsSections = [
194 this.destinationSettings_,
195 this.pageSettings_,
196 this.copiesSettings_,
197 this.mediaSizeSettings_,
198 this.layoutSettings_,
199 this.marginSettings_,
200 this.colorSettings_,
201 this.dpiSettings_,
202 this.otherOptionsSettings_,
203 this.advancedOptionsSettings_];
205 * Component representing more/less settings button.
206 * @type {!print_preview.MoreSettings}
207 * @private
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}
216 * @private
218 this.previewArea_ = new print_preview.PreviewArea(this.destinationStore_,
219 this.printTicketStore_,
220 this.nativeLayer_,
221 this.documentInfo_);
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}
228 * @private
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
236 * been selected.
237 * @type {boolean}
238 * @private
240 this.isInKioskAutoPrintMode_ = false;
243 * Whether Print Preview is in App Kiosk mode, basically, use only printers
244 * available for the device.
245 * @type {boolean}
246 * @private
248 this.isInAppKioskMode_ = false;
251 * Whether Print with System Dialog link should be hidden. Overrides the
252 * default rules for System dialog link visibility.
253 * @type {boolean}
254 * @private
256 this.hideSystemDialogLink_ = true;
259 * State of the print preview UI.
260 * @type {print_preview.PrintPreview.UiState_}
261 * @private
263 this.uiState_ = PrintPreview.UiState_.INITIALIZING;
266 * Whether document preview generation is in progress.
267 * @type {boolean}
268 * @private
270 this.isPreviewGenerationInProgress_ = true;
273 * Whether to show system dialog before next printing.
274 * @type {boolean}
275 * @private
277 this.showSystemDialogBeforeNextPrint_ = false;
281 * States of the print preview.
282 * @enum {string}
283 * @private
285 PrintPreview.UiState_ = {
286 INITIALIZING: 'initializing',
287 READY: 'ready',
288 OPENING_PDF_PREVIEW: 'opening-pdf-preview',
289 OPENING_NATIVE_PRINT_DIALOG: 'opening-native-print-dialog',
290 PRINTING: 'printing',
291 FILE_SELECTION: 'file-selection',
292 CLOSING: 'closing',
293 ERROR: 'error'
297 * What can happen when print preview tries to print.
298 * @enum {string}
299 * @private
301 PrintPreview.PrintAttemptResult_ = {
302 NOT_READY: 'not-ready',
303 PRINTED: 'printed',
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);
321 /** @override */
322 enterDocument: function() {
323 // Native layer events.
324 this.tracker.add(
325 this.nativeLayer_,
326 print_preview.NativeLayer.EventType.INITIAL_SETTINGS_SET,
327 this.onInitialSettingsSet_.bind(this));
328 this.tracker.add(
329 this.nativeLayer_,
330 print_preview.NativeLayer.EventType.CLOUD_PRINT_ENABLE,
331 this.onCloudPrintEnable_.bind(this));
332 this.tracker.add(
333 this.nativeLayer_,
334 print_preview.NativeLayer.EventType.PRINT_TO_CLOUD,
335 this.onPrintToCloud_.bind(this));
336 this.tracker.add(
337 this.nativeLayer_,
338 print_preview.NativeLayer.EventType.FILE_SELECTION_CANCEL,
339 this.onFileSelectionCancel_.bind(this));
340 this.tracker.add(
341 this.nativeLayer_,
342 print_preview.NativeLayer.EventType.FILE_SELECTION_COMPLETE,
343 this.onFileSelectionComplete_.bind(this));
344 this.tracker.add(
345 this.nativeLayer_,
346 print_preview.NativeLayer.EventType.SETTINGS_INVALID,
347 this.onSettingsInvalid_.bind(this));
348 this.tracker.add(
349 this.nativeLayer_,
350 print_preview.NativeLayer.EventType.PRINT_PRESET_OPTIONS,
351 this.onPrintPresetOptionsFromDocument_.bind(this));
352 this.tracker.add(
353 this.nativeLayer_,
354 print_preview.NativeLayer.EventType.PRIVET_PRINT_FAILED,
355 this.onPrivetPrintFailed_.bind(this));
356 this.tracker.add(
357 this.nativeLayer_,
358 print_preview.NativeLayer.EventType.MANIPULATE_SETTINGS_FOR_TEST,
359 this.onManipulateSettingsForTest_.bind(this));
361 if ($('system-dialog-link')) {
362 this.tracker.add(
363 $('system-dialog-link'),
364 'click',
365 this.openSystemPrintDialog_.bind(this));
367 if ($('open-pdf-in-preview-link')) {
368 this.tracker.add(
369 $('open-pdf-in-preview-link'),
370 'click',
371 this.onOpenPdfInPreviewLinkClick_.bind(this));
374 this.tracker.add(
375 this.previewArea_,
376 print_preview.PreviewArea.EventType.PREVIEW_GENERATION_IN_PROGRESS,
377 this.onPreviewGenerationInProgress_.bind(this));
378 this.tracker.add(
379 this.previewArea_,
380 print_preview.PreviewArea.EventType.PREVIEW_GENERATION_DONE,
381 this.onPreviewGenerationDone_.bind(this));
382 this.tracker.add(
383 this.previewArea_,
384 print_preview.PreviewArea.EventType.PREVIEW_GENERATION_FAIL,
385 this.onPreviewGenerationFail_.bind(this));
386 this.tracker.add(
387 this.previewArea_,
388 print_preview.PreviewArea.EventType.OPEN_SYSTEM_DIALOG_CLICK,
389 this.openSystemPrintDialog_.bind(this));
391 this.tracker.add(
392 this.destinationStore_,
393 print_preview.DestinationStore.EventType.
394 SELECTED_DESTINATION_CAPABILITIES_READY,
395 this.printIfReady_.bind(this));
396 this.tracker.add(
397 this.destinationStore_,
398 print_preview.DestinationStore.EventType.DESTINATION_SELECT,
399 this.onDestinationSelect_.bind(this));
400 this.tracker.add(
401 this.destinationStore_,
402 print_preview.DestinationStore.EventType.DESTINATION_SEARCH_DONE,
403 this.onDestinationSearchDone_.bind(this));
405 this.tracker.add(
406 this.printHeader_,
407 print_preview.PrintHeader.EventType.PRINT_BUTTON_CLICK,
408 this.onPrintButtonClick_.bind(this));
409 this.tracker.add(
410 this.printHeader_,
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));
417 this.tracker.add(
418 this.destinationSettings_,
419 print_preview.DestinationSettings.EventType.CHANGE_BUTTON_ACTIVATE,
420 this.onDestinationChangeButtonActivate_.bind(this));
422 this.tracker.add(
423 this.destinationSearch_,
424 print_preview.DestinationSearch.EventType.MANAGE_CLOUD_DESTINATIONS,
425 this.onManageCloudDestinationsActivated_.bind(this));
426 this.tracker.add(
427 this.destinationSearch_,
428 print_preview.DestinationSearch.EventType.MANAGE_LOCAL_DESTINATIONS,
429 this.onManageLocalDestinationsActivated_.bind(this));
430 this.tracker.add(
431 this.destinationSearch_,
432 print_preview.DestinationSearch.EventType.ADD_ACCOUNT,
433 this.onCloudPrintSignInActivated_.bind(this, true /*addAccount*/));
434 this.tracker.add(
435 this.destinationSearch_,
436 print_preview.DestinationSearch.EventType.SIGN_IN,
437 this.onCloudPrintSignInActivated_.bind(this, false /*addAccount*/));
438 this.tracker.add(
439 this.destinationSearch_,
440 print_preview.DestinationListItem.EventType.REGISTER_PROMO_CLICKED,
441 this.onCloudPrintRegisterPromoClick_.bind(this));
443 this.tracker.add(
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.
450 this.tracker.add(
451 this.getChildElement('#no-destinations-promo .close-button'),
452 'click',
453 this.onNoDestinationsPromoClose_.bind(this));
454 this.tracker.add(
455 this.getChildElement('#no-destinations-promo .not-now-button'),
456 'click',
457 this.onNoDestinationsPromoClose_.bind(this));
458 this.tracker.add(
459 this.getChildElement('#no-destinations-promo .add-printer-button'),
460 'click',
461 this.onNoDestinationsPromoClick_.bind(this));
464 /** @override */
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
486 * enabled.
487 * @private
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.
510 * @private
512 printDocumentOrOpenPdfPreview_: function(isPdfPreview) {
513 assert(this.uiState_ == PrintPreview.UiState_.READY,
514 'Print document request received when not in ready state: ' +
515 this.uiState_);
516 if (isPdfPreview) {
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;
521 } else {
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.
546 * @private
548 printIfReady_: function() {
549 var okToPrint =
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;
556 if (!okToPrint) {
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_,
576 this.documentInfo_,
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.
585 * @private
587 close_: function() {
588 this.exitDocument();
589 this.uiState_ = PrintPreview.UiState_.CLOSING;
590 this.nativeLayer_.startCloseDialog();
594 * Opens the native system print dialog after disabling all controls.
595 * @private
597 openSystemPrintDialog_: function() {
598 if (!this.shouldShowSystemDialogLink_())
599 return;
600 if ($('system-dialog-link').classList.contains('disabled'))
601 return;
602 if (cr.isWindows) {
603 this.showSystemDialogBeforeNextPrint_ = true;
604 this.printDocumentOrOpenPdfPreview_(false /*isPdfPreview*/);
605 return;
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
616 * destinations.
617 * @param {Event} event Contains the initial print preview settings
618 * persisted through the session.
619 * @private
621 onInitialSettingsSet_: function(event) {
622 assert(this.uiState_ == PrintPreview.UiState_.INITIALIZING,
623 'Updating initial settings when not in initializing state: ' +
624 this.uiState_);
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.
632 this.appState_.init(
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,
642 settings.unitType,
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
660 * service.
661 * @private
663 onCloudPrintEnable_: function(event) {
664 this.cloudPrintInterface_ = new cloudprint.CloudPrintInterface(
665 event.baseCloudPrintUrl,
666 this.nativeLayer_,
667 this.userInfo_,
668 event.appKioskMode);
669 this.tracker.add(
670 this.cloudPrintInterface_,
671 cloudprint.CloudPrintInterface.EventType.SUBMIT_DONE,
672 this.onCloudPrintSubmitDone_.bind(this));
673 this.tracker.add(
674 this.cloudPrintInterface_,
675 cloudprint.CloudPrintInterface.EventType.SEARCH_FAILED,
676 this.onCloudPrintError_.bind(this));
677 this.tracker.add(
678 this.cloudPrintInterface_,
679 cloudprint.CloudPrintInterface.EventType.SUBMIT_FAILED,
680 this.onCloudPrintError_.bind(this));
681 this.tracker.add(
682 this.cloudPrintInterface_,
683 cloudprint.CloudPrintInterface.EventType.PRINTER_FAILED,
684 this.onCloudPrintError_.bind(this));
685 this.tracker.add(
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.
702 * @private
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_,
713 this.documentInfo_,
714 event.data);
718 * Called from the native layer when the user cancels the save-to-pdf file
719 * selection dialog.
720 * @private
722 onFileSelectionCancel_: function() {
723 assert(this.uiState_ == PrintPreview.UiState_.FILE_SELECTION,
724 'File selection cancelled when not in file-selection state: ' +
725 this.uiState_);
726 this.setIsEnabled_(true);
727 this.uiState_ = PrintPreview.UiState_.READY;
731 * Called from the native layer when save-to-pdf file selection is complete.
732 * @private
734 onFileSelectionComplete_: function() {
735 assert(this.uiState_ == PrintPreview.UiState_.FILE_SELECTION,
736 'File selection completed when not in file-selection state: ' +
737 this.uiState_);
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.
746 * @private
748 onCloudPrintSubmitDone_: function(event) {
749 assert(this.uiState_ == PrintPreview.UiState_.PRINTING,
750 'Submited job to Google Cloud Print but not in printing state ' +
751 this.uiState_);
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=' +
756 event.jobId);
758 this.close_();
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.
765 * @private
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.
774 } else {
775 this.printHeader_.setErrorMessage(event.message);
777 if (event.status == 200) {
778 console.error('Google Cloud Print Error: (' + event.errorCode + ') ' +
779 event.message);
780 } else {
781 console.error('Google Cloud Print Error: HTTP status ' + event.status);
786 * Called when the preview area's preview generation is in progress.
787 * @private
789 onPreviewGenerationInProgress_: function() {
790 this.isPreviewGenerationInProgress_ = true;
794 * Called when the preview area's preview generation is complete.
795 * @private
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.
806 * @private
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
817 * preview app.
818 * @private
820 onOpenPdfInPreviewLinkClick_: function() {
821 if ($('open-pdf-in-preview-link').classList.contains('disabled'))
822 return;
823 assert(this.uiState_ == PrintPreview.UiState_.READY,
824 'Trying to open pdf in preview when not in ready state: ' +
825 this.uiState_);
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
834 * document.
835 * @private
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
845 * print dialog.
846 * @private
848 onCancelButtonClick_: function() {
849 this.close_();
853 * Called when the register promo for Cloud Print is clicked.
854 * @private
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.
866 * @private
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 &&
874 !e.metaKey) {
875 // On non-mac with toolkit-views, ESC key is handled by C++-side instead
876 // of JS-side.
877 if (cr.isMac) {
878 this.close_();
879 e.preventDefault();
881 return;
884 // On Mac, Cmd- should close the print dialog.
885 if (cr.isMac && e.keyCode == 189 && e.metaKey) {
886 this.close_();
887 e.preventDefault();
888 return;
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_();
896 e.preventDefault();
897 return;
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*/);
912 e.preventDefault();
914 return;
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.
923 * @private
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.
935 * @private
937 onDestinationChangeButtonActivate_: function() {
938 this.destinationSearch_.setIsVisible(true);
942 * Called when the destination settings' change button is activated.
943 * Displays the destination search component.
944 * @private
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.
954 * @private
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.
963 * @private
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.
974 * @private
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.
983 * @private
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.
1007 * @private
1009 onPrivetPrintFailed_: function(event) {
1010 console.error('Privet printing failed with error code ' +
1011 event.httpError);
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.
1020 * @private
1022 onManipulateSettingsForTest_: function(event) {
1023 var settings =
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
1043 * as a pdf.
1044 * @private
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();
1051 return;
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];
1060 break;
1064 if (pdfDestination)
1065 this.destinationStore_.selectDestination(pdfDestination);
1066 else
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.
1075 * @private
1077 setLayoutSettingsForTest_: function(portrait) {
1078 var combobox = document.querySelector('.layout-settings-select');
1079 if (combobox.value == 'portrait') {
1080 this.nativeLayer_.previewReadyForTest();
1081 } else {
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.
1092 * @private
1094 setPageRangeForTest_: function(pageRange) {
1095 var textbox = document.querySelector('.page-settings-custom-input');
1096 if (textbox.value == pageRange) {
1097 this.nativeLayer_.previewReadyForTest();
1098 } else {
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.
1109 * @private
1111 setHeadersAndFootersForTest_: function(headersAndFooters) {
1112 var checkbox = document.querySelector('.header-footer-checkbox');
1113 if (headersAndFooters == checkbox.checked)
1114 this.nativeLayer_.previewReadyForTest();
1115 else
1116 checkbox.click();
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.
1124 * @private
1126 setBackgroundColorsAndImagesForTest_: function(backgroundColorsAndImages) {
1127 var checkbox = document.querySelector('.css-background-checkbox');
1128 if (backgroundColorsAndImages == checkbox.checked)
1129 this.nativeLayer_.previewReadyForTest();
1130 else
1131 checkbox.click();
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.
1139 * @private
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_();
1148 } else {
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_)
1160 return false;
1161 if (!cr.isWindows)
1162 return true;
1163 var selectedDest = this.destinationStore_.selectedDestination;
1164 return !!selectedDest &&
1165 selectedDest.origin == print_preview.Destination.Origin.LOCAL &&
1166 selectedDest.id !=
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.
1173 * @private
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.
1190 * @private
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'),
1201 isPromoVisible);
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.
1211 * @private
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.
1223 * @private
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');
1231 this.close_();
1235 // Export
1236 return {
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();