lUpdate();
}
}
// Move pinned tabs to the beginning of the list
if (this.pinnedTabsGridView) {
// Can set maxTabsLength to -1 to have no max
this.unpinnedTabs = this.tabItems.filter(
tab => !tab.indicators.includes("pinned")
);
this.pinnedTabs = this.tabItems.filter(tab =>
tab.indicators.includes("pinned")
);
if (this.maxTabsLength > 0) {
this.unpinnedTabs = this.unpinnedTabs.slice(0, this.maxTabsLength);
}
this.tabItems = [...this.pinnedTabs, ...this.unpinnedTabs];
} else if (this.maxTabsLength > 0) {
this.tabItems = this.tabItems.slice(0, this.maxTabsLength);
}
}
/**
* Focuses the expected element (either the link or button) within fxview-tab-row
* The currently focused/active element ID within a row is stored in this.currentActiveElementId
*/
handleFocusElementInRow(e) {
let fxviewTabRow = e.target;
if (e.code == "ArrowUp") {
// Focus either the link or button of the previous row based on this.currentActiveElementId
e.preventDefault();
if (
(this.pinnedTabsGridView &&
this.activeIndex >= this.pinnedTabs.length) ||
!this.pinnedTabsGridView
) {
this.focusPrevRow();
}
} else if (e.code == "ArrowDown") {
// Focus either the link or button of the next row based on this.currentActiveElementId
e.preventDefault();
if (
this.pinnedTabsGridView &&
this.activeIndex < this.pinnedTabs.length
) {
this.focusIndex(this.pinnedTabs.length);
} else {
this.focusNextRow();
}
} else if (e.code == "ArrowRight") {
// Focus either the link or the button in the current row and
// set this.currentActiveElementId to that element's ID
e.preventDefault();
if (document.dir == "rtl") {
fxviewTabRow.moveFocusLeft();
} else {
fxviewTabRow.moveFocusRight();
}
} else if (e.code == "ArrowLeft") {
// Focus either the link or the button in the current row and
// set this.currentActiveElementId to that element's ID
e.preventDefault();
if (document.dir == "rtl") {
fxviewTabRow.moveFocusRight();
} else {
fxviewTabRow.moveFocusLeft();
}
}
}
async focusIndex(index) {
// Focus link or button of item
if (
((this.pinnedTabsGridView && index > this.pinnedTabs.length) ||
!this.pinnedTabsGridView) &&
lazy.virtualListEnabledPref
) {
let row = this.rootVirtualListEl.getItem(index - this.pinnedTabs.length);
if (!row) {
return;
}
let subList = this.rootVirtualListEl.getSubListForItem(
index - this.pinnedTabs.length
);
if (!subList) {
return;
}
this.activeIndex = index;
// In Bug 1866845, these manual updates to the sublists should be removed
// and scrollIntoView() should also be iterated on so that we aren't constantly
// moving the focused item to the center of the viewport
for (const sublist of Array.from(this.rootVirtualListEl.children)) {
await sublist.requestUpdate();
await sublist.updateComplete;
}
row.scrollIntoView({ block: "center" });
row.focus();
} else if (index >= 0 && index < this.rowEls?.length) {
this.rowEls[index].focus();
this.activeIndex = index;
}
}
#getTabListWrapperClasses() {
let wrapperClasses = ["fxview-tab-list"];
let tabsToCheck = this.pinnedTabsGridView
? this.unpinnedTabs
: this.tabItems;
if (tabsToCheck.some(tab => tab.containerObj)) {
wrapperClasses.push(`hasContainerTab`);
}
return wrapperClasses;
}
itemTemplate = (tabItem, i) => {
let time;
if (tabItem.time || tabItem.closedAt) {
let stringTime = (tabItem.time || tabItem.closedAt).toString();
// Different APIs return time in different units, so we use
// the length to decide if it's milliseconds or nanoseconds.
if (stringTime.length === 16) {
time = (tabItem.time || tabItem.closedAt) / 1000;
} else {
time = tabItem.time || tabItem.closedAt;
}
}
return html``;
};
render() {
if (this.searchQuery && this.tabItems.length === 0) {
return this.emptySearchResultsTemplate();
}
return html`
${this.stylesheets()}
${when(
this.pinnedTabsGridView && this.pinnedTabs.length,
() => html`