blob: bd7e21396a26b8c15d0daa1d29d4a21263a590ca [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'chrome://resources/cr_elements/cr_hidden_style.css.js';
import 'chrome://resources/cr_elements/cr_shared_vars.css.js';
import 'chrome://resources/js/util_ts.js';
import 'chrome://resources/polymer/v3_0/iron-iconset-svg/iron-iconset-svg.js';
import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
import 'chrome://resources/polymer/v3_0/iron-media-query/iron-media-query.js';
import './destination_dropdown_cros.js';
import './destination_select_style.css.js';
import './icons.html.js';
import './print_preview_shared.css.js';
import './throbber.css.js';
import '../strings.m.js';
import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {Destination, DestinationOrigin, GooglePromotedDestinationId, PDF_DESTINATION_KEY} from '../data/destination.js';
import {ERROR_STRING_KEY_MAP, getPrinterStatusIcon, PrinterStatusReason} from '../data/printer_status_cros.js';
import {PrintPreviewDestinationDropdownCrosElement} from './destination_dropdown_cros.js';
import {getTemplate} from './destination_select_cros.html.js';
import {SelectMixin} from './select_mixin.js';
import {PrintPreviewSettingsSectionElement} from './settings_section.js';
export interface PrintPreviewDestinationSelectCrosElement {
$: {
destinationEulaWrapper: PrintPreviewSettingsSectionElement,
dropdown: PrintPreviewDestinationDropdownCrosElement,
};
}
const PrintPreviewDestinationSelectCrosElementBase =
I18nMixin(SelectMixin(PolymerElement));
export class PrintPreviewDestinationSelectCrosElement extends
PrintPreviewDestinationSelectCrosElementBase {
static get is() {
return 'print-preview-destination-select-cros';
}
static get template() {
return getTemplate();
}
static get properties() {
return {
activeUser: String,
dark: Boolean,
destination: Object,
disabled: Boolean,
driveDestinationKey: String,
loaded: Boolean,
noDestinations: Boolean,
pdfPrinterDisabled: Boolean,
recentDestinationList: {
type: Array,
observer: 'onRecentDestinationListChanged_',
},
pdfDestinationKey_: {
type: String,
value: PDF_DESTINATION_KEY,
},
statusText_: {
type: String,
computed:
'computeStatusText_(destination, destination.printerStatusReason)',
},
destinationIcon_: {
type: String,
computed: 'computeDestinationIcon_(' +
'selectedValue, destination, destination.printerStatusReason,' +
'isDarkModeActive_)',
},
isCurrentDestinationCrosLocal_: {
type: Boolean,
computed: 'computeIsCurrentDestinationCrosLocal_(destination)',
reflectToAttribute: true,
},
// Holds status of iron-media-query (prefers-color-scheme: dark).
isDarkModeActive_: Boolean,
};
}
destination: Destination;
disabled: boolean;
loaded: boolean;
pdfPrinterDisabled: boolean;
recentDestinationList: Destination[];
private pdfDestinationKey_: string;
private statusText_: TrustedHTML;
private destinationIcon_: string;
private isCurrentDestinationCrosLocal_: boolean;
private isDarkModeActive_: boolean;
override focus() {
this.shadowRoot!.querySelector(
'print-preview-destination-dropdown-cros')!.focus();
}
/** Sets the select to the current value of |destination|. */
updateDestination() {
this.selectedValue = this.destination.key;
}
/**
* Returns the iconset and icon for the selected printer. If printer details
* have not yet been retrieved from the backend, attempts to return an
* appropriate icon early based on the printer's sticky information.
* @return The iconset and icon for the current selection.
*/
private computeDestinationIcon_(): string {
if (!this.selectedValue) {
return '';
}
// If the destination matches the selected value, pull the icon from the
// destination.
if (this.destination && this.destination.key === this.selectedValue) {
if (this.isCurrentDestinationCrosLocal_) {
return getPrinterStatusIcon(
this.destination.printerStatusReason,
this.destination.isEnterprisePrinter, this.isDarkModeActive_);
}
return this.destination.icon;
}
// Check for the Docs or Save as PDF ids first.
const keyParams = this.selectedValue.split('/');
if (keyParams[0] === GooglePromotedDestinationId.SAVE_TO_DRIVE_CROS) {
return 'print-preview:save-to-drive';
}
if (keyParams[0] === GooglePromotedDestinationId.SAVE_AS_PDF) {
return 'cr:insert-drive-file';
}
// Otherwise, must be in the recent list.
const recent = this.recentDestinationList.find(d => {
return d.key === this.selectedValue;
});
if (recent && recent.icon) {
return recent.icon;
}
// The key/recent destinations don't have information about what icon to
// use, so just return the generic print icon for now. It will be updated
// when the destination is set.
return 'print-preview:print';
}
private hideDestinationAdditionalInfo_(): boolean {
return this.statusText_ === window.trustedTypes!.emptyHTML;
}
private fireSelectedOptionChange_(value: string) {
this.dispatchEvent(new CustomEvent(
'selected-option-change',
{bubbles: true, composed: true, detail: value}));
}
override onProcessSelectChange(value: string) {
this.fireSelectedOptionChange_(value);
}
private onDropdownValueSelected_(e: CustomEvent<HTMLButtonElement>) {
const selectedItem = e.detail;
if (!selectedItem || selectedItem.value === this.destination.key) {
return;
}
this.fireSelectedOptionChange_(selectedItem.value);
}
/**
* Send a printer status request for any new destination in the dropdown.
*/
private onRecentDestinationListChanged_() {
for (const destination of this.recentDestinationList) {
if (!destination || destination.origin !== DestinationOrigin.CROS) {
continue;
}
destination.requestPrinterStatus().then(
destinationKey => this.onPrinterStatusReceived_(destinationKey));
}
}
/**
* Check if the printer is currently in the dropdown then update its status
* icon if it's present.
*/
private onPrinterStatusReceived_(destinationKey: string) {
const indexFound = this.recentDestinationList.findIndex(destination => {
return destination.key === destinationKey;
});
if (indexFound === -1) {
return;
}
// Use notifyPath to trigger the matching printer located in the dropdown to
// recalculate its status icon.
this.notifyPath(`recentDestinationList.${indexFound}.printerStatusReason`);
// If |destinationKey| matches the currently selected printer, use
// notifyPath to trigger the destination to recalculate its status icon and
// error status text.
if (this.destination && this.destination.key === destinationKey) {
this.notifyPath(`destination.printerStatusReason`);
}
}
/**
* @return An error status for the current destination. If no error
* status exists, an empty string.
*/
private computeStatusText_(): TrustedHTML {
// |destination| can be either undefined, or null here.
if (!this.destination) {
return window.trustedTypes!.emptyHTML;
}
// Non-local printers do not show an error status.
if (this.destination.origin !== DestinationOrigin.CROS) {
return window.trustedTypes!.emptyHTML;
}
const printerStatusReason = this.destination.printerStatusReason;
if (printerStatusReason === null ||
printerStatusReason === PrinterStatusReason.NO_ERROR ||
printerStatusReason === PrinterStatusReason.UNKNOWN_REASON) {
return window.trustedTypes!.emptyHTML;
}
return this.getErrorString_(printerStatusReason);
}
private getErrorString_(printerStatusReason: PrinterStatusReason):
TrustedHTML {
const errorStringKey = ERROR_STRING_KEY_MAP.get(printerStatusReason);
return errorStringKey ? this.i18nAdvanced(errorStringKey) :
window.trustedTypes!.emptyHTML;
}
/**
* True when the currently selected destination is a CrOS local printer.
*/
private computeIsCurrentDestinationCrosLocal_(): boolean {
return this.destination &&
this.destination.origin === DestinationOrigin.CROS;
}
/**
* Return the options currently visible to the user for testing purposes.
*/
getVisibleItemsForTest(): NodeListOf<HTMLButtonElement> {
return this.shadowRoot!.querySelector('#dropdown')!.shadowRoot!
.querySelectorAll<HTMLButtonElement>('.list-item:not([hidden])');
}
}
declare global {
interface HTMLElementTagNameMap {
'print-preview-destination-select-cros':
PrintPreviewDestinationSelectCrosElement;
}
}
customElements.define(
PrintPreviewDestinationSelectCrosElement.is,
PrintPreviewDestinationSelectCrosElement);