254 lines
7.4 KiB
JavaScript
254 lines
7.4 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/. */
|
|
|
|
import { MozLitElement } from "chrome://global/content/lit-utils.mjs";
|
|
|
|
// eslint-disable-next-line import/no-unassigned-import
|
|
import "chrome://browser/content/firefoxview/card-container.mjs";
|
|
// eslint-disable-next-line import/no-unassigned-import
|
|
import "chrome://browser/content/firefoxview/fxview-empty-state.mjs";
|
|
// eslint-disable-next-line import/no-unassigned-import
|
|
import "chrome://browser/content/firefoxview/fxview-search-textbox.mjs";
|
|
// eslint-disable-next-line import/no-unassigned-import
|
|
import "chrome://browser/content/firefoxview/fxview-tab-list.mjs";
|
|
|
|
const lazy = {};
|
|
|
|
ChromeUtils.defineESModuleGetters(lazy, {
|
|
BrowserUtils: "resource://gre/modules/BrowserUtils.sys.mjs",
|
|
DeferredTask: "resource://gre/modules/DeferredTask.sys.mjs",
|
|
});
|
|
|
|
const WIN_RESIZE_DEBOUNCE_RATE_MS = 500;
|
|
const WIN_RESIZE_DEBOUNCE_TIMEOUT_MS = 1000;
|
|
|
|
/**
|
|
* A base class for content container views displayed on firefox-view.
|
|
*
|
|
* @property {boolean} recentBrowsing
|
|
* Is part of the recentbrowsing page view
|
|
* @property {boolean} paused
|
|
* No content will be updated and rendered while paused
|
|
*/
|
|
export class ViewPageContent extends MozLitElement {
|
|
static get properties() {
|
|
return {
|
|
recentBrowsing: { type: Boolean },
|
|
paused: { type: Boolean },
|
|
};
|
|
}
|
|
constructor() {
|
|
super();
|
|
// don't update or render until explicitly un-paused
|
|
this.paused = true;
|
|
}
|
|
|
|
get ownerViewPage() {
|
|
return this.closest("[type='page']") || this;
|
|
}
|
|
|
|
get isVisible() {
|
|
if (!this.isConnected || this.ownerDocument.visibilityState != "visible") {
|
|
return false;
|
|
}
|
|
return this.ownerViewPage.selectedTab;
|
|
}
|
|
|
|
/**
|
|
* Override this function to run a callback whenever this content is visible.
|
|
*/
|
|
viewVisibleCallback() {}
|
|
|
|
/**
|
|
* Override this function to run a callback whenever this content is hidden.
|
|
*/
|
|
viewHiddenCallback() {}
|
|
|
|
getWindow() {
|
|
return window.browsingContext.embedderWindowGlobal.browsingContext.window;
|
|
}
|
|
|
|
get isSelectedBrowserTab() {
|
|
const { gBrowser } = this.getWindow();
|
|
return gBrowser.selectedBrowser.browsingContext == window.browsingContext;
|
|
}
|
|
|
|
copyLink(e) {
|
|
lazy.BrowserUtils.copyLink(this.triggerNode.url, this.triggerNode.title);
|
|
this.recordContextMenuTelemetry("copy-link", e);
|
|
}
|
|
|
|
openInNewWindow(e) {
|
|
this.getWindow().openTrustedLinkIn(this.triggerNode.url, "window", {
|
|
private: false,
|
|
});
|
|
this.recordContextMenuTelemetry("open-in-new-window", e);
|
|
}
|
|
|
|
openInNewPrivateWindow(e) {
|
|
this.getWindow().openTrustedLinkIn(this.triggerNode.url, "window", {
|
|
private: true,
|
|
});
|
|
this.recordContextMenuTelemetry("open-in-private-window", e);
|
|
}
|
|
|
|
recordContextMenuTelemetry(menuAction, event) {
|
|
Glean.firefoxviewNext.contextMenuTabs.record({
|
|
menu_action: menuAction,
|
|
data_type: event.target.panel.dataset.tabType,
|
|
});
|
|
}
|
|
|
|
shouldUpdate(changedProperties) {
|
|
return !this.paused && super.shouldUpdate(changedProperties);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A "page" in firefox view, which may be hidden or shown by the named-deck container or
|
|
* via the owner document's visibility
|
|
*
|
|
* @property {boolean} selectedTab
|
|
* Is this page the selected view in the named-deck container
|
|
*/
|
|
export class ViewPage extends ViewPageContent {
|
|
static get properties() {
|
|
return {
|
|
selectedTab: { type: Boolean },
|
|
searchTextboxSize: { type: Number },
|
|
};
|
|
}
|
|
|
|
constructor() {
|
|
super();
|
|
this.selectedTab = false;
|
|
this.recentBrowsing = Boolean(this.recentBrowsingElement);
|
|
this.onTabSelect = this.onTabSelect.bind(this);
|
|
this.onResize = this.onResize.bind(this);
|
|
}
|
|
|
|
get recentBrowsingElement() {
|
|
return this.closest("VIEW-RECENTBROWSING");
|
|
}
|
|
|
|
onResize() {
|
|
this.windowResizeTask = new lazy.DeferredTask(
|
|
() => this.updateAllVirtualLists(),
|
|
WIN_RESIZE_DEBOUNCE_RATE_MS,
|
|
WIN_RESIZE_DEBOUNCE_TIMEOUT_MS
|
|
);
|
|
this.windowResizeTask?.arm();
|
|
}
|
|
|
|
onTabSelect({ target }) {
|
|
const win = target.ownerGlobal;
|
|
|
|
let selfBrowser = window.docShell?.chromeEventHandler;
|
|
const { gBrowser } = this.getWindow();
|
|
let isForegroundTab = gBrowser.selectedBrowser == selfBrowser;
|
|
|
|
if (win.FirefoxViewHandler.tab?.selected && isForegroundTab) {
|
|
this.paused = false;
|
|
this.viewVisibleCallback();
|
|
} else {
|
|
this.paused = true;
|
|
this.viewHiddenCallback();
|
|
}
|
|
}
|
|
|
|
connectedCallback() {
|
|
super.connectedCallback();
|
|
}
|
|
|
|
disconnectedCallback() {
|
|
super.disconnectedCallback();
|
|
this.getWindow().removeEventListener("resize", this.onResize);
|
|
this.getWindow().removeEventListener("TabSelect", this.onTabSelect);
|
|
}
|
|
|
|
updateAllVirtualLists() {
|
|
if (!this.paused) {
|
|
let tabLists = [];
|
|
if (this.recentBrowsing) {
|
|
let viewComponents = this.querySelectorAll("[slot]");
|
|
viewComponents.forEach(viewComponent => {
|
|
let currentTabLists = [];
|
|
if (viewComponent.nodeName.includes("OPENTABS")) {
|
|
viewComponent.viewCards.forEach(viewCard => {
|
|
currentTabLists.push(viewCard.tabList);
|
|
});
|
|
} else {
|
|
currentTabLists =
|
|
viewComponent.shadowRoot.querySelectorAll("fxview-tab-list");
|
|
}
|
|
tabLists.push(...currentTabLists);
|
|
});
|
|
} else {
|
|
tabLists = this.shadowRoot.querySelectorAll("fxview-tab-list");
|
|
}
|
|
tabLists.forEach(tabList => {
|
|
if (!tabList.updatesPaused && tabList.rootVirtualListEl?.isVisible) {
|
|
tabList.rootVirtualListEl.recalculateAfterWindowResize();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
toggleVisibilityInCardContainer(isOpenTabs) {
|
|
let cards = [];
|
|
let tabLists = [];
|
|
if (!isOpenTabs) {
|
|
cards = this.shadowRoot.querySelectorAll("card-container");
|
|
tabLists = this.shadowRoot.querySelectorAll(
|
|
"fxview-tab-list, syncedtabs-tab-list"
|
|
);
|
|
} else {
|
|
this.viewCards.forEach(viewCard => {
|
|
if (viewCard.cardEl) {
|
|
cards.push(viewCard.cardEl);
|
|
tabLists.push(viewCard.tabList);
|
|
}
|
|
});
|
|
}
|
|
if (tabLists.length && cards.length) {
|
|
cards.forEach(cardEl => {
|
|
if (cardEl.visible !== !this.paused) {
|
|
cardEl.visible = !this.paused;
|
|
} else if (
|
|
cardEl.isExpanded &&
|
|
Array.from(tabLists).some(
|
|
tabList => tabList.updatesPaused !== this.paused
|
|
)
|
|
) {
|
|
// If card is already visible and expanded but tab-list has updatesPaused,
|
|
// update the tab-list updatesPaused prop from here instead of card-container
|
|
tabLists.forEach(tabList => {
|
|
tabList.updatesPaused = this.paused;
|
|
});
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
enter() {
|
|
this.selectedTab = true;
|
|
if (this.isVisible) {
|
|
this.paused = false;
|
|
this.viewVisibleCallback();
|
|
this.getWindow().addEventListener("resize", this.onResize);
|
|
this.getWindow().addEventListener("TabSelect", this.onTabSelect);
|
|
}
|
|
}
|
|
|
|
exit() {
|
|
this.selectedTab = false;
|
|
this.paused = true;
|
|
this.viewHiddenCallback();
|
|
if (!this.windowResizeTask?.isFinalized) {
|
|
this.windowResizeTask?.finalize();
|
|
}
|
|
this.getWindow().removeEventListener("resize", this.onResize);
|
|
this.getWindow().removeEventListener("TabSelect", this.onTabSelect);
|
|
}
|
|
}
|