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. 4 5// TODO(rltoscano): Move data/* into print_preview.data namespace 6 7var localStrings = new LocalStrings(templateData); 8 9<include src="component.js"/> 10 11cr.define('print_preview', function() { 12 'use strict'; 13 14 /** 15 * Container class for Chromium's print preview. 16 * @constructor 17 * @extends {print_preview.Component} 18 */ 19 function PrintPreview() { 20 print_preview.Component.call(this); 21 22 /** 23 * Used to communicate with Chromium's print system. 24 * @type {!print_preview.NativeLayer} 25 * @private 26 */ 27 this.nativeLayer_ = new print_preview.NativeLayer(); 28 29 /** 30 * Event target that contains information about the logged in user. 31 * @type {!print_preview.UserInfo} 32 * @private 33 */ 34 this.userInfo_ = new print_preview.UserInfo(); 35 36 /** 37 * Metrics object used to report usage statistics. 38 * @type {!print_preview.Metrics} 39 * @private 40 */ 41 this.metrics_ = new print_preview.Metrics(); 42 43 /** 44 * Application state. 45 * @type {!print_preview.AppState} 46 * @private 47 */ 48 this.appState_ = new print_preview.AppState(); 49 50 /** 51 * Data model that holds information about the document to print. 52 * @type {!print_preview.DocumentInfo} 53 * @private 54 */ 55 this.documentInfo_ = new print_preview.DocumentInfo(); 56 57 /** 58 * Data store which holds print destinations. 59 * @type {!print_preview.DestinationStore} 60 * @private 61 */ 62 this.destinationStore_ = new print_preview.DestinationStore( 63 this.nativeLayer_, this.appState_, this.metrics_); 64 65 /** 66 * Storage of the print ticket used to create the print job. 67 * @type {!print_preview.PrintTicketStore} 68 * @private 69 */ 70 this.printTicketStore_ = new print_preview.PrintTicketStore( 71 this.destinationStore_, this.appState_, this.documentInfo_); 72 73 /** 74 * Holds the print and cancel buttons and renders some document statistics. 75 * @type {!print_preview.PrintHeader} 76 * @private 77 */ 78 this.printHeader_ = new print_preview.PrintHeader( 79 this.printTicketStore_, this.destinationStore_); 80 this.addChild(this.printHeader_); 81 82 /** 83 * Component used to search for print destinations. 84 * @type {!print_preview.DestinationSearch} 85 * @private 86 */ 87 this.destinationSearch_ = new print_preview.DestinationSearch( 88 this.destinationStore_, this.userInfo_, this.metrics_); 89 this.addChild(this.destinationSearch_); 90 91 /** 92 * Component that renders the print destination. 93 * @type {!print_preview.DestinationSettings} 94 * @private 95 */ 96 this.destinationSettings_ = new print_preview.DestinationSettings( 97 this.destinationStore_); 98 this.addChild(this.destinationSettings_); 99 100 /** 101 * Component that renders UI for entering in page range. 102 * @type {!print_preview.PageSettings} 103 * @private 104 */ 105 this.pageSettings_ = new print_preview.PageSettings( 106 this.printTicketStore_.pageRange); 107 this.addChild(this.pageSettings_); 108 109 /** 110 * Component that renders the copies settings. 111 * @type {!print_preview.CopiesSettings} 112 * @private 113 */ 114 this.copiesSettings_ = new print_preview.CopiesSettings( 115 this.printTicketStore_.copies, this.printTicketStore_.collate); 116 this.addChild(this.copiesSettings_); 117 118 /** 119 * Component that renders the layout settings. 120 * @type {!print_preview.LayoutSettings} 121 * @private 122 */ 123 this.layoutSettings_ = 124 new print_preview.LayoutSettings(this.printTicketStore_.landscape); 125 this.addChild(this.layoutSettings_); 126 127 /** 128 * Component that renders the color options. 129 * @type {!print_preview.ColorSettings} 130 * @private 131 */ 132 this.colorSettings_ = 133 new print_preview.ColorSettings(this.printTicketStore_.color); 134 this.addChild(this.colorSettings_); 135 136 /** 137 * Component that renders a select box for choosing margin settings. 138 * @type {!print_preview.MarginSettings} 139 * @private 140 */ 141 this.marginSettings_ = 142 new print_preview.MarginSettings(this.printTicketStore_.marginsType); 143 this.addChild(this.marginSettings_); 144 145 /** 146 * Component that renders miscellaneous print options. 147 * @type {!print_preview.OtherOptionsSettings} 148 * @private 149 */ 150 this.otherOptionsSettings_ = new print_preview.OtherOptionsSettings( 151 this.printTicketStore_.duplex, 152 this.printTicketStore_.fitToPage, 153 this.printTicketStore_.cssBackground, 154 this.printTicketStore_.selectionOnly, 155 this.printTicketStore_.headerFooter); 156 this.addChild(this.otherOptionsSettings_); 157 158 /** 159 * Area of the UI that holds the print preview. 160 * @type {!print_preview.PreviewArea} 161 * @private 162 */ 163 this.previewArea_ = new print_preview.PreviewArea(this.destinationStore_, 164 this.printTicketStore_, 165 this.nativeLayer_, 166 this.documentInfo_); 167 this.addChild(this.previewArea_); 168 169 /** 170 * Interface to the Google Cloud Print API. Null if Google Cloud Print 171 * integration is disabled. 172 * @type {cloudprint.CloudPrintInterface} 173 * @private 174 */ 175 this.cloudPrintInterface_ = null; 176 177 /** 178 * Whether in kiosk mode where print preview can print automatically without 179 * user intervention. See http://crbug.com/31395. Print will start when 180 * both the print ticket has been initialized, and an initial printer has 181 * been selected. 182 * @type {boolean} 183 * @private 184 */ 185 this.isInKioskAutoPrintMode_ = false; 186 187 /** 188 * State of the print preview UI. 189 * @type {print_preview.PrintPreview.UiState_} 190 * @private 191 */ 192 this.uiState_ = PrintPreview.UiState_.INITIALIZING; 193 194 /** 195 * Whether document preview generation is in progress. 196 * @type {boolean} 197 * @private 198 */ 199 this.isPreviewGenerationInProgress_ = true; 200 }; 201 202 /** 203 * States of the print preview. 204 * @enum {string} 205 * @private 206 */ 207 PrintPreview.UiState_ = { 208 INITIALIZING: 'initializing', 209 READY: 'ready', 210 OPENING_PDF_PREVIEW: 'opening-pdf-preview', 211 OPENING_NATIVE_PRINT_DIALOG: 'opening-native-print-dialog', 212 PRINTING: 'printing', 213 FILE_SELECTION: 'file-selection', 214 CLOSING: 'closing', 215 ERROR: 'error' 216 }; 217 218 PrintPreview.prototype = { 219 __proto__: print_preview.Component.prototype, 220 221 /** Sets up the page and print preview by getting the printer list. */ 222 initialize: function() { 223 this.decorate($('print-preview')); 224 i18nTemplate.process(document, templateData); 225 if (!this.previewArea_.hasCompatiblePlugin) { 226 this.setIsEnabled_(false); 227 } 228 this.nativeLayer_.startGetInitialSettings(); 229 cr.ui.FocusOutlineManager.forDocument(document); 230 }, 231 232 /** @override */ 233 enterDocument: function() { 234 // Native layer events. 235 this.tracker.add( 236 this.nativeLayer_, 237 print_preview.NativeLayer.EventType.INITIAL_SETTINGS_SET, 238 this.onInitialSettingsSet_.bind(this)); 239 this.tracker.add( 240 this.nativeLayer_, 241 print_preview.NativeLayer.EventType.CLOUD_PRINT_ENABLE, 242 this.onCloudPrintEnable_.bind(this)); 243 this.tracker.add( 244 this.nativeLayer_, 245 print_preview.NativeLayer.EventType.PRINT_TO_CLOUD, 246 this.onPrintToCloud_.bind(this)); 247 this.tracker.add( 248 this.nativeLayer_, 249 print_preview.NativeLayer.EventType.FILE_SELECTION_CANCEL, 250 this.onFileSelectionCancel_.bind(this)); 251 this.tracker.add( 252 this.nativeLayer_, 253 print_preview.NativeLayer.EventType.FILE_SELECTION_COMPLETE, 254 this.onFileSelectionComplete_.bind(this)); 255 this.tracker.add( 256 this.nativeLayer_, 257 print_preview.NativeLayer.EventType.SETTINGS_INVALID, 258 this.onSettingsInvalid_.bind(this)); 259 this.tracker.add( 260 this.nativeLayer_, 261 print_preview.NativeLayer.EventType.DISABLE_SCALING, 262 this.onDisableScaling_.bind(this)); 263 this.tracker.add( 264 this.nativeLayer_, 265 print_preview.NativeLayer.EventType.PRIVET_PRINT_FAILED, 266 this.onPrivetPrintFailed_.bind(this)); 267 268 269 this.tracker.add( 270 $('system-dialog-link'), 271 'click', 272 this.openSystemPrintDialog_.bind(this)); 273 this.tracker.add( 274 $('cloud-print-dialog-link'), 275 'click', 276 this.onCloudPrintDialogLinkClick_.bind(this)); 277 this.tracker.add( 278 $('open-pdf-in-preview-link'), 279 'click', 280 this.onOpenPdfInPreviewLinkClick_.bind(this)); 281 282 this.tracker.add( 283 this.previewArea_, 284 print_preview.PreviewArea.EventType.PREVIEW_GENERATION_IN_PROGRESS, 285 this.onPreviewGenerationInProgress_.bind(this)); 286 this.tracker.add( 287 this.previewArea_, 288 print_preview.PreviewArea.EventType.PREVIEW_GENERATION_DONE, 289 this.onPreviewGenerationDone_.bind(this)); 290 this.tracker.add( 291 this.previewArea_, 292 print_preview.PreviewArea.EventType.PREVIEW_GENERATION_FAIL, 293 this.onPreviewGenerationFail_.bind(this)); 294 this.tracker.add( 295 this.previewArea_, 296 print_preview.PreviewArea.EventType.OPEN_SYSTEM_DIALOG_CLICK, 297 this.openSystemPrintDialog_.bind(this)); 298 299 this.tracker.add( 300 this.destinationStore_, 301 print_preview.DestinationStore.EventType. 302 SELECTED_DESTINATION_CAPABILITIES_READY, 303 this.printIfReady_.bind(this)); 304 this.tracker.add( 305 this.destinationStore_, 306 print_preview.DestinationStore.EventType.DESTINATION_SELECT, 307 this.onDestinationSelect_.bind(this)); 308 this.tracker.add( 309 this.destinationStore_, 310 print_preview.DestinationStore.EventType.DESTINATION_SEARCH_DONE, 311 this.onDestinationSearchDone_.bind(this)); 312 313 this.tracker.add( 314 this.printHeader_, 315 print_preview.PrintHeader.EventType.PRINT_BUTTON_CLICK, 316 this.onPrintButtonClick_.bind(this)); 317 this.tracker.add( 318 this.printHeader_, 319 print_preview.PrintHeader.EventType.CANCEL_BUTTON_CLICK, 320 this.onCancelButtonClick_.bind(this)); 321 322 this.tracker.add(window, 'keydown', this.onKeyDown_.bind(this)); 323 324 this.tracker.add( 325 this.destinationSettings_, 326 print_preview.DestinationSettings.EventType.CHANGE_BUTTON_ACTIVATE, 327 this.onDestinationChangeButtonActivate_.bind(this)); 328 329 this.tracker.add( 330 this.destinationSearch_, 331 print_preview.DestinationSearch.EventType.MANAGE_CLOUD_DESTINATIONS, 332 this.onManageCloudDestinationsActivated_.bind(this)); 333 this.tracker.add( 334 this.destinationSearch_, 335 print_preview.DestinationSearch.EventType.MANAGE_LOCAL_DESTINATIONS, 336 this.onManageLocalDestinationsActivated_.bind(this)); 337 this.tracker.add( 338 this.destinationSearch_, 339 print_preview.DestinationSearch.EventType.SIGN_IN, 340 this.onCloudPrintSignInActivated_.bind(this)); 341 this.tracker.add( 342 this.destinationSearch_, 343 print_preview.DestinationListItem.EventType.REGISTER_PROMO_CLICKED, 344 this.onCloudPrintRegisterPromoClick_.bind(this)); 345 346 // TODO(rltoscano): Move no-destinations-promo into its own component 347 // instead being part of PrintPreview. 348 this.tracker.add( 349 this.getChildElement('#no-destinations-promo .close-button'), 350 'click', 351 this.onNoDestinationsPromoClose_.bind(this)); 352 this.tracker.add( 353 this.getChildElement('#no-destinations-promo .not-now-button'), 354 'click', 355 this.onNoDestinationsPromoClose_.bind(this)); 356 this.tracker.add( 357 this.getChildElement('#no-destinations-promo .add-printer-button'), 358 'click', 359 this.onNoDestinationsPromoClick_.bind(this)); 360 }, 361 362 /** @override */ 363 decorateInternal: function() { 364 this.printHeader_.decorate($('print-header')); 365 this.destinationSearch_.decorate($('destination-search')); 366 this.destinationSettings_.decorate($('destination-settings')); 367 this.pageSettings_.decorate($('page-settings')); 368 this.copiesSettings_.decorate($('copies-settings')); 369 this.layoutSettings_.decorate($('layout-settings')); 370 this.colorSettings_.decorate($('color-settings')); 371 this.marginSettings_.decorate($('margin-settings')); 372 this.otherOptionsSettings_.decorate($('other-options-settings')); 373 this.previewArea_.decorate($('preview-area')); 374 375 setIsVisible($('open-pdf-in-preview-link'), cr.isMac); 376 }, 377 378 /** 379 * Sets whether the controls in the print preview are enabled. 380 * @param {boolean} isEnabled Whether the controls in the print preview are 381 * enabled. 382 * @private 383 */ 384 setIsEnabled_: function(isEnabled) { 385 $('system-dialog-link').disabled = !isEnabled; 386 $('cloud-print-dialog-link').disabled = !isEnabled; 387 $('open-pdf-in-preview-link').disabled = !isEnabled; 388 this.printHeader_.isEnabled = isEnabled; 389 this.destinationSettings_.isEnabled = isEnabled; 390 this.pageSettings_.isEnabled = isEnabled; 391 this.copiesSettings_.isEnabled = isEnabled; 392 this.layoutSettings_.isEnabled = isEnabled; 393 this.colorSettings_.isEnabled = isEnabled; 394 this.marginSettings_.isEnabled = isEnabled; 395 this.otherOptionsSettings_.isEnabled = isEnabled; 396 }, 397 398 /** 399 * Prints the document or launches a pdf preview on the local system. 400 * @param {boolean} isPdfPreview Whether to launch the pdf preview. 401 * @private 402 */ 403 printDocumentOrOpenPdfPreview_: function(isPdfPreview) { 404 assert(this.uiState_ == PrintPreview.UiState_.READY, 405 'Print document request received when not in ready state: ' + 406 this.uiState_); 407 if (isPdfPreview) { 408 this.uiState_ = PrintPreview.UiState_.OPENING_PDF_PREVIEW; 409 } else if (this.destinationStore_.selectedDestination.id == 410 print_preview.Destination.GooglePromotedId.SAVE_AS_PDF) { 411 this.uiState_ = PrintPreview.UiState_.FILE_SELECTION; 412 } else { 413 this.uiState_ = PrintPreview.UiState_.PRINTING; 414 } 415 this.setIsEnabled_(false); 416 this.printHeader_.isCancelButtonEnabled = true; 417 if (this.printIfReady_() && 418 ((this.destinationStore_.selectedDestination.isLocal && 419 !this.destinationStore_.selectedDestination.isPrivet && 420 this.destinationStore_.selectedDestination.id != 421 print_preview.Destination.GooglePromotedId.SAVE_AS_PDF) || 422 this.uiState_ == PrintPreview.UiState_.OPENING_PDF_PREVIEW)) { 423 // Hide the dialog for now. The actual print command will be issued when 424 // the preview generation is done. 425 this.nativeLayer_.startHideDialog(); 426 } 427 }, 428 429 /** 430 * Attempts to print if needed and if ready. 431 * @return {boolean} Whether a print request was issued. 432 * @private 433 */ 434 printIfReady_: function() { 435 if ((this.uiState_ == PrintPreview.UiState_.PRINTING || 436 this.uiState_ == PrintPreview.UiState_.OPENING_PDF_PREVIEW || 437 this.uiState_ == PrintPreview.UiState_.FILE_SELECTION || 438 this.isInKioskAutoPrintMode_) && 439 !this.isPreviewGenerationInProgress_ && 440 this.destinationStore_.selectedDestination && 441 this.destinationStore_.selectedDestination.capabilities) { 442 assert(this.printTicketStore_.isTicketValid(), 443 'Trying to print with invalid ticket'); 444 this.nativeLayer_.startPrint( 445 this.destinationStore_.selectedDestination, 446 this.printTicketStore_, 447 this.cloudPrintInterface_, 448 this.documentInfo_, 449 this.uiState_ == PrintPreview.UiState_.OPENING_PDF_PREVIEW); 450 return true; 451 } else { 452 return false; 453 } 454 }, 455 456 /** 457 * Closes the print preview. 458 * @private 459 */ 460 close_: function() { 461 this.exitDocument(); 462 this.uiState_ = PrintPreview.UiState_.CLOSING; 463 this.nativeLayer_.startCloseDialog(); 464 }, 465 466 /** 467 * Opens the native system print dialog after disabling all controls. 468 * @private 469 */ 470 openSystemPrintDialog_: function() { 471 setIsVisible($('system-dialog-throbber'), true); 472 this.setIsEnabled_(false); 473 this.uiState_ = PrintPreview.UiState_.OPENING_NATIVE_PRINT_DIALOG; 474 this.nativeLayer_.startShowSystemDialog(); 475 }, 476 477 /** 478 * Called when the native layer has initial settings to set. Sets the 479 * initial settings of the print preview and begins fetching print 480 * destinations. 481 * @param {Event} event Contains the initial print preview settings 482 * persisted through the session. 483 * @private 484 */ 485 onInitialSettingsSet_: function(event) { 486 assert(this.uiState_ == PrintPreview.UiState_.INITIALIZING, 487 'Updating initial settings when not in initializing state: ' + 488 this.uiState_); 489 this.uiState_ = PrintPreview.UiState_.READY; 490 491 var settings = event.initialSettings; 492 this.isInKioskAutoPrintMode_ = settings.isInKioskAutoPrintMode; 493 494 // The following components must be initialized in this order. 495 this.appState_.init(settings.serializedAppStateStr); 496 this.documentInfo_.init( 497 settings.isDocumentModifiable, 498 settings.documentTitle, 499 settings.documentHasSelection); 500 this.printTicketStore_.init( 501 settings.thousandsDelimeter, 502 settings.decimalDelimeter, 503 settings.unitType, 504 settings.selectionOnly); 505 this.destinationStore_.init(settings.systemDefaultDestinationId); 506 this.appState_.setInitialized(); 507 508 $('document-title').innerText = settings.documentTitle; 509 setIsVisible($('system-dialog-link'), 510 !settings.hidePrintWithSystemDialogLink); 511 }, 512 513 /** 514 * Calls when the native layer enables Google Cloud Print integration. 515 * Fetches the user's cloud printers. 516 * @param {Event} event Contains the base URL of the Google Cloud Print 517 * service. 518 * @private 519 */ 520 onCloudPrintEnable_: function(event) { 521 this.cloudPrintInterface_ = 522 new cloudprint.CloudPrintInterface(event.baseCloudPrintUrl, 523 this.nativeLayer_); 524 this.tracker.add( 525 this.cloudPrintInterface_, 526 cloudprint.CloudPrintInterface.EventType.SUBMIT_DONE, 527 this.onCloudPrintSubmitDone_.bind(this)); 528 this.tracker.add( 529 this.cloudPrintInterface_, 530 cloudprint.CloudPrintInterface.EventType.SEARCH_FAILED, 531 this.onCloudPrintError_.bind(this)); 532 this.tracker.add( 533 this.cloudPrintInterface_, 534 cloudprint.CloudPrintInterface.EventType.SUBMIT_FAILED, 535 this.onCloudPrintError_.bind(this)); 536 this.tracker.add( 537 this.cloudPrintInterface_, 538 cloudprint.CloudPrintInterface.EventType.PRINTER_FAILED, 539 this.onCloudPrintError_.bind(this)); 540 this.tracker.add( 541 this.cloudPrintInterface_, 542 cloudprint.CloudPrintInterface.EventType. 543 UPDATE_PRINTER_TOS_ACCEPTANCE_FAILED, 544 this.onCloudPrintError_.bind(this)); 545 546 this.userInfo_.setCloudPrintInterface(this.cloudPrintInterface_); 547 this.destinationStore_.setCloudPrintInterface(this.cloudPrintInterface_); 548 if (this.destinationSearch_.getIsVisible()) { 549 this.destinationStore_.startLoadCloudDestinations(); 550 } 551 }, 552 553 /** 554 * Called from the native layer when ready to print to Google Cloud Print. 555 * @param {Event} event Contains the body to send in the HTTP request. 556 * @private 557 */ 558 onPrintToCloud_: function(event) { 559 assert(this.uiState_ == PrintPreview.UiState_.PRINTING, 560 'Document ready to be sent to the cloud when not in printing ' + 561 'state: ' + this.uiState_); 562 assert(this.cloudPrintInterface_ != null, 563 'Google Cloud Print is not enabled'); 564 this.cloudPrintInterface_.submit( 565 this.destinationStore_.selectedDestination, 566 this.printTicketStore_, 567 this.documentInfo_, 568 event.data); 569 }, 570 571 /** 572 * Called from the native layer when the user cancels the save-to-pdf file 573 * selection dialog. 574 * @private 575 */ 576 onFileSelectionCancel_: function() { 577 assert(this.uiState_ == PrintPreview.UiState_.FILE_SELECTION, 578 'File selection cancelled when not in file-selection state: ' + 579 this.uiState_); 580 this.setIsEnabled_(true); 581 this.uiState_ = PrintPreview.UiState_.READY; 582 }, 583 584 /** 585 * Called from the native layer when save-to-pdf file selection is complete. 586 * @private 587 */ 588 onFileSelectionComplete_: function() { 589 assert(this.uiState_ == PrintPreview.UiState_.FILE_SELECTION, 590 'File selection completed when not in file-selection state: ' + 591 this.uiState_); 592 this.previewArea_.showCustomMessage( 593 localStrings.getString('printingToPDFInProgress')); 594 this.uiState_ = PrintPreview.UiState_.PRINTING; 595 }, 596 597 /** 598 * Called after successfully submitting a job to Google Cloud Print. 599 * @param {!Event} event Contains the ID of the submitted print job. 600 * @private 601 */ 602 onCloudPrintSubmitDone_: function(event) { 603 assert(this.uiState_ == PrintPreview.UiState_.PRINTING, 604 'Submited job to Google Cloud Print but not in printing state ' + 605 this.uiState_); 606 if (this.destinationStore_.selectedDestination.id == 607 print_preview.Destination.GooglePromotedId.FEDEX) { 608 this.nativeLayer_.startForceOpenNewTab( 609 'https://www.google.com/cloudprint/fedexcode.html?jobid=' + 610 event.jobId); 611 } 612 this.close_(); 613 }, 614 615 /** 616 * Called when there was an error communicating with Google Cloud print. 617 * Displays an error message in the print header. 618 * @param {!Event} event Contains the error message. 619 * @private 620 */ 621 onCloudPrintError_: function(event) { 622 if (event.status == 403) { 623 this.destinationSearch_.showCloudPrintPromo(); 624 } else if (event.status == 0) { 625 return; // Ignore, the system does not have internet connectivity. 626 } else { 627 this.printHeader_.setErrorMessage(event.message); 628 } 629 if (event.status == 200) { 630 console.error('Google Cloud Print Error: (' + event.errorCode + ') ' + 631 event.message); 632 } else { 633 console.error('Google Cloud Print Error: HTTP status ' + event.status); 634 } 635 }, 636 637 /** 638 * Called when the preview area's preview generation is in progress. 639 * @private 640 */ 641 onPreviewGenerationInProgress_: function() { 642 this.isPreviewGenerationInProgress_ = true; 643 }, 644 645 /** 646 * Called when the preview area's preview generation is complete. 647 * @private 648 */ 649 onPreviewGenerationDone_: function() { 650 this.isPreviewGenerationInProgress_ = false; 651 this.printHeader_.isPrintButtonEnabled = true; 652 this.printIfReady_(); 653 }, 654 655 /** 656 * Called when the preview area's preview failed to load. 657 * @private 658 */ 659 onPreviewGenerationFail_: function() { 660 this.isPreviewGenerationInProgress_ = false; 661 this.printHeader_.isPrintButtonEnabled = false; 662 if (this.uiState_ == PrintPreview.UiState_.PRINTING) { 663 this.nativeLayer_.startCancelPendingPrint(); 664 } 665 }, 666 667 /** 668 * Called when the 'Open pdf in preview' link is clicked. Launches the pdf 669 * preview app. 670 * @private 671 */ 672 onOpenPdfInPreviewLinkClick_: function() { 673 assert(this.uiState_ == PrintPreview.UiState_.READY, 674 'Trying to open pdf in preview when not in ready state: ' + 675 this.uiState_); 676 setIsVisible($('open-preview-app-throbber'), true); 677 this.previewArea_.showCustomMessage( 678 localStrings.getString('openingPDFInPreview')); 679 this.printDocumentOrOpenPdfPreview_(true /*isPdfPreview*/); 680 }, 681 682 /** 683 * Called when the print header's print button is clicked. Prints the 684 * document. 685 * @private 686 */ 687 onPrintButtonClick_: function() { 688 assert(this.uiState_ == PrintPreview.UiState_.READY, 689 'Trying to print when not in ready state: ' + this.uiState_); 690 this.printDocumentOrOpenPdfPreview_(false /*isPdfPreview*/); 691 }, 692 693 /** 694 * Called when the print header's cancel button is clicked. Closes the 695 * print dialog. 696 * @private 697 */ 698 onCancelButtonClick_: function() { 699 this.close_(); 700 }, 701 702 /** 703 * Called when the register promo for Cloud Print is clicked. 704 * @private 705 */ 706 onCloudPrintRegisterPromoClick_: function(e) { 707 var devicesUrl = 'chrome://devices/register?id=' + e.destination.id; 708 this.nativeLayer_.startForceOpenNewTab(devicesUrl); 709 }, 710 711 /** 712 * Consume escape key presses and ctrl + shift + p. Delegate everything else 713 * to the preview area. 714 * @param {KeyboardEvent} e The keyboard event. 715 * @private 716 */ 717 onKeyDown_: function(e) { 718 // Escape key closes the dialog. 719 if (e.keyCode == 27 && !e.shiftKey && !e.ctrlKey && !e.altKey && 720 !e.metaKey) { 721 if (this.destinationSearch_.getIsVisible()) { 722 this.destinationSearch_.setIsVisible(false); 723 this.metrics_.incrementDestinationSearchBucket( 724 print_preview.Metrics.DestinationSearchBucket.CANCELED); 725 } else { 726 // <if expr="pp_ifdef('toolkit_views')"> 727 // On the toolkit_views environment, ESC key is handled by C++-side 728 // instead of JS-side. 729 return; 730 // </if> 731 // <if expr="not pp_ifdef('toolkit_views')"> 732 // Dummy comment to absorb previous line's comment symbol. 733 this.close_(); 734 // </if> 735 } 736 e.preventDefault(); 737 return; 738 } 739 740 // Ctrl + Shift + p / Mac equivalent. 741 if (e.keyCode == 80) { 742 if ((cr.isMac && e.metaKey && e.altKey && !e.shiftKey && !e.ctrlKey) || 743 (!cr.isMac && e.shiftKey && e.ctrlKey && !e.altKey && !e.metaKey)) { 744 this.openSystemPrintDialog_(); 745 e.preventDefault(); 746 return; 747 } 748 } 749 750 if (e.keyCode == 13 /*enter*/ && 751 !this.destinationSearch_.getIsVisible() && 752 this.printTicketStore_.isTicketValid()) { 753 assert(this.uiState_ == PrintPreview.UiState_.READY, 754 'Trying to print when not in ready state: ' + this.uiState_); 755 this.printDocumentOrOpenPdfPreview_(false /*isPdfPreview*/); 756 e.preventDefault(); 757 return; 758 } 759 760 // Pass certain directional keyboard events to the PDF viewer. 761 this.previewArea_.handleDirectionalKeyEvent(e); 762 }, 763 764 /** 765 * Called when native layer receives invalid settings for a print request. 766 * @private 767 */ 768 onSettingsInvalid_: function() { 769 this.uiState_ = PrintPreview.UiState_.ERROR; 770 console.error('Invalid settings error reported from native layer'); 771 this.previewArea_.showCustomMessage( 772 localStrings.getString('invalidPrinterSettings')); 773 }, 774 775 /** 776 * Called when the destination settings' change button is activated. 777 * Displays the destination search component. 778 * @private 779 */ 780 onDestinationChangeButtonActivate_: function() { 781 this.destinationSearch_.setIsVisible(true); 782 this.destinationStore_.startLoadCloudDestinations(); 783 this.destinationStore_.startLoadLocalDestinations(); 784 this.destinationStore_.startLoadPrivetDestinations(); 785 this.metrics_.incrementDestinationSearchBucket( 786 print_preview.Metrics.DestinationSearchBucket.SHOWN); 787 }, 788 789 /** 790 * Called when the destination search dispatches manage cloud destinations 791 * event. Calls corresponding native layer method. 792 * @private 793 */ 794 onManageCloudDestinationsActivated_: function() { 795 this.nativeLayer_.startManageCloudDestinations(); 796 }, 797 798 /** 799 * Called when the destination search dispatches manage local destinations 800 * event. Calls corresponding native layer method. 801 * @private 802 */ 803 onManageLocalDestinationsActivated_: function() { 804 this.nativeLayer_.startManageLocalDestinations(); 805 }, 806 807 /** 808 * Called when the user wants to sign in to Google Cloud Print. Calls the 809 * corresponding native layer event. 810 * @private 811 */ 812 onCloudPrintSignInActivated_: function() { 813 this.nativeLayer_.startCloudPrintSignIn(); 814 }, 815 816 /** 817 * Called when the native layer dispatches a DISABLE_SCALING event. Resets 818 * fit-to-page selection and updates document info. 819 * @private 820 */ 821 onDisableScaling_: function() { 822 this.printTicketStore_.fitToPage.updateValue(null); 823 this.documentInfo_.updateIsScalingDisabled(true); 824 }, 825 826 /** 827 * Called when privet printing fails. 828 * @param {Event} event Event object representing the failure. 829 * @private 830 */ 831 onPrivetPrintFailed_: function(event) { 832 console.error('Privet printing failed with error code ' + 833 event.httpError); 834 this.printHeader_.setErrorMessage( 835 localStrings.getString('couldNotPrint')); 836 }, 837 838 /** 839 * Called when the open-cloud-print-dialog link is clicked. Opens the Google 840 * Cloud Print web dialog. 841 * @private 842 */ 843 onCloudPrintDialogLinkClick_: function() { 844 assert(this.uiState_ == PrintPreview.UiState_.READY, 845 'Opening Google Cloud Print dialog when not in ready state: ' + 846 this.uiState_); 847 setIsVisible($('cloud-print-dialog-throbber'), true); 848 this.setIsEnabled_(false); 849 this.uiState_ = PrintPreview.UiState_.OPENING_NATIVE_PRINT_DIALOG; 850 this.nativeLayer_.startShowCloudPrintDialog( 851 this.printTicketStore_.pageRange.getPageNumberSet().size); 852 }, 853 854 /** 855 * Called when a print destination is selected. Shows/hides the "Print with 856 * Cloud Print" link in the navbar. 857 * @private 858 */ 859 onDestinationSelect_: function() { 860 var selectedDest = this.destinationStore_.selectedDestination; 861 setIsVisible($('cloud-print-dialog-link'), 862 !cr.isChromeOS && !selectedDest.isLocal); 863 }, 864 865 /** 866 * Called when the destination store loads a group of destinations. Shows 867 * a promo on Chrome OS if the user has no print destinations promoting 868 * Google Cloud Print. 869 * @private 870 */ 871 onDestinationSearchDone_: function() { 872 var isPromoVisible = cr.isChromeOS && 873 this.cloudPrintInterface_ && 874 this.userInfo_.getUserEmail() && 875 !this.appState_.isGcpPromoDismissed && 876 !this.destinationStore_.isLocalDestinationsSearchInProgress && 877 !this.destinationStore_.isCloudDestinationsSearchInProgress && 878 this.destinationStore_.hasOnlyDefaultCloudDestinations(); 879 setIsVisible(this.getChildElement('#no-destinations-promo'), 880 isPromoVisible); 881 if (isPromoVisible) { 882 this.metrics_.incrementGcpPromoBucket( 883 print_preview.Metrics.GcpPromoBucket.SHOWN); 884 } 885 }, 886 887 /** 888 * Called when the close button on the no-destinations-promotion is clicked. 889 * Hides the promotion. 890 * @private 891 */ 892 onNoDestinationsPromoClose_: function() { 893 this.metrics_.incrementGcpPromoBucket( 894 print_preview.Metrics.GcpPromoBucket.DISMISSED); 895 setIsVisible(this.getChildElement('#no-destinations-promo'), false); 896 this.appState_.persistIsGcpPromoDismissed(true); 897 }, 898 899 /** 900 * Called when the no-destinations promotion link is clicked. Opens the 901 * Google Cloud Print management page and closes the print preview. 902 * @private 903 */ 904 onNoDestinationsPromoClick_: function() { 905 this.metrics_.incrementGcpPromoBucket( 906 print_preview.Metrics.GcpPromoBucket.CLICKED); 907 this.appState_.persistIsGcpPromoDismissed(true); 908 window.open(this.cloudPrintInterface_.baseUrl + '?user=' + 909 this.userInfo_.getUserEmail() + '#printers'); 910 this.close_(); 911 } 912 }; 913 914 // Export 915 return { 916 PrintPreview: PrintPreview 917 }; 918}); 919 920// Pull in all other scripts in a single shot. 921<include src="data/page_number_set.js"/> 922<include src="data/destination.js"/> 923<include src="data/local_parsers.js"/> 924<include src="data/cloud_parsers.js"/> 925<include src="data/destination_store.js"/> 926<include src="data/margins.js"/> 927<include src="data/document_info.js"/> 928<include src="data/printable_area.js"/> 929<include src="data/measurement_system.js"/> 930<include src="data/print_ticket_store.js"/> 931<include src="data/coordinate2d.js"/> 932<include src="data/size.js"/> 933<include src="data/capabilities_holder.js"/> 934<include src="data/user_info.js"/> 935<include src="data/app_state.js"/> 936 937<include src="data/ticket_items/ticket_item.js"/> 938 939<include src="data/ticket_items/custom_margins.js"/> 940<include src="data/ticket_items/collate.js"/> 941<include src="data/ticket_items/color.js"/> 942<include src="data/ticket_items/copies.js"/> 943<include src="data/ticket_items/duplex.js"/> 944<include src="data/ticket_items/header_footer.js"/> 945<include src="data/ticket_items/landscape.js"/> 946<include src="data/ticket_items/margins_type.js"/> 947<include src="data/ticket_items/page_range.js"/> 948<include src="data/ticket_items/fit_to_page.js"/> 949<include src="data/ticket_items/css_background.js"/> 950<include src="data/ticket_items/selection_only.js"/> 951 952<include src="native_layer.js"/> 953<include src="print_preview_animations.js"/> 954<include src="cloud_print_interface.js"/> 955<include src="print_preview_utils.js"/> 956<include src="print_header.js"/> 957<include src="metrics.js"/> 958 959<include src="settings/page_settings.js"/> 960<include src="settings/copies_settings.js"/> 961<include src="settings/layout_settings.js"/> 962<include src="settings/color_settings.js"/> 963<include src="settings/margin_settings.js"/> 964<include src="settings/destination_settings.js"/> 965<include src="settings/other_options_settings.js"/> 966 967<include src="previewarea/margin_control.js"/> 968<include src="previewarea/margin_control_container.js"/> 969<include src="previewarea/preview_area.js"/> 970<include src="preview_generator.js"/> 971 972<include src="search/destination_list.js"/> 973<include src="search/cloud_destination_list.js"/> 974<include src="search/recent_destination_list.js"/> 975<include src="search/destination_list_item.js"/> 976<include src="search/destination_search.js"/> 977<include src="search/search_box.js"/> 978<include src="search/fedex_tos.js"/> 979 980window.addEventListener('DOMContentLoaded', function() { 981 printPreview = new print_preview.PrintPreview(); 982 printPreview.initialize(); 983}); 984