Move Webstore URL concepts to //extensions and out
[chromium-blink-merge.git] / chrome / browser / resources / print_preview / print_preview.js
blobb2f110bf77cc031a78ac7daf96b84b3e1ee0ecea
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 var localStrings = new LocalStrings(templateData);
9 <include src="component.js"/>
10 <include src="print_preview_focus_manager.js"/>
12 cr.define('print_preview', function() {
13 'use strict';
15 /**
16 * Container class for Chromium's print preview.
17 * @constructor
18 * @extends {print_preview.Component}
20 function PrintPreview() {
21 print_preview.Component.call(this);
23 /**
24 * Used to communicate with Chromium's print system.
25 * @type {!print_preview.NativeLayer}
26 * @private
28 this.nativeLayer_ = new print_preview.NativeLayer();
30 /**
31 * Event target that contains information about the logged in user.
32 * @type {!print_preview.UserInfo}
33 * @private
35 this.userInfo_ = new print_preview.UserInfo();
37 /**
38 * Application state.
39 * @type {!print_preview.AppState}
40 * @private
42 this.appState_ = new print_preview.AppState();
44 /**
45 * Data model that holds information about the document to print.
46 * @type {!print_preview.DocumentInfo}
47 * @private
49 this.documentInfo_ = new print_preview.DocumentInfo();
51 /**
52 * Data store which holds print destinations.
53 * @type {!print_preview.DestinationStore}
54 * @private
56 this.destinationStore_ = new print_preview.DestinationStore(
57 this.nativeLayer_, this.userInfo_, this.appState_);
59 /**
60 * Storage of the print ticket used to create the print job.
61 * @type {!print_preview.PrintTicketStore}
62 * @private
64 this.printTicketStore_ = new print_preview.PrintTicketStore(
65 this.destinationStore_, this.appState_, this.documentInfo_);
67 /**
68 * Holds the print and cancel buttons and renders some document statistics.
69 * @type {!print_preview.PrintHeader}
70 * @private
72 this.printHeader_ = new print_preview.PrintHeader(
73 this.printTicketStore_, this.destinationStore_);
74 this.addChild(this.printHeader_);
76 /**
77 * Component used to search for print destinations.
78 * @type {!print_preview.DestinationSearch}
79 * @private
81 this.destinationSearch_ = new print_preview.DestinationSearch(
82 this.destinationStore_, this.userInfo_);
83 this.addChild(this.destinationSearch_);
85 /**
86 * Component that renders the print destination.
87 * @type {!print_preview.DestinationSettings}
88 * @private
90 this.destinationSettings_ = new print_preview.DestinationSettings(
91 this.destinationStore_);
92 this.addChild(this.destinationSettings_);
94 /**
95 * Component that renders UI for entering in page range.
96 * @type {!print_preview.PageSettings}
97 * @private
99 this.pageSettings_ = new print_preview.PageSettings(
100 this.printTicketStore_.pageRange);
101 this.addChild(this.pageSettings_);
104 * Component that renders the copies settings.
105 * @type {!print_preview.CopiesSettings}
106 * @private
108 this.copiesSettings_ = new print_preview.CopiesSettings(
109 this.printTicketStore_.copies, this.printTicketStore_.collate);
110 this.addChild(this.copiesSettings_);
113 * Component that renders the media size settings.
114 * @type {!print_preview.MediaSizeSettings}
115 * @private
117 this.mediaSizeSettings_ =
118 new print_preview.MediaSizeSettings(this.printTicketStore_.mediaSize);
119 this.addChild(this.mediaSizeSettings_);
122 * Component that renders the layout settings.
123 * @type {!print_preview.LayoutSettings}
124 * @private
126 this.layoutSettings_ =
127 new print_preview.LayoutSettings(this.printTicketStore_.landscape);
128 this.addChild(this.layoutSettings_);
131 * Component that renders the color options.
132 * @type {!print_preview.ColorSettings}
133 * @private
135 this.colorSettings_ =
136 new print_preview.ColorSettings(this.printTicketStore_.color);
137 this.addChild(this.colorSettings_);
140 * Component that renders a select box for choosing margin settings.
141 * @type {!print_preview.MarginSettings}
142 * @private
144 this.marginSettings_ =
145 new print_preview.MarginSettings(this.printTicketStore_.marginsType);
146 this.addChild(this.marginSettings_);
149 * Component that renders miscellaneous print options.
150 * @type {!print_preview.OtherOptionsSettings}
151 * @private
153 this.otherOptionsSettings_ = new print_preview.OtherOptionsSettings(
154 this.printTicketStore_.duplex,
155 this.printTicketStore_.fitToPage,
156 this.printTicketStore_.cssBackground,
157 this.printTicketStore_.selectionOnly,
158 this.printTicketStore_.headerFooter);
159 this.addChild(this.otherOptionsSettings_);
162 * Component that renders the advanced options button.
163 * @type {!print_preview.AdvancedOptionsSettings}
164 * @private
166 this.advancedOptionsSettings_ = new print_preview.AdvancedOptionsSettings(
167 this.destinationStore_);
168 this.addChild(this.advancedOptionsSettings_);
171 * Component used to search for print destinations.
172 * @type {!print_preview.AdvancedSettings}
173 * @private
175 this.advancedSettings_ = new print_preview.AdvancedSettings(
176 this.printTicketStore_);
177 this.addChild(this.advancedSettings_);
180 * Component representing more/less settings button.
181 * @type {!print_preview.MoreSettings}
182 * @private
184 var settingsSections = [
185 this.destinationSettings_,
186 this.pageSettings_,
187 this.copiesSettings_,
188 this.mediaSizeSettings_,
189 this.layoutSettings_,
190 this.marginSettings_,
191 this.colorSettings_,
192 this.otherOptionsSettings_,
193 this.advancedOptionsSettings_];
194 this.moreSettings_ = new print_preview.MoreSettings(
195 this.destinationStore_, settingsSections);
196 this.addChild(this.moreSettings_);
199 * Area of the UI that holds the print preview.
200 * @type {!print_preview.PreviewArea}
201 * @private
203 this.previewArea_ = new print_preview.PreviewArea(this.destinationStore_,
204 this.printTicketStore_,
205 this.nativeLayer_,
206 this.documentInfo_);
207 this.addChild(this.previewArea_);
210 * Interface to the Google Cloud Print API. Null if Google Cloud Print
211 * integration is disabled.
212 * @type {cloudprint.CloudPrintInterface}
213 * @private
215 this.cloudPrintInterface_ = null;
218 * Whether in kiosk mode where print preview can print automatically without
219 * user intervention. See http://crbug.com/31395. Print will start when
220 * both the print ticket has been initialized, and an initial printer has
221 * been selected.
222 * @type {boolean}
223 * @private
225 this.isInKioskAutoPrintMode_ = false;
228 * Whether Print Preview is in App Kiosk mode, basically, use only printers
229 * available for the device.
230 * @type {boolean}
231 * @private
233 this.isInAppKioskMode_ = false;
236 * Whether Print with System Dialog option is available.
237 * @type {boolean}
238 * @private
240 this.isSystemDialogAvailable_ = false;
243 * State of the print preview UI.
244 * @type {print_preview.PrintPreview.UiState_}
245 * @private
247 this.uiState_ = PrintPreview.UiState_.INITIALIZING;
250 * Whether document preview generation is in progress.
251 * @type {boolean}
252 * @private
254 this.isPreviewGenerationInProgress_ = true;
257 * Whether to show system dialog before next printing.
258 * @type {boolean}
259 * @private
261 this.showSystemDialogBeforeNextPrint_ = false;
265 * States of the print preview.
266 * @enum {string}
267 * @private
269 PrintPreview.UiState_ = {
270 INITIALIZING: 'initializing',
271 READY: 'ready',
272 OPENING_PDF_PREVIEW: 'opening-pdf-preview',
273 OPENING_CLOUD_PRINT_DIALOG: 'opening-cloud-print-dialog',
274 OPENING_NATIVE_PRINT_DIALOG: 'opening-native-print-dialog',
275 PRINTING: 'printing',
276 FILE_SELECTION: 'file-selection',
277 CLOSING: 'closing',
278 ERROR: 'error'
282 * What can happen when print preview tries to print.
283 * @enum {string}
284 * @private
286 PrintPreview.PrintAttemptResult_ = {
287 NOT_READY: 'not-ready',
288 PRINTED: 'printed',
289 READY_WAITING_FOR_PREVIEW: 'ready-waiting-for-preview'
292 PrintPreview.prototype = {
293 __proto__: print_preview.Component.prototype,
295 /** Sets up the page and print preview by getting the printer list. */
296 initialize: function() {
297 this.decorate($('print-preview'));
298 i18nTemplate.process(document, templateData);
299 if (!this.previewArea_.hasCompatiblePlugin) {
300 this.setIsEnabled_(false);
302 this.nativeLayer_.startGetInitialSettings();
303 print_preview.PrintPreviewFocusManager.getInstance().initialize();
304 cr.ui.FocusOutlineManager.forDocument(document);
307 /** @override */
308 enterDocument: function() {
309 // Native layer events.
310 this.tracker.add(
311 this.nativeLayer_,
312 print_preview.NativeLayer.EventType.INITIAL_SETTINGS_SET,
313 this.onInitialSettingsSet_.bind(this));
314 this.tracker.add(
315 this.nativeLayer_,
316 print_preview.NativeLayer.EventType.CLOUD_PRINT_ENABLE,
317 this.onCloudPrintEnable_.bind(this));
318 this.tracker.add(
319 this.nativeLayer_,
320 print_preview.NativeLayer.EventType.PRINT_TO_CLOUD,
321 this.onPrintToCloud_.bind(this));
322 this.tracker.add(
323 this.nativeLayer_,
324 print_preview.NativeLayer.EventType.FILE_SELECTION_CANCEL,
325 this.onFileSelectionCancel_.bind(this));
326 this.tracker.add(
327 this.nativeLayer_,
328 print_preview.NativeLayer.EventType.FILE_SELECTION_COMPLETE,
329 this.onFileSelectionComplete_.bind(this));
330 this.tracker.add(
331 this.nativeLayer_,
332 print_preview.NativeLayer.EventType.SETTINGS_INVALID,
333 this.onSettingsInvalid_.bind(this));
334 this.tracker.add(
335 this.nativeLayer_,
336 print_preview.NativeLayer.EventType.DISABLE_SCALING,
337 this.onDisableScaling_.bind(this));
338 this.tracker.add(
339 this.nativeLayer_,
340 print_preview.NativeLayer.EventType.PRIVET_PRINT_FAILED,
341 this.onPrivetPrintFailed_.bind(this));
342 this.tracker.add(
343 this.nativeLayer_,
344 print_preview.NativeLayer.EventType.MANIPULATE_SETTINGS_FOR_TEST,
345 this.onManipulateSettingsForTest_.bind(this));
347 this.tracker.add(
348 $('system-dialog-link'),
349 'click',
350 this.openSystemPrintDialog_.bind(this));
351 this.tracker.add(
352 $('cloud-print-dialog-link'),
353 'click',
354 this.onCloudPrintDialogLinkClick_.bind(this));
355 this.tracker.add(
356 $('open-pdf-in-preview-link'),
357 'click',
358 this.onOpenPdfInPreviewLinkClick_.bind(this));
360 this.tracker.add(
361 this.previewArea_,
362 print_preview.PreviewArea.EventType.PREVIEW_GENERATION_IN_PROGRESS,
363 this.onPreviewGenerationInProgress_.bind(this));
364 this.tracker.add(
365 this.previewArea_,
366 print_preview.PreviewArea.EventType.PREVIEW_GENERATION_DONE,
367 this.onPreviewGenerationDone_.bind(this));
368 this.tracker.add(
369 this.previewArea_,
370 print_preview.PreviewArea.EventType.PREVIEW_GENERATION_FAIL,
371 this.onPreviewGenerationFail_.bind(this));
372 this.tracker.add(
373 this.previewArea_,
374 print_preview.PreviewArea.EventType.OPEN_SYSTEM_DIALOG_CLICK,
375 this.openSystemPrintDialog_.bind(this));
377 this.tracker.add(
378 this.destinationStore_,
379 print_preview.DestinationStore.EventType.
380 SELECTED_DESTINATION_CAPABILITIES_READY,
381 this.printIfReady_.bind(this));
382 this.tracker.add(
383 this.destinationStore_,
384 print_preview.DestinationStore.EventType.DESTINATION_SELECT,
385 this.onDestinationSelect_.bind(this));
386 this.tracker.add(
387 this.destinationStore_,
388 print_preview.DestinationStore.EventType.DESTINATION_SEARCH_DONE,
389 this.onDestinationSearchDone_.bind(this));
391 this.tracker.add(
392 this.printHeader_,
393 print_preview.PrintHeader.EventType.PRINT_BUTTON_CLICK,
394 this.onPrintButtonClick_.bind(this));
395 this.tracker.add(
396 this.printHeader_,
397 print_preview.PrintHeader.EventType.CANCEL_BUTTON_CLICK,
398 this.onCancelButtonClick_.bind(this));
400 this.tracker.add(window, 'keydown', this.onKeyDown_.bind(this));
402 this.tracker.add(
403 this.destinationSettings_,
404 print_preview.DestinationSettings.EventType.CHANGE_BUTTON_ACTIVATE,
405 this.onDestinationChangeButtonActivate_.bind(this));
407 this.tracker.add(
408 this.destinationSearch_,
409 print_preview.DestinationSearch.EventType.MANAGE_CLOUD_DESTINATIONS,
410 this.onManageCloudDestinationsActivated_.bind(this));
411 this.tracker.add(
412 this.destinationSearch_,
413 print_preview.DestinationSearch.EventType.MANAGE_LOCAL_DESTINATIONS,
414 this.onManageLocalDestinationsActivated_.bind(this));
415 this.tracker.add(
416 this.destinationSearch_,
417 print_preview.DestinationSearch.EventType.ADD_ACCOUNT,
418 this.onCloudPrintSignInActivated_.bind(this, true /*addAccount*/));
419 this.tracker.add(
420 this.destinationSearch_,
421 print_preview.DestinationSearch.EventType.SIGN_IN,
422 this.onCloudPrintSignInActivated_.bind(this, false /*addAccount*/));
423 this.tracker.add(
424 this.destinationSearch_,
425 print_preview.DestinationListItem.EventType.REGISTER_PROMO_CLICKED,
426 this.onCloudPrintRegisterPromoClick_.bind(this));
428 this.tracker.add(
429 this.advancedOptionsSettings_,
430 print_preview.AdvancedOptionsSettings.EventType.BUTTON_ACTIVATED,
431 this.onAdvancedOptionsButtonActivated_.bind(this));
433 // TODO(rltoscano): Move no-destinations-promo into its own component
434 // instead being part of PrintPreview.
435 this.tracker.add(
436 this.getChildElement('#no-destinations-promo .close-button'),
437 'click',
438 this.onNoDestinationsPromoClose_.bind(this));
439 this.tracker.add(
440 this.getChildElement('#no-destinations-promo .not-now-button'),
441 'click',
442 this.onNoDestinationsPromoClose_.bind(this));
443 this.tracker.add(
444 this.getChildElement('#no-destinations-promo .add-printer-button'),
445 'click',
446 this.onNoDestinationsPromoClick_.bind(this));
449 /** @override */
450 decorateInternal: function() {
451 this.printHeader_.decorate($('print-header'));
452 this.destinationSearch_.decorate($('destination-search'));
453 this.destinationSettings_.decorate($('destination-settings'));
454 this.pageSettings_.decorate($('page-settings'));
455 this.copiesSettings_.decorate($('copies-settings'));
456 this.mediaSizeSettings_.decorate($('media-size-settings'));
457 this.layoutSettings_.decorate($('layout-settings'));
458 this.colorSettings_.decorate($('color-settings'));
459 this.marginSettings_.decorate($('margin-settings'));
460 this.otherOptionsSettings_.decorate($('other-options-settings'));
461 this.advancedOptionsSettings_.decorate($('advanced-options-settings'));
462 this.advancedSettings_.decorate($('advanced-settings'));
463 this.moreSettings_.decorate($('more-settings'));
464 this.previewArea_.decorate($('preview-area'));
466 setIsVisible($('open-pdf-in-preview-link'), cr.isMac);
470 * Sets whether the controls in the print preview are enabled.
471 * @param {boolean} isEnabled Whether the controls in the print preview are
472 * enabled.
473 * @private
475 setIsEnabled_: function(isEnabled) {
476 $('system-dialog-link').disabled = !isEnabled;
477 $('cloud-print-dialog-link').disabled = !isEnabled;
478 $('open-pdf-in-preview-link').disabled = !isEnabled;
479 this.printHeader_.isEnabled = isEnabled;
480 this.destinationSettings_.isEnabled = isEnabled;
481 this.pageSettings_.isEnabled = isEnabled;
482 this.copiesSettings_.isEnabled = isEnabled;
483 this.mediaSizeSettings_.isEnabled = isEnabled;
484 this.layoutSettings_.isEnabled = isEnabled;
485 this.colorSettings_.isEnabled = isEnabled;
486 this.marginSettings_.isEnabled = isEnabled;
487 this.otherOptionsSettings_.isEnabled = isEnabled;
488 this.advancedOptionsSettings_.isEnabled = isEnabled;
492 * Prints the document or launches a pdf preview on the local system.
493 * @param {boolean} isPdfPreview Whether to launch the pdf preview.
494 * @private
496 printDocumentOrOpenPdfPreview_: function(isPdfPreview) {
497 assert(this.uiState_ == PrintPreview.UiState_.READY,
498 'Print document request received when not in ready state: ' +
499 this.uiState_);
500 if (isPdfPreview) {
501 this.uiState_ = PrintPreview.UiState_.OPENING_PDF_PREVIEW;
502 } else if (this.destinationStore_.selectedDestination.id ==
503 print_preview.Destination.GooglePromotedId.SAVE_AS_PDF) {
504 this.uiState_ = PrintPreview.UiState_.FILE_SELECTION;
505 } else {
506 this.uiState_ = PrintPreview.UiState_.PRINTING;
508 this.setIsEnabled_(false);
509 this.printHeader_.isCancelButtonEnabled = true;
510 var printAttemptResult = this.printIfReady_();
511 if (printAttemptResult == PrintPreview.PrintAttemptResult_.PRINTED ||
512 printAttemptResult ==
513 PrintPreview.PrintAttemptResult_.READY_WAITING_FOR_PREVIEW) {
514 if ((this.destinationStore_.selectedDestination.isLocal &&
515 !this.destinationStore_.selectedDestination.isPrivet &&
516 this.destinationStore_.selectedDestination.id !=
517 print_preview.Destination.GooglePromotedId.SAVE_AS_PDF) ||
518 this.uiState_ == PrintPreview.UiState_.OPENING_PDF_PREVIEW) {
519 // Hide the dialog for now. The actual print command will be issued
520 // when the preview generation is done.
521 this.nativeLayer_.startHideDialog();
527 * Attempts to print if needed and if ready.
528 * @return {PrintPreview.PrintAttemptResult_} Attempt result.
529 * @private
531 printIfReady_: function() {
532 var okToPrint =
533 (this.uiState_ == PrintPreview.UiState_.PRINTING ||
534 this.uiState_ == PrintPreview.UiState_.OPENING_PDF_PREVIEW ||
535 this.uiState_ == PrintPreview.UiState_.FILE_SELECTION ||
536 this.uiState_ == PrintPreview.UiState_.OPENING_CLOUD_PRINT_DIALOG ||
537 this.isInKioskAutoPrintMode_) &&
538 this.destinationStore_.selectedDestination &&
539 this.destinationStore_.selectedDestination.capabilities;
540 if (!okToPrint) {
541 return PrintPreview.PrintAttemptResult_.NOT_READY;
543 if (this.isPreviewGenerationInProgress_) {
544 return PrintPreview.PrintAttemptResult_.READY_WAITING_FOR_PREVIEW;
546 assert(this.printTicketStore_.isTicketValid(),
547 'Trying to print with invalid ticket');
548 if (this.uiState_ == PrintPreview.UiState_.OPENING_CLOUD_PRINT_DIALOG) {
549 this.nativeLayer_.startShowCloudPrintDialog(
550 this.printTicketStore_.pageRange.getPageNumberSet().size);
551 } else {
552 this.nativeLayer_.startPrint(
553 this.destinationStore_.selectedDestination,
554 this.printTicketStore_,
555 this.cloudPrintInterface_,
556 this.documentInfo_,
557 this.uiState_ == PrintPreview.UiState_.OPENING_PDF_PREVIEW,
558 this.showSystemDialogBeforeNextPrint_);
559 this.showSystemDialogBeforeNextPrint_ = false;
561 return PrintPreview.PrintAttemptResult_.PRINTED;
565 * Closes the print preview.
566 * @private
568 close_: function() {
569 this.exitDocument();
570 this.uiState_ = PrintPreview.UiState_.CLOSING;
571 this.nativeLayer_.startCloseDialog();
575 * Opens the native system print dialog after disabling all controls.
576 * @private
578 openSystemPrintDialog_: function() {
579 if (!this.shouldShowSystemDialogLink_())
580 return;
581 if (cr.isWindows) {
582 this.showSystemDialogBeforeNextPrint_ = true;
583 this.printDocumentOrOpenPdfPreview_(false /*isPdfPreview*/);
584 return;
586 setIsVisible($('system-dialog-throbber'), true);
587 this.setIsEnabled_(false);
588 this.uiState_ = PrintPreview.UiState_.OPENING_NATIVE_PRINT_DIALOG;
589 this.nativeLayer_.startShowSystemDialog();
593 * Called when the native layer has initial settings to set. Sets the
594 * initial settings of the print preview and begins fetching print
595 * destinations.
596 * @param {Event} event Contains the initial print preview settings
597 * persisted through the session.
598 * @private
600 onInitialSettingsSet_: function(event) {
601 assert(this.uiState_ == PrintPreview.UiState_.INITIALIZING,
602 'Updating initial settings when not in initializing state: ' +
603 this.uiState_);
604 this.uiState_ = PrintPreview.UiState_.READY;
606 var settings = event.initialSettings;
607 this.isInKioskAutoPrintMode_ = settings.isInKioskAutoPrintMode;
608 this.isInAppKioskMode_ = settings.isInAppKioskMode;
610 // The following components must be initialized in this order.
611 this.appState_.init(
612 settings.serializedAppStateStr,
613 settings.systemDefaultDestinationId);
614 this.documentInfo_.init(
615 settings.isDocumentModifiable,
616 settings.documentTitle,
617 settings.documentHasSelection);
618 this.printTicketStore_.init(
619 settings.thousandsDelimeter,
620 settings.decimalDelimeter,
621 settings.unitType,
622 settings.selectionOnly);
623 this.destinationStore_.init(settings.isInAppKioskMode);
624 this.appState_.setInitialized();
626 $('document-title').innerText = settings.documentTitle;
627 this.isSystemDialogAvailable_ = !settings.hidePrintWithSystemDialogLink &&
628 !settings.isInAppKioskMode;
629 setIsVisible($('system-dialog-link'), this.shouldShowSystemDialogLink_());
633 * Calls when the native layer enables Google Cloud Print integration.
634 * Fetches the user's cloud printers.
635 * @param {Event} event Contains the base URL of the Google Cloud Print
636 * service.
637 * @private
639 onCloudPrintEnable_: function(event) {
640 this.cloudPrintInterface_ = new cloudprint.CloudPrintInterface(
641 event.baseCloudPrintUrl,
642 this.nativeLayer_,
643 this.userInfo_,
644 event.appKioskMode);
645 this.tracker.add(
646 this.cloudPrintInterface_,
647 cloudprint.CloudPrintInterface.EventType.SUBMIT_DONE,
648 this.onCloudPrintSubmitDone_.bind(this));
649 this.tracker.add(
650 this.cloudPrintInterface_,
651 cloudprint.CloudPrintInterface.EventType.SEARCH_FAILED,
652 this.onCloudPrintError_.bind(this));
653 this.tracker.add(
654 this.cloudPrintInterface_,
655 cloudprint.CloudPrintInterface.EventType.SUBMIT_FAILED,
656 this.onCloudPrintError_.bind(this));
657 this.tracker.add(
658 this.cloudPrintInterface_,
659 cloudprint.CloudPrintInterface.EventType.PRINTER_FAILED,
660 this.onCloudPrintError_.bind(this));
661 this.tracker.add(
662 this.cloudPrintInterface_,
663 cloudprint.CloudPrintInterface.EventType.
664 UPDATE_PRINTER_TOS_ACCEPTANCE_FAILED,
665 this.onCloudPrintError_.bind(this));
667 this.destinationStore_.setCloudPrintInterface(this.cloudPrintInterface_);
668 if (this.destinationSearch_.getIsVisible()) {
669 this.destinationStore_.startLoadCloudDestinations();
674 * Called from the native layer when ready to print to Google Cloud Print.
675 * @param {Event} event Contains the body to send in the HTTP request.
676 * @private
678 onPrintToCloud_: function(event) {
679 assert(this.uiState_ == PrintPreview.UiState_.PRINTING,
680 'Document ready to be sent to the cloud when not in printing ' +
681 'state: ' + this.uiState_);
682 assert(this.cloudPrintInterface_ != null,
683 'Google Cloud Print is not enabled');
684 this.cloudPrintInterface_.submit(
685 this.destinationStore_.selectedDestination,
686 this.printTicketStore_,
687 this.documentInfo_,
688 event.data);
692 * Called from the native layer when the user cancels the save-to-pdf file
693 * selection dialog.
694 * @private
696 onFileSelectionCancel_: function() {
697 assert(this.uiState_ == PrintPreview.UiState_.FILE_SELECTION,
698 'File selection cancelled when not in file-selection state: ' +
699 this.uiState_);
700 this.setIsEnabled_(true);
701 this.uiState_ = PrintPreview.UiState_.READY;
705 * Called from the native layer when save-to-pdf file selection is complete.
706 * @private
708 onFileSelectionComplete_: function() {
709 assert(this.uiState_ == PrintPreview.UiState_.FILE_SELECTION,
710 'File selection completed when not in file-selection state: ' +
711 this.uiState_);
712 this.previewArea_.showCustomMessage(
713 localStrings.getString('printingToPDFInProgress'));
714 this.uiState_ = PrintPreview.UiState_.PRINTING;
718 * Called after successfully submitting a job to Google Cloud Print.
719 * @param {!Event} event Contains the ID of the submitted print job.
720 * @private
722 onCloudPrintSubmitDone_: function(event) {
723 assert(this.uiState_ == PrintPreview.UiState_.PRINTING,
724 'Submited job to Google Cloud Print but not in printing state ' +
725 this.uiState_);
726 if (this.destinationStore_.selectedDestination.id ==
727 print_preview.Destination.GooglePromotedId.FEDEX) {
728 this.nativeLayer_.startForceOpenNewTab(
729 'https://www.google.com/cloudprint/fedexcode.html?jobid=' +
730 event.jobId);
732 this.close_();
736 * Called when there was an error communicating with Google Cloud print.
737 * Displays an error message in the print header.
738 * @param {!Event} event Contains the error message.
739 * @private
741 onCloudPrintError_: function(event) {
742 if (event.status == 403) {
743 if (!this.isInAppKioskMode_) {
744 this.destinationSearch_.showCloudPrintPromo();
746 } else if (event.status == 0) {
747 return; // Ignore, the system does not have internet connectivity.
748 } else {
749 this.printHeader_.setErrorMessage(event.message);
751 if (event.status == 200) {
752 console.error('Google Cloud Print Error: (' + event.errorCode + ') ' +
753 event.message);
754 } else {
755 console.error('Google Cloud Print Error: HTTP status ' + event.status);
760 * Called when the preview area's preview generation is in progress.
761 * @private
763 onPreviewGenerationInProgress_: function() {
764 this.isPreviewGenerationInProgress_ = true;
768 * Called when the preview area's preview generation is complete.
769 * @private
771 onPreviewGenerationDone_: function() {
772 this.isPreviewGenerationInProgress_ = false;
773 this.printHeader_.isPrintButtonEnabled = true;
774 this.nativeLayer_.previewReadyForTest();
775 this.printIfReady_();
779 * Called when the preview area's preview failed to load.
780 * @private
782 onPreviewGenerationFail_: function() {
783 this.isPreviewGenerationInProgress_ = false;
784 this.printHeader_.isPrintButtonEnabled = false;
785 if (this.uiState_ == PrintPreview.UiState_.PRINTING) {
786 this.nativeLayer_.startCancelPendingPrint();
787 } else if (this.uiState_ ==
788 PrintPreview.UiState_.OPENING_CLOUD_PRINT_DIALOG) {
789 this.uiState_ = PrintPreview.UiState_.READY;
794 * Called when the 'Open pdf in preview' link is clicked. Launches the pdf
795 * preview app.
796 * @private
798 onOpenPdfInPreviewLinkClick_: function() {
799 assert(this.uiState_ == PrintPreview.UiState_.READY,
800 'Trying to open pdf in preview when not in ready state: ' +
801 this.uiState_);
802 setIsVisible($('open-preview-app-throbber'), true);
803 this.previewArea_.showCustomMessage(
804 localStrings.getString('openingPDFInPreview'));
805 this.printDocumentOrOpenPdfPreview_(true /*isPdfPreview*/);
809 * Called when the print header's print button is clicked. Prints the
810 * document.
811 * @private
813 onPrintButtonClick_: function() {
814 assert(this.uiState_ == PrintPreview.UiState_.READY,
815 'Trying to print when not in ready state: ' + this.uiState_);
816 this.printDocumentOrOpenPdfPreview_(false /*isPdfPreview*/);
820 * Called when the print header's cancel button is clicked. Closes the
821 * print dialog.
822 * @private
824 onCancelButtonClick_: function() {
825 this.close_();
829 * Called when the register promo for Cloud Print is clicked.
830 * @private
832 onCloudPrintRegisterPromoClick_: function(e) {
833 var devicesUrl = 'chrome://devices/register?id=' + e.destination.id;
834 this.nativeLayer_.startForceOpenNewTab(devicesUrl);
835 this.destinationStore_.waitForRegister(e.destination.id);
839 * Consume escape key presses and ctrl + shift + p. Delegate everything else
840 * to the preview area.
841 * @param {KeyboardEvent} e The keyboard event.
842 * @private
844 onKeyDown_: function(e) {
845 // Escape key closes the dialog.
846 if (e.keyCode == 27 && !e.shiftKey && !e.ctrlKey && !e.altKey &&
847 !e.metaKey) {
848 <if expr="toolkit_views">
849 // On the toolkit_views environment, ESC key is handled by C++-side
850 // instead of JS-side.
851 return;
852 </if>
853 <if expr="not toolkit_views">
854 this.close_();
855 </if>
856 e.preventDefault();
857 return;
860 // On Mac, Cmd- should close the print dialog.
861 if (cr.isMac && e.keyCode == 189 && e.metaKey) {
862 this.close_();
863 e.preventDefault();
864 return;
867 // Ctrl + Shift + p / Mac equivalent.
868 if (e.keyCode == 80) {
869 if ((cr.isMac && e.metaKey && e.altKey && !e.shiftKey && !e.ctrlKey) ||
870 (!cr.isMac && e.shiftKey && e.ctrlKey && !e.altKey && !e.metaKey)) {
871 this.openSystemPrintDialog_();
872 e.preventDefault();
873 return;
877 if (e.keyCode == 13 /*enter*/ &&
878 !document.querySelector('.overlay:not([hidden])') &&
879 this.destinationStore_.selectedDestination &&
880 this.printTicketStore_.isTicketValid()) {
881 assert(this.uiState_ == PrintPreview.UiState_.READY,
882 'Trying to print when not in ready state: ' + this.uiState_);
883 var activeElementTag = document.activeElement ?
884 document.activeElement.tagName.toUpperCase() : '';
885 if (activeElementTag != 'BUTTON' && activeElementTag != 'SELECT') {
886 this.printDocumentOrOpenPdfPreview_(false /*isPdfPreview*/);
887 e.preventDefault();
889 return;
892 // Pass certain directional keyboard events to the PDF viewer.
893 this.previewArea_.handleDirectionalKeyEvent(e);
897 * Called when native layer receives invalid settings for a print request.
898 * @private
900 onSettingsInvalid_: function() {
901 this.uiState_ = PrintPreview.UiState_.ERROR;
902 console.error('Invalid settings error reported from native layer');
903 this.previewArea_.showCustomMessage(
904 localStrings.getString('invalidPrinterSettings'));
908 * Called when the destination settings' change button is activated.
909 * Displays the destination search component.
910 * @private
912 onDestinationChangeButtonActivate_: function() {
913 this.destinationSearch_.setIsVisible(true);
914 this.destinationStore_.startLoadCloudDestinations();
915 this.destinationStore_.startLoadLocalDestinations();
916 this.destinationStore_.startLoadPrivetDestinations();
920 * Called when the destination settings' change button is activated.
921 * Displays the destination search component.
922 * @private
924 onAdvancedOptionsButtonActivated_: function() {
925 this.advancedSettings_.showForDestination(
926 this.destinationStore_.selectedDestination);
930 * Called when the destination search dispatches manage cloud destinations
931 * event. Calls corresponding native layer method.
932 * @private
934 onManageCloudDestinationsActivated_: function() {
935 this.nativeLayer_.startManageCloudDestinations();
939 * Called when the destination search dispatches manage local destinations
940 * event. Calls corresponding native layer method.
941 * @private
943 onManageLocalDestinationsActivated_: function() {
944 this.nativeLayer_.startManageLocalDestinations();
948 * Called when the user wants to sign in to Google Cloud Print. Calls the
949 * corresponding native layer event.
950 * @param {boolean} addAccount Whether to open an 'add a new account' or
951 * default sign in page.
952 * @private
954 onCloudPrintSignInActivated_: function(addAccount) {
955 this.nativeLayer_.startCloudPrintSignIn(addAccount);
959 * Called when the native layer dispatches a DISABLE_SCALING event. Resets
960 * fit-to-page selection and updates document info.
961 * @private
963 onDisableScaling_: function() {
964 this.printTicketStore_.fitToPage.updateValue(null);
965 this.documentInfo_.updateIsScalingDisabled(true);
969 * Called when privet printing fails.
970 * @param {Event} event Event object representing the failure.
971 * @private
973 onPrivetPrintFailed_: function(event) {
974 console.error('Privet printing failed with error code ' +
975 event.httpError);
976 this.printHeader_.setErrorMessage(
977 localStrings.getString('couldNotPrint'));
981 * Called when the print preview settings need to be changed for testing.
982 * @param {Event} event Event object that contains the option that is to
983 * be changed and what to set that option.
984 * @private
986 onManipulateSettingsForTest_: function(event) {
987 if ('selectSaveAsPdfDestination' in event.settings) {
988 this.saveAsPdfForTest_(); // No parameters.
989 } else if ('layoutSettings' in event.settings) {
990 this.setLayoutSettingsForTest_(event.settings.layoutSettings.portrait);
991 } else if ('pageRange' in event.settings) {
992 this.setPageRangeForTest_(event.settings.pageRange);
993 } else if ('headersAndFooters' in event.settings) {
994 this.setHeadersAndFootersForTest_(event.settings.headersAndFooters);
995 } else if ('backgroundColorsAndImages' in event.settings) {
996 this.setBackgroundColorsAndImagesForTest_(
997 event.settings.backgroundColorsAndImages);
998 } else if ('margins' in event.settings) {
999 this.setMarginsForTest_(event.settings.margins);
1004 * Called by onManipulateSettingsForTest_(). Sets the print destination
1005 * as a pdf.
1006 * @private
1008 saveAsPdfForTest_: function() {
1009 if (this.destinationStore_.selectedDestination &&
1010 print_preview.Destination.GooglePromotedId.SAVE_AS_PDF ==
1011 this.destinationStore_.selectedDestination.id) {
1012 this.nativeLayer_.previewReadyForTest();
1013 return;
1016 var destinations = this.destinationStore_.destinations();
1017 var pdfDestination = null;
1018 for (var i = 0; i < destinations.length; i++) {
1019 if (destinations[i].id ==
1020 print_preview.Destination.GooglePromotedId.SAVE_AS_PDF) {
1021 pdfDestination = destinations[i];
1022 break;
1026 if (pdfDestination)
1027 this.destinationStore_.selectDestination(pdfDestination);
1028 else
1029 this.nativeLayer_.previewFailedForTest();
1033 * Called by onManipulateSettingsForTest_(). Sets the layout settings to
1034 * either portrait or landscape.
1035 * @param {boolean} portrait Whether to use portrait page layout;
1036 * if false: landscape.
1037 * @private
1039 setLayoutSettingsForTest_: function(portrait) {
1040 var combobox = document.querySelector('.layout-settings-select');
1041 if (combobox.value == 'portrait') {
1042 this.nativeLayer_.previewReadyForTest();
1043 } else {
1044 combobox.value = 'landscape';
1045 this.layoutSettings_.onSelectChange_();
1050 * Called by onManipulateSettingsForTest_(). Sets the page range for
1051 * for the print preview settings.
1052 * @param {string} pageRange Sets the page range to the desired value(s).
1053 * Ex: "1-5,9" means pages 1 through 5 and page 9 will be printed.
1054 * @private
1056 setPageRangeForTest_: function(pageRange) {
1057 var textbox = document.querySelector('.page-settings-custom-input');
1058 if (textbox.value == pageRange) {
1059 this.nativeLayer_.previewReadyForTest();
1060 } else {
1061 textbox.value = pageRange;
1062 document.querySelector('.page-settings-custom-radio').click();
1067 * Called by onManipulateSettings_(). Checks or unchecks the headers and
1068 * footers option on print preview.
1069 * @param {boolean} headersAndFooters Whether the "Headers and Footers"
1070 * checkbox should be checked.
1071 * @private
1073 setHeadersAndFootersForTest_: function(headersAndFooters) {
1074 var checkbox = document.querySelector('.header-footer-checkbox');
1075 if (headersAndFooters == checkbox.checked)
1076 this.nativeLayer_.previewReadyForTest();
1077 else
1078 checkbox.click();
1082 * Called by onManipulateSettings_(). Checks or unchecks the background
1083 * colors and images option on print preview.
1084 * @param {boolean} backgroundColorsAndImages If true, the checkbox should
1085 * be checked. Otherwise it should be unchecked.
1086 * @private
1088 setBackgroundColorsAndImagesForTest_: function(backgroundColorsAndImages) {
1089 var checkbox = document.querySelector('.css-background-checkbox');
1090 if (backgroundColorsAndImages == checkbox.checked)
1091 this.nativeLayer_.previewReadyForTest();
1092 else
1093 checkbox.click();
1097 * Called by onManipulateSettings_(). Sets the margin settings
1098 * that are desired. Custom margin settings aren't currently supported.
1099 * @param {number} margins The desired margins combobox index. Must be
1100 * a valid index or else the test fails.
1101 * @private
1103 setMarginsForTest_: function(margins) {
1104 var combobox = document.querySelector('.margin-settings-select');
1105 if (margins == combobox.selectedIndex) {
1106 this.nativeLayer_.previewReadyForTest();
1107 } else if (margins >= 0 && margins < combobox.length) {
1108 combobox.selectedIndex = margins;
1109 this.marginSettings_.onSelectChange_();
1110 } else {
1111 this.nativeLayer_.previewFailedForTest();
1116 * Returns true if "Print using system dialog" link should be shown for
1117 * current destination.
1118 * @return {boolean} Returns true if link should be shown.
1120 shouldShowSystemDialogLink_: function() {
1121 if (!this.isSystemDialogAvailable_)
1122 return false;
1123 if (!cr.isWindows)
1124 return true;
1125 var selectedDest = this.destinationStore_.selectedDestination;
1126 return selectedDest &&
1127 selectedDest.origin == print_preview.Destination.Origin.LOCAL &&
1128 selectedDest.id !=
1129 print_preview.Destination.GooglePromotedId.SAVE_AS_PDF;
1133 * Called when the open-cloud-print-dialog link is clicked. Opens the Google
1134 * Cloud Print web dialog.
1135 * @private
1137 onCloudPrintDialogLinkClick_: function() {
1138 assert(this.uiState_ == PrintPreview.UiState_.READY,
1139 'Opening Google Cloud Print dialog when not in ready state: ' +
1140 this.uiState_);
1141 setIsVisible($('cloud-print-dialog-throbber'), true);
1142 this.setIsEnabled_(false);
1143 this.uiState_ = PrintPreview.UiState_.OPENING_CLOUD_PRINT_DIALOG;
1144 this.printIfReady_();
1148 * Called when a print destination is selected. Shows/hides the "Print with
1149 * Cloud Print" link in the navbar.
1150 * @private
1152 onDestinationSelect_: function() {
1153 var selectedDest = this.destinationStore_.selectedDestination;
1154 setIsVisible(
1155 $('cloud-print-dialog-link'),
1156 selectedDest && !cr.isChromeOS && !selectedDest.isLocal);
1157 setIsVisible(
1158 $('system-dialog-link'),
1159 this.shouldShowSystemDialogLink_());
1160 if (selectedDest && this.isInKioskAutoPrintMode_) {
1161 this.onPrintButtonClick_();
1166 * Called when the destination store loads a group of destinations. Shows
1167 * a promo on Chrome OS if the user has no print destinations promoting
1168 * Google Cloud Print.
1169 * @private
1171 onDestinationSearchDone_: function() {
1172 var isPromoVisible = cr.isChromeOS &&
1173 this.cloudPrintInterface_ &&
1174 this.userInfo_.activeUser &&
1175 !this.appState_.isGcpPromoDismissed &&
1176 !this.destinationStore_.isLocalDestinationsSearchInProgress &&
1177 !this.destinationStore_.isCloudDestinationsSearchInProgress &&
1178 this.destinationStore_.hasOnlyDefaultCloudDestinations();
1179 setIsVisible(this.getChildElement('#no-destinations-promo'),
1180 isPromoVisible);
1181 if (isPromoVisible) {
1182 new print_preview.GcpPromoMetricsContext().record(
1183 print_preview.Metrics.GcpPromoBucket.PROMO_SHOWN);
1188 * Called when the close button on the no-destinations-promotion is clicked.
1189 * Hides the promotion.
1190 * @private
1192 onNoDestinationsPromoClose_: function() {
1193 new print_preview.GcpPromoMetricsContext().record(
1194 print_preview.Metrics.GcpPromoBucket.PROMO_CLOSED);
1195 setIsVisible(this.getChildElement('#no-destinations-promo'), false);
1196 this.appState_.persistIsGcpPromoDismissed(true);
1200 * Called when the no-destinations promotion link is clicked. Opens the
1201 * Google Cloud Print management page and closes the print preview.
1202 * @private
1204 onNoDestinationsPromoClick_: function() {
1205 new print_preview.GcpPromoMetricsContext().record(
1206 print_preview.Metrics.GcpPromoBucket.PROMO_CLICKED);
1207 this.appState_.persistIsGcpPromoDismissed(true);
1208 window.open(this.cloudPrintInterface_.baseUrl + '?user=' +
1209 this.userInfo_.activeUser + '#printers');
1210 this.close_();
1214 // Export
1215 return {
1216 PrintPreview: PrintPreview
1220 // Pull in all other scripts in a single shot.
1221 <include src="common/overlay.js"/>
1222 <include src="common/search_box.js"/>
1223 <include src="common/search_bubble.js"/>
1225 <include src="data/page_number_set.js"/>
1226 <include src="data/destination.js"/>
1227 <include src="data/local_parsers.js"/>
1228 <include src="data/cloud_parsers.js"/>
1229 <include src="data/destination_store.js"/>
1230 <include src="data/margins.js"/>
1231 <include src="data/document_info.js"/>
1232 <include src="data/printable_area.js"/>
1233 <include src="data/measurement_system.js"/>
1234 <include src="data/print_ticket_store.js"/>
1235 <include src="data/coordinate2d.js"/>
1236 <include src="data/size.js"/>
1237 <include src="data/capabilities_holder.js"/>
1238 <include src="data/user_info.js"/>
1239 <include src="data/app_state.js"/>
1241 <include src="data/ticket_items/ticket_item.js"/>
1243 <include src="data/ticket_items/custom_margins.js"/>
1244 <include src="data/ticket_items/collate.js"/>
1245 <include src="data/ticket_items/color.js"/>
1246 <include src="data/ticket_items/copies.js"/>
1247 <include src="data/ticket_items/duplex.js"/>
1248 <include src="data/ticket_items/header_footer.js"/>
1249 <include src="data/ticket_items/media_size.js"/>
1250 <include src="data/ticket_items/landscape.js"/>
1251 <include src="data/ticket_items/margins_type.js"/>
1252 <include src="data/ticket_items/page_range.js"/>
1253 <include src="data/ticket_items/fit_to_page.js"/>
1254 <include src="data/ticket_items/css_background.js"/>
1255 <include src="data/ticket_items/selection_only.js"/>
1256 <include src="data/ticket_items/vendor_items.js"/>
1258 <include src="native_layer.js"/>
1259 <include src="print_preview_animations.js"/>
1260 <include src="cloud_print_interface.js"/>
1261 <include src="print_preview_utils.js"/>
1262 <include src="print_header.js"/>
1263 <include src="metrics.js"/>
1265 <include src="settings/settings_section.js"/>
1266 <include src="settings/page_settings.js"/>
1267 <include src="settings/copies_settings.js"/>
1268 <include src="settings/media_size_settings.js"/>
1269 <include src="settings/layout_settings.js"/>
1270 <include src="settings/color_settings.js"/>
1271 <include src="settings/margin_settings.js"/>
1272 <include src="settings/destination_settings.js"/>
1273 <include src="settings/other_options_settings.js"/>
1274 <include src="settings/advanced_options_settings.js"/>
1275 <include src="settings/advanced_settings/advanced_settings.js"/>
1276 <include src="settings/advanced_settings/advanced_settings_item.js"/>
1277 <include src="settings/more_settings.js"/>
1279 <include src="previewarea/margin_control.js"/>
1280 <include src="previewarea/margin_control_container.js"/>
1281 <include src="../pdf/pdf_scripting_api.js" />
1282 <include src="previewarea/preview_area.js"/>
1283 <include src="preview_generator.js"/>
1285 <include src="search/destination_list.js"/>
1286 <include src="search/cloud_destination_list.js"/>
1287 <include src="search/recent_destination_list.js"/>
1288 <include src="search/destination_list_item.js"/>
1289 <include src="search/destination_search.js"/>
1290 <include src="search/fedex_tos.js"/>
1292 window.addEventListener('DOMContentLoaded', function() {
1293 printPreview = new print_preview.PrintPreview();
1294 printPreview.initialize();