summaryrefslogtreecommitdiffstats
path: root/browser/components/tabpreview
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-15 03:35:49 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-15 03:35:49 +0000
commitd8bbc7858622b6d9c278469aab701ca0b609cddf (patch)
treeeff41dc61d9f714852212739e6b3738b82a2af87 /browser/components/tabpreview
parentReleasing progress-linux version 125.0.3-1~progress7.99u1. (diff)
downloadfirefox-d8bbc7858622b6d9c278469aab701ca0b609cddf.tar.xz
firefox-d8bbc7858622b6d9c278469aab701ca0b609cddf.zip
Merging upstream version 126.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'browser/components/tabpreview')
-rw-r--r--browser/components/tabpreview/jar.mn2
-rw-r--r--browser/components/tabpreview/tab-preview-panel.mjs174
-rw-r--r--browser/components/tabpreview/tabpreview.css53
-rw-r--r--browser/components/tabpreview/tabpreview.mjs237
4 files changed, 194 insertions, 272 deletions
diff --git a/browser/components/tabpreview/jar.mn b/browser/components/tabpreview/jar.mn
index 8ff09ebb17..589bc71430 100644
--- a/browser/components/tabpreview/jar.mn
+++ b/browser/components/tabpreview/jar.mn
@@ -3,5 +3,5 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
browser.jar:
- content/browser/tabpreview/tabpreview.mjs (tabpreview.mjs)
+ content/browser/tabpreview/tab-preview-panel.mjs (tab-preview-panel.mjs)
content/browser/tabpreview/tabpreview.css (tabpreview.css)
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);
+ }
+}
diff --git a/browser/components/tabpreview/tabpreview.css b/browser/components/tabpreview/tabpreview.css
index 776f520c7d..e978266e5d 100644
--- a/browser/components/tabpreview/tabpreview.css
+++ b/browser/components/tabpreview/tabpreview.css
@@ -2,32 +2,21 @@
* 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/. */
-.tab-preview-container {
- --tab-preview-background-color: light-dark(#fff, #42414d);
- --tab-preview-text-color: light-dark(#15141a, #fbfbfe);
- --tab-preview-border-color: light-dark(#cfcfd8, #8f8f9d);
-
- @media (prefers-contrast) {
- --tab-preview-background-color: Canvas;
- --tab-preview-text-color: CanvasText;
- }
+#tab-preview-panel {
+ --panel-width: 280px;
+ --panel-padding: 0;
+ --panel-background: var(--tab-selected-bgcolor);
+ --panel-color: var(--tab-selected-textcolor);
}
-.tab-preview-container {
- background-color: var(--tab-preview-background-color);
- color: var(--tab-preview-text-color);
- border-radius: 9px;
- display: inline-block;
- width: 280px;
- overflow: hidden;
- line-height: 1.5;
- border: 1px solid var(--tab-preview-border-color);
+.tab-preview-text-container {
+ padding: var(--space-small);
}
.tab-preview-title {
max-height: 3em;
overflow: hidden;
- font-weight: 600;
+ font-weight: var(--font-weight-bold);
}
.tab-preview-uri {
@@ -38,22 +27,18 @@
text-overflow: ellipsis;
}
-.tab-preview-text-container {
- padding: 8px;
-}
-
.tab-preview-thumbnail-container {
- border-top: 1px solid var(--tab-preview-border-color);
-}
-
-.tab-preview-thumbnail-container img,
-.tab-preview-thumbnail-container canvas {
- display: block;
- width: 100%;
-}
-
-@media (max-width: 640px) {
- .tab-preview-thumbnail-container {
+ border-top: 1px solid var(--panel-border-color);
+ &:empty {
display: none;
}
+ @media (width < 640px) {
+ display: none;
+ }
+
+ > img,
+ > canvas {
+ display: block;
+ width: 100%;
+ }
}
diff --git a/browser/components/tabpreview/tabpreview.mjs b/browser/components/tabpreview/tabpreview.mjs
deleted file mode 100644
index 2409c3fa7a..0000000000
--- a/browser/components/tabpreview/tabpreview.mjs
+++ /dev/null
@@ -1,237 +0,0 @@
-/* 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 { html } from "chrome://global/content/vendor/lit.all.mjs";
-import { MozLitElement } from "chrome://global/content/lit-utils.mjs";
-
-var { XPCOMUtils } = ChromeUtils.importESModule(
- "resource://gre/modules/XPCOMUtils.sys.mjs"
-);
-
-const TAB_PREVIEW_USE_THUMBNAILS_PREF =
- "browser.tabs.cardPreview.showThumbnails";
-
-/**
- * Detailed preview card that displays when hovering a tab
- *
- * @property {MozTabbrowserTab} tab - the tab to preview
- * @fires TabPreview#previewhidden
- * @fires TabPreview#previewshown
- * @fires TabPreview#previewThumbnailUpdated
- */
-export default class TabPreview extends MozLitElement {
- static properties = {
- tab: { type: Object },
-
- _previewIsActive: { type: Boolean, state: true },
- _previewDelayTimeout: { type: Number, state: true },
- _displayTitle: { type: String, state: true },
- _displayURI: { type: String, state: true },
- _displayImg: { type: Object, state: true },
- };
-
- constructor() {
- super();
- XPCOMUtils.defineLazyPreferenceGetter(
- this,
- "_prefPreviewDelay",
- "ui.tooltip.delay_ms"
- );
- XPCOMUtils.defineLazyPreferenceGetter(
- this,
- "_prefDisplayThumbnail",
- TAB_PREVIEW_USE_THUMBNAILS_PREF,
- false
- );
- }
-
- // render this inside a <panel>
- createRenderRoot() {
- if (!document.createXULElement) {
- console.error(
- "Unable to create panel: document.createXULElement is not available"
- );
- return super.createRenderRoot();
- }
- this.attachShadow({ mode: "open" });
- this.panel = document.createXULElement("panel");
- this.panel.setAttribute("id", "tabPreviewPanel");
- this.panel.setAttribute("noautofocus", true);
- this.panel.setAttribute("norolluponanchor", true);
- this.panel.setAttribute("consumeoutsideclicks", "never");
- this.panel.setAttribute("rolluponmousewheel", "true");
- this.panel.setAttribute("level", "parent");
- this.shadowRoot.append(this.panel);
- return this.panel;
- }
-
- get previewCanShow() {
- return this._previewIsActive && this.tab;
- }
-
- get thumbnailCanShow() {
- return (
- this.previewCanShow &&
- this._prefDisplayThumbnail &&
- !this.tab.selected &&
- this._displayImg
- );
- }
-
- getPrettyURI(uri) {
- try {
- const url = new URL(uri);
- return `${url.hostname}`.replace(/^w{3}\./, "");
- } catch {
- return uri;
- }
- }
-
- handleEvent(e) {
- switch (e.type) {
- case "TabSelect": {
- this.requestUpdate();
- break;
- }
- case "popuphidden": {
- this.previewHidden();
- break;
- }
- }
- }
-
- showPreview() {
- this.panel.openPopup(this.tab, {
- position: "bottomleft topleft",
- y: -2,
- isContextMenu: false,
- });
- window.addEventListener("TabSelect", this);
- this.panel.addEventListener("popuphidden", this);
- }
-
- hidePreview() {
- this.panel.hidePopup();
- }
-
- previewHidden() {
- window.removeEventListener("TabSelect", this);
- this.panel.removeEventListener("popuphidden", this);
-
- /**
- * @event TabPreview#previewhidden
- * @type {CustomEvent}
- */
- this.dispatchEvent(new CustomEvent("previewhidden"));
- }
-
- // compute values derived from tab element
- willUpdate(changedProperties) {
- if (!changedProperties.has("tab")) {
- return;
- }
- if (!this.tab) {
- this._displayTitle = "";
- this._displayURI = "";
- this._displayImg = null;
- return;
- }
- this._displayTitle = this.tab.textLabel.textContent;
- this._displayURI = this.getPrettyURI(
- this.tab.linkedBrowser.currentURI.spec
- );
- this._displayImg = null;
- let { tab } = this;
- window.tabPreviews.get(this.tab).then(el => {
- if (this.tab == tab) {
- this._displayImg = el;
- }
- });
- }
-
- updated(changedProperties) {
- if (changedProperties.has("tab")) {
- // handle preview delay
- if (!this.tab) {
- clearTimeout(this._previewDelayTimeout);
- this._previewIsActive = false;
- } else {
- let lastTabVal = changedProperties.get("tab");
- if (!lastTabVal) {
- // tab was set from an empty state,
- // so wait for the delay duration before showing
- this._previewDelayTimeout = setTimeout(() => {
- this._previewIsActive = true;
- }, this._prefPreviewDelay);
- }
- }
- }
- if (changedProperties.has("_previewIsActive")) {
- if (!this._previewIsActive) {
- this.hidePreview();
- }
- }
- if (
- (changedProperties.has("tab") ||
- changedProperties.has("_previewIsActive")) &&
- this.previewCanShow
- ) {
- this.updateComplete.then(() => {
- if (this.panel.state == "open" || this.panel.state == "showing") {
- this.panel.moveToAnchor(this.tab, "bottomleft topleft", 0, -2);
- } else {
- this.showPreview();
- }
-
- this.dispatchEvent(
- /**
- * @event TabPreview#previewshown
- * @type {CustomEvent}
- * @property {object} detail
- * @property {MozTabbrowserTab} detail.tab - the tab being previewed
- */
- new CustomEvent("previewshown", {
- detail: { tab: this.tab },
- })
- );
- });
- }
- if (changedProperties.has("_displayImg")) {
- this.updateComplete.then(() => {
- /**
- * fires when the thumbnail for a preview is loaded
- * and added to the document.
- *
- * @event TabPreview#previewThumbnailUpdated
- * @type {CustomEvent}
- */
- this.dispatchEvent(new CustomEvent("previewThumbnailUpdated"));
- });
- }
- }
-
- render() {
- return html`
- <link
- rel="stylesheet"
- type="text/css"
- href="chrome://browser/content/tabpreview/tabpreview.css"
- />
- <div class="tab-preview-container">
- <div class="tab-preview-text-container">
- <div class="tab-preview-title">${this._displayTitle}</div>
- <div class="tab-preview-uri">${this._displayURI}</div>
- </div>
- ${this.thumbnailCanShow
- ? html`
- <div class="tab-preview-thumbnail-container">
- ${this._displayImg}
- </div>
- `
- : ""}
- </div>
- `;
- }
-}
-customElements.define("tab-preview", TabPreview);