Upstream mozilla-firefox/firefox state of the touched files before eb0738e2cb
This commit is contained in:
commit
8a12eaac21
3 files changed
+2157
No files matched your search
@@ -0,0 +1,456 @@
|
||||
/* 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/. */
|
||||
|
||||
const lazy = {};
|
||||
ChromeUtils.defineESModuleGetters(lazy, {
|
||||
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs",
|
||||
SyncedTabsController: "resource:///modules/SyncedTabsController.sys.mjs",
|
||||
});
|
||||
|
||||
const { TabsSetupFlowManager } = ChromeUtils.importESModule(
|
||||
"resource:///modules/firefox-view-tabs-setup-manager.sys.mjs"
|
||||
);
|
||||
|
||||
import {
|
||||
html,
|
||||
ifDefined,
|
||||
when,
|
||||
} from "chrome://global/content/vendor/lit.all.mjs";
|
||||
import { ViewPage } from "./viewpage.mjs";
|
||||
import {
|
||||
escapeHtmlEntities,
|
||||
MAX_TABS_FOR_RECENT_BROWSING,
|
||||
navigateToLink,
|
||||
} from "./helpers.mjs";
|
||||
// eslint-disable-next-line import/no-unassigned-import
|
||||
import "chrome://browser/content/firefoxview/syncedtabs-tab-list.mjs";
|
||||
// eslint-disable-next-line import/no-unassigned-import
|
||||
import "chrome://global/content/elements/moz-button.mjs";
|
||||
|
||||
const UI_OPEN_STATE = "browser.tabs.firefox-view.ui-state.tab-pickup.open";
|
||||
|
||||
class SyncedTabsInView extends ViewPage {
|
||||
controller = new lazy.SyncedTabsController(this, {
|
||||
contextMenu: true,
|
||||
pairDeviceCallback: () =>
|
||||
Glean.firefoxviewNext.fxaMobileSync.record({
|
||||
has_devices: TabsSetupFlowManager.secondaryDeviceConnected,
|
||||
}),
|
||||
signupCallback: () => Glean.firefoxviewNext.fxaContinueSync.record(),
|
||||
});
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this._started = false;
|
||||
this._id = Math.floor(Math.random() * 10e6);
|
||||
if (this.recentBrowsing) {
|
||||
this.maxTabsLength = MAX_TABS_FOR_RECENT_BROWSING;
|
||||
} else {
|
||||
// Setting maxTabsLength to -1 for no max
|
||||
this.maxTabsLength = -1;
|
||||
}
|
||||
this.fullyUpdated = false;
|
||||
this.showAll = false;
|
||||
this.cumulativeSearches = 0;
|
||||
this.onSearchQuery = this.onSearchQuery.bind(this);
|
||||
}
|
||||
|
||||
static properties = {
|
||||
...ViewPage.properties,
|
||||
showAll: { type: Boolean },
|
||||
cumulativeSearches: { type: Number },
|
||||
};
|
||||
|
||||
static queries = {
|
||||
cardEls: { all: "card-container" },
|
||||
emptyState: "fxview-empty-state",
|
||||
searchTextbox: "moz-input-search",
|
||||
tabLists: { all: "syncedtabs-tab-list" },
|
||||
};
|
||||
|
||||
start() {
|
||||
if (this._started) {
|
||||
return;
|
||||
}
|
||||
this._started = true;
|
||||
this.controller.addSyncObservers();
|
||||
this.controller.updateStates();
|
||||
this.onVisibilityChange();
|
||||
|
||||
if (this.recentBrowsing) {
|
||||
this.recentBrowsingElement.addEventListener(
|
||||
"MozInputSearch:search",
|
||||
this.onSearchQuery
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
stop() {
|
||||
if (!this._started) {
|
||||
return;
|
||||
}
|
||||
this._started = false;
|
||||
TabsSetupFlowManager.updateViewVisibility(this._id, "unloaded");
|
||||
this.onVisibilityChange();
|
||||
this.controller.removeSyncObservers();
|
||||
|
||||
if (this.recentBrowsing) {
|
||||
this.recentBrowsingElement.removeEventListener(
|
||||
"MozInputSearch:search",
|
||||
this.onSearchQuery
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
this.stop();
|
||||
}
|
||||
|
||||
viewVisibleCallback() {
|
||||
this.start();
|
||||
}
|
||||
|
||||
viewHiddenCallback() {
|
||||
this.stop();
|
||||
}
|
||||
|
||||
onVisibilityChange() {
|
||||
const isOpen = this.open;
|
||||
const isVisible = this.isVisible;
|
||||
if (isVisible && isOpen) {
|
||||
this.update();
|
||||
TabsSetupFlowManager.updateViewVisibility(this._id, "visible");
|
||||
} else {
|
||||
TabsSetupFlowManager.updateViewVisibility(
|
||||
this._id,
|
||||
isVisible ? "closed" : "hidden"
|
||||
);
|
||||
}
|
||||
|
||||
this.toggleVisibilityInCardContainer();
|
||||
}
|
||||
|
||||
generateMessageCard({
|
||||
action,
|
||||
buttonLabel,
|
||||
descriptionArray,
|
||||
descriptionLink,
|
||||
header,
|
||||
mainImageUrl,
|
||||
}) {
|
||||
return html`
|
||||
<fxview-empty-state
|
||||
headerLabel=${header}
|
||||
.descriptionLabels=${descriptionArray}
|
||||
.descriptionLink=${ifDefined(descriptionLink)}
|
||||
class="empty-state synced-tabs error"
|
||||
?isSelectedTab=${this.selectedTab}
|
||||
?isInnerCard=${this.recentBrowsing}
|
||||
mainImageUrl=${ifDefined(mainImageUrl)}
|
||||
id="empty-container"
|
||||
>
|
||||
<moz-button
|
||||
class="primary"
|
||||
type="primary"
|
||||
slot="primary-action"
|
||||
?hidden=${!buttonLabel}
|
||||
data-l10n-id=${ifDefined(buttonLabel)}
|
||||
data-action=${action}
|
||||
@click=${e => this.controller.handleEvent(e)}
|
||||
></moz-button>
|
||||
</fxview-empty-state>
|
||||
`;
|
||||
}
|
||||
|
||||
onOpenLink(event) {
|
||||
navigateToLink(event);
|
||||
|
||||
Glean.firefoxviewNext.syncedTabsTabs.record({
|
||||
page: this.recentBrowsing ? "recentbrowsing" : "syncedtabs",
|
||||
});
|
||||
|
||||
if (this.controller.searchQuery) {
|
||||
Glean.firefoxview.cumulativeSearches[
|
||||
this.recentBrowsing ? "recentbrowsing" : "syncedtabs"
|
||||
].accumulateSingleSample(this.cumulativeSearches);
|
||||
this.cumulativeSearches = 0;
|
||||
}
|
||||
}
|
||||
|
||||
onContextMenu(e) {
|
||||
this.triggerNode = e.originalTarget;
|
||||
e.target.querySelector("panel-list").toggle(e.detail.originalEvent);
|
||||
}
|
||||
|
||||
onCloseTab(e) {
|
||||
const { url, fxaDeviceId, tertiaryActionClass } = e.originalTarget;
|
||||
if (tertiaryActionClass === "dismiss-button") {
|
||||
// Set new pending close tab
|
||||
this.controller.requestCloseRemoteTab(fxaDeviceId, url);
|
||||
} else if (tertiaryActionClass === "undo-button") {
|
||||
// User wants to undo
|
||||
this.controller.removePendingTabToClose(fxaDeviceId, url);
|
||||
}
|
||||
this.requestUpdate();
|
||||
}
|
||||
|
||||
panelListTemplate() {
|
||||
return html`
|
||||
<panel-list slot="menu" data-tab-type="syncedtabs">
|
||||
<panel-item
|
||||
@click=${this.openInNewWindow}
|
||||
data-l10n-id="fxviewtabrow-open-in-window"
|
||||
data-l10n-attrs="accesskey"
|
||||
></panel-item>
|
||||
<panel-item
|
||||
@click=${this.openInNewPrivateWindow}
|
||||
data-l10n-id="fxviewtabrow-open-in-private-window"
|
||||
data-l10n-attrs="accesskey"
|
||||
?hidden=${!lazy.PrivateBrowsingUtils.enabled}
|
||||
></panel-item>
|
||||
<hr />
|
||||
<panel-item
|
||||
@click=${this.copyLink}
|
||||
data-l10n-id="fxviewtabrow-copy-link"
|
||||
data-l10n-attrs="accesskey"
|
||||
></panel-item>
|
||||
</panel-list>
|
||||
`;
|
||||
}
|
||||
|
||||
noDeviceTabsTemplate(deviceName, deviceType, isSearchResultsEmpty = false) {
|
||||
const template = html`<h3
|
||||
slot=${ifDefined(this.recentBrowsing ? null : "header")}
|
||||
class="device-header"
|
||||
>
|
||||
<span class="icon ${deviceType}" role="presentation"></span>
|
||||
${deviceName}
|
||||
</h3>
|
||||
${when(
|
||||
isSearchResultsEmpty,
|
||||
() => html`
|
||||
<div
|
||||
slot=${ifDefined(this.recentBrowsing ? null : "main")}
|
||||
class="blackbox notabs search-results-empty"
|
||||
data-l10n-id="firefoxview-search-results-empty"
|
||||
data-l10n-args=${JSON.stringify({
|
||||
query: escapeHtmlEntities(this.controller.searchQuery),
|
||||
})}
|
||||
></div>
|
||||
`,
|
||||
() => html`
|
||||
<div
|
||||
slot=${ifDefined(this.recentBrowsing ? null : "main")}
|
||||
class="blackbox notabs"
|
||||
data-l10n-id="firefoxview-syncedtabs-device-notabs"
|
||||
></div>
|
||||
`
|
||||
)}`;
|
||||
return this.recentBrowsing
|
||||
? template
|
||||
: html`<card-container
|
||||
shortPageName=${this.recentBrowsing ? "syncedtabs" : null}
|
||||
>${template}</card-container
|
||||
>`;
|
||||
}
|
||||
|
||||
onSearchQuery(e) {
|
||||
if (!this.recentBrowsing) {
|
||||
Glean.firefoxviewNext.searchInitiatedSearch.record({
|
||||
page: "syncedtabs",
|
||||
});
|
||||
}
|
||||
this.controller.searchQuery = e.detail.query;
|
||||
this.cumulativeSearches = e.detail.query ? this.cumulativeSearches + 1 : 0;
|
||||
this.showAll = false;
|
||||
}
|
||||
|
||||
deviceTemplate(deviceName, deviceType, tabItems) {
|
||||
return html`<h3
|
||||
slot=${!this.recentBrowsing ? "header" : null}
|
||||
class="device-header"
|
||||
>
|
||||
<span class="icon ${deviceType}" role="presentation"></span>
|
||||
${deviceName}
|
||||
</h3>
|
||||
<syncedtabs-tab-list
|
||||
slot="main"
|
||||
.hasPopup=${"menu"}
|
||||
.tabItems=${ifDefined(tabItems)}
|
||||
.searchQuery=${this.controller.searchQuery}
|
||||
.maxTabsLength=${this.showAll ? -1 : this.maxTabsLength}
|
||||
@fxview-tab-list-primary-action=${this.onOpenLink}
|
||||
@fxview-tab-list-secondary-action=${this.onContextMenu}
|
||||
@fxview-tab-list-tertiary-action=${this.onCloseTab}
|
||||
secondaryActionClass="options-button"
|
||||
>
|
||||
${this.panelListTemplate()}
|
||||
</syncedtabs-tab-list>`;
|
||||
}
|
||||
|
||||
generateTabList() {
|
||||
let renderArray = [];
|
||||
let renderInfo = this.controller.getRenderInfo();
|
||||
for (let id in renderInfo) {
|
||||
let tabItems = renderInfo[id].tabItems;
|
||||
if (tabItems.length) {
|
||||
const template = this.recentBrowsing
|
||||
? this.deviceTemplate(
|
||||
renderInfo[id].name,
|
||||
renderInfo[id].deviceType,
|
||||
tabItems
|
||||
)
|
||||
: html`<card-container
|
||||
shortPageName=${this.recentBrowsing ? "syncedtabs" : null}
|
||||
>${this.deviceTemplate(
|
||||
renderInfo[id].name,
|
||||
renderInfo[id].deviceType,
|
||||
tabItems
|
||||
)}
|
||||
</card-container>`;
|
||||
renderArray.push(template);
|
||||
if (this.isShowAllLinkVisible(tabItems)) {
|
||||
renderArray.push(
|
||||
html` <div class="show-all-link-container">
|
||||
<div
|
||||
class="show-all-link"
|
||||
@click=${this.enableShowAll}
|
||||
@keydown=${this.enableShowAll}
|
||||
data-l10n-id="firefoxview-show-all"
|
||||
tabindex="0"
|
||||
role="link"
|
||||
></div>
|
||||
</div>`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Check renderInfo[id].tabs.length to determine whether to display an
|
||||
// empty tab list message or empty search results message.
|
||||
// If there are no synced tabs, we always display the empty tab list
|
||||
// message, even if there is an active search query.
|
||||
renderArray.push(
|
||||
this.noDeviceTabsTemplate(
|
||||
renderInfo[id].name,
|
||||
renderInfo[id].deviceType,
|
||||
Boolean(renderInfo[id].tabs.length)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
return renderArray;
|
||||
}
|
||||
|
||||
isShowAllLinkVisible(tabItems) {
|
||||
return (
|
||||
this.recentBrowsing &&
|
||||
this.controller.searchQuery &&
|
||||
tabItems.length > this.maxTabsLength &&
|
||||
!this.showAll
|
||||
);
|
||||
}
|
||||
|
||||
enableShowAll(event) {
|
||||
if (
|
||||
event.type == "click" ||
|
||||
(event.type == "keydown" && event.code == "Enter") ||
|
||||
(event.type == "keydown" && event.code == "Space")
|
||||
) {
|
||||
event.preventDefault();
|
||||
this.showAll = true;
|
||||
Glean.firefoxviewNext.searchShowAllShowallbutton.record({
|
||||
section: "syncedtabs",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
generateCardContent() {
|
||||
const cardProperties = this.controller.getMessageCard();
|
||||
return cardProperties
|
||||
? this.generateMessageCard(cardProperties)
|
||||
: this.generateTabList();
|
||||
}
|
||||
|
||||
render() {
|
||||
this.open =
|
||||
!TabsSetupFlowManager.isTabSyncSetupComplete ||
|
||||
Services.prefs.getBoolPref(UI_OPEN_STATE, true);
|
||||
|
||||
let renderArray = [];
|
||||
renderArray.push(
|
||||
html` <link
|
||||
rel="stylesheet"
|
||||
href="chrome://browser/content/firefoxview/view-syncedtabs.css"
|
||||
/>`
|
||||
);
|
||||
renderArray.push(
|
||||
html` <link
|
||||
rel="stylesheet"
|
||||
href="chrome://browser/content/firefoxview/firefoxview.css"
|
||||
/>`
|
||||
);
|
||||
|
||||
if (!this.recentBrowsing) {
|
||||
renderArray.push(
|
||||
html`<div class="sticky-container bottom-fade">
|
||||
<h2
|
||||
class="page-header"
|
||||
data-l10n-id="firefoxview-synced-tabs-header"
|
||||
></h2>
|
||||
<div class="syncedtabs-header">
|
||||
<div>
|
||||
<moz-input-search
|
||||
data-l10n-id="firefoxview-search-text-box-tabs"
|
||||
data-l10n-attrs="placeholder"
|
||||
@MozInputSearch:search=${this.onSearchQuery}
|
||||
></moz-input-search>
|
||||
</div>
|
||||
${when(
|
||||
this.controller.currentSetupStateIndex === 4,
|
||||
() => html`
|
||||
<moz-button
|
||||
iconSrc="chrome://global/skin/icons/plus.svg"
|
||||
data-l10n-id="firefoxview-syncedtabs-connect-another-device"
|
||||
data-action="add-device"
|
||||
@click=${e => this.controller.handleEvent(e)}
|
||||
></moz-button>
|
||||
`
|
||||
)}
|
||||
</div>
|
||||
</div>`
|
||||
);
|
||||
}
|
||||
|
||||
if (this.recentBrowsing) {
|
||||
renderArray.push(
|
||||
html`<card-container
|
||||
preserveCollapseState
|
||||
shortPageName="syncedtabs"
|
||||
?showViewAll=${this.controller.currentSetupStateIndex == 4 &&
|
||||
this.controller.currentSyncedTabs.length}
|
||||
?isEmptyState=${!this.controller.currentSyncedTabs.length}
|
||||
>
|
||||
>
|
||||
<h3
|
||||
slot="header"
|
||||
data-l10n-id="firefoxview-synced-tabs-header"
|
||||
class="recentbrowsing-header"
|
||||
></h3>
|
||||
<div slot="main">${this.generateCardContent()}</div>
|
||||
</card-container>`
|
||||
);
|
||||
} else {
|
||||
renderArray.push(
|
||||
html`<div class="cards-container">${this.generateCardContent()}</div>`
|
||||
);
|
||||
}
|
||||
return renderArray;
|
||||
}
|
||||
|
||||
updated() {
|
||||
this.fullyUpdated = true;
|
||||
this.toggleVisibilityInCardContainer();
|
||||
}
|
||||
}
|
||||
customElements.define("view-syncedtabs", SyncedTabsInView);
|
||||
Reference in new issue
Block a user