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