OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // require: cr/ui/print_preview_cloud.js | 5 // TODO Might be a problem where might be in fetching destinations state, then |
| 6 // to file selection state, then cancel, which results in the fetching |
| 7 // destinations state being lost. |
| 8 |
| 9 // TODO Move data/* into print_preview.data namespace |
| 10 |
| 11 // TODO Handle case where cloud print is initial destination, but cloud print is |
| 12 // not enabled. |
6 | 13 |
7 var localStrings = new LocalStrings(); | 14 var localStrings = new LocalStrings(); |
8 | 15 |
9 // If useCloudPrint is true we attempt to connect to cloud print | |
10 // and populate the list of printers with cloud print printers. | |
11 var useCloudPrint = false; | |
12 | |
13 // Store the last selected printer index. | |
14 var lastSelectedPrinterIndex = 0; | |
15 | |
16 // Used to disable some printing options when the preview is not modifiable. | |
17 var previewModifiable = false; | |
18 | |
19 // Used to identify whether the printing frame has specific page size style. | |
20 var hasPageSizeStyle = false; | |
21 | |
22 // Destination list special value constants. | 16 // Destination list special value constants. |
23 | 17 /** @const **/ var PRINT_TO_PDF = 'Save as PDF'; |
24 /** @const */ var MANAGE_CLOUD_PRINTERS = 'manageCloudPrinters'; | |
25 /** @const */ var MANAGE_LOCAL_PRINTERS = 'manageLocalPrinters'; | |
26 /** @const */ var SIGN_IN = 'signIn'; | |
27 /** @const */ var PRINT_TO_PDF = 'Save as PDF'; | |
28 /** @const */ var PRINT_WITH_CLOUD_PRINT = 'printWithCloudPrint'; | |
29 | |
30 // State of the print preview settings. | |
31 var printSettings = new PrintSettings(); | |
32 | |
33 // Print ready data index. | |
34 /** @const */ var PRINT_READY_DATA_INDEX = -1; | |
35 | |
36 // The name of the default or last used printer. | |
37 var defaultOrLastUsedPrinterName = ''; | |
38 | |
39 // True when a pending print preview request exists. | |
40 var hasPendingPreviewRequest = false; | |
41 | |
42 // True when the first page is loaded in the plugin. | |
43 var isFirstPageLoaded = false; | |
44 | |
45 // The ID of the last preview request. | |
46 var lastPreviewRequestID = -1; | |
47 | |
48 // The ID of the initial preview request. | |
49 var initialPreviewRequestID = -1; | |
50 | |
51 // True when a pending print file request exists. | |
52 var hasPendingPrintDocumentRequest = false; | |
53 | |
54 // True when the complete metafile for the previewed doc is ready. | |
55 var isPrintReadyMetafileReady = false; | |
56 | |
57 // True when preview tab is hidden. | |
58 var isTabHidden = false; | |
59 | |
60 // True in kiosk mode where print preview can print automatically without | |
61 // user intervention. See http://crbug.com/31395. | |
62 var printAutomaticallyInKioskMode = false; | |
63 | |
64 // @type {print_preview.PrintHeader} Holds the print and cancel buttons. | |
65 var printHeader; | |
66 | |
67 // @type {print_preview.PageSettings} Holds all the pages related settings. | |
68 var pageSettings; | |
69 | |
70 // @type {print_preview.CopiesSettings} Holds all the copies related settings. | |
71 var copiesSettings; | |
72 | |
73 // @type {print_preview.LayoutSettings} Holds all the layout related settings. | |
74 var layoutSettings; | |
75 | |
76 // @type {print_preview.MarginSettings} Holds all the margin related settings. | |
77 var marginSettings; | |
78 | |
79 // @type {print_preview.HeaderFooterSettings} Holds all the header footer | |
80 // related settings. | |
81 var headerFooterSettings; | |
82 | |
83 // @type {print_preview.ColorSettings} Holds all the color related settings. | |
84 var colorSettings; | |
85 | |
86 // @type {print_preview.PreviewArea} Holds information related to the preview | |
87 // area (on the right). | |
88 var previewArea; | |
89 | |
90 // True if the user has click 'Advanced...' in order to open the system print | |
91 // dialog. | |
92 var showingSystemDialog = false; | |
93 | |
94 // True if the user has clicked 'Open PDF in Preview' option. | |
95 var previewAppRequested = false; | |
96 | |
97 // The range of options in the printer dropdown controlled by cloud print. | |
98 var firstCloudPrintOptionPos = 0; | |
99 var lastCloudPrintOptionPos = firstCloudPrintOptionPos; | |
100 | |
101 // Store the current previewUid. | |
102 var currentPreviewUid = ''; | |
103 | |
104 // True if we need to generate draft preview data. | |
105 var generateDraftData = true; | |
106 | 18 |
107 // The last element clicked with the mouse. | 19 // The last element clicked with the mouse. |
108 var lastClickedElement = null; | 20 var lastClickedElement = null; |
109 | 21 |
110 // A dictionary of cloud printers that have been added to the printer | 22 cr.define('print_preview', function() { |
111 // dropdown. | 23 'use strict'; |
112 var addedCloudPrinters = {}; | 24 |
113 | 25 /** |
114 // The maximum number of cloud printers to allow in the dropdown. | 26 * Container class for Chromium's print preview. |
115 /** @const */ var maxCloudPrinters = 10; | 27 * @constructor |
116 | 28 */ |
117 /** @const */ var MIN_REQUEST_ID = 0; | 29 function PrintPreview() { |
118 /** @const */ var MAX_REQUEST_ID = 32000; | 30 // TODO Inherit from print_preview.Component |
119 | 31 |
120 // Names of all the custom events used. | 32 /** |
121 var customEvents = { | 33 * Data store which holds print destinations. |
122 // Fired when the mouse moves while a margin line is being dragged. | 34 * @type {print_preview.DestinationStore!} |
123 MARGIN_LINE_DRAG: 'marginLineDrag', | 35 * @private |
124 // Fired when a mousedown event occurs on a margin line. | 36 */ |
125 MARGIN_LINE_MOUSE_DOWN: 'marginLineMouseDown', | 37 this.destinationStore_ = new print_preview.DestinationStore(); |
126 // Fired when a margin textbox gains focus. | 38 |
127 MARGIN_TEXTBOX_FOCUSED: 'marginTextboxFocused', | 39 /** |
128 // Fired when a new preview might be needed because of margin changes. | 40 * Storage of the print ticket used to create the print job. |
129 MARGINS_MAY_HAVE_CHANGED: 'marginsMayHaveChanged', | 41 * @type {print_preview.PrintTicketStore!} |
130 // Fired when a pdf generation related error occurs. | 42 * @private |
131 PDF_GENERATION_ERROR: 'PDFGenerationError', | 43 */ |
132 // Fired once the first page of the pdf document is loaded in the plugin. | 44 this.printTicketStore_ = new print_preview.PrintTicketStore( |
133 PDF_LOADED: 'PDFLoaded', | 45 this.destinationStore_); |
134 // Fired when the selected printer capabilities change. | 46 |
135 PRINTER_CAPABILITIES_UPDATED: 'printerCapabilitiesUpdated', | 47 /** |
136 // Fired when the print button needs to be updated. | 48 * Widget used to search for print destinations. |
137 UPDATE_PRINT_BUTTON: 'updatePrintButton', | 49 * @type {print_preview.DestinationSearch!} |
138 // Fired when the print summary needs to be updated. | 50 * @private |
139 UPDATE_SUMMARY: 'updateSummary' | 51 */ |
140 }; | 52 this.destinationSearch_ = new print_preview.DestinationSearch( |
141 | 53 this.destinationStore_); |
142 /** | 54 |
143 * Window onload handler, sets up the page and starts print preview by getting | 55 /** |
144 * the printer list. | 56 * Holds the print and cancel buttons and renders some document statistics. |
145 */ | 57 * @type {print_preview.PrintHeader!} |
146 function onLoad() { | 58 * @private |
147 initialPreviewRequestID = randomInteger(MIN_REQUEST_ID, MAX_REQUEST_ID); | 59 */ |
148 lastPreviewRequestID = initialPreviewRequestID; | 60 this.printHeader_ = new print_preview.PrintHeader( |
149 | 61 this.printTicketStore_, this.destinationStore_); |
150 previewArea = print_preview.PreviewArea.getInstance(); | 62 |
151 printHeader = print_preview.PrintHeader.getInstance(); | 63 /** |
152 document.addEventListener(customEvents.PDF_GENERATION_ERROR, | 64 * Component that renders the print destination. |
153 cancelPendingPrintRequest); | 65 * @type {print_preview.DestinationSettings!} |
154 document.addEventListener('click', setLastClickedElement); | 66 * @private |
155 | 67 */ |
156 if (!checkCompatiblePluginExists()) { | 68 this.destinationSettings_ = new print_preview.DestinationSettings( |
157 disableInputElementsInSidebar(); | 69 this.destinationStore_); |
158 $('cancel-button').focus(); | 70 |
159 previewArea.displayErrorMessageWithButtonAndNotify( | 71 /** |
160 localStrings.getString('noPlugin'), | 72 * Component that renders UI for entering in page range. |
161 localStrings.getString('launchNativeDialog'), | 73 * @type {print_preview.PageSettings!} |
162 launchNativePrintDialog); | 74 * @private |
163 $('mainview').parentElement.removeChild($('dummy-viewer')); | 75 */ |
164 return; | 76 this.pageSettings_ = new print_preview.PageSettings(this.printTicketStore_); |
165 } | 77 |
166 | 78 /** |
167 $('system-dialog-link').addEventListener('click', onSystemDialogLinkClicked); | 79 * Component that renders the copies settings. |
168 if (cr.isMac) { | 80 * @type {print_preview.CopiesSettings!} |
169 $('open-pdf-in-preview-link').addEventListener( | 81 * @private |
170 'click', onOpenPdfInPreviewLinkClicked); | 82 */ |
171 } | 83 this.copiesSettings_ = new print_preview.CopiesSettings( |
172 $('mainview').parentElement.removeChild($('dummy-viewer')); | 84 this.printTicketStore_); |
173 | 85 |
174 $('printer-list').disabled = true; | 86 /** |
175 | 87 * Component that renders the layout settings. |
176 pageSettings = print_preview.PageSettings.getInstance(); | 88 * @type {print_preview.LayoutSettings!} |
177 copiesSettings = print_preview.CopiesSettings.getInstance(); | 89 * @private |
178 layoutSettings = print_preview.LayoutSettings.getInstance(); | 90 */ |
179 marginSettings = print_preview.MarginSettings.getInstance(); | 91 this.layoutSettings_ = new print_preview.LayoutSettings( |
180 headerFooterSettings = print_preview.HeaderFooterSettings.getInstance(); | 92 this.printTicketStore_); |
181 colorSettings = print_preview.ColorSettings.getInstance(); | 93 |
182 $('printer-list').onchange = updateControlsWithSelectedPrinterCapabilities; | 94 /** |
183 | 95 * Component that renders the color options. |
184 previewArea.showLoadingAnimation(); | 96 * @type {print_preview.ColorSettings!} |
185 chrome.send('getInitialSettings'); | 97 * @private |
186 } | 98 */ |
187 | 99 this.colorSettings_ = new print_preview.ColorSettings( |
188 /** | 100 this.printTicketStore_); |
189 * @param {object} initialSettings An object containing all the initial | 101 |
190 * settings. | 102 /** |
191 */ | 103 * Component that renders a select box for choosing margin settings. |
192 function setInitialSettings(initialSettings) { | 104 * @type {print_preview.MarginSettings!} |
193 setInitiatorTabTitle(initialSettings['initiatorTabTitle']); | 105 * @private |
194 previewModifiable = initialSettings['previewModifiable']; | 106 */ |
195 if (previewModifiable) { | 107 this.marginSettings_ = new print_preview.MarginSettings( |
196 print_preview.MarginSettings.setNumberFormatAndMeasurementSystem( | 108 this.printTicketStore_); |
197 initialSettings['numberFormat'], | 109 |
198 initialSettings['measurementSystem']); | 110 /** |
199 marginSettings.setLastUsedMargins(initialSettings); | 111 * Holds all the header footer related settings. |
200 } | 112 * @type {print_preview.HeaderFooterSettings!} |
201 printAutomaticallyInKioskMode = | 113 * @private |
202 initialSettings['printAutomaticallyInKioskMode']; | 114 */ |
203 headerFooterSettings.setChecked(initialSettings['headerFooterEnabled']); | 115 this.headerFooterSettings_ = new print_preview.HeaderFooterSettings( |
204 copiesSettings.previousDuplexMode = initialSettings['duplex']; | 116 this.printTicketStore_); |
205 setDefaultPrinter(initialSettings['printerName'], | 117 |
206 initialSettings['cloudPrintData']); | 118 /** |
207 } | 119 * Area of the UI that holds the print preview. |
208 | 120 * @type {print_preview.PreviewArea!} |
209 /** | 121 * @private |
210 * Disables the input elements in the sidebar. | 122 */ |
211 */ | 123 this.previewArea_ = new print_preview.PreviewArea( |
212 function disableInputElementsInSidebar() { | 124 this.printTicketStore_, this.previewGenerator_); |
213 var els = $('navbar-container').querySelectorAll('input, button, select'); | 125 |
214 for (var i = 0; i < els.length; i++) { | 126 /** |
215 if (els[i] == printHeader.cancelButton) | 127 * Interface to the Google Cloud Print API. Null if Google Cloud Print |
216 continue; | 128 * integration is disabled. |
217 els[i].disabled = true; | 129 * @type {cloudprint.CloudPrintInterface?} |
218 } | 130 * @private |
219 } | 131 */ |
220 | 132 this.cloudPrintInterface_ = null; |
221 /** | 133 |
222 * Enables the input elements in the sidebar. | 134 /** |
223 */ | 135 * Event tracker for the print preview. |
224 function enableInputElementsInSidebar() { | 136 * TODO Remove this when using print_preview.Component |
225 var els = $('navbar-container').querySelectorAll('input, button, select'); | 137 * @type {EventTracker!} |
226 for (var i = 0; i < els.length; i++) | 138 * @private |
227 els[i].disabled = false; | 139 */ |
228 } | 140 this.tracker_ = new EventTracker(); |
| 141 |
| 142 /** |
| 143 * Whether in kiosk mode where print preview can print automatically without |
| 144 * user intervention. See http://crbug.com/31395. |
| 145 * TODO Use this variable. |
| 146 * @type {boolean} |
| 147 * @private |
| 148 */ |
| 149 this.isInKioskAutoPrintMode_ = false; |
| 150 |
| 151 /** |
| 152 * State of the print preview UI. |
| 153 * @type {PrintPreview.UiState} |
| 154 * @private |
| 155 */ |
| 156 this.uiState_ = PrintPreview.UiState.INITIALIZING; |
| 157 |
| 158 /** |
| 159 * Current state of fetching destinations. |
| 160 * @type {PrintPreview.FetchPrintersState} |
| 161 * @private |
| 162 */ |
| 163 this.fetchState_ = PrintPreview.FetchState.READY; |
| 164 |
| 165 window.addEventListener('DOMContentLoaded', this.onWindowLoad_.bind(this)); |
| 166 }; |
| 167 |
| 168 /** |
| 169 * States of the print preview. |
| 170 * @enum {string} |
| 171 */ |
| 172 PrintPreview.UiState = { |
| 173 INITIALIZING: 'initializing', |
| 174 FETCHING_DESTINATIONS: 'fetching-destinations', |
| 175 READY: 'ready', |
| 176 OPENING_PDF_PREVIEW: 'opening-pdf-preview', |
| 177 OPENING_NATIVE_PRINT_DIALOG: 'opening-native-print-dialog', |
| 178 PRINTING: 'printing', |
| 179 FILE_SELECTION: 'file-selection', |
| 180 CLOSING: 'closing' |
| 181 }; |
| 182 |
| 183 /** |
| 184 * Bitfield of the states of fetching destinations. |
| 185 * @enum {number} |
| 186 * @private |
| 187 */ |
| 188 PrintPreview.FetchState = { |
| 189 READY: 1, |
| 190 LOCAL_DESTINATIONS: 2, |
| 191 RECENT_CLOUD_DESTINATIONS: 4, |
| 192 ALL_CLOUD_DESTINATIONS: 8 |
| 193 }; |
| 194 |
| 195 PrintPreview.prototype = { |
| 196 /** |
| 197 * Renders the UI of the print preview. |
| 198 * @private |
| 199 */ |
| 200 render_: function() { |
| 201 this.destinationSearch_.decorate($('destination-search')); |
| 202 this.printHeader_.decorate($('print-header')); |
| 203 this.destinationSettings_.decorate($('destination-settings')); |
| 204 this.pageSettings_.decorate($('page-settings')); |
| 205 this.copiesSettings_.decorate($('copies-settings')); |
| 206 this.layoutSettings_.decorate($('layout-settings')); |
| 207 this.colorSettings_.decorate($('color-settings')); |
| 208 this.marginSettings_.decorate($('margin-settings')); |
| 209 this.headerFooterSettings_.decorate($('header-footer-settings')); |
| 210 this.previewArea_.decorate($('preview-area')); |
| 211 this.addEventListeners_(); |
| 212 }, |
| 213 |
| 214 disable_: function() { |
| 215 $('system-dialog-link').disabled = true; |
| 216 if (cr.isMac) { |
| 217 $('open-pdf-in-preview-link').disabled = true; |
| 218 } |
| 219 this.printHeader_.isEnabled = false; |
| 220 this.destinationSettings_.isEnabled = false; |
| 221 this.pageSettings_.isEnabled = false; |
| 222 this.copiesSettings_.isEnabled = false; |
| 223 this.layoutSettings_.isEnabled = false; |
| 224 this.colorSettings_.isEnabled = false; |
| 225 this.marginSettings_.isEnabled = false; |
| 226 this.headerFooterSettings_.isEnabled = false; |
| 227 }, |
| 228 |
| 229 /** |
| 230 * Creates a local PDF print destination. |
| 231 * @return {print_preview.Destination} A new local PDF print destination. |
| 232 * @private |
| 233 */ |
| 234 createLocalPdfPrintDestination_: function() { |
| 235 var pdfDestination = new print_preview.Destination( |
| 236 PRINT_TO_PDF, |
| 237 localStrings.getString('printToPDF'), |
| 238 PRINT_TO_PDF == this.initialDestinationId_, |
| 239 true); |
| 240 var caps = new print_preview.CapabilityList(); |
| 241 pdfDestination.capabilities = caps; |
| 242 return pdfDestination; |
| 243 }, |
| 244 |
| 245 printDocumentOrOpenPdfPreview_: function(isPdfPreview) { |
| 246 if (this.uiState_ != PrintPreview.UiState.READY && |
| 247 this.uiState_ != PrintPreview.UiState.FETCHING_DESTINATIONS) { |
| 248 throw Error( |
| 249 'Print document request received when not in ready nor ' + |
| 250 'fetching-destinations state: ' + this.uiState_); |
| 251 } |
| 252 if (!this.printTicketStore_.isTicketValid()) { |
| 253 throw Error('Trying to print with an invalid print ticket'); |
| 254 } |
| 255 nativeLayer.startSaveDestinationAndTicket( |
| 256 this.destinationStore_.selectedDestination.id, |
| 257 this.printTicketStore_.serializeTicket()); |
| 258 nativeLayer.startPrint( |
| 259 this.printTicketStore_.createTicketForChromium(), |
| 260 this.printTicketStore_.createTicketForCloudPrint()); |
| 261 // TODO handle case when need to pop open file selection dialog. |
| 262 // if (isPdfPreview) { |
| 263 // settings.OpenPDFInPreview = isPdfPreview; |
| 264 // } |
| 265 this.uiState_ = isPdfPreview ? |
| 266 PrintPreview.UiState.OPENING_PDF_PREVIEW : |
| 267 PrintPreview.UiState.PRINTING; |
| 268 }, |
| 269 |
| 270 /** |
| 271 * Closes the print preview. |
| 272 * @private |
| 273 */ |
| 274 close_: function() { |
| 275 this.removeEventListeners_(); |
| 276 this.uiState_ = PrintPreview.UiState.CLOSING; |
| 277 nativeLayer.startCloseDialog(); |
| 278 }, |
| 279 |
| 280 openSystemPrintDialog_: function() { |
| 281 if (this.uiState_ != PrintPreview.UiState.READY && |
| 282 this.uiState_ != PrintPreview.UiState.FETCHING_DESTINATIONS) { |
| 283 throw Error( |
| 284 'Request to open system dialog received when not in ready nor ' + |
| 285 'fetching-destinations state: ' + this.uiState_); |
| 286 } |
| 287 this.disable_(); |
| 288 this.uiState_ = PrintPreview.UiState.OPENING_NATIVE_PRINT_DIALOG; |
| 289 nativeLayer.startShowSystemDialog(); |
| 290 }, |
| 291 |
| 292 /** |
| 293 * Adds event listeners used by this component. |
| 294 * @private |
| 295 */ |
| 296 addEventListeners_: function() { |
| 297 // Native layer events. |
| 298 this.tracker_.add( |
| 299 nativeLayer, |
| 300 print_preview.NativeLayer.Event.INITIAL_SETTINGS_SET, |
| 301 this.onInitialSettingsSet_.bind(this)); |
| 302 this.tracker_.add( |
| 303 nativeLayer, |
| 304 print_preview.NativeLayer.Event.CLOUD_PRINT_ENABLE, |
| 305 this.onCloudPrintEnable_.bind(this)); |
| 306 this.tracker_.add( |
| 307 nativeLayer, |
| 308 print_preview.NativeLayer.Event.LOCAL_DESTINATIONS_SET, |
| 309 this.onLocalDestinationsSet_.bind(this)); |
| 310 this.tracker_.add( |
| 311 nativeLayer, |
| 312 print_preview.NativeLayer.Event.CAPABILITIES_SET, |
| 313 this.onLocalDestinationCapabilitiesSet_.bind(this)); |
| 314 this.tracker_.add( |
| 315 nativeLayer, |
| 316 print_preview.NativeLayer.Event.DESTINATIONS_RELOAD, |
| 317 this.onDestinationsReload_.bind(this)); |
| 318 this.tracker_.add( |
| 319 nativeLayer, |
| 320 print_preview.NativeLayer.Event.PRINT_TO_CLOUD, |
| 321 this.onPrintToCloud_.bind(this)); |
| 322 this.tracker_.add( |
| 323 nativeLayer, |
| 324 print_preview.NativeLayer.Event.FILE_SELECTION_CANCEL, |
| 325 this.onFileSelectionCancel_.bind(this)); |
| 326 this.tracker_.add( |
| 327 nativeLayer, |
| 328 print_preview.NativeLayer.Event.FILE_SELECTION_COMPLETE, |
| 329 this.onFileSelectionComplete_.bind(this)); |
| 330 this.tracker_.add( |
| 331 nativeLayer, |
| 332 print_preview.NativeLayer.Event.SETTINGS_INVALID, |
| 333 this.onSettingsInvalid_.bind(this)); |
| 334 |
| 335 this.tracker_.add( |
| 336 this.destinationSettings_, |
| 337 print_preview.DestinationSettings.Event.CHANGE_BUTTON_ACTIVATE, |
| 338 this.onDestinationChangeButtonActivate_.bind(this)); |
| 339 |
| 340 this.tracker_.add( |
| 341 $('system-dialog-link'), |
| 342 'click', |
| 343 this.onSystemDialogLinkClicked_.bind(this)); |
| 344 |
| 345 if (cr.isMac) { |
| 346 this.tracker_.add( |
| 347 $('open-pdf-in-preview-link'), |
| 348 'click', |
| 349 this.onOpenPdfInPreviewLinkClick_.bind(this)); |
| 350 } |
| 351 |
| 352 // TODO Do we still need this? |
| 353 this.tracker_.add(document, 'click', setLastClickedElement); |
| 354 |
| 355 this.tracker_.add( |
| 356 this.previewArea_, |
| 357 print_preview.PreviewArea.Event.PREVIEW_GENERATION_FAIL, |
| 358 this.onPreviewGenerationFail_.bind(this)); |
| 359 this.tracker_.add( |
| 360 this.previewArea_, |
| 361 print_preview.PreviewArea.Event.OPEN_SYSTEM_DIALOG_CLICK, |
| 362 this.openSystemPrintDialog_.bind(this)); |
| 363 |
| 364 this.tracker_.add( |
| 365 this.destinationStore_, |
| 366 print_preview.DestinationStore.Event.DESTINATION_SELECT, |
| 367 this.onDestinationSelect_.bind(this)); |
| 368 |
| 369 this.tracker_.add( |
| 370 this.printHeader_, |
| 371 print_preview.PrintHeader.Event.PRINT_BUTTON_CLICK, |
| 372 this.onPrintButtonClick_.bind(this)); |
| 373 this.tracker_.add( |
| 374 this.printHeader_, |
| 375 print_preview.PrintHeader.Event.CANCEL_BUTTON_CLICK, |
| 376 this.onCancelButtonClick_.bind(this)); |
| 377 |
| 378 this.tracker_.add( |
| 379 this.destinationSearch_, |
| 380 print_preview.DestinationSearch.Event.SIGN_IN, |
| 381 this.onCloudPrintSignInRequested_.bind(this)); |
| 382 |
| 383 this.tracker_.add(window, 'keydown', this.onKeyDown_.bind(this)); |
| 384 }, |
| 385 |
| 386 /** |
| 387 * Removes all event listeners used by this component. |
| 388 * @private |
| 389 */ |
| 390 removeEventListeners_: function() { |
| 391 this.tracker_.removeAll(); |
| 392 }, |
| 393 |
| 394 /** |
| 395 * Window onload handler, sets up the page and starts print preview by |
| 396 * getting the printer list. |
| 397 * @private |
| 398 */ |
| 399 onWindowLoad_: function() { |
| 400 this.render_(); |
| 401 i18nTemplate.process(document, templateData); |
| 402 if (!this.previewArea_.hasCompatiblePlugin) { |
| 403 this.disable_(); |
| 404 } |
| 405 nativeLayer.startGetInitialSettings(); |
| 406 $('clear-log-button').onclick = function() { |
| 407 $('log').innerHTML = ''; |
| 408 }; |
| 409 }, |
| 410 |
| 411 /** |
| 412 * Called when the native layer has initial settings to set. Sets the |
| 413 * initial settings of the print preview and begins fetching print |
| 414 * destinations. |
| 415 * @param {cr.Event} evt Contains the initial print preview |
| 416 * settings persisted through the session. |
| 417 * @private |
| 418 */ |
| 419 onInitialSettingsSet_: function(evt) { |
| 420 if (this.uiState_ != PrintPreview.UiState.INITIALIZING) { |
| 421 throw Error( |
| 422 'Updating initial settings when not in initializing state: ' + |
| 423 this.uiState_); |
| 424 } |
| 425 |
| 426 var initialSettings = evt.initialSettings; |
| 427 |
| 428 // Not using initialSettings['initiatorTabTitle'] since the print preview |
| 429 // no longer opens in a new tab. And because of this, |
| 430 // localStrings.getStringF('printPreviewTitleFormat', initiatorTabTitle) |
| 431 // is also not used. |
| 432 |
| 433 // TODO use this boolean |
| 434 this.isInKioskAutoPrintMode_ = |
| 435 initialSettings['printAutomaticallyInKioskMode']; |
| 436 |
| 437 var customMargins = null; |
| 438 if (initialSettings.hasOwnProperty('marginTop') && |
| 439 initialSettings.hasOwnProperty('marginRight') && |
| 440 initialSettings.hasOwnProperty('marginBottom') && |
| 441 initialSettings.hasOwnProperty('marginLeft')) { |
| 442 customMargins = [ |
| 443 initialSettings['marginTop'], |
| 444 initialSettings['marginRight'], |
| 445 initialSettings['marginBottom'], |
| 446 initialSettings['marginLeft'] |
| 447 ]; |
| 448 } |
| 449 |
| 450 // TODO Use initialSettings['cloudPrintData'] somehow. Btw, |
| 451 // initialSettings['cloudPrintData'] is the JSON form of the cloud |
| 452 // printer's capabilities. |
| 453 |
| 454 this.printTicketStore_.initialize( |
| 455 initialSettings['previewModifiable'], |
| 456 initialSettings['duplex'], |
| 457 initialSettings['headerFooterEnabled'], |
| 458 initialSettings['marginsType'], |
| 459 customMargins, |
| 460 initialSettings['numberFormat'], |
| 461 initialSettings['measurementSystem']); |
| 462 |
| 463 this.destinationStore_.initialDestinationId = |
| 464 initialSettings['printerName']; |
| 465 |
| 466 nativeLayer.startGetLocalDestinations(); |
| 467 this.uiState_ = PrintPreview.UiState.FETCHING_DESTINATIONS; |
| 468 }, |
| 469 |
| 470 /** |
| 471 * Calls when the native layer enables Google Cloud Print integration. |
| 472 * Fetches the user's cloud printers. |
| 473 * @param {cr.Event} evt Contains the base URL of the Google Cloud Print |
| 474 * service. |
| 475 * @private |
| 476 */ |
| 477 onCloudPrintEnable_: function(evt) { |
| 478 if (this.uiState_ != PrintPreview.UiState.FETCHING_DESTINATIONS) { |
| 479 throw Error( |
| 480 'Enabling Google Cloud Print when not in fetching-destinations ' + |
| 481 'state: ' + this.uiState_); |
| 482 } |
| 483 this.cloudPrintInterface_ = new cloudprint.CloudPrintInterface( |
| 484 evt.baseCloudPrintUrl); |
| 485 this.tracker_.add( |
| 486 this.cloudPrintInterface_, |
| 487 cloudprint.CloudPrintInterface.Event.SEARCH_DONE, |
| 488 this.onCloudPrintSearchDone_.bind(this)); |
| 489 this.tracker_.add( |
| 490 this.cloudPrintInterface_, |
| 491 cloudprint.CloudPrintInterface.Event.PRINTER_DONE, |
| 492 this.onCloudPrintPrinterDone_.bind(this)); |
| 493 this.tracker_.add( |
| 494 this.cloudPrintInterface_, |
| 495 cloudprint.CloudPrintInterface.Event.SUBMIT_DONE, |
| 496 this.onCloudPrintSubmitDone_.bind(this)); |
| 497 this.tracker_.add( |
| 498 this.cloudPrintInterface_, |
| 499 cloudprint.CloudPrintInterface.Event.ERROR, |
| 500 this.onCloudPrintError_.bind(this)); |
| 501 |
| 502 // Fetch recent printers. |
| 503 this.cloudPrintInterface_.search(true /*isRecent*/); |
| 504 // Fetch the full printer list. |
| 505 this.cloudPrintInterface_.search(false /*isRecent*/); |
| 506 |
| 507 this.fetchState_ |= |
| 508 PrintPreview.FetchState.RECENT_CLOUD_DESTINATIONS | |
| 509 PrintPreview.FetchState.ALL_CLOUD_DESTINATIONS; |
| 510 }, |
| 511 |
| 512 /** |
| 513 * Called when the native layer gets local destinations. Adds local |
| 514 * destination objects received from the operating system to the destination |
| 515 * store. |
| 516 * @param {cr.Event} Contains the local destinations to set. |
| 517 * @private |
| 518 */ |
| 519 onLocalDestinationsSet_: function(evt) { |
| 520 if (this.uiState_ != PrintPreview.UiState.FETCHING_DESTINATIONS) { |
| 521 throw Error( |
| 522 'Received local destinations when not in fetching-destinations ' + |
| 523 'state: ' + this.uiState_); |
| 524 } |
| 525 |
| 526 var localDestinations = []; |
| 527 |
| 528 // Add local destinations. |
| 529 for (var destInfo, i = 0; destInfo = evt.destinationInfos[i]; i++) { |
| 530 localDestinations.push( |
| 531 print_preview.LocalDestinationParser.parse(destInfo)); |
| 532 } |
| 533 |
| 534 // Add print-to-pdf destination. |
| 535 localDestinations.push(this.createLocalPdfPrintDestination_()); |
| 536 |
| 537 this.destinationStore_.insertDestinations(localDestinations); |
| 538 |
| 539 this.fetchState_ &= ~PrintPreview.FetchState.LOCAL_DESTINATIONS; |
| 540 if (this.fetchState_ == PrintPreview.FetchState.READY) { |
| 541 this.uiState_ = PrintPreview.UiState.READY; |
| 542 } |
| 543 }, |
| 544 |
| 545 /** |
| 546 * Called when the native layer retrieves the capabilities for the selected |
| 547 * local destination. |
| 548 * @param {cr.Event} evt Contains the capabilities of the local print |
| 549 * destination. |
| 550 * @private |
| 551 */ |
| 552 onLocalDestinationCapabilitiesSet_: function(evt) { |
| 553 // TODO There may be a race condition here. This method is assumed to |
| 554 // return capabilities for the currently selected printer. But between the |
| 555 // time the local printer was selected and the capabilities were |
| 556 // retrieved, the selected printer can change. One way to address this is |
| 557 // to include the destination ID in the settingsInfo parameter. |
| 558 // TODO Change data type of Destination.capabilities to |
| 559 // ChromiumCapabilities. |
| 560 var capabilities = print_preview.LocalCapabilitiesParser.parse( |
| 561 evt.settingsInfo); |
| 562 this.destinationStore_.selectedDestination.capabilities = capabilities; |
| 563 this.printTicketStore_.updateDestinationCapabilities(capabilities); |
| 564 }, |
| 565 |
| 566 /** |
| 567 * Called from native layer after the user was requested to sign in, and did |
| 568 * so successfully. |
| 569 * @private |
| 570 */ |
| 571 onDestinationsReload_: function() { |
| 572 if (this.uiState_ != PrintPreview.UiState.READY) { |
| 573 throw Error( |
| 574 'Reload request received but not in ready state: ' + this.uiState_); |
| 575 } |
| 576 this.destinationStore_.clear(); |
| 577 nativeLayer.startGetLocalDestinations(); |
| 578 if (this.cloudPrintInterface_) { |
| 579 // Fetch recent printers. |
| 580 this.cloudPrintInterface_.search(true /*isRecent*/); |
| 581 // Fetch the full printer list. |
| 582 this.cloudPrintInterface_.search(false /*isRecent*/); |
| 583 } |
| 584 this.uiState_ = PrintPreview.UiState.FETCHING_DESTINATIONS; |
| 585 this.fetchState_ = |
| 586 PrintPreview.FetchState.LOCAL_DESTINATIONS | |
| 587 PrintPreview.FetchState.ALL_CLOUD_DESTINATIONS | |
| 588 PrintPreview.FetchState.RECENT_CLOUD_DESTINATIONS; |
| 589 }, |
| 590 |
| 591 /** |
| 592 * Called from the native layer when ready to print to Google Cloud Print. |
| 593 * @param {cr.Event} evt Contains the body to send in the HTTP request. |
| 594 * @private |
| 595 */ |
| 596 onPrintToCloud_: function(evt) { |
| 597 if (this.uiState_ != PrintPreview.UiState.PRINTING) { |
| 598 throw Error( |
| 599 'Document ready to be sent to the cloud when not in printing ' + |
| 600 'state: ' + this.uiState_); |
| 601 } |
| 602 if (this.cloudPrintInterface_) { |
| 603 this.cloudPrintInterface_.submit(evt.data); |
| 604 } else { |
| 605 throw Error('Google Cloud Print is not enabled'); |
| 606 } |
| 607 }, |
| 608 |
| 609 /** |
| 610 * Called from the native layer when the user cancels the save-to-pdf file |
| 611 * selection dialog. |
| 612 * @private |
| 613 */ |
| 614 onFileSelectionCancel_: function() { |
| 615 if (this.uiState_ != PrintPreview.UiState.FILE_SELECTION) { |
| 616 throw Error( |
| 617 'File selection cancelled when not in file-selection state: ' + |
| 618 this.uiState_); |
| 619 } |
| 620 // TODO Reenable controls. |
| 621 this.uiState_ = PrintPreview.UiState.READY; |
| 622 }, |
| 623 |
| 624 /** |
| 625 * Called from the native layer when save-to-pdf file selection is complete. |
| 626 * @private |
| 627 */ |
| 628 onFileSelectionComplete_: function() { |
| 629 this.disable_(); |
| 630 this.previewArea_.showCustomMessage( |
| 631 localStrings.getString('printingToPDFInProgress')); |
| 632 // TODO |
| 633 }, |
| 634 |
| 635 /** |
| 636 * Called when the print destination 'Change' button is activated. |
| 637 * @private |
| 638 */ |
| 639 onDestinationChangeButtonActivate_: function() { |
| 640 this.destinationSearch_.isVisible = true; |
| 641 }, |
| 642 |
| 643 /** |
| 644 * Called when the Google Cloud Print search API call completes. Adds |
| 645 * destinations to the printer store and selects one if it matches the |
| 646 * initial destination. |
| 647 * @param {cr.Event} evt Contains the new cloud destinations. |
| 648 * @private |
| 649 */ |
| 650 onCloudPrintSearchDone_: function(evt) { |
| 651 this.destinationSearch_.cloudPrintEmail = evt.email; |
| 652 this.destinationStore_.insertDestinations(evt.printers); |
| 653 |
| 654 if (evt.isRecent) { |
| 655 this.fetchState_ &= ~PrintPreview.FetchState.RECENT_CLOUD_DESTINATIONS; |
| 656 } else { |
| 657 this.fetchState_ &= ~PrintPreview.FetchState.ALL_CLOUD_DESTINATIONS; |
| 658 } |
| 659 if (this.fetchState_ == PrintPreview.FetchState.READY) { |
| 660 this.uiState_ = PrintPreview.UiState.READY; |
| 661 } |
| 662 }, |
| 663 |
| 664 /** |
| 665 * Called when the Google Cloud Print printer API call completes. Updates |
| 666 * the UI with the newly received capabilities. |
| 667 * @param {cr.Event} evt Contains the destination returned in the printer |
| 668 * API call. |
| 669 */ |
| 670 onCloudPrintPrinterDone_: function(evt) { |
| 671 var dest = this.destinationStore_.updateDestination(evt.printer); |
| 672 if (this.destinationStore_.selectedDestination == dest) { |
| 673 this.printTicketStore_.updateDestinationCapabilities(dest.capabilities); |
| 674 } |
| 675 }, |
| 676 |
| 677 onCloudPrintSubmitDone_: function(evt) { |
| 678 this.close_(); |
| 679 }, |
| 680 |
| 681 /** |
| 682 * Called when there was an error communicating with Google Cloud print. |
| 683 * Displays an error message in the print header. |
| 684 * @param {cr.Event} evt Contains the error message. |
| 685 * @private |
| 686 */ |
| 687 onCloudPrintError_: function(evt) { |
| 688 if (evt.message == '403') { |
| 689 this.destinationSearch_.showCloudPrintPromo(); |
| 690 } else { |
| 691 this.printHeader_.setErrorMessage(evt.message); |
| 692 } |
| 693 this.fetchState_ &= |
| 694 (~PrintPreview.FetchState.RECENT_CLOUD_DESTINATIONS & |
| 695 ~PrintPreview.FetchState.ALL_CLOUD_DESTINATIONS); |
| 696 if (this.fetchState_ == PrintPreview.FetchState.READY) { |
| 697 this.uiState_ = PrintPreview.UiState.READY; |
| 698 } |
| 699 }, |
| 700 |
| 701 onCloudPrintSignInRequested_: function() { |
| 702 nativeLayer.startCloudPrintSignIn(); |
| 703 }, |
| 704 |
| 705 /** |
| 706 * Called when a new destination has been selected. Fetches the |
| 707 * destination's capability list. |
| 708 * @private |
| 709 */ |
| 710 onDestinationSelect_: function() { |
| 711 var destination = this.destinationStore_.selectedDestination; |
| 712 |
| 713 // Fetch destination capabilities if necessary. |
| 714 if (!destination.capabilities) { |
| 715 if (destination.isLocal) { |
| 716 nativeLayer.startGetLocalDestinationCapabilities(destination.id); |
| 717 } else if (this.cloudPrintInterface_) { |
| 718 this.cloudPrintInterface_.printer(destination.id); |
| 719 } else { |
| 720 // TODO Probably a cloud printer was initially selected, but cloud |
| 721 // print is no longer available. Maybe default to the system's local |
| 722 // default? What about Chrome OS? |
| 723 throw Error( |
| 724 'Selected destination is a cloud destination, but Google Cloud ' + |
| 725 'Print is not enabled'); |
| 726 } |
| 727 } else { |
| 728 this.printTicketStore_.updateDestinationCapabilities( |
| 729 destination.capabilities); |
| 730 } |
| 731 }, |
| 732 |
| 733 /** |
| 734 * Called when the preview area's preview failed to load. |
| 735 * @private |
| 736 */ |
| 737 onPreviewGenerationFail_: function() { |
| 738 if (this.uiState_ == PrintPreview.UiState.PRINTING) { |
| 739 nativeLayer.startCancelPendingPrint(); |
| 740 } |
| 741 }, |
| 742 |
| 743 onSystemDialogLinkClicked_: function() { |
| 744 $('system-dialog-throbber').hidden = false; |
| 745 this.openSystemPrintDialog_(); |
| 746 }, |
| 747 |
| 748 /** |
| 749 * Called when the 'Open pdf in preview' link is clicked. Launches the pdf |
| 750 * preview app. |
| 751 * @private |
| 752 */ |
| 753 onOpenPdfInPreviewLinkClick_: function() { |
| 754 if (this.uiState_ != PrintPreview.UiState.READY && |
| 755 this.uiState_ != PrintPreview.UiState.FETCHING_DESTINATIONS) { |
| 756 throw Error( |
| 757 'Trying to open pdf in preview when not in ready nor ' + |
| 758 'fetching-destinations state: ' + this.uiState_); |
| 759 } |
| 760 $('open-preview-app-throbber').hidden = false; |
| 761 this.disable_(); |
| 762 previewArea.showCustomMessage( |
| 763 localStrings.getString('openingPDFInPreview')); |
| 764 this.uiState_ = PrintPreview.UiState.OPENING_PDF_PREVIEW; |
| 765 this.printDocumentOrOpenPdfPreview_(true /*isPdfPreview*/); |
| 766 }, |
| 767 |
| 768 /** |
| 769 * Called when the print header's print button is clicked. Prints the |
| 770 * document. |
| 771 * @private |
| 772 */ |
| 773 onPrintButtonClick_: function() { |
| 774 if (this.uiState_ != PrintPreview.UiState.READY && |
| 775 this.uiState_ != PrintPreview.UiState.FETCHING_DESTINATIONS) { |
| 776 throw Error( |
| 777 'Trying to print when not in ready nor fetching-destinations ' + |
| 778 'state: ' + this.uiState_); |
| 779 } |
| 780 this.printDocumentOrOpenPdfPreview_(false /*isPdfPreview*/); |
| 781 }, |
| 782 |
| 783 /** |
| 784 * Called when the print header's cancel button is clicked. Closes the |
| 785 * print dialog. |
| 786 * @private |
| 787 */ |
| 788 onCancelButtonClick_: function() { |
| 789 this.close_(); |
| 790 }, |
| 791 |
| 792 /** |
| 793 * Consume escape key presses and ctrl + shift + p. Delegate everything else |
| 794 * to the preview area. |
| 795 * @param {KeyboardEvent} e The keyboard event. |
| 796 * @private |
| 797 */ |
| 798 onKeyDown_: function(e) { |
| 799 // Escape key closes the dialog. |
| 800 if (e.keyCode == 27 && !e.shiftKey && !e.ctrlKey && !e.altKey && |
| 801 !e.metaKey) { |
| 802 if (this.destinationSearch_.isVisible) { |
| 803 this.destinationSearch_.isVisible = false; |
| 804 } else { |
| 805 this.close_(); |
| 806 } |
| 807 e.preventDefault(); |
| 808 return; |
| 809 } |
| 810 |
| 811 // Ctrl + Shift + p / Mac equivalent. |
| 812 if (e.keyCode == 80) { |
| 813 if ((cr.isMac && e.metaKey && e.altKey && !e.shiftKey && !e.ctrlKey) || |
| 814 (!cr.isMac && e.shiftKey && e.ctrlKey && !e.altKey && !e.metaKey)) { |
| 815 this.openSystemPrintDialog_(); |
| 816 e.preventDefault(); |
| 817 return; |
| 818 } |
| 819 } |
| 820 |
| 821 // Pass certain directional keyboard events to the PDF viewer. |
| 822 this.previewArea_.handleDirectionalKeyEvent(e); |
| 823 }, |
| 824 |
| 825 /** |
| 826 * Called when native layer receives invalid settings for a print request. |
| 827 * @private |
| 828 */ |
| 829 onSettingsInvalid_: function() { |
| 830 // TODO UI state change |
| 831 if (cr.isMac) { |
| 832 if (previewAppRequested) { |
| 833 $('open-preview-app-throbber').hidden = true; |
| 834 this.previewArea_.clearCustomMessageWithDots(); |
| 835 previewAppRequested = false; |
| 836 hasPendingPrintDocumentRequest = false; |
| 837 enableInputElementsInSidebar(); |
| 838 } |
| 839 $('open-pdf-in-preview-link').disabled = true; |
| 840 } |
| 841 this.previewArea_.displayErrorMessageAndNotify( |
| 842 localStrings.getString('invalidPrinterSettings')); |
| 843 } |
| 844 }; |
| 845 |
| 846 return { |
| 847 PrintPreview: PrintPreview |
| 848 }; |
| 849 }); |
229 | 850 |
230 /** | 851 /** |
231 * Keep track of the last element to receive a click. | 852 * Keep track of the last element to receive a click. |
232 * @param {Event} e The click event. | 853 * @param {Event} e The click event. |
233 */ | 854 */ |
234 function setLastClickedElement(e) { | 855 function setLastClickedElement(e) { |
235 lastClickedElement = e.target; | 856 lastClickedElement = e.target; |
236 } | 857 } |
237 | 858 |
238 /** | 859 function log(message) { |
239 * Disables the controls in the sidebar, shows the throbber and instructs the | 860 $('log').appendChild(document.createTextNode(message)); |
240 * backend to open the native print dialog. | 861 $('log').appendChild(document.createElement('br')); |
241 */ | |
242 function onSystemDialogLinkClicked() { | |
243 if (showingSystemDialog) | |
244 return; | |
245 showingSystemDialog = true; | |
246 disableInputElementsInSidebar(); | |
247 printHeader.disableCancelButton(); | |
248 $('system-dialog-throbber').hidden = false; | |
249 chrome.send('showSystemDialog'); | |
250 } | 862 } |
251 | 863 |
252 /** | 864 // Pull in all other scripts in a single shot. |
253 * Disables the controls in the sidebar, shows the throbber and instructs the | 865 <include src="native_layer.js"/> |
254 * backend to open the pdf in native preview app. This is only for Mac. | 866 <include src="component.js"/> |
255 */ | 867 <include src="data/page_number_set.js"/> |
256 function onOpenPdfInPreviewLinkClicked() { | 868 <include src="data/capabilities.js"/> |
257 if (previewAppRequested) | 869 <include src="data/destination.js"/> |
258 return; | 870 <include src="data/local_parsers.js"/> |
259 previewAppRequested = true; | 871 <include src="data/cloud_parsers.js"/> |
260 disableInputElementsInSidebar(); | 872 <include src="data/chromium_capabilities.js"/> |
261 $('open-preview-app-throbber').hidden = false; | 873 <include src="data/destination_store.js"/> |
262 printHeader.disableCancelButton(); | 874 <include src="data/margins.js"/> |
263 requestToPrintDocument(); | 875 <include src="data/page_layout.js"/> |
264 } | 876 <include src="data/measurement_system.js"/> |
265 | 877 <include src="data/print_ticket_store.js"/> |
266 /** | |
267 * Similar to onSystemDialogLinkClicked(), but specific to the | |
268 * 'Launch native print dialog' UI. | |
269 */ | |
270 function launchNativePrintDialog() { | |
271 if (showingSystemDialog) | |
272 return; | |
273 showingSystemDialog = true; | |
274 previewArea.errorButton.disabled = true; | |
275 printHeader.disableCancelButton(); | |
276 $('native-print-dialog-throbber').hidden = false; | |
277 chrome.send('showSystemDialog'); | |
278 } | |
279 | |
280 /** | |
281 * Gets the selected printer capabilities and updates the controls accordingly. | |
282 */ | |
283 function updateControlsWithSelectedPrinterCapabilities() { | |
284 var printerList = $('printer-list'); | |
285 var selectedIndex = printerList.selectedIndex; | |
286 if (selectedIndex < 0) | |
287 return; | |
288 if (cr.isMac) | |
289 $('open-pdf-in-preview-link').disabled = false; | |
290 | |
291 var skip_refresh = false; | |
292 var selectedValue = printerList.options[selectedIndex].value; | |
293 if (cloudprint.isCloudPrint(printerList.options[selectedIndex])) { | |
294 cloudprint.updatePrinterCaps(printerList.options[selectedIndex], | |
295 doUpdateCloudPrinterCapabilities); | |
296 skip_refresh = true; | |
297 } else if (selectedValue == SIGN_IN || | |
298 selectedValue == MANAGE_CLOUD_PRINTERS || | |
299 selectedValue == MANAGE_LOCAL_PRINTERS) { | |
300 printerList.selectedIndex = lastSelectedPrinterIndex; | |
301 chrome.send(selectedValue); | |
302 skip_refresh = true; | |
303 } else if (selectedValue == PRINT_TO_PDF || | |
304 selectedValue == PRINT_WITH_CLOUD_PRINT) { | |
305 updateWithPrinterCapabilities({ | |
306 'disableColorOption': true, | |
307 'setColorAsDefault': true, | |
308 'setDuplexAsDefault': false, | |
309 'printerColorModelForColor': print_preview.ColorSettings.COLOR, | |
310 'printerDefaultDuplexValue': copiesSettings.UNKNOWN_DUPLEX_MODE, | |
311 'disableCopiesOption': true}); | |
312 if (cr.isChromeOS && selectedValue == PRINT_WITH_CLOUD_PRINT) | |
313 requestToPrintDocument(); | |
314 } else { | |
315 // This message will call back to 'updateWithPrinterCapabilities' | |
316 // function. | |
317 chrome.send('getPrinterCapabilities', [selectedValue]); | |
318 } | |
319 if (!skip_refresh) { | |
320 lastSelectedPrinterIndex = selectedIndex; | |
321 | |
322 // Regenerate the preview data based on selected printer settings. | |
323 // Do not reset the margins if no preview request has been made. | |
324 var resetMargins = lastPreviewRequestID != initialPreviewRequestID; | |
325 setDefaultValuesAndRegeneratePreview(resetMargins); | |
326 } | |
327 } | |
328 | |
329 /** | |
330 * Helper function to do the actual work of updating cloud printer | |
331 * capabilities. | |
332 * @param {Object} printer The printer object to set capabilities for. | |
333 */ | |
334 function doUpdateCloudPrinterCapabilities(printer) { | |
335 var settings = {'disableColorOption': !cloudprint.supportsColor(printer), | |
336 'setColorAsDefault': cloudprint.colorIsDefault(printer), | |
337 'disableCopiesOption': true, | |
338 'disableLandscapeOption': true}; | |
339 updateWithPrinterCapabilities(settings); | |
340 var printerList = $('printer-list'); | |
341 var selectedIndex = printerList.selectedIndex; | |
342 lastSelectedPrinterIndex = selectedIndex; | |
343 | |
344 // Regenerate the preview data based on selected printer settings. | |
345 // Do not reset the margins if no preview request has been made. | |
346 var resetMargins = lastPreviewRequestID != initialPreviewRequestID; | |
347 setDefaultValuesAndRegeneratePreview(resetMargins); | |
348 } | |
349 | |
350 /** | |
351 * Notifies listeners of |customEvents.PRINTER_CAPABILITIES_UPDATED| about the | |
352 * capabilities of the currently selected printer. It is called from C++ too. | |
353 * @param {Object} settingInfo printer setting information. | |
354 */ | |
355 function updateWithPrinterCapabilities(settingInfo) { | |
356 var customEvent = new cr.Event(customEvents.PRINTER_CAPABILITIES_UPDATED); | |
357 customEvent.printerCapabilities = settingInfo; | |
358 document.dispatchEvent(customEvent); | |
359 } | |
360 | |
361 /** | |
362 * Reloads the printer list. | |
363 */ | |
364 function reloadPrintersList() { | |
365 $('printer-list').length = 0; | |
366 firstCloudPrintOptionPos = 0; | |
367 lastCloudPrintOptionPos = 0; | |
368 chrome.send('getPrinters'); | |
369 } | |
370 | |
371 /** | |
372 * Turn on the integration of Cloud Print. | |
373 * @param {string} cloudPrintURL The URL to use for cloud print servers. | |
374 */ | |
375 function setUseCloudPrint(cloudPrintURL) { | |
376 useCloudPrint = true; | |
377 cloudprint.setBaseURL(cloudPrintURL); | |
378 } | |
379 | |
380 /** | |
381 * Take the PDF data handed to us and submit it to the cloud, closing the print | |
382 * preview tab once the upload is successful. | |
383 * @param {string} data Data to send as the print job. | |
384 */ | |
385 function printToCloud(data) { | |
386 cloudprint.printToCloud(data, finishedCloudPrinting); | |
387 } | |
388 | |
389 /** | |
390 * Cloud print upload of the PDF file is finished, time to close the dialog. | |
391 */ | |
392 function finishedCloudPrinting() { | |
393 closePrintPreviewTab(); | |
394 } | |
395 | |
396 /** | |
397 * Checks whether the specified settings are valid. | |
398 * | |
399 * @return {boolean} true if settings are valid, false if not. | |
400 */ | |
401 function areSettingsValid() { | |
402 var selectedPrinter = getSelectedPrinterName(); | |
403 return pageSettings.isPageSelectionValid() && | |
404 marginSettings.areMarginSettingsValid() && | |
405 (copiesSettings.isValid() || selectedPrinter == PRINT_TO_PDF || | |
406 selectedPrinter == PRINT_WITH_CLOUD_PRINT); | |
407 } | |
408 | |
409 /** | |
410 * Creates an object based on the values in the printer settings. | |
411 * | |
412 * @return {Object} Object containing print job settings. | |
413 */ | |
414 function getSettings() { | |
415 var deviceName = getSelectedPrinterName(); | |
416 var printToPDF = deviceName == PRINT_TO_PDF; | |
417 var printWithCloudPrint = deviceName == PRINT_WITH_CLOUD_PRINT; | |
418 | |
419 var settings = | |
420 {'deviceName': deviceName, | |
421 'pageRange': pageSettings.selectedPageRanges, | |
422 'duplex': copiesSettings.duplexMode, | |
423 'copies': copiesSettings.numberOfCopies, | |
424 'collate': copiesSettings.isCollated(), | |
425 'landscape': layoutSettings.isLandscape(), | |
426 'color': colorSettings.colorMode, | |
427 'printToPDF': printToPDF, | |
428 'printWithCloudPrint': printWithCloudPrint, | |
429 'isFirstRequest' : false, | |
430 'headerFooterEnabled': headerFooterSettings.hasHeaderFooter(), | |
431 'marginsType': marginSettings.selectedMarginsValue, | |
432 'requestID': -1, | |
433 'generateDraftData': generateDraftData, | |
434 'previewModifiable': previewModifiable}; | |
435 | |
436 if (marginSettings.isCustomMarginsSelected()) | |
437 settings['marginsCustom'] = marginSettings.customMargins; | |
438 | |
439 var printerList = $('printer-list'); | |
440 var selectedPrinter = printerList.selectedIndex; | |
441 if (cloudprint.isCloudPrint(printerList.options[selectedPrinter])) { | |
442 settings['cloudPrintID'] = | |
443 printerList.options[selectedPrinter].value; | |
444 } | |
445 return settings; | |
446 } | |
447 | |
448 /** | |
449 * Creates an object based on the values in the printer settings. | |
450 * Note: |lastPreviewRequestID| is being modified every time this function is | |
451 * called. Only call this function when a preview request is actually sent, | |
452 * otherwise (for example when debugging) call getSettings(). | |
453 * | |
454 * @return {Object} Object containing print job settings. | |
455 */ | |
456 function getSettingsWithRequestID() { | |
457 var settings = getSettings(); | |
458 settings.requestID = generatePreviewRequestID(); | |
459 settings.isFirstRequest = isFirstPreviewRequest(); | |
460 return settings; | |
461 } | |
462 | |
463 /** | |
464 * @return {number} The next unused preview request id. | |
465 */ | |
466 function generatePreviewRequestID() { | |
467 return ++lastPreviewRequestID; | |
468 } | |
469 | |
470 /** | |
471 * @return {boolean} True iff a preview has been requested. | |
472 */ | |
473 function hasRequestedPreview() { | |
474 return lastPreviewRequestID != initialPreviewRequestID; | |
475 } | |
476 | |
477 /** | |
478 * @return {boolean} True if |lastPreviewRequestID| corresponds to the initial | |
479 * preview request. | |
480 */ | |
481 function isFirstPreviewRequest() { | |
482 return lastPreviewRequestID == initialPreviewRequestID + 1; | |
483 } | |
484 | |
485 /** | |
486 * Checks if |previewResponseId| matches |lastPreviewRequestId|. Used to ignore | |
487 * obsolete preview data responses. | |
488 * @param {number} previewResponseId The id to check. | |
489 * @return {boolean} True if previewResponseId reffers to the expected response. | |
490 */ | |
491 function isExpectedPreviewResponse(previewResponseId) { | |
492 return lastPreviewRequestID == previewResponseId; | |
493 } | |
494 | |
495 /** | |
496 * Returns the name of the selected printer or the empty string if no | |
497 * printer is selected. | |
498 * @return {string} The name of the currently selected printer. | |
499 */ | |
500 function getSelectedPrinterName() { | |
501 var printerList = $('printer-list'); | |
502 var selectedPrinter = printerList.selectedIndex; | |
503 if (selectedPrinter < 0) | |
504 return ''; | |
505 return printerList.options[selectedPrinter].value; | |
506 } | |
507 | |
508 /** | |
509 * Asks the browser to print the preview PDF based on current print | |
510 * settings. If the preview is still loading, printPendingFile() will get | |
511 * called once the preview loads. | |
512 */ | |
513 function requestToPrintDocument() { | |
514 hasPendingPrintDocumentRequest = !isPrintReadyMetafileReady; | |
515 var selectedPrinterName = getSelectedPrinterName(); | |
516 var printToPDF = selectedPrinterName == PRINT_TO_PDF; | |
517 var printWithCloudPrint = selectedPrinterName == PRINT_WITH_CLOUD_PRINT; | |
518 if (hasPendingPrintDocumentRequest) { | |
519 if (previewAppRequested) { | |
520 previewArea.showCustomMessage( | |
521 localStrings.getString('openingPDFInPreview')); | |
522 } else if (printToPDF) { | |
523 sendPrintDocumentRequest(); | |
524 } else if (printWithCloudPrint) { | |
525 previewArea.showCustomMessage( | |
526 localStrings.getString('printWithCloudPrintWait')); | |
527 disableInputElementsInSidebar(); | |
528 } else { | |
529 isTabHidden = true; | |
530 chrome.send('hidePreview'); | |
531 } | |
532 return; | |
533 } | |
534 | |
535 if (printToPDF || previewAppRequested) { | |
536 sendPrintDocumentRequest(); | |
537 } else { | |
538 window.setTimeout(function() { sendPrintDocumentRequest(); }, 1000); | |
539 } | |
540 } | |
541 | |
542 /** | |
543 * Sends a message to cancel the pending print request. | |
544 */ | |
545 function cancelPendingPrintRequest() { | |
546 if (isTabHidden) | |
547 chrome.send('cancelPendingPrintRequest'); | |
548 } | |
549 | |
550 /** | |
551 * Sends a message to initiate print workflow. | |
552 */ | |
553 function sendPrintDocumentRequest() { | |
554 var printerList = $('printer-list'); | |
555 var printer = printerList[printerList.selectedIndex]; | |
556 chrome.send('saveLastPrinter', [printer.value, cloudprint.getData(printer)]); | |
557 | |
558 var settings = getSettings(); | |
559 if (cr.isMac && previewAppRequested) | |
560 settings.OpenPDFInPreview = true; | |
561 | |
562 chrome.send('print', [JSON.stringify(settings), | |
563 cloudprint.getPrintTicketJSON(printer)]); | |
564 } | |
565 | |
566 /** | |
567 * Loads the selected preview pages. | |
568 */ | |
569 function loadSelectedPages() { | |
570 pageSettings.updatePageSelection(); | |
571 var pageSet = pageSettings.previouslySelectedPages; | |
572 var pageCount = pageSet.length; | |
573 if (pageCount == 0 || currentPreviewUid == '') | |
574 return; | |
575 | |
576 cr.dispatchSimpleEvent(document, customEvents.UPDATE_SUMMARY); | |
577 for (var i = 0; i < pageCount; i++) | |
578 onDidPreviewPage(pageSet[i] - 1, currentPreviewUid, lastPreviewRequestID); | |
579 } | |
580 | |
581 /** | |
582 * Asks the browser to generate a preview PDF based on current print settings. | |
583 */ | |
584 function requestPrintPreview() { | |
585 if (!isTabHidden) | |
586 previewArea.showLoadingAnimation(); | |
587 | |
588 if (!hasPendingPreviewRequest && previewModifiable && | |
589 hasOnlyPageSettingsChanged()) { | |
590 loadSelectedPages(); | |
591 generateDraftData = false; | |
592 } else { | |
593 hasPendingPreviewRequest = true; | |
594 generateDraftData = true; | |
595 pageSettings.updatePageSelection(); | |
596 } | |
597 | |
598 printSettings.save(); | |
599 layoutSettings.updateState(); | |
600 previewArea.resetState(); | |
601 isPrintReadyMetafileReady = false; | |
602 isFirstPageLoaded = false; | |
603 | |
604 var totalPageCount = pageSettings.totalPageCount; | |
605 if (!previewModifiable && totalPageCount > 0) | |
606 generateDraftData = false; | |
607 | |
608 var pageCount = totalPageCount != undefined ? totalPageCount : -1; | |
609 chrome.send('getPreview', [JSON.stringify(getSettingsWithRequestID()), | |
610 pageCount, | |
611 previewModifiable]); | |
612 } | |
613 | |
614 /** | |
615 * Called from PrintPreviewUI::OnFileSelectionCancelled to notify the print | |
616 * preview tab regarding the file selection cancel event. | |
617 */ | |
618 function fileSelectionCancelled() { | |
619 printHeader.enableCancelButton(); | |
620 } | |
621 | |
622 /** | |
623 * Called from PrintPreviewUI::OnFileSelectionCompleted to notify the print | |
624 * preview tab regarding the file selection completed event. | |
625 */ | |
626 function fileSelectionCompleted() { | |
627 // If the file selection is completed and the tab is not already closed it | |
628 // means that a pending print to pdf request exists. | |
629 disableInputElementsInSidebar(); | |
630 previewArea.showCustomMessage( | |
631 localStrings.getString('printingToPDFInProgress')); | |
632 } | |
633 | |
634 /** | |
635 * Set the default printer. If there is one, generate a print preview. | |
636 * @param {string} printerName Name of the default printer. Empty if none. | |
637 * @param {string} cloudPrintData Cloud print related data to restore if | |
638 * the default printer is a cloud printer. | |
639 */ | |
640 function setDefaultPrinter(printerName, cloudPrintData) { | |
641 // Add a placeholder value so the printer list looks valid. | |
642 addDestinationListOption('', '', true, true, true); | |
643 if (printerName) { | |
644 defaultOrLastUsedPrinterName = printerName; | |
645 if (cloudPrintData) { | |
646 cloudprint.setDefaultPrinter(printerName, | |
647 cloudPrintData, | |
648 addDestinationListOptionAtPosition, | |
649 doUpdateCloudPrinterCapabilities); | |
650 } else { | |
651 $('printer-list')[0].value = defaultOrLastUsedPrinterName; | |
652 updateControlsWithSelectedPrinterCapabilities(); | |
653 } | |
654 } | |
655 chrome.send('getPrinters'); | |
656 } | |
657 | |
658 /** | |
659 * Fill the printer list drop down. | |
660 * Called from PrintPreviewHandler::SetupPrinterList(). | |
661 * @param {Array} printers Array of printer info objects. | |
662 */ | |
663 function setPrinters(printers) { | |
664 var printerList = $('printer-list'); | |
665 // Remove empty entry added by setDefaultPrinter. | |
666 if (printerList[0] && printerList[0].textContent == '') | |
667 printerList.remove(0); | |
668 for (var i = 0; i < printers.length; ++i) { | |
669 var isDefault = (printers[i].deviceName == defaultOrLastUsedPrinterName); | |
670 addDestinationListOption(printers[i].printerName, printers[i].deviceName, | |
671 isDefault, false, false); | |
672 } | |
673 | |
674 if (printers.length != 0) | |
675 addDestinationListOption('', '', false, true, true); | |
676 | |
677 // Adding option for saving PDF to disk. | |
678 addDestinationListOption(localStrings.getString('printToPDF'), | |
679 PRINT_TO_PDF, | |
680 defaultOrLastUsedPrinterName == PRINT_TO_PDF, | |
681 false, | |
682 false); | |
683 addDestinationListOption('', '', false, true, true); | |
684 if (useCloudPrint) { | |
685 addDestinationListOption(localStrings.getString('printWithCloudPrint'), | |
686 PRINT_WITH_CLOUD_PRINT, | |
687 false, | |
688 false, | |
689 false); | |
690 addDestinationListOption('', '', false, true, true); | |
691 } | |
692 // Add options to manage printers. | |
693 if (!cr.isChromeOS) { | |
694 addDestinationListOption(localStrings.getString('managePrinters'), | |
695 MANAGE_LOCAL_PRINTERS, false, false, false); | |
696 } else if (useCloudPrint) { | |
697 // Fetch recent printers. | |
698 cloudprint.fetchPrinters(addDestinationListOptionAtPosition, false); | |
699 // Fetch the full printer list. | |
700 cloudprint.fetchPrinters(addDestinationListOptionAtPosition, true); | |
701 addDestinationListOption(localStrings.getString('managePrinters'), | |
702 MANAGE_CLOUD_PRINTERS, false, false, false); | |
703 } | |
704 | |
705 printerList.disabled = false; | |
706 | |
707 if (!hasRequestedPreview()) | |
708 updateControlsWithSelectedPrinterCapabilities(); | |
709 } | |
710 | |
711 /** | |
712 * Creates an option that can be added to the printer destination list. | |
713 * @param {string} optionText specifies the option text content. | |
714 * @param {string} optionValue specifies the option value. | |
715 * @param {boolean} isDefault is true if the option needs to be selected. | |
716 * @param {boolean} isDisabled is true if the option needs to be disabled. | |
717 * @param {boolean} isSeparator is true if the option is a visual separator and | |
718 * needs to be disabled. | |
719 * @return {Object} The created option. | |
720 */ | |
721 function createDestinationListOption(optionText, optionValue, isDefault, | |
722 isDisabled, isSeparator) { | |
723 var option = document.createElement('option'); | |
724 option.textContent = optionText; | |
725 option.value = optionValue; | |
726 option.selected = isDefault; | |
727 option.disabled = isSeparator || isDisabled; | |
728 // Adding attribute for improved accessibility. | |
729 if (isSeparator) | |
730 option.setAttribute('role', 'separator'); | |
731 return option; | |
732 } | |
733 | |
734 /** | |
735 * Adds an option to the printer destination list. | |
736 * @param {string} optionText specifies the option text content. | |
737 * @param {string} optionValue specifies the option value. | |
738 * @param {boolean} isDefault is true if the option needs to be selected. | |
739 * @param {boolean} isDisabled is true if the option needs to be disabled. | |
740 * @param {boolean} isSeparator is true if the option serves just as a | |
741 * separator. | |
742 * @return {Object} The created option. | |
743 */ | |
744 function addDestinationListOption(optionText, optionValue, isDefault, | |
745 isDisabled, isSeparator) { | |
746 var option = createDestinationListOption(optionText, | |
747 optionValue, | |
748 isDefault, | |
749 isDisabled, | |
750 isSeparator); | |
751 $('printer-list').add(option); | |
752 return option; | |
753 } | |
754 | |
755 /** | |
756 * Adds an option to the printer destination list at a specified position. | |
757 * @param {number} position The index in the printer-list wher the option | |
758 should be created. | |
759 * @param {string} optionText specifies the option text content. | |
760 * @param {string} optionValue specifies the option value. | |
761 * @param {boolean} isDefault is true if the option needs to be selected. | |
762 * @param {boolean} isDisabled is true if the option needs to be disabled. | |
763 * @param {boolean} isSeparator is true if the option is a visual separator and | |
764 * needs to be disabled. | |
765 * @return {Object} The created option. | |
766 */ | |
767 function addDestinationListOptionAtPosition(position, | |
768 optionText, | |
769 optionValue, | |
770 isDefault, | |
771 isDisabled, | |
772 isSeparator) { | |
773 var option = createDestinationListOption(optionText, | |
774 optionValue, | |
775 isDefault, | |
776 isDisabled, | |
777 isSeparator); | |
778 var printerList = $('printer-list'); | |
779 var before = printerList[position]; | |
780 printerList.add(option, before); | |
781 return option; | |
782 } | |
783 /** | |
784 * Sets the color mode for the PDF plugin. | |
785 * Called from PrintPreviewHandler::ProcessColorSetting(). | |
786 * @param {boolean} color is true if the PDF plugin should display in color. | |
787 */ | |
788 function setColor(color) { | |
789 if (!previewArea.pdfPlugin) | |
790 return; | |
791 | |
792 previewArea.pdfPlugin.grayscale(!color); | |
793 var printerList = $('printer-list'); | |
794 cloudprint.setColor(printerList[printerList.selectedIndex], color); | |
795 } | |
796 | |
797 /** | |
798 * Display an error message when print preview fails. | |
799 * Called from PrintPreviewMessageHandler::OnPrintPreviewFailed(). | |
800 */ | |
801 function printPreviewFailed() { | |
802 previewArea.displayErrorMessageWithButtonAndNotify( | |
803 localStrings.getString('previewFailed'), | |
804 localStrings.getString('launchNativeDialog'), | |
805 launchNativePrintDialog); | |
806 } | |
807 | |
808 /** | |
809 * Display an error message when encountered invalid printer settings. | |
810 * Called from PrintPreviewMessageHandler::OnInvalidPrinterSettings(). | |
811 */ | |
812 function invalidPrinterSettings() { | |
813 if (cr.isMac) { | |
814 if (previewAppRequested) { | |
815 $('open-preview-app-throbber').hidden = true; | |
816 previewArea.clearCustomMessageWithDots(); | |
817 previewAppRequested = false; | |
818 hasPendingPrintDocumentRequest = false; | |
819 enableInputElementsInSidebar(); | |
820 } | |
821 $('open-pdf-in-preview-link').disabled = true; | |
822 } | |
823 previewArea.displayErrorMessageAndNotify( | |
824 localStrings.getString('invalidPrinterSettings')); | |
825 } | |
826 | |
827 /** | |
828 * Called when the PDF plugin loads its document. | |
829 */ | |
830 function onPDFLoad() { | |
831 if (previewModifiable) { | |
832 setPluginPreviewPageCount(); | |
833 } | |
834 // Instruct the plugin which page numbers to display in the page number | |
835 // indicator. | |
836 previewArea.pdfPlugin.setPageNumbers( | |
837 JSON.stringify(pageSettings.selectedPagesSet)); | |
838 cr.dispatchSimpleEvent(document, customEvents.PDF_LOADED); | |
839 isFirstPageLoaded = true; | |
840 checkAndHideOverlayLayerIfValid(); | |
841 sendPrintDocumentRequestIfNeeded(); | |
842 if (printAutomaticallyInKioskMode) | |
843 printHeader.printButton.click(); | |
844 } | |
845 | |
846 function setPluginPreviewPageCount() { | |
847 previewArea.pdfPlugin.printPreviewPageCount( | |
848 pageSettings.previouslySelectedPages.length); | |
849 } | |
850 | |
851 /** | |
852 * Update the page count and check the page range. | |
853 * Called from PrintPreviewUI::OnDidGetPreviewPageCount(). | |
854 * @param {number} pageCount The number of pages. | |
855 * @param {number} previewResponseId The preview request id that resulted in | |
856 * this response. | |
857 */ | |
858 function onDidGetPreviewPageCount(pageCount, previewResponseId) { | |
859 if (!isExpectedPreviewResponse(previewResponseId)) | |
860 return; | |
861 pageSettings.updateState(pageCount); | |
862 if (!previewModifiable && pageSettings.requestPrintPreviewIfNeeded()) | |
863 return; | |
864 | |
865 cr.dispatchSimpleEvent(document, customEvents.UPDATE_SUMMARY); | |
866 } | |
867 | |
868 /** | |
869 * @param {{contentWidth: number, contentHeight: number, marginLeft: number, | |
870 * marginRight: number, marginTop: number, marginBottom: number, | |
871 * printableAreaX: number, printableAreaY: number, | |
872 * printableAreaWidth: number, printableAreaHeight: number}} pageLayout | |
873 * Specifies default page layout details in points. | |
874 * @param {boolean} hasCustomPageSizeStyle Indicates whether the previewed | |
875 * document has a custom page size style. | |
876 */ | |
877 function onDidGetDefaultPageLayout(pageLayout, hasCustomPageSizeStyle) { | |
878 hasPageSizeStyle = hasCustomPageSizeStyle; | |
879 marginSettings.currentDefaultPageLayout = new print_preview.PageLayout( | |
880 pageLayout.contentWidth, | |
881 pageLayout.contentHeight, | |
882 pageLayout.marginLeft, | |
883 pageLayout.marginTop, | |
884 pageLayout.marginRight, | |
885 pageLayout.marginBottom); | |
886 headerFooterSettings.checkAndHideHeaderFooterOption( | |
887 pageLayout, marginSettings.selectedMarginsValue); | |
888 } | |
889 | |
890 /** | |
891 * This function sends a request to hide the overlay layer only if there is no | |
892 * pending print document request and we are not waiting for the print ready | |
893 * metafile. | |
894 */ | |
895 function checkAndHideOverlayLayerIfValid() { | |
896 var selectedPrinter = getSelectedPrinterName(); | |
897 var printToDialog = selectedPrinter == PRINT_TO_PDF || | |
898 selectedPrinter == PRINT_WITH_CLOUD_PRINT; | |
899 if ((printToDialog || !previewModifiable) && | |
900 !isPrintReadyMetafileReady && hasPendingPrintDocumentRequest) { | |
901 return; | |
902 } | |
903 previewArea.hideOverlayLayer(); | |
904 } | |
905 | |
906 /** | |
907 * Called when no pipelining previewed pages. | |
908 * @param {string} previewUid Preview unique identifier. | |
909 * @param {number} previewResponseId The preview request id that resulted in | |
910 * this response. | |
911 */ | |
912 function reloadPreviewPages(previewUid, previewResponseId) { | |
913 if (!isExpectedPreviewResponse(previewResponseId)) | |
914 return; | |
915 | |
916 cr.dispatchSimpleEvent(document, customEvents.UPDATE_PRINT_BUTTON); | |
917 checkAndHideOverlayLayerIfValid(); | |
918 var pageSet = pageSettings.previouslySelectedPages; | |
919 for (var i = 0; i < pageSet.length; i++) { | |
920 previewArea.pdfPlugin.loadPreviewPage( | |
921 getPageSrcURL(previewUid, pageSet[i] - 1), i); | |
922 } | |
923 | |
924 hasPendingPreviewRequest = false; | |
925 isPrintReadyMetafileReady = true; | |
926 previewArea.pdfLoaded = true; | |
927 sendPrintDocumentRequestIfNeeded(); | |
928 } | |
929 | |
930 /** | |
931 * Notification that a print preview page has been rendered. | |
932 * Check if the settings have changed and request a regeneration if needed. | |
933 * Called from PrintPreviewUI::OnDidPreviewPage(). | |
934 * @param {number} pageNumber The page number, 0-based. | |
935 * @param {string} previewUid Preview unique identifier. | |
936 * @param {number} previewResponseId The preview request id that resulted in | |
937 * this response. | |
938 */ | |
939 function onDidPreviewPage(pageNumber, previewUid, previewResponseId) { | |
940 if (!isExpectedPreviewResponse(previewResponseId)) | |
941 return; | |
942 | |
943 // Refactor | |
944 if (!previewModifiable) | |
945 return; | |
946 | |
947 if (pageSettings.requestPrintPreviewIfNeeded()) | |
948 return; | |
949 | |
950 var pageIndex = pageSettings.previouslySelectedPages.indexOf(pageNumber + 1); | |
951 if (pageIndex == -1) | |
952 return; | |
953 | |
954 currentPreviewUid = previewUid; | |
955 if (pageIndex == 0) | |
956 previewArea.createOrReloadPDFPlugin(pageNumber); | |
957 | |
958 previewArea.pdfPlugin.loadPreviewPage( | |
959 getPageSrcURL(previewUid, pageNumber), pageIndex); | |
960 | |
961 if (pageIndex + 1 == pageSettings.previouslySelectedPages.length) { | |
962 hasPendingPreviewRequest = false; | |
963 if (pageIndex != 0) | |
964 sendPrintDocumentRequestIfNeeded(); | |
965 } | |
966 } | |
967 | |
968 /** | |
969 * Update the print preview when new preview data is available. | |
970 * Create the PDF plugin as needed. | |
971 * Called from PrintPreviewUI::PreviewDataIsAvailable(). | |
972 * @param {string} previewUid Preview unique identifier. | |
973 * @param {number} previewResponseId The preview request id that resulted in | |
974 * this response. | |
975 */ | |
976 function updatePrintPreview(previewUid, previewResponseId) { | |
977 if (!isExpectedPreviewResponse(previewResponseId)) | |
978 return; | |
979 isPrintReadyMetafileReady = true; | |
980 | |
981 if (!previewModifiable) { | |
982 // If the preview is not modifiable the plugin has not been created yet. | |
983 currentPreviewUid = previewUid; | |
984 hasPendingPreviewRequest = false; | |
985 previewArea.createOrReloadPDFPlugin(PRINT_READY_DATA_INDEX); | |
986 } | |
987 | |
988 cr.dispatchSimpleEvent(document, customEvents.UPDATE_PRINT_BUTTON); | |
989 if (previewModifiable) | |
990 sendPrintDocumentRequestIfNeeded(); | |
991 } | |
992 | |
993 /** | |
994 * Checks to see if the requested print data is available for printing and | |
995 * sends a print document request if needed. | |
996 */ | |
997 function sendPrintDocumentRequestIfNeeded() { | |
998 if (!hasPendingPrintDocumentRequest || !isFirstPageLoaded) | |
999 return; | |
1000 | |
1001 // If the selected printer is PRINT_TO_PDF or PRINT_WITH_CLOUD_PRINT or | |
1002 // the preview source is not modifiable, we need the print ready data for | |
1003 // printing. If the preview source is modifiable, we need to wait till all | |
1004 // the requested pages are loaded in the plugin for printing. | |
1005 var selectedPrinter = getSelectedPrinterName(); | |
1006 var printToDialog = selectedPrinter == PRINT_TO_PDF || | |
1007 selectedPrinter == PRINT_WITH_CLOUD_PRINT; | |
1008 if (((printToDialog || !previewModifiable) && !isPrintReadyMetafileReady) || | |
1009 (previewModifiable && hasPendingPreviewRequest)) { | |
1010 return; | |
1011 } | |
1012 | |
1013 hasPendingPrintDocumentRequest = false; | |
1014 | |
1015 if (!areSettingsValid()) { | |
1016 cancelPendingPrintRequest(); | |
1017 return; | |
1018 } | |
1019 sendPrintDocumentRequest(); | |
1020 } | |
1021 | |
1022 /** | |
1023 * Check if only page selection has been changed since the last preview request | |
1024 * and is valid. | |
1025 * @return {boolean} true if the new page selection is valid. | |
1026 */ | |
1027 function hasOnlyPageSettingsChanged() { | |
1028 var tempPrintSettings = new PrintSettings(); | |
1029 tempPrintSettings.save(); | |
1030 | |
1031 return !!(printSettings.deviceName == tempPrintSettings.deviceName && | |
1032 printSettings.isLandscape == tempPrintSettings.isLandscape && | |
1033 printSettings.hasHeaderFooter == | |
1034 tempPrintSettings.hasHeaderFooter && | |
1035 pageSettings.hasPageSelectionChangedAndIsValid()); | |
1036 } | |
1037 | |
1038 /** | |
1039 * Called either when there is a scroll event or when the plugin size changes. | |
1040 */ | |
1041 function onPreviewPositionChanged() { | |
1042 marginSettings.onPreviewPositionChanged(); | |
1043 } | |
1044 | |
1045 /** | |
1046 * @return {boolean} true if a compatible pdf plugin exists. | |
1047 */ | |
1048 function checkCompatiblePluginExists() { | |
1049 var dummyPlugin = $('dummy-viewer'); | |
1050 var pluginInterface = [dummyPlugin.onload, | |
1051 dummyPlugin.goToPage, | |
1052 dummyPlugin.removePrintButton, | |
1053 dummyPlugin.loadPreviewPage, | |
1054 dummyPlugin.printPreviewPageCount, | |
1055 dummyPlugin.resetPrintPreviewUrl, | |
1056 dummyPlugin.onPluginSizeChanged, | |
1057 dummyPlugin.onScroll, | |
1058 dummyPlugin.pageXOffset, | |
1059 dummyPlugin.pageYOffset, | |
1060 dummyPlugin.setZoomLevel, | |
1061 dummyPlugin.setPageNumbers, | |
1062 dummyPlugin.setPageXOffset, | |
1063 dummyPlugin.setPageYOffset, | |
1064 dummyPlugin.getHorizontalScrollbarThickness, | |
1065 dummyPlugin.getVerticalScrollbarThickness, | |
1066 dummyPlugin.getPageLocationNormalized, | |
1067 dummyPlugin.getHeight, | |
1068 dummyPlugin.getWidth]; | |
1069 | |
1070 for (var i = 0; i < pluginInterface.length; i++) { | |
1071 if (!pluginInterface[i]) | |
1072 return false; | |
1073 } | |
1074 return true; | |
1075 } | |
1076 | |
1077 /** | |
1078 * Sets the default values and sends a request to regenerate preview data. | |
1079 * Resets the margin options only if |resetMargins| is true. | |
1080 * @param {boolean} resetMargins True if margin settings should be resetted. | |
1081 */ | |
1082 function setDefaultValuesAndRegeneratePreview(resetMargins) { | |
1083 if (resetMargins) | |
1084 marginSettings.resetMarginsIfNeeded(); | |
1085 pageSettings.resetState(); | |
1086 requestPrintPreview(); | |
1087 } | |
1088 | |
1089 /** | |
1090 * Class that represents the state of the print settings. | |
1091 * @constructor | |
1092 */ | |
1093 function PrintSettings() { | |
1094 this.deviceName = ''; | |
1095 this.isLandscape = ''; | |
1096 this.hasHeaderFooter = ''; | |
1097 } | |
1098 | |
1099 /** | |
1100 * Takes a snapshot of the print settings. | |
1101 */ | |
1102 PrintSettings.prototype.save = function() { | |
1103 this.deviceName = getSelectedPrinterName(); | |
1104 this.isLandscape = layoutSettings.isLandscape(); | |
1105 this.hasHeaderFooter = headerFooterSettings.hasHeaderFooter(); | |
1106 }; | |
1107 | |
1108 /** | |
1109 * Updates the title of the print preview tab according to |initiatorTabTitle|. | |
1110 * @param {string} initiatorTabTitle The title of the initiator tab. | |
1111 */ | |
1112 function setInitiatorTabTitle(initiatorTabTitle) { | |
1113 if (initiatorTabTitle == '') | |
1114 return; | |
1115 document.title = localStrings.getStringF( | |
1116 'printPreviewTitleFormat', initiatorTabTitle); | |
1117 } | |
1118 | |
1119 /** | |
1120 * Closes this print preview tab. | |
1121 */ | |
1122 function closePrintPreviewTab() { | |
1123 window.removeEventListener('keydown', onKeyDown); | |
1124 chrome.send('closePrintPreviewTab'); | |
1125 chrome.send('DialogClose'); | |
1126 } | |
1127 | |
1128 /** | |
1129 * Pass certain directional keyboard events to the PDF viewer. | |
1130 * @param {Event} e The keydown event. | |
1131 */ | |
1132 function tryToHandleDirectionKeyDown(e) { | |
1133 // Make sure the PDF plugin is there. | |
1134 if (!previewArea.pdfPlugin) | |
1135 return; | |
1136 | |
1137 // We only care about: PageUp, PageDown, Left, Up, Right, Down. | |
1138 if (!(e.keyCode == 33 || e.keyCode == 34 || | |
1139 (e.keyCode >= 37 && e.keyCode <= 40))) { | |
1140 return; | |
1141 } | |
1142 | |
1143 // If the user is holding a modifier key, ignore. | |
1144 if (e.metaKey || e.altKey || e.shiftKey || e.ctrlKey) | |
1145 return; | |
1146 | |
1147 // Don't handle the key event for these elements. | |
1148 var tagName = document.activeElement.tagName; | |
1149 if (tagName == 'INPUT' || tagName == 'SELECT' || tagName == 'EMBED') | |
1150 return; | |
1151 | |
1152 // For the most part, if any div of header was the last clicked element, | |
1153 // then the active element is the body. Starting with the last clicked | |
1154 // element, and work up the DOM tree to see if any element has a scrollbar. | |
1155 // If there exists a scrollbar, do not handle the key event here. | |
1156 var element = document.activeElement; | |
1157 if (element == document.body) { | |
1158 if (lastClickedElement) | |
1159 element = lastClickedElement; | |
1160 while (element) { | |
1161 if (element.scrollHeight > element.clientHeight) | |
1162 return; | |
1163 element = element.parentElement; | |
1164 } | |
1165 } | |
1166 | |
1167 // No scroll bar anywhere, or the active element is something else, like a | |
1168 // button. Note: buttons have a bigger scrollHeight than clientHeight. | |
1169 previewArea.pdfPlugin.sendKeyEvent(e.keyCode); | |
1170 e.preventDefault(); | |
1171 } | |
1172 | |
1173 /** | |
1174 * Handle keyboard events. | |
1175 * @param {KeyboardEvent} e The keyboard event. | |
1176 */ | |
1177 function onKeyDown(e) { | |
1178 // Escape key closes the dialog. | |
1179 if (e.keyCode == 27 && !e.shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey) { | |
1180 printHeader.disableCancelButton(); | |
1181 closePrintPreviewTab(); | |
1182 e.preventDefault(); | |
1183 } | |
1184 // Ctrl + Shift + p / Mac equivalent. | |
1185 if (e.keyCode == 80) { | |
1186 if ((cr.isMac && e.metaKey && e.altKey && !e.shiftKey && !e.ctrlKey) || | |
1187 (!cr.isMac && e.shiftKey && e.ctrlKey && !e.altKey && !e.metaKey)) { | |
1188 window.removeEventListener('keydown', onKeyDown); | |
1189 onSystemDialogLinkClicked(); | |
1190 e.preventDefault(); | |
1191 } | |
1192 } | |
1193 | |
1194 tryToHandleDirectionKeyDown(e); | |
1195 } | |
1196 | |
1197 window.addEventListener('DOMContentLoaded', onLoad); | |
1198 window.addEventListener('keydown', onKeyDown); | |
1199 | |
1200 /// Pull in all other scripts in a single shot. | |
1201 <include src="print_preview_animations.js"/> | 878 <include src="print_preview_animations.js"/> |
1202 <include src="print_preview_cloud.js"/> | 879 <include src="print_preview_cloud.js"/> |
1203 <include src="print_preview_utils.js"/> | 880 <include src="print_preview_utils.js"/> |
1204 <include src="print_header.js"/> | 881 <include src="print_header.js"/> |
1205 <include src="page_settings.js"/> | 882 <include src="settings/page_settings.js"/> |
1206 <include src="copies_settings.js"/> | 883 <include src="settings/copies_settings.js"/> |
1207 <include src="header_footer_settings.js"/> | 884 <include src="settings/header_footer_settings.js"/> |
1208 <include src="layout_settings.js"/> | 885 <include src="settings/layout_settings.js"/> |
1209 <include src="color_settings.js"/> | 886 <include src="settings/color_settings.js"/> |
1210 <include src="margin_settings.js"/> | 887 <include src="settings/margin_settings.js"/> |
1211 <include src="margin_textbox.js"/> | 888 <include src="settings/destination_settings.js"/> |
1212 <include src="margin_utils.js"/> | 889 <include src="previewarea/margin_textbox.js"/> |
1213 <include src="margins_ui.js"/> | 890 <include src="previewarea/margin_utils.js"/> |
1214 <include src="margins_ui_pair.js"/> | 891 <include src="previewarea/margins_ui.js"/> |
1215 <include src="preview_area.js"/> | 892 <include src="previewarea/margins_ui_pair.js"/> |
| 893 <include src="previewarea/preview_area.js"/> |
| 894 <include src="search/destination_list_item.js"/> |
| 895 <include src="search/destination_list.js"/> |
| 896 <include src="search/search_box.js"/> |
| 897 <include src="search/destination_search.js"/> |
| 898 <include src="preview_generator.js"/> |
| 899 |
| 900 var printPreview = new print_preview.PrintPreview(); |
OLD | NEW |