| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| cr.exportPath('print_preview_new'); |
| /** |
| * @typedef {{ |
| * version: string, |
| * recentDestinations: (!Array<!print_preview.RecentDestination> | |
| * undefined), |
| * dpi: ({horizontal_dpi: number, |
| * vertical_dpi: number, |
| * is_default: (boolean | undefined)} | undefined), |
| * mediaSize: ({height_microns: number, |
| * width_microns: number, |
| * custom_display_name: (string | undefined), |
| * is_default: (boolean | undefined)} | undefined), |
| * marginsType: (print_preview.ticket_items.MarginsTypeValue | undefined), |
| * customMargins: (print_preview.MarginsSetting | undefined), |
| * isColorEnabled: (boolean | undefined), |
| * isDuplexEnabled: (boolean | undefined), |
| * isHeaderFooterEnabled: (boolean | undefined), |
| * isLandscapeEnabled: (boolean | undefined), |
| * isCollateEnabled: (boolean | undefined), |
| * isFitToPageEnabled: (boolean | undefined), |
| * isCssBackgroundEnabled: (boolean | undefined), |
| * scaling: (string | undefined), |
| * vendor_options: (Object | undefined) |
| * }} |
| */ |
| print_preview_new.SerializedSettings; |
| |
| /** |
| * @typedef {{ |
| * value: *, |
| * managed: boolean |
| * }} |
| */ |
| print_preview_new.PolicyEntry; |
| |
| /** |
| * @typedef {{ |
| * headerFooter: print_preview_new.PolicyEntry |
| * }} |
| */ |
| print_preview_new.PolicySettings; |
| |
| /** |
| * Constant values matching printing::DuplexMode enum. |
| * @enum {number} |
| */ |
| print_preview_new.DuplexMode = { |
| SIMPLEX: 0, |
| LONG_EDGE: 1, |
| UNKNOWN_DUPLEX_MODE: -1 |
| }; |
| |
| /** |
| * Values matching the types of duplex in a CDD. |
| * @enum {string} |
| */ |
| print_preview_new.DuplexType = { |
| NO_DUPLEX: 'NO_DUPLEX', |
| LONG_EDGE: 'LONG_EDGE', |
| SHORT_EDGE: 'SHORT_EDGE' |
| }; |
| |
| (function() { |
| 'use strict'; |
| |
| /** @type {number} Number of recent destinations to save. */ |
| const NUM_DESTINATIONS = 3; |
| |
| /** |
| * Sticky setting names. Alphabetical except for fitToPage, which must be set |
| * after scaling in updateFromStickySettings(). |
| * @type {!Array<string>} |
| */ |
| const STICKY_SETTING_NAMES = [ |
| 'collate', |
| 'color', |
| 'cssBackground', |
| 'customMargins', |
| 'dpi', |
| 'duplex', |
| 'headerFooter', |
| 'layout', |
| 'margins', |
| 'mediaSize', |
| 'scaling', |
| 'fitToPage', |
| 'vendorItems', |
| ]; |
| |
| /** |
| * Minimum height of page in microns to allow headers and footers. Should |
| * match the value for min_size_printer_units in printing/print_settings.cc |
| * so that we do not request header/footer for margins that will be zero. |
| * @type {number} |
| */ |
| const MINIMUM_HEIGHT_MICRONS = 25400; |
| |
| Polymer({ |
| is: 'print-preview-model', |
| |
| behaviors: [SettingsBehavior], |
| |
| properties: { |
| /** |
| * Object containing current settings of Print Preview, for use by Polymer |
| * controls. |
| * @type {!print_preview_new.Settings} |
| */ |
| settings: { |
| type: Object, |
| notify: true, |
| value: function() { |
| return { |
| pages: { |
| value: [1], |
| unavailableValue: [], |
| valid: true, |
| available: true, |
| setByPolicy: false, |
| key: '', |
| }, |
| copies: { |
| value: '1', |
| unavailableValue: '1', |
| valid: true, |
| available: true, |
| setByPolicy: false, |
| key: '', |
| }, |
| collate: { |
| value: true, |
| unavailableValue: false, |
| valid: true, |
| available: true, |
| setByPolicy: false, |
| key: 'isCollateEnabled', |
| }, |
| layout: { |
| value: false, /* portrait */ |
| unavailableValue: false, |
| valid: true, |
| available: true, |
| setByPolicy: false, |
| key: 'isLandscapeEnabled', |
| }, |
| color: { |
| value: true, /* color */ |
| unavailableValue: false, |
| valid: true, |
| available: true, |
| setByPolicy: false, |
| key: 'isColorEnabled', |
| }, |
| mediaSize: { |
| value: { |
| width_microns: 215900, |
| height_microns: 279400, |
| }, |
| unavailableValue: {}, |
| valid: true, |
| available: true, |
| setByPolicy: false, |
| key: 'mediaSize', |
| }, |
| margins: { |
| value: print_preview.ticket_items.MarginsTypeValue.DEFAULT, |
| unavailableValue: |
| print_preview.ticket_items.MarginsTypeValue.DEFAULT, |
| valid: true, |
| available: true, |
| setByPolicy: false, |
| key: 'marginsType', |
| }, |
| customMargins: { |
| value: {}, |
| unavailableValue: {}, |
| valid: true, |
| available: true, |
| setByPolicy: false, |
| key: 'customMargins', |
| }, |
| dpi: { |
| value: {}, |
| unavailableValue: {}, |
| valid: true, |
| available: true, |
| setByPolicy: false, |
| key: 'dpi', |
| }, |
| fitToPage: { |
| value: false, |
| unavailableValue: false, |
| valid: true, |
| available: true, |
| setByPolicy: false, |
| key: 'isFitToPageEnabled', |
| }, |
| scaling: { |
| value: '100', |
| unavailableValue: '100', |
| valid: true, |
| available: true, |
| setByPolicy: false, |
| key: 'scaling', |
| }, |
| duplex: { |
| value: true, |
| unavailableValue: false, |
| valid: true, |
| available: true, |
| setByPolicy: false, |
| key: 'isDuplexEnabled', |
| }, |
| cssBackground: { |
| value: false, |
| unavailableValue: false, |
| valid: true, |
| available: true, |
| setByPolicy: false, |
| key: 'isCssBackgroundEnabled', |
| }, |
| selectionOnly: { |
| value: false, |
| unavailableValue: false, |
| valid: true, |
| available: true, |
| setByPolicy: false, |
| key: '', |
| }, |
| headerFooter: { |
| value: true, |
| unavailableValue: false, |
| valid: true, |
| available: true, |
| setByPolicy: false, |
| key: 'isHeaderFooterEnabled', |
| }, |
| rasterize: { |
| value: false, |
| unavailableValue: false, |
| valid: true, |
| available: true, |
| setByPolicy: false, |
| key: '', |
| }, |
| vendorItems: { |
| value: {}, |
| unavailableValue: {}, |
| valid: true, |
| available: true, |
| setByPolicy: false, |
| key: 'vendorOptions', |
| }, |
| pagesPerSheet: { |
| value: 1, |
| unavailableValue: 1, |
| valid: true, |
| available: true, |
| setByPolicy: false, |
| key: '', |
| }, |
| // This does not represent a real setting value, and is used only to |
| // expose the availability of the other options settings section. |
| otherOptions: { |
| value: null, |
| unavailableValue: null, |
| valid: true, |
| available: true, |
| setByPolicy: false, |
| key: '', |
| }, |
| // This does not represent a real settings value, but is used to |
| // propagate the correctly formatted ranges for print tickets. |
| ranges: { |
| value: [], |
| unavailableValue: [], |
| valid: true, |
| available: true, |
| setByPolicy: false, |
| key: '', |
| }, |
| }; |
| }, |
| }, |
| |
| /** @type {print_preview.Destination} */ |
| destination: { |
| type: Object, |
| notify: true, |
| }, |
| |
| /** @type {!print_preview.DocumentSettings} */ |
| documentSettings: Object, |
| |
| /** @type {print_preview.Margins} */ |
| margins: Object, |
| |
| /** @type {!print_preview.Size} */ |
| pageSize: Object, |
| |
| /** @type {!Array<!print_preview.RecentDestination>} */ |
| recentDestinations: { |
| type: Array, |
| notify: true, |
| value: function() { |
| return []; |
| }, |
| }, |
| }, |
| |
| observers: [ |
| 'updateSettingsFromDestination_(destination.capabilities)', |
| 'updateSettingsAvailabilityFromDocumentSettings_(' + |
| 'documentSettings.isModifiable, documentSettings.hasCssMediaStyles,' + |
| 'documentSettings.hasSelection, documentSettings.isScalingDisabled)', |
| 'updateHeaderFooterAvailable_(' + |
| 'margins, settings.margins.value, ' + |
| 'settings.customMargins.value, settings.mediaSize.value)', |
| 'updateRecentDestinations_(destination, destination.capabilities)', |
| 'stickySettingsChanged_(' + |
| 'settings.collate.value, settings.layout.value, settings.color.value,' + |
| 'settings.mediaSize.value, settings.margins.value, ' + |
| 'settings.customMargins.value, settings.dpi.value, ' + |
| 'settings.fitToPage.value, settings.scaling.value, ' + |
| 'settings.duplex.value, settings.headerFooter.value, ' + |
| 'settings.cssBackground.value, settings.vendorItems.value)', |
| ], |
| |
| /** @private {boolean} */ |
| initialized_: false, |
| |
| /** @private {?print_preview_new.SerializedSettings} */ |
| stickySettings_: null, |
| |
| /** @private {?print_preview_new.PolicySettings} */ |
| policySettings_: null, |
| |
| /** @private {?print_preview.Cdd} */ |
| lastDestinationCapabilities_: null, |
| |
| /** |
| * Updates the availability of the settings sections and values of dpi and |
| * media size settings based on the destination capabilities. |
| * @private |
| */ |
| updateSettingsFromDestination_: function() { |
| if (!this.destination) { |
| return; |
| } |
| |
| if (this.destination.capabilities == this.lastDestinationCapabilities_) { |
| return; |
| } |
| |
| this.lastDestinationCapabilities_ = this.destination.capabilities; |
| |
| const caps = !!this.destination.capabilities ? |
| this.destination.capabilities.printer : |
| null; |
| this.updateSettingsAvailabilityFromDestination_(caps); |
| |
| if (!caps) { |
| return; |
| } |
| |
| this.updateSettingsValues_(caps); |
| }, |
| |
| /** |
| * @param {?print_preview.CddCapabilities} caps The printer capabilities. |
| * @private |
| */ |
| updateSettingsAvailabilityFromDestination_: function(caps) { |
| this.set('settings.copies.available', !!caps && !!(caps.copies)); |
| this.set('settings.collate.available', !!caps && !!(caps.collate)); |
| this.set('settings.layout.available', this.isLayoutAvailable_(caps)); |
| this.set('settings.color.available', this.destination.hasColorCapability); |
| |
| this.set( |
| 'settings.dpi.available', |
| !!caps && !!caps.dpi && !!caps.dpi.option && |
| caps.dpi.option.length > 1); |
| |
| this.set( |
| 'settings.duplex.available', |
| !!caps && !!caps.duplex && !!caps.duplex.option && |
| caps.duplex.option.some( |
| o => o.type == print_preview_new.DuplexType.LONG_EDGE) && |
| caps.duplex.option.some( |
| o => o.type == print_preview_new.DuplexType.NO_DUPLEX)); |
| |
| this.set( |
| 'settings.vendorItems.available', !!caps && !!caps.vendor_capability); |
| |
| if (this.documentSettings) { |
| this.updateSettingsAvailabilityFromDestinationAndDocumentSettings_(); |
| } |
| }, |
| |
| /** @private */ |
| updateSettingsAvailabilityFromDestinationAndDocumentSettings_: function() { |
| const isSaveAsPDF = this.destination.id == |
| print_preview.Destination.GooglePromotedId.SAVE_AS_PDF; |
| const knownSizeToSaveAsPdf = isSaveAsPDF && |
| (!this.documentSettings.isModifiable || |
| this.documentSettings.hasCssMediaStyles); |
| this.set('settings.fitToPage.unavailableValue', !isSaveAsPDF); |
| this.set( |
| 'settings.fitToPage.available', |
| !knownSizeToSaveAsPdf && !this.documentSettings.isModifiable && |
| !this.documentSettings.isScalingDisabled); |
| this.set( |
| 'settings.scaling.available', |
| !knownSizeToSaveAsPdf && !this.documentSettings.isScalingDisabled); |
| const caps = (!!this.destination && !!this.destination.capabilities) ? |
| this.destination.capabilities.printer : |
| null; |
| this.set( |
| 'settings.mediaSize.available', |
| !!caps && !!caps.media_size && !knownSizeToSaveAsPdf); |
| this.set('settings.layout.available', this.isLayoutAvailable_(caps)); |
| this.set( |
| 'settings.otherOptions.available', |
| this.settings.duplex.available || |
| this.settings.cssBackground.available || |
| this.settings.selectionOnly.available || |
| this.settings.headerFooter.available || |
| this.settings.rasterize.available); |
| }, |
| |
| /** @private */ |
| updateSettingsAvailabilityFromDocumentSettings_: function() { |
| this.set('settings.margins.available', this.documentSettings.isModifiable); |
| this.set( |
| 'settings.customMargins.available', this.documentSettings.isModifiable); |
| this.set( |
| 'settings.cssBackground.available', this.documentSettings.isModifiable); |
| this.set( |
| 'settings.selectionOnly.available', |
| this.documentSettings.isModifiable && |
| this.documentSettings.hasSelection); |
| this.set( |
| 'settings.headerFooter.available', this.isHeaderFooterAvailable_()); |
| this.set( |
| 'settings.rasterize.available', |
| !this.documentSettings.isModifiable && !cr.isWindows && !cr.isMac); |
| |
| if (this.destination) { |
| this.updateSettingsAvailabilityFromDestinationAndDocumentSettings_(); |
| } |
| }, |
| |
| /** @private */ |
| updateHeaderFooterAvailable_: function() { |
| if (this.documentSettings === undefined) { |
| return; |
| } |
| |
| this.set( |
| 'settings.headerFooter.available', this.isHeaderFooterAvailable_()); |
| }, |
| |
| /** |
| * @return {boolean} Whether the header/footer setting should be available. |
| * @private |
| */ |
| isHeaderFooterAvailable_: function() { |
| // Always unavailable for PDFs. |
| if (!this.documentSettings.isModifiable) { |
| return false; |
| } |
| |
| // Always unavailable for small paper sizes. |
| const microns = this.getSettingValue('layout') ? |
| this.getSettingValue('mediaSize').width_microns : |
| this.getSettingValue('mediaSize').height_microns; |
| if (microns < MINIMUM_HEIGHT_MICRONS) { |
| return false; |
| } |
| |
| // Otherwise, availability depends on the margins. |
| let available = false; |
| const marginsType = |
| /** @type {!print_preview.ticket_items.MarginsTypeValue} */ ( |
| this.getSettingValue('margins')); |
| switch (marginsType) { |
| case print_preview.ticket_items.MarginsTypeValue.DEFAULT: |
| available = !this.margins || |
| this.margins.get( |
| print_preview.ticket_items.CustomMarginsOrientation.TOP) > 0 || |
| this.margins.get( |
| print_preview.ticket_items.CustomMarginsOrientation.BOTTOM) > 0; |
| break; |
| case print_preview.ticket_items.MarginsTypeValue.NO_MARGINS: |
| break; |
| case print_preview.ticket_items.MarginsTypeValue.MINIMUM: |
| available = true; |
| break; |
| case print_preview.ticket_items.MarginsTypeValue.CUSTOM: |
| const margins = this.getSettingValue('customMargins'); |
| available = margins.marginTop > 0 || margins.marginBottom > 0; |
| break; |
| default: |
| break; |
| } |
| return available; |
| }, |
| |
| /** |
| * @param {?print_preview.CddCapabilities} caps The printer capabilities. |
| * @private |
| */ |
| isLayoutAvailable_: function(caps) { |
| if (!caps || !caps.page_orientation || !caps.page_orientation.option || |
| !this.documentSettings.isModifiable || |
| this.documentSettings.hasCssMediaStyles) { |
| return false; |
| } |
| let hasAutoOrPortraitOption = false; |
| let hasLandscapeOption = false; |
| caps.page_orientation.option.forEach(option => { |
| hasAutoOrPortraitOption = hasAutoOrPortraitOption || |
| option.type == 'AUTO' || option.type == 'PORTRAIT'; |
| hasLandscapeOption = hasLandscapeOption || option.type == 'LANDSCAPE'; |
| }); |
| return hasLandscapeOption && hasAutoOrPortraitOption; |
| }, |
| |
| /** |
| * @param {?print_preview.CddCapabilities} caps The printer capabilities. |
| * @private |
| */ |
| updateSettingsValues_: function(caps) { |
| if (this.settings.mediaSize.available) { |
| const defaultOption = caps.media_size.option.find(o => !!o.is_default); |
| this.setSetting('mediaSize', defaultOption); |
| } |
| |
| if (this.settings.dpi.available) { |
| const defaultOption = caps.dpi.option.find(o => !!o.is_default); |
| this.setSetting('dpi', defaultOption); |
| } else if ( |
| caps && caps.dpi && caps.dpi.option && caps.dpi.option.length > 0) { |
| this.set('settings.dpi.unavailableValue', caps.dpi.option[0]); |
| } |
| |
| if (this.settings.color.available) { |
| const defaultOption = this.destination.defaultColorOption; |
| if (defaultOption) { |
| this.setSetting( |
| 'color', |
| !['STANDARD_MONOCHROME', 'CUSTOM_MONOCHROME'].includes( |
| defaultOption.type)); |
| } |
| } else if ( |
| this.destination.id === |
| print_preview.Destination.GooglePromotedId.DOCS || |
| this.destination.type === print_preview.DestinationType.MOBILE) { |
| this.set('settings.color.unavailableValue', true); |
| } else if ( |
| caps && caps.color && caps.color.option && |
| caps.color.option.length > 0) { |
| this.set( |
| 'settings.color.unavailableValue', |
| !['STANDARD_MONOCHROME', 'CUSTOM_MONOCHROME'].includes( |
| caps.color.option[0].type)); |
| } else { // if no color capability is reported, assume black and white. |
| this.set('settings.color.unavailableValue', false); |
| } |
| |
| if (this.settings.duplex.available) { |
| const defaultOption = caps.duplex.option.find(o => !!o.is_default); |
| this.setSetting( |
| 'duplex', |
| defaultOption ? |
| defaultOption.type == print_preview_new.DuplexType.LONG_EDGE : |
| false); |
| } else if ( |
| caps && caps.duplex && caps.duplex.option && |
| !caps.duplex.option.some( |
| o => o.type != print_preview_new.DuplexType.LONG_EDGE)) { |
| // If the only option available is long edge, the value should always be |
| // true. |
| this.set('settings.duplex.unavailableValue', true); |
| } else { // If no duplex capability is reported, assume false. |
| this.set('settings.duplex.unavailableValue', false); |
| } |
| |
| if (this.settings.vendorItems.available) { |
| const vendorSettings = {}; |
| for (const item of caps.vendor_capability) { |
| let defaultValue = null; |
| if (item.type == 'SELECT' && !!item.select_cap && |
| !!item.select_cap.option) { |
| const defaultOption = |
| item.select_cap.option.find(o => !!o.is_default); |
| defaultValue = !!defaultOption ? defaultOption.value : null; |
| } else if (item.type == 'RANGE') { |
| if (!!item.range_cap) { |
| defaultValue = item.range_cap.default || null; |
| } |
| } else if (item.type == 'TYPED_VALUE') { |
| if (!!item.typed_value_cap) { |
| defaultValue = item.typed_value_cap.default || null; |
| } |
| } |
| if (defaultValue != null) { |
| vendorSettings[item.id] = defaultValue; |
| } |
| } |
| this.setSetting('vendorItems', vendorSettings); |
| } |
| }, |
| |
| /** @private */ |
| updateRecentDestinations_: function() { |
| if (!this.initialized_ || !this.destination) { |
| return; |
| } |
| |
| // Determine if this destination is already in the recent destinations, |
| // and where in the array it is located. |
| const newDestination = |
| print_preview.makeRecentDestination(assert(this.destination)); |
| let indexFound = this.recentDestinations.findIndex(function(recent) { |
| return ( |
| newDestination.id == recent.id && |
| newDestination.origin == recent.origin); |
| }); |
| |
| // No change |
| if (indexFound == 0 && |
| this.recentDestinations[0].capabilities == |
| newDestination.capabilities) { |
| return; |
| } |
| |
| // Shift the array so that the nth most recent destination is located at |
| // index n. |
| if (indexFound == -1 && |
| this.recentDestinations.length == NUM_DESTINATIONS) { |
| indexFound = NUM_DESTINATIONS - 1; |
| } |
| if (indexFound != -1) { |
| this.recentDestinations.splice(indexFound, 1); |
| } |
| |
| // Add the most recent destination |
| this.splice('recentDestinations', 0, 0, newDestination); |
| |
| // Persist sticky settings. |
| this.stickySettingsChanged_(); |
| }, |
| |
| /** |
| * Caches the sticky settings and sets up the recent destinations. Sticky |
| * settings will be applied when destinaton capabilities have been retrieved. |
| * @param {?string} savedSettingsStr The sticky settings from native layer |
| */ |
| setStickySettings: function(savedSettingsStr) { |
| assert(!this.stickySettings_ && this.recentDestinations.length == 0); |
| |
| if (!savedSettingsStr) { |
| return; |
| } |
| |
| let savedSettings; |
| try { |
| savedSettings = /** @type {print_preview_new.SerializedSettings} */ ( |
| JSON.parse(savedSettingsStr)); |
| } catch (e) { |
| console.error('Unable to parse state ' + e); |
| return; // use default values rather than updating. |
| } |
| if (savedSettings.version != 2) { |
| return; |
| } |
| |
| let recentDestinations = savedSettings.recentDestinations || []; |
| if (!Array.isArray(recentDestinations)) { |
| recentDestinations = [recentDestinations]; |
| } |
| this.recentDestinations = recentDestinations; |
| |
| this.stickySettings_ = savedSettings; |
| }, |
| |
| /** |
| * Sets settings in accordance to policies from native code, and prevents |
| * those settings from being changed via other means. |
| * @param {boolean|undefined} headerFooter Value of |
| * printing.print_header_footer, if set in prefs (or undefined, if not). |
| * @param {boolean} isHeaderFooterManaged true if the header/footer UI state |
| * is managed by a policy. |
| */ |
| setPolicySettings: function(headerFooter, isHeaderFooterManaged) { |
| this.policySettings_ = { |
| headerFooter: { |
| value: headerFooter, |
| managed: isHeaderFooterManaged, |
| }, |
| }; |
| }, |
| |
| applyStickySettings: function() { |
| if (this.stickySettings_) { |
| STICKY_SETTING_NAMES.forEach(settingName => { |
| const setting = this.get(settingName, this.settings); |
| const value = this.stickySettings_[setting.key]; |
| if (value != undefined) { |
| this.setSetting(settingName, value); |
| } |
| }); |
| } |
| if (this.policySettings_) { |
| for (const [settingName, policy] of Object.entries( |
| this.policySettings_)) { |
| if (policy.value !== undefined) { |
| this.setSetting(settingName, policy.value); |
| } |
| if (policy.managed) { |
| this.set(`settings.${settingName}.setByPolicy`, true); |
| } |
| } |
| } |
| this.initialized_ = true; |
| this.stickySettings_ = null; |
| this.updateRecentDestinations_(); |
| this.stickySettingsChanged_(); |
| }, |
| |
| /** |
| * Restricts settings and applies defaults as defined by policy applicable to |
| * current destination. |
| */ |
| applyDestinationSpecificPolicies: function() { |
| const colorPolicy = this.destination.colorPolicy; |
| const colorValue = |
| colorPolicy ? colorPolicy : this.destination.defaultColorPolicy; |
| if (colorValue) { |
| // |this.setSetting| does nothing if policy is present. |
| // We want to set the value nevertheless so we call |this.set| directly. |
| this.set( |
| 'settings.color.value', colorValue == print_preview.ColorMode.COLOR); |
| } |
| this.set('settings.color.setByPolicy', !!colorPolicy); |
| |
| const duplexPolicy = this.destination.duplexPolicy; |
| const duplexValue = |
| duplexPolicy ? duplexPolicy : this.destination.defaultDuplexPolicy; |
| if (duplexValue) { |
| this.set( |
| 'settings.duplex.value', |
| duplexValue != print_preview.DuplexModeRestriction.SIMPLEX); |
| } |
| this.set('settings.duplex.setByPolicy', !!duplexPolicy); |
| }, |
| |
| /** @return {boolean} Whether the model has been initialized. */ |
| initialized: function() { |
| return this.initialized_; |
| }, |
| |
| /** @private */ |
| stickySettingsChanged_: function() { |
| if (!this.initialized_) { |
| return; |
| } |
| |
| const serialization = { |
| version: 2, |
| recentDestinations: this.recentDestinations, |
| }; |
| |
| STICKY_SETTING_NAMES.forEach(settingName => { |
| const setting = this.get(settingName, this.settings); |
| serialization[assert(setting.key)] = setting.value; |
| }); |
| this.fire('save-sticky-settings', JSON.stringify(serialization)); |
| }, |
| |
| /** |
| * Creates a string that represents a print ticket. |
| * @param {!print_preview.Destination} destination Destination to print to. |
| * @param {boolean} openPdfInPreview Whether this print request is to open |
| * the PDF in Preview app (Mac only). |
| * @param {boolean} showSystemDialog Whether this print request is to show |
| * the system dialog. |
| * @return {string} Serialized print ticket. |
| */ |
| createPrintTicket: function(destination, openPdfInPreview, showSystemDialog) { |
| const dpi = /** @type {{horizontal_dpi: (number | undefined), |
| vertical_dpi: (number | undefined), |
| vendor_id: (number | undefined)}} */ ( |
| this.getSettingValue('dpi')); |
| |
| const ticket = { |
| mediaSize: this.getSettingValue('mediaSize'), |
| pageCount: this.getSettingValue('pages').length, |
| landscape: this.getSettingValue('layout'), |
| color: destination.getNativeColorModel( |
| /** @type {boolean} */ (this.getSettingValue('color'))), |
| headerFooterEnabled: false, // only used in print preview |
| marginsType: this.getSettingValue('margins'), |
| duplex: this.getSettingValue('duplex') ? |
| print_preview_new.DuplexMode.LONG_EDGE : |
| print_preview_new.DuplexMode.SIMPLEX, |
| copies: parseInt(this.getSettingValue('copies'), 10), |
| collate: this.getSettingValue('collate'), |
| shouldPrintBackgrounds: this.getSettingValue('cssBackground'), |
| shouldPrintSelectionOnly: false, // only used in print preview |
| previewModifiable: this.documentSettings.isModifiable, |
| printToPDF: destination.id == |
| print_preview.Destination.GooglePromotedId.SAVE_AS_PDF, |
| printToGoogleDrive: |
| destination.id == print_preview.Destination.GooglePromotedId.DOCS, |
| printWithCloudPrint: !destination.isLocal, |
| printWithPrivet: destination.isPrivet, |
| printWithExtension: destination.isExtension, |
| rasterizePDF: this.getSettingValue('rasterize'), |
| scaleFactor: parseInt(this.getSettingValue('scaling'), 10), |
| pagesPerSheet: this.getSettingValue('pagesPerSheet'), |
| dpiHorizontal: (dpi && 'horizontal_dpi' in dpi) ? dpi.horizontal_dpi : 0, |
| dpiVertical: (dpi && 'vertical_dpi' in dpi) ? dpi.vertical_dpi : 0, |
| dpiDefault: (dpi && 'is_default' in dpi) ? dpi.is_default : false, |
| deviceName: destination.id, |
| fitToPageEnabled: this.getSettingValue('fitToPage'), |
| pageWidth: this.pageSize.width, |
| pageHeight: this.pageSize.height, |
| showSystemDialog: showSystemDialog, |
| }; |
| |
| // Set 'cloudPrintID' only if the destination is not local. |
| if (!destination.isLocal) { |
| ticket.cloudPrintID = destination.id; |
| } |
| |
| if (this.getSettingValue('margins') == |
| print_preview.ticket_items.MarginsTypeValue.CUSTOM) { |
| ticket.marginsCustom = this.getSettingValue('customMargins'); |
| } |
| |
| if (destination.isPrivet || destination.isExtension) { |
| // TODO(rbpotter): Get local and PDF printers to use the same ticket and |
| // send only this ticket instead of nesting it in a larger ticket. |
| ticket.ticket = this.createCloudJobTicket(destination); |
| ticket.capabilities = JSON.stringify(destination.capabilities); |
| } |
| |
| if (openPdfInPreview) { |
| ticket.OpenPDFInPreview = true; |
| } |
| |
| return JSON.stringify(ticket); |
| }, |
| |
| /** |
| * Creates an object that represents a Google Cloud Print print ticket. |
| * @param {!print_preview.Destination} destination Destination to print to. |
| * @return {string} Google Cloud Print print ticket. |
| */ |
| createCloudJobTicket: function(destination) { |
| assert( |
| !destination.isLocal || destination.isPrivet || destination.isExtension, |
| 'Trying to create a Google Cloud Print print ticket for a local ' + |
| ' non-privet and non-extension destination'); |
| assert( |
| destination.capabilities, |
| 'Trying to create a Google Cloud Print print ticket for a ' + |
| 'destination with no print capabilities'); |
| |
| // Create CJT (Cloud Job Ticket) |
| const cjt = {version: '1.0', print: {}}; |
| if (this.settings.collate.available) { |
| cjt.print.collate = {collate: this.settings.collate.value}; |
| } |
| if (this.settings.color.available) { |
| const selectedOption = destination.getSelectedColorOption( |
| /** @type {boolean} */ (this.settings.color.value)); |
| if (!selectedOption) { |
| console.error('Could not find correct color option'); |
| } else { |
| cjt.print.color = {type: selectedOption.type}; |
| if (selectedOption.hasOwnProperty('vendor_id')) { |
| cjt.print.color.vendor_id = selectedOption.vendor_id; |
| } |
| } |
| } else { |
| // Always try setting the color in the print ticket, otherwise a |
| // reasonable reader of the ticket will have to do more work, or process |
| // the ticket sub-optimally, in order to safely handle the lack of a |
| // color ticket item. |
| const defaultOption = destination.defaultColorOption; |
| if (defaultOption) { |
| cjt.print.color = {type: defaultOption.type}; |
| if (defaultOption.hasOwnProperty('vendor_id')) { |
| cjt.print.color.vendor_id = defaultOption.vendor_id; |
| } |
| } |
| } |
| if (this.settings.copies.available) { |
| cjt.print.copies = {copies: parseInt(this.getSettingValue('copies'), 10)}; |
| } |
| if (this.settings.duplex.available) { |
| cjt.print.duplex = { |
| type: this.settings.duplex.value ? |
| print_preview_new.DuplexType.LONG_EDGE : |
| print_preview_new.DuplexType.NO_DUPLEX, |
| }; |
| } |
| if (this.settings.mediaSize.available) { |
| const mediaValue = this.settings.mediaSize.value; |
| cjt.print.media_size = { |
| width_microns: mediaValue.width_microns, |
| height_microns: mediaValue.height_microns, |
| is_continuous_feed: mediaValue.is_continuous_feed, |
| vendor_id: mediaValue.vendor_id |
| }; |
| } |
| if (!this.settings.layout.available) { |
| // In this case "orientation" option is hidden from user, so user can't |
| // adjust it for page content, see Landscape.isCapabilityAvailable(). |
| // We can improve results if we set AUTO here. |
| const capability = destination.capabilities.printer ? |
| destination.capabilities.printer.page_orientation : |
| null; |
| if (capability && capability.option && |
| capability.option.some(option => option.type == 'AUTO')) { |
| cjt.print.page_orientation = {type: 'AUTO'}; |
| } |
| } else { |
| cjt.print.page_orientation = { |
| type: this.settings.layout.value ? 'LANDSCAPE' : 'PORTRAIT' |
| }; |
| } |
| if (this.settings.dpi.available) { |
| const dpiValue = this.settings.dpi.value; |
| cjt.print.dpi = { |
| horizontal_dpi: dpiValue.horizontal_dpi, |
| vertical_dpi: dpiValue.vertical_dpi, |
| vendor_id: dpiValue.vendor_id |
| }; |
| } |
| if (this.settings.vendorItems.available) { |
| const items = this.settings.vendorItems.value; |
| cjt.print.vendor_ticket_item = []; |
| for (const itemId in items) { |
| if (items.hasOwnProperty(itemId)) { |
| cjt.print.vendor_ticket_item.push({id: itemId, value: items[itemId]}); |
| } |
| } |
| } |
| return JSON.stringify(cjt); |
| }, |
| }); |
| })(); |