diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-15 03:35:49 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-15 03:35:49 +0000 |
commit | d8bbc7858622b6d9c278469aab701ca0b609cddf (patch) | |
tree | eff41dc61d9f714852212739e6b3738b82a2af87 /browser/components/tabpreview | |
parent | Releasing progress-linux version 125.0.3-1~progress7.99u1. (diff) | |
download | firefox-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.mn | 2 | ||||
-rw-r--r-- | browser/components/tabpreview/tab-preview-panel.mjs | 174 | ||||
-rw-r--r-- | browser/components/tabpreview/tabpreview.css | 53 | ||||
-rw-r--r-- | browser/components/tabpreview/tabpreview.mjs | 237 |
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); |