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.Duplex}
93 this.duplex_
= new print_preview
.ticket_items
.Duplex(
94 this.appState_
, this.destinationStore_
);
97 * Page range ticket item.
98 * @type {!print_preview.ticket_items.PageRange}
102 new print_preview
.ticket_items
.PageRange(this.documentInfo_
);
105 * Custom margins ticket item.
106 * @type {!print_preview.ticket_items.CustomMargins}
109 this.customMargins_
= new print_preview
.ticket_items
.CustomMargins(
110 this.appState_
, this.documentInfo_
);
113 * Margins type ticket item.
114 * @type {!print_preview.ticket_items.MarginsType}
117 this.marginsType_
= new print_preview
.ticket_items
.MarginsType(
118 this.appState_
, this.documentInfo_
, this.customMargins_
);
121 * Media size ticket item.
122 * @type {!print_preview.ticket_items.MediaSize}
125 this.mediaSize_
= new print_preview
.ticket_items
.MediaSize(
127 this.destinationStore_
,
130 this.customMargins_
);
133 * Landscape ticket item.
134 * @type {!print_preview.ticket_items.Landscape}
137 this.landscape_
= new print_preview
.ticket_items
.Landscape(
139 this.destinationStore_
,
142 this.customMargins_
);
145 * Header-footer ticket item.
146 * @type {!print_preview.ticket_items.HeaderFooter}
149 this.headerFooter_
= new print_preview
.ticket_items
.HeaderFooter(
153 this.customMargins_
);
156 * Fit-to-page ticket item.
157 * @type {!print_preview.ticket_items.FitToPage}
160 this.fitToPage_
= new print_preview
.ticket_items
.FitToPage(
161 this.documentInfo_
, this.destinationStore_
);
164 * Print CSS backgrounds ticket item.
165 * @type {!print_preview.ticket_items.CssBackground}
168 this.cssBackground_
= new print_preview
.ticket_items
.CssBackground(
169 this.appState_
, this.documentInfo_
);
172 * Print selection only ticket item.
173 * @type {!print_preview.ticket_items.SelectionOnly}
176 this.selectionOnly_
=
177 new print_preview
.ticket_items
.SelectionOnly(this.documentInfo_
);
180 * Vendor ticket items.
181 * @type {!print_preview.ticket_items.VendorItems}
184 this.vendorItems_
= new print_preview
.ticket_items
.VendorItems(
185 this.appState_
, this.destinationStore_
);
188 * Keeps track of event listeners for the print ticket store.
189 * @type {!EventTracker}
192 this.tracker_
= new EventTracker();
195 * Whether the print preview has been initialized.
199 this.isInitialized_
= false;
201 this.addEventListeners_();
205 * Event types dispatched by the print ticket store.
208 PrintTicketStore
.EventType
= {
209 CAPABILITIES_CHANGE
: 'print_preview.PrintTicketStore.CAPABILITIES_CHANGE',
210 DOCUMENT_CHANGE
: 'print_preview.PrintTicketStore.DOCUMENT_CHANGE',
211 INITIALIZE
: 'print_preview.PrintTicketStore.INITIALIZE',
212 TICKET_CHANGE
: 'print_preview.PrintTicketStore.TICKET_CHANGE'
215 PrintTicketStore
.prototype = {
216 __proto__
: cr
.EventTarget
.prototype,
219 * Whether the print preview has been initialized.
222 get isInitialized() {
223 return this.isInitialized_
;
227 return this.collate_
;
238 get cssBackground() {
239 return this.cssBackground_
;
242 get customMargins() {
243 return this.customMargins_
;
251 return this.fitToPage_
;
255 return this.headerFooter_
;
259 return this.mediaSize_
;
263 return this.landscape_
;
267 return this.marginsType_
;
271 return this.pageRange_
;
274 get selectionOnly() {
275 return this.selectionOnly_
;
279 return this.vendorItems_
;
283 * @return {!print_preview.MeasurementSystem} Measurement system of the
286 get measurementSystem() {
287 return this.measurementSystem_
;
291 * Initializes the print ticket store. Dispatches an INITIALIZE event.
292 * @param {string} thousandsDelimeter Delimeter of the thousands place.
293 * @param {string} decimalDelimeter Delimeter of the decimal point.
294 * @param {!print_preview.MeasurementSystem.UnitType} unitType Type of unit
295 * of the local measurement system.
296 * @param {boolean} selectionOnly Whether only selected content should be
300 thousandsDelimeter
, decimalDelimeter
, unitType
, selectionOnly
) {
301 this.measurementSystem_
.setSystem(thousandsDelimeter
, decimalDelimeter
,
303 this.selectionOnly_
.updateValue(selectionOnly
);
305 // Initialize ticket with user's previous values.
306 if (this.appState_
.hasField(
307 print_preview
.AppState
.Field
.IS_COLOR_ENABLED
)) {
308 this.color_
.updateValue(this.appState_
.getField(
309 print_preview
.AppState
.Field
.IS_COLOR_ENABLED
));
311 if (this.appState_
.hasField(
312 print_preview
.AppState
.Field
.IS_DUPLEX_ENABLED
)) {
313 this.duplex_
.updateValue(this.appState_
.getField(
314 print_preview
.AppState
.Field
.IS_DUPLEX_ENABLED
));
316 if (this.appState_
.hasField(print_preview
.AppState
.Field
.MEDIA_SIZE
)) {
317 this.mediaSize_
.updateValue(this.appState_
.getField(
318 print_preview
.AppState
.Field
.MEDIA_SIZE
));
320 if (this.appState_
.hasField(
321 print_preview
.AppState
.Field
.IS_LANDSCAPE_ENABLED
)) {
322 this.landscape_
.updateValue(this.appState_
.getField(
323 print_preview
.AppState
.Field
.IS_LANDSCAPE_ENABLED
));
325 // Initialize margins after landscape because landscape may reset margins.
326 if (this.appState_
.hasField(print_preview
.AppState
.Field
.MARGINS_TYPE
)) {
327 this.marginsType_
.updateValue(
328 this.appState_
.getField(print_preview
.AppState
.Field
.MARGINS_TYPE
));
330 if (this.appState_
.hasField(
331 print_preview
.AppState
.Field
.CUSTOM_MARGINS
)) {
332 this.customMargins_
.updateValue(this.appState_
.getField(
333 print_preview
.AppState
.Field
.CUSTOM_MARGINS
));
335 if (this.appState_
.hasField(
336 print_preview
.AppState
.Field
.IS_HEADER_FOOTER_ENABLED
)) {
337 this.headerFooter_
.updateValue(this.appState_
.getField(
338 print_preview
.AppState
.Field
.IS_HEADER_FOOTER_ENABLED
));
340 if (this.appState_
.hasField(
341 print_preview
.AppState
.Field
.IS_COLLATE_ENABLED
)) {
342 this.collate_
.updateValue(this.appState_
.getField(
343 print_preview
.AppState
.Field
.IS_COLLATE_ENABLED
));
345 if (this.appState_
.hasField(
346 print_preview
.AppState
.Field
.IS_CSS_BACKGROUND_ENABLED
)) {
347 this.cssBackground_
.updateValue(this.appState_
.getField(
348 print_preview
.AppState
.Field
.IS_CSS_BACKGROUND_ENABLED
));
350 if (this.appState_
.hasField(
351 print_preview
.AppState
.Field
.VENDOR_OPTIONS
)) {
352 this.vendorItems_
.updateValue(this.appState_
.getField(
353 print_preview
.AppState
.Field
.VENDOR_OPTIONS
));
358 * @return {boolean} {@code true} if the stored print ticket is valid,
359 * {@code false} otherwise.
361 isTicketValid: function() {
362 return this.isTicketValidForPreview() &&
363 (!this.copies_
.isCapabilityAvailable() || this.copies_
.isValid()) &&
364 (!this.pageRange_
.isCapabilityAvailable() ||
365 this.pageRange_
.isValid());
368 /** @return {boolean} Whether the ticket is valid for preview generation. */
369 isTicketValidForPreview: function() {
370 return (!this.marginsType_
.isCapabilityAvailable() ||
371 !this.marginsType_
.isValueEqual(
372 print_preview
.ticket_items
.MarginsType
.Value
.CUSTOM
) ||
373 this.customMargins_
.isValid());
377 * Creates an object that represents a Google Cloud Print print ticket.
378 * @param {!print_preview.Destination} destination Destination to print to.
379 * @return {!Object} Google Cloud Print print ticket.
381 createPrintTicket: function(destination
) {
382 assert(!destination
.isLocal
|| destination
.isPrivet
,
383 'Trying to create a Google Cloud Print print ticket for a local ' +
384 ' non-privet destination');
386 assert(destination
.capabilities
,
387 'Trying to create a Google Cloud Print print ticket for a ' +
388 'destination with no print capabilities');
393 if (this.collate
.isCapabilityAvailable() && this.collate
.isUserEdited()) {
394 cjt
.print
.collate
= {collate
: this.collate
.getValue()};
396 if (this.color
.isCapabilityAvailable() && this.color
.isUserEdited()) {
397 var selectedOption
= this.color
.getSelectedOption();
398 if (!selectedOption
) {
399 console
.error('Could not find correct color option');
401 cjt
.print
.color
= {type
: selectedOption
.type
};
402 if (selectedOption
.hasOwnProperty('vendor_id')) {
403 cjt
.print
.color
.vendor_id
= selectedOption
.vendor_id
;
407 if (this.copies
.isCapabilityAvailable() && this.copies
.isUserEdited()) {
408 cjt
.print
.copies
= {copies
: this.copies
.getValueAsNumber()};
410 if (this.duplex
.isCapabilityAvailable() && this.duplex
.isUserEdited()) {
412 {type
: this.duplex
.getValue() ? 'LONG_EDGE' : 'NO_DUPLEX'};
414 if (this.mediaSize
.isCapabilityAvailable()) {
415 var value
= this.mediaSize
.getValue();
416 cjt
.print
.media_size
= {
417 width_microns
: value
.width_microns
,
418 height_microns
: value
.height_microns
,
419 is_continuous_feed
: value
.is_continuous_feed
,
420 vendor_id
: value
.vendor_id
423 if (this.landscape
.isCapabilityAvailable() &&
424 this.landscape
.isUserEdited()) {
425 cjt
.print
.page_orientation
=
426 {type
: this.landscape
.getValue() ? 'LANDSCAPE' : 'PORTRAIT'};
428 if (this.vendorItems
.isCapabilityAvailable() &&
429 this.vendorItems
.isUserEdited()) {
430 var items
= this.vendorItems
.ticketItems
;
431 cjt
.print
.vendor_ticket_item
= [];
432 for (var itemId
in items
) {
433 if (items
.hasOwnProperty(itemId
)) {
434 cjt
.print
.vendor_ticket_item
.push(
435 {id
: itemId
, value
: items
[itemId
]});
439 return JSON
.stringify(cjt
);
443 * Adds event listeners for the print ticket store.
446 addEventListeners_: function() {
448 this.destinationStore_
,
449 print_preview
.DestinationStore
.EventType
.DESTINATION_SELECT
,
450 this.onDestinationSelect_
.bind(this));
453 this.destinationStore_
,
454 print_preview
.DestinationStore
.EventType
.
455 SELECTED_DESTINATION_CAPABILITIES_READY
,
456 this.onSelectedDestinationCapabilitiesReady_
.bind(this));
459 this.destinationStore_
,
460 print_preview
.DestinationStore
.EventType
.
461 CACHED_SELECTED_DESTINATION_INFO_READY
,
462 this.onSelectedDestinationCapabilitiesReady_
.bind(this));
464 // TODO(rltoscano): Print ticket store shouldn't be re-dispatching these
465 // events, the consumers of the print ticket store events should listen
466 // for the events from document info instead. Will move this when
467 // consumers are all migrated.
470 print_preview
.DocumentInfo
.EventType
.CHANGE
,
471 this.onDocumentInfoChange_
.bind(this));
475 * Called when the destination selected.
478 onDestinationSelect_: function() {
479 // Reset user selection for certain ticket items.
480 if (this.capabilitiesHolder_
.get() != null) {
481 this.customMargins_
.updateValue(null);
482 if (this.marginsType_
.getValue() ==
483 print_preview
.ticket_items
.MarginsType
.Value
.CUSTOM
) {
484 this.marginsType_
.updateValue(
485 print_preview
.ticket_items
.MarginsType
.Value
.DEFAULT
);
487 this.vendorItems_
.updateValue({});
492 * Called when the capabilities of the selected destination are ready.
495 onSelectedDestinationCapabilitiesReady_: function() {
496 var caps
= this.destinationStore_
.selectedDestination
.capabilities
;
497 var isFirstUpdate
= this.capabilitiesHolder_
.get() == null;
498 this.capabilitiesHolder_
.set(caps
);
500 this.isInitialized_
= true;
501 cr
.dispatchSimpleEvent(this, PrintTicketStore
.EventType
.INITIALIZE
);
503 cr
.dispatchSimpleEvent(
504 this, PrintTicketStore
.EventType
.CAPABILITIES_CHANGE
);
509 * Called when document data model has changed. Dispatches a print ticket
513 onDocumentInfoChange_: function() {
514 cr
.dispatchSimpleEvent(this, PrintTicketStore
.EventType
.DOCUMENT_CHANGE
);
520 PrintTicketStore
: PrintTicketStore