Files
tubestation/browser/components/firefoxview/tab-pickup-list.mjs

198 lines
5.3 KiB
JavaScript

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
XPCOMUtils.defineLazyModuleGetters(globalThis, {
SyncedTabs: "resource://services-sync/SyncedTabs.jsm",
Services: "resource://gre/modules/Services.jsm",
});
import {
formatURIForDisplay,
convertTimestamp,
createFaviconElement,
} from "./helpers.mjs";
const SYNCED_TABS_CHANGED = "services.sync.tabs.changed";
class TabPickupList extends HTMLElement {
constructor() {
super();
this.maxTabsLength = 3;
this.boundObserve = (...args) => this.getSyncedTabData(...args);
}
get tabsList() {
return this.querySelector("ol");
}
get fluentStrings() {
if (!this._fluentStrings) {
this._fluentStrings = new Localization(["preview/firefoxView.ftl"], true);
}
return this._fluentStrings;
}
connectedCallback() {
this.addEventListener("click", this);
this.getSyncedTabData();
Services.obs.addObserver(this.boundObserve, SYNCED_TABS_CHANGED);
}
handleEvent(event) {
if (
event.type == "click" ||
(event.type == "keydown" && event.keyCode == KeyEvent.DOM_VK_RETURN)
) {
this.openTab(event);
}
}
cleanup() {
Services.obs.removeObserver(this.boundObserve, SYNCED_TABS_CHANGED);
}
openTab(event) {
event.preventDefault();
const item = event.target.closest(".synced-tab-li");
window.open(item.dataset.targetURI, "_blank");
}
async getSyncedTabData() {
let tabs = [];
let clients = await SyncedTabs.getTabClients();
for (let client of clients) {
for (let tab of client.tabs) {
tab.device = client.name;
tab.deviceType = client.clientType;
}
tabs = [...tabs, ...client.tabs.reverse()];
}
tabs = tabs
.sort((a, b) => b.lastUsed - a.lastUsed)
.slice(0, this.maxTabsLength);
this.updateTabsList(tabs);
}
updateTabsList(syncedTabs) {
while (this.tabsList.firstChild) {
this.tabsList.firstChild.remove();
}
if (!syncedTabs.length) {
// TODO show empty state placeholder, see bug 1774168
this.tabsList.hidden = true;
return;
}
for (let i = 0; i < this.maxTabsLength; i++) {
let li = null;
if (!syncedTabs[i]) {
li = this.generatePlaceholder();
} else {
li = this.generateListItem(syncedTabs[i], i);
}
this.tabsList.append(li);
}
if (this.tabsList.hidden) {
this.tabsList.hidden = false;
}
}
generatePlaceholder() {
const li = document.createElement("li");
li.classList.add("synced-tab-li-placeholder");
li.setAttribute("role", "presentation");
const favicon = document.createElement("span");
favicon.classList.add("li-placeholder-favicon");
const title = document.createElement("span");
title.classList.add("li-placeholder-title");
const domain = document.createElement("span");
domain.classList.add("li-placeholder-domain");
li.append(favicon, title, domain);
return li;
}
generateListItem(tab, index) {
const li = document.createElement("li");
li.classList.add("synced-tab-li");
li.setAttribute("tabindex", 0);
li.setAttribute("role", "button");
const title = document.createElement("span");
title.textContent = tab.title;
title.classList.add("synced-tab-li-title");
const favicon = createFaviconElement(tab.icon);
const targetURI = tab.url;
li.dataset.targetURI = targetURI;
document.l10n.setAttributes(li, "firefoxview-tabs-list-tab-button", {
targetURI,
});
const time = document.createElement("span");
time.textContent = convertTimestamp(
tab.lastUsed * 1000,
this.fluentStrings
);
time.classList.add("synced-tab-li-time");
const url = document.createElement("span");
const device = document.createElement("span");
const deviceIcon = document.createElement("div");
deviceIcon.classList.add("icon", tab.deviceType);
deviceIcon.setAttribute("role", "presentation");
const deviceText = tab.device;
device.textContent = deviceText;
device.prepend(deviceIcon);
device.title = deviceText;
url.textContent = formatURIForDisplay(tab.url);
url.classList.add("synced-tab-li-url");
device.classList.add("synced-tab-li-device");
// the first list item is diffent from second and third
if (index == 0) {
const badge = this.createBadge();
li.append(favicon, badge, title, url, device, time);
} else {
const urlWithDevice = document.createElement("span");
urlWithDevice.append(url, " • ", device);
urlWithDevice.classList.add("synced-tab-li-url-device");
li.append(favicon, title, urlWithDevice, time);
}
return li;
}
createBadge() {
const badge = document.createElement("div");
const dot = document.createElement("span");
const badgeText = document.createElement("span");
badgeText.setAttribute("data-l10n-id", "firefoxview-pickup-tabs-badge");
badgeText.classList.add("badge-text");
badge.classList.add("last-active-badge");
dot.classList.add("dot");
badge.append(dot, badgeText);
return badge;
}
}
customElements.define("tab-pickup-list", TabPickupList);