Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(282)

Side by Side Diff: chrome/browser/resources/print_preview/print_preview.js

Issue 10108001: Refactor print preview web ui (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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();
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698