blob: cce2dc11bdee73061e1d141a290aa89a05716ba8 [file] [log] [blame]
// Copyright 2020 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.
import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js';
import 'chrome://resources/cr_elements/cr_icons_css.m.js';
import 'chrome://resources/cr_elements/icons.m.js';
import 'chrome://resources/cr_elements/mwb_element_shared_style.css.js';
import 'chrome://resources/cr_elements/mwb_shared_vars.css.js';
import 'chrome://resources/cr_elements/shared_vars_css.m.js';
import './icons.html.js';
import {MouseHoverableMixin} from 'chrome://resources/cr_elements/mouse_hoverable_mixin.js';
import {assertNotReached} from 'chrome://resources/js/assert_ts.js';
import {getFaviconForPageURL} from 'chrome://resources/js/icon.js';
import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {ReadLaterEntry} from './reading_list.mojom-webui.js';
import {ReadingListApiProxy, ReadingListApiProxyImpl} from './reading_list_api_proxy.js';
import {getTemplate} from './reading_list_item.html.js';
const navigationKeys: Set<string> =
new Set([' ', 'Enter', 'ArrowRight', 'ArrowLeft']);
export interface ReadingListItemElement {
$: {
updateStatusButton: HTMLElement,
deleteButton: HTMLElement,
};
}
const ReadingListItemElementBase = MouseHoverableMixin(PolymerElement);
export class ReadingListItemElement extends ReadingListItemElementBase {
static get is() {
return 'reading-list-item';
}
static get template() {
return getTemplate();
}
static get properties() {
return {
data: Object,
buttonRipples: Boolean,
title: {
computed: 'computeTitle_(data.title)',
reflectToAttribute: true,
},
};
}
data: ReadLaterEntry;
buttonRipples: boolean;
private apiProxy_: ReadingListApiProxy =
ReadingListApiProxyImpl.getInstance();
override ready() {
super.ready();
this.addEventListener('click', this.onClick_);
this.addEventListener('auxclick', this.onAuxClick_.bind(this));
this.addEventListener('contextmenu', this.onContextMenu_.bind(this));
this.addEventListener('keydown', this.onKeyDown_.bind(this));
}
private computeTitle_(): string {
return this.data.title;
}
private onAuxClick_(e: MouseEvent) {
if (e.button !== 1) {
// Not a middle click.
return;
}
this.apiProxy_.openURL(this.data.url, true, {
middleButton: true,
altKey: e.altKey,
ctrlKey: e.ctrlKey,
metaKey: e.metaKey,
shiftKey: e.shiftKey,
});
}
private onClick_(e: MouseEvent|KeyboardEvent) {
this.apiProxy_.openURL(this.data.url, true, {
middleButton: false,
altKey: e.altKey,
ctrlKey: e.ctrlKey,
metaKey: e.metaKey,
shiftKey: e.shiftKey,
});
}
private onContextMenu_(e: MouseEvent) {
this.apiProxy_.showContextMenuForURL(this.data.url, e.clientX, e.clientY);
}
private onKeyDown_(e: KeyboardEvent) {
if (e.shiftKey || !navigationKeys.has(e.key)) {
return;
}
switch (e.key) {
case ' ':
case 'Enter':
this.onClick_(e);
break;
case 'ArrowRight':
if (!this.shadowRoot!.activeElement) {
this.$.updateStatusButton.focus();
} else if (this.shadowRoot!.activeElement.nextElementSibling) {
(this.shadowRoot!.activeElement.nextElementSibling as HTMLElement)
.focus();
} else {
this.focus();
}
break;
case 'ArrowLeft':
if (!this.shadowRoot!.activeElement) {
this.$.deleteButton.focus();
} else if (this.shadowRoot!.activeElement.nextElementSibling) {
} else if (this.shadowRoot!.activeElement.previousElementSibling) {
(this.shadowRoot!.activeElement.previousElementSibling as HTMLElement)
.focus();
} else {
this.focus();
}
break;
default:
assertNotReached();
}
e.preventDefault();
e.stopPropagation();
}
private onUpdateStatusClick_(e: Event) {
e.stopPropagation();
this.apiProxy_.updateReadStatus(this.data.url, !this.data.read);
}
private onItemDeleteClick_(e: Event) {
e.stopPropagation();
this.apiProxy_.removeEntry(this.data.url);
}
private getFaviconUrl_(url: string): string {
return getFaviconForPageURL(url, false);
}
/**
* @return The appropriate icon for the current state
*/
private getUpdateStatusButtonIcon_(
markAsUnreadIcon: string, markAsReadIcon: string): string {
return this.data.read ? markAsUnreadIcon : markAsReadIcon;
}
/**
* @return The appropriate tooltip for the current state
*/
private getUpdateStatusButtonTooltip_(
markAsUnreadTooltip: string, markAsReadTooltip: string): string {
return this.data.read ? markAsUnreadTooltip : markAsReadTooltip;
}
}
declare global {
interface HTMLElementTagNameMap {
'reading-list-item': ReadingListItemElement;
}
}
customElements.define(ReadingListItemElement.is, ReadingListItemElement);