1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 cr
.define('print_preview', function() {
8 // TODO(rltoscano): Maybe clear print ticket when destination changes. Or
9 // better yet, carry over any print ticket state that is possible. I.e. if
10 // destination changes, the new destination might not support duplex anymore,
11 // so we should clear the ticket's isDuplexEnabled state.
14 * Storage of the print ticket and document statistics. Dispatches events when
15 * the contents of the print ticket or document statistics change. Also
16 * handles validation of the print ticket against destination capabilities and
17 * against the document.
18 * @param {!print_preview.DestinationStore} destinationStore Used to
19 * understand which printer is selected.
20 * @param {!print_preview.AppState} appState Print preview application state.
21 * @param {!print_preview.DocumentInfo} documentInfo Document data model.
23 * @extends {cr.EventTarget}
25 function PrintTicketStore(destinationStore
, appState
, documentInfo
) {
26 cr
.EventTarget
.call(this);
29 * Destination store used to understand which printer is selected.
30 * @type {!print_preview.DestinationStore}
33 this.destinationStore_
= destinationStore
;
36 * App state used to persist and load ticket values.
37 * @type {!print_preview.AppState}
40 this.appState_
= appState
;
43 * Information about the document to print.
44 * @type {!print_preview.DocumentInfo}
47 this.documentInfo_
= documentInfo
;
50 * Printing capabilities of Chromium and the currently selected destination.
51 * @type {!print_preview.CapabilitiesHolder}
54 this.capabilitiesHolder_
= new print_preview
.CapabilitiesHolder();
57 * Current measurement system. Used to work with margin measurements.
58 * @type {!print_preview.MeasurementSystem}
61 this.measurementSystem_
= new print_preview
.MeasurementSystem(
62 ',', '.', print_preview
.MeasurementSystem
.UnitType
.IMPERIAL
);
65 * Collate ticket item.
66 * @type {!print_preview.ticket_items.Collate}
69 this.collate_
= new print_preview
.ticket_items
.Collate(
70 this.appState_
, this.destinationStore_
);
74 * @type {!print_preview.ticket_items.Color}
77 this.color_
= new print_preview
.ticket_items
.Color(
78 this.appState_
, this.destinationStore_
);
82 * @type {!print_preview.ticket_items.Copies}
86 new print_preview
.ticket_items
.Copies(this.destinationStore_
);
90 * @type {!print_preview.ticket_items.Dpi}
93 this.dpi_
= new print_preview
.ticket_items
.Dpi(
94 this.appState_
, this.destinationStore_
);
98 * @type {!print_preview.ticket_items.Duplex}
101 this.duplex_
= new print_preview
.ticket_items
.Duplex(
102 this.appState_
, this.destinationStore_
);
105 * Page range ticket item.
106 * @type {!print_preview.ticket_items.PageRange}
110 new print_preview
.ticket_items
.PageRange(this.documentInfo_
);
113 * Custom margins ticket item.
114 * @type {!print_preview.ticket_items.CustomMargins}
117 this.customMargins_
= new print_preview
.ticket_items
.CustomMargins(
118 this.appState_
, this.documentInfo_
);
121 * Margins type ticket item.
122 * @type {!print_preview.ticket_items.MarginsType}
125 this.marginsType_
= new print_preview
.ticket_items
.MarginsType(
126 this.appState_
, this.documentInfo_
, this.customMargins_
);
129 * Media size ticket item.
130 * @type {!print_preview.ticket_items.MediaSize}
133 this.mediaSize_
= new print_preview
.ticket_items
.MediaSize(
135 this.destinationStore_
,
138 this.customMargins_
);
141 * Landscape ticket item.
142 * @type {!print_preview.ticket_items.Landscape}
145 this.landscape_
= new print_preview
.ticket_items
.Landscape(
147 this.destinationStore_
,
150 this.customMargins_
);
153 * Header-footer ticket item.
154 * @type {!print_preview.ticket_items.HeaderFooter}
157 this.headerFooter_
= new print_preview
.ticket_items
.HeaderFooter(
161 this.customMargins_
);
164 * Fit-to-page ticket item.
165 * @type {!print_preview.ticket_items.FitToPage}
168 this.fitToPage_
= new print_preview
.ticket_items
.FitToPage(
169 this.documentInfo_
, this.destinationStore_
);
172 * Print CSS backgrounds ticket item.
173 * @type {!print_preview.ticket_items.CssBackground}
176 this.cssBackground_
= new print_preview
.ticket_items
.CssBackground(
177 this.appState_
, this.documentInfo_
);
180 * Print selection only ticket item.
181 * @type {!print_preview.ticket_items.SelectionOnly}
184 this.selectionOnly_
=
185 new print_preview
.ticket_items
.SelectionOnly(this.documentInfo_
);
188 * Vendor ticket items.
189 * @type {!print_preview.ticket_items.VendorItems}
192 this.vendorItems_
= new print_preview
.ticket_items
.VendorItems(
193 this.appState_
, this.destinationStore_
);
196 * Keeps track of event listeners for the print ticket store.
197 * @type {!EventTracker}
200 this.tracker_
= new EventTracker();
203 * Whether the print preview has been initialized.
207 this.isInitialized_
= false;
209 this.addEventListeners_();
213 * Event types dispatched by the print ticket store.
216 PrintTicketStore
.EventType
= {
217 CAPABILITIES_CHANGE
: 'print_preview.PrintTicketStore.CAPABILITIES_CHANGE',
218 DOCUMENT_CHANGE
: 'print_preview.PrintTicketStore.DOCUMENT_CHANGE',
219 INITIALIZE
: 'print_preview.PrintTicketStore.INITIALIZE',
220 TICKET_CHANGE
: 'print_preview.PrintTicketStore.TICKET_CHANGE'
223 PrintTicketStore
.prototype = {
224 __proto__
: cr
.EventTarget
.prototype,
227 * Whether the print preview has been initialized.
230 get isInitialized() {
231 return this.isInitialized_
;
235 return this.collate_
;
246 get cssBackground() {
247 return this.cssBackground_
;
250 get customMargins() {
251 return this.customMargins_
;
263 return this.fitToPage_
;
267 return this.headerFooter_
;
271 return this.mediaSize_
;
275 return this.landscape_
;
279 return this.marginsType_
;
283 return this.pageRange_
;
286 get selectionOnly() {
287 return this.selectionOnly_
;
291 return this.vendorItems_
;
295 * @return {!print_preview.MeasurementSystem} Measurement system of the
298 get measurementSystem() {
299 return this.measurementSystem_
;
303 * Initializes the print ticket store. Dispatches an INITIALIZE event.
304 * @param {string} thousandsDelimeter Delimeter of the thousands place.
305 * @param {string} decimalDelimeter Delimeter of the decimal point.
306 * @param {!print_preview.MeasurementSystem.UnitType} unitType Type of unit
307 * of the local measurement system.
308 * @param {boolean} selectionOnly Whether only selected content should be
312 thousandsDelimeter
, decimalDelimeter
, unitType
, selectionOnly
) {
313 this.measurementSystem_
.setSystem(thousandsDelimeter
, decimalDelimeter
,
315 this.selectionOnly_
.updateValue(selectionOnly
);
317 // Initialize ticket with user's previous values.
318 if (this.appState_
.hasField(
319 print_preview
.AppState
.Field
.IS_COLOR_ENABLED
)) {
320 this.color_
.updateValue(
321 /** @type {!Object} */(this.appState_
.getField(
322 print_preview
.AppState
.Field
.IS_COLOR_ENABLED
)));
324 if (this.appState_
.hasField(print_preview
.AppState
.Field
.DPI
)) {
325 this.dpi_
.updateValue(
326 /** @type {!Object} */(this.appState_
.getField(
327 print_preview
.AppState
.Field
.DPI
)));
329 if (this.appState_
.hasField(
330 print_preview
.AppState
.Field
.IS_DUPLEX_ENABLED
)) {
331 this.duplex_
.updateValue(
332 /** @type {!Object} */(this.appState_
.getField(
333 print_preview
.AppState
.Field
.IS_DUPLEX_ENABLED
)));
335 if (this.appState_
.hasField(print_preview
.AppState
.Field
.MEDIA_SIZE
)) {
336 this.mediaSize_
.updateValue(
337 /** @type {!Object} */(this.appState_
.getField(
338 print_preview
.AppState
.Field
.MEDIA_SIZE
)));
340 if (this.appState_
.hasField(
341 print_preview
.AppState
.Field
.IS_LANDSCAPE_ENABLED
)) {
342 this.landscape_
.updateValue(
343 /** @type {!Object} */(this.appState_
.getField(
344 print_preview
.AppState
.Field
.IS_LANDSCAPE_ENABLED
)));
346 // Initialize margins after landscape because landscape may reset margins.
347 if (this.appState_
.hasField(print_preview
.AppState
.Field
.MARGINS_TYPE
)) {
348 this.marginsType_
.updateValue(
349 /** @type {!Object} */(this.appState_
.getField(
350 print_preview
.AppState
.Field
.MARGINS_TYPE
)));
352 if (this.appState_
.hasField(
353 print_preview
.AppState
.Field
.CUSTOM_MARGINS
)) {
354 this.customMargins_
.updateValue(
355 /** @type {!Object} */(this.appState_
.getField(
356 print_preview
.AppState
.Field
.CUSTOM_MARGINS
)));
358 if (this.appState_
.hasField(
359 print_preview
.AppState
.Field
.IS_HEADER_FOOTER_ENABLED
)) {
360 this.headerFooter_
.updateValue(
361 /** @type {!Object} */(this.appState_
.getField(
362 print_preview
.AppState
.Field
.IS_HEADER_FOOTER_ENABLED
)));
364 if (this.appState_
.hasField(
365 print_preview
.AppState
.Field
.IS_COLLATE_ENABLED
)) {
366 this.collate_
.updateValue(
367 /** @type {!Object} */(this.appState_
.getField(
368 print_preview
.AppState
.Field
.IS_COLLATE_ENABLED
)));
370 if (this.appState_
.hasField(
371 print_preview
.AppState
.Field
.IS_CSS_BACKGROUND_ENABLED
)) {
372 this.cssBackground_
.updateValue(
373 /** @type {!Object} */(this.appState_
.getField(
374 print_preview
.AppState
.Field
.IS_CSS_BACKGROUND_ENABLED
)));
376 if (this.appState_
.hasField(
377 print_preview
.AppState
.Field
.VENDOR_OPTIONS
)) {
378 this.vendorItems_
.updateValue(
379 /** @type {!Object<string>} */(this.appState_
.getField(
380 print_preview
.AppState
.Field
.VENDOR_OPTIONS
)));
385 * @return {boolean} {@code true} if the stored print ticket is valid,
386 * {@code false} otherwise.
388 isTicketValid: function() {
389 return this.isTicketValidForPreview() &&
390 (!this.copies_
.isCapabilityAvailable() || this.copies_
.isValid()) &&
391 (!this.pageRange_
.isCapabilityAvailable() ||
392 this.pageRange_
.isValid());
395 /** @return {boolean} Whether the ticket is valid for preview generation. */
396 isTicketValidForPreview: function() {
397 return (!this.marginsType_
.isCapabilityAvailable() ||
398 !this.marginsType_
.isValueEqual(
399 print_preview
.ticket_items
.MarginsType
.Value
.CUSTOM
) ||
400 this.customMargins_
.isValid());
404 * Creates an object that represents a Google Cloud Print print ticket.
405 * @param {!print_preview.Destination} destination Destination to print to.
406 * @return {!Object} Google Cloud Print print ticket.
408 createPrintTicket: function(destination
) {
409 assert(!destination
.isLocal
||
410 destination
.isPrivet
|| destination
.isExtension
,
411 'Trying to create a Google Cloud Print print ticket for a local ' +
412 ' non-privet and non-extension destination');
414 assert(destination
.capabilities
,
415 'Trying to create a Google Cloud Print print ticket for a ' +
416 'destination with no print capabilities');
421 if (this.collate
.isCapabilityAvailable() && this.collate
.isUserEdited()) {
422 cjt
.print
.collate
= {collate
: this.collate
.getValue()};
424 if (this.color
.isCapabilityAvailable() && this.color
.isUserEdited()) {
425 var selectedOption
= this.color
.getSelectedOption();
426 if (!selectedOption
) {
427 console
.error('Could not find correct color option');
429 cjt
.print
.color
= {type
: selectedOption
.type
};
430 if (selectedOption
.hasOwnProperty('vendor_id')) {
431 cjt
.print
.color
.vendor_id
= selectedOption
.vendor_id
;
435 if (this.copies
.isCapabilityAvailable() && this.copies
.isUserEdited()) {
436 cjt
.print
.copies
= {copies
: this.copies
.getValueAsNumber()};
438 if (this.duplex
.isCapabilityAvailable() && this.duplex
.isUserEdited()) {
440 {type
: this.duplex
.getValue() ? 'LONG_EDGE' : 'NO_DUPLEX'};
442 if (this.mediaSize
.isCapabilityAvailable()) {
443 var value
= this.mediaSize
.getValue();
444 cjt
.print
.media_size
= {
445 width_microns
: value
.width_microns
,
446 height_microns
: value
.height_microns
,
447 is_continuous_feed
: value
.is_continuous_feed
,
448 vendor_id
: value
.vendor_id
451 if (!this.landscape
.isCapabilityAvailable()) {
452 // In this case "orientation" option is hidden from user, so user can't
453 // adjust it for page content, see Landscape.isCapabilityAvailable().
454 // We can improve results if we set AUTO here.
455 if (this.landscape
.hasOption('AUTO'))
456 cjt
.print
.page_orientation
= { type
: 'AUTO' };
457 } else if (this.landscape
.isUserEdited()) {
458 cjt
.print
.page_orientation
=
459 {type
: this.landscape
.getValue() ? 'LANDSCAPE' : 'PORTRAIT'};
461 if (this.dpi
.isCapabilityAvailable()) {
462 var value
= this.dpi
.getValue();
464 horizontal_dpi
: value
.horizontal_dpi
,
465 vertical_dpi
: value
.vertical_dpi
,
466 vendor_id
: value
.vendor_id
469 if (this.vendorItems
.isCapabilityAvailable() &&
470 this.vendorItems
.isUserEdited()) {
471 var items
= this.vendorItems
.ticketItems
;
472 cjt
.print
.vendor_ticket_item
= [];
473 for (var itemId
in items
) {
474 if (items
.hasOwnProperty(itemId
)) {
475 cjt
.print
.vendor_ticket_item
.push(
476 {id
: itemId
, value
: items
[itemId
]});
480 return JSON
.stringify(cjt
);
484 * Adds event listeners for the print ticket store.
487 addEventListeners_: function() {
489 this.destinationStore_
,
490 print_preview
.DestinationStore
.EventType
.DESTINATION_SELECT
,
491 this.onDestinationSelect_
.bind(this));
494 this.destinationStore_
,
495 print_preview
.DestinationStore
.EventType
.
496 SELECTED_DESTINATION_CAPABILITIES_READY
,
497 this.onSelectedDestinationCapabilitiesReady_
.bind(this));
500 this.destinationStore_
,
501 print_preview
.DestinationStore
.EventType
.
502 CACHED_SELECTED_DESTINATION_INFO_READY
,
503 this.onSelectedDestinationCapabilitiesReady_
.bind(this));
505 // TODO(rltoscano): Print ticket store shouldn't be re-dispatching these
506 // events, the consumers of the print ticket store events should listen
507 // for the events from document info instead. Will move this when
508 // consumers are all migrated.
511 print_preview
.DocumentInfo
.EventType
.CHANGE
,
512 this.onDocumentInfoChange_
.bind(this));
516 * Called when the destination selected.
519 onDestinationSelect_: function() {
520 // Reset user selection for certain ticket items.
521 if (this.capabilitiesHolder_
.get() != null) {
522 this.customMargins_
.updateValue(null);
523 if (this.marginsType_
.getValue() ==
524 print_preview
.ticket_items
.MarginsType
.Value
.CUSTOM
) {
525 this.marginsType_
.updateValue(
526 print_preview
.ticket_items
.MarginsType
.Value
.DEFAULT
);
528 this.vendorItems_
.updateValue({});
533 * Called when the capabilities of the selected destination are ready.
536 onSelectedDestinationCapabilitiesReady_: function() {
538 this.destinationStore_
.selectedDestination
.capabilities
);
539 var isFirstUpdate
= this.capabilitiesHolder_
.get() == null;
540 this.capabilitiesHolder_
.set(caps
);
542 this.isInitialized_
= true;
543 cr
.dispatchSimpleEvent(this, PrintTicketStore
.EventType
.INITIALIZE
);
545 cr
.dispatchSimpleEvent(
546 this, PrintTicketStore
.EventType
.CAPABILITIES_CHANGE
);
551 * Called when document data model has changed. Dispatches a print ticket
555 onDocumentInfoChange_: function() {
556 cr
.dispatchSimpleEvent(this, PrintTicketStore
.EventType
.DOCUMENT_CHANGE
);
562 PrintTicketStore
: PrintTicketStore