summaryrefslogtreecommitdiffstats
path: root/browser/components/tabpreview/tab-preview-panel.mjs
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/tabpreview/tab-preview-panel.mjs')
-rw-r--r--browser/components/tabpreview/tab-preview-panel.mjs174
1 files changed, 174 insertions, 0 deletions
diff --git a/browser/components/tabpreview/tab-preview-panel.mjs b/browser/components/tabpreview/tab-preview-panel.mjs
new file mode 100644
index 0000000000..683b2c17ec
--- /dev/null
+++ b/browser/components/tabpreview/tab-preview-panel.mjs
@@ -0,0 +1,174 @@
+/* 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/. */
+
+var { XPCOMUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/XPCOMUtils.sys.mjs"
+);
+
+const POPUP_OPTIONS = {
+ position: "bottomleft topleft",
+ x: 0,
+ y: -2,
+};
+
+/**
+ * Detailed preview card that displays when hovering a tab
+ */
+export default class TabPreviewPanel {
+ constructor(panel) {
+ this._panel = panel;
+ this._win = panel.ownerGlobal;
+ this._tab = null;
+ this._thumbnailElement = null;
+ XPCOMUtils.defineLazyPreferenceGetter(
+ this,
+ "_prefDisableAutohide",
+ "ui.popup.disable_autohide",
+ false
+ );
+ XPCOMUtils.defineLazyPreferenceGetter(
+ this,
+ "_prefPreviewDelay",
+ "ui.tooltip.delay_ms"
+ );
+ XPCOMUtils.defineLazyPreferenceGetter(
+ this,
+ "_prefDisplayThumbnail",
+ "browser.tabs.cardPreview.showThumbnails",
+ false
+ );
+ this._timer = null;
+ }
+
+ getPrettyURI(uri) {
+ try {
+ const url = new URL(uri);
+ return `${url.hostname}`.replace(/^w{3}\./, "");
+ } catch {
+ return uri;
+ }
+ }
+
+ _needsThumbnailFor(tab) {
+ return !tab.selected;
+ }
+
+ _maybeRequestThumbnail() {
+ if (!this._prefDisplayThumbnail) {
+ return;
+ }
+ if (!this._needsThumbnailFor(this._tab)) {
+ return;
+ }
+ let tab = this._tab;
+ this._win.tabPreviews.get(tab).then(el => {
+ if (this._tab == tab && this._needsThumbnailFor(tab)) {
+ this._thumbnailElement = el;
+ this._updatePreview();
+ }
+ });
+ }
+
+ activate(tab) {
+ this._tab = tab;
+ this._thumbnailElement = null;
+ this._maybeRequestThumbnail();
+ if (this._panel.state == "open") {
+ this._updatePreview();
+ }
+ if (this._timer) {
+ return;
+ }
+ this._timer = this._win.setTimeout(() => {
+ this._timer = null;
+ this._panel.openPopup(this._tab, POPUP_OPTIONS);
+ }, this._prefPreviewDelay);
+ this._win.addEventListener("TabSelect", this);
+ this._panel.addEventListener("popupshowing", this);
+ }
+
+ deactivate(leavingTab = null) {
+ if (leavingTab) {
+ if (this._tab != leavingTab) {
+ return;
+ }
+ this._win.requestAnimationFrame(() => {
+ if (this._tab == leavingTab) {
+ this.deactivate();
+ }
+ });
+ return;
+ }
+ this._tab = null;
+ this._thumbnailElement = null;
+ this._panel.removeEventListener("popupshowing", this);
+ this._win.removeEventListener("TabSelect", this);
+ if (!this._prefDisableAutohide) {
+ this._panel.hidePopup();
+ }
+ if (this._timer) {
+ this._win.clearTimeout(this._timer);
+ this._timer = null;
+ }
+ }
+
+ handleEvent(e) {
+ switch (e.type) {
+ case "popupshowing":
+ this._updatePreview();
+ break;
+ case "TabSelect":
+ if (this._thumbnailElement && !this._needsThumbnailFor(this._tab)) {
+ this._thumbnailElement.remove();
+ this._thumbnailElement = null;
+ }
+ break;
+ }
+ }
+
+ _updatePreview() {
+ this._panel.querySelector(".tab-preview-title").textContent =
+ this._displayTitle;
+ this._panel.querySelector(".tab-preview-uri").textContent =
+ this._displayURI;
+ let thumbnailContainer = this._panel.querySelector(
+ ".tab-preview-thumbnail-container"
+ );
+ if (thumbnailContainer.firstChild != this._thumbnailElement) {
+ thumbnailContainer.replaceChildren();
+ if (this._thumbnailElement) {
+ thumbnailContainer.appendChild(this._thumbnailElement);
+ }
+ this._panel.dispatchEvent(
+ new CustomEvent("previewThumbnailUpdated", {
+ detail: {
+ thumbnail: this._thumbnailElement,
+ },
+ })
+ );
+ }
+ if (this._tab && this._panel.state == "open") {
+ this._panel.moveToAnchor(
+ this._tab,
+ POPUP_OPTIONS.position,
+ POPUP_OPTIONS.x,
+ POPUP_OPTIONS.y
+ );
+ }
+ }
+
+ get _displayTitle() {
+ if (!this._tab) {
+ return "";
+ }
+ return this._tab.textLabel.textContent;
+ }
+
+ get _displayURI() {
+ if (!this._tab) {
+ return "";
+ }
+ return this.getPrettyURI(this._tab.linkedBrowser.currentURI.spec);
+ }
+}