зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changeset 698658fc606b (bug 1774397) for causing multiple mochitest failures. CLOSED TREE
This commit is contained in:
Родитель
8e59a7d48d
Коммит
9737f1fdf2
|
@ -2495,8 +2495,6 @@ var gBrowserInit = {
|
|||
|
||||
gAccessibilityServiceIndicator.uninit();
|
||||
|
||||
FirefoxViewHandler.uninit();
|
||||
|
||||
if (gToolbarKeyNavEnabled) {
|
||||
ToolbarKeyboardNavigator.uninit();
|
||||
}
|
||||
|
@ -9913,29 +9911,18 @@ var ConfirmationHint = {
|
|||
var FirefoxViewHandler = {
|
||||
tab: null,
|
||||
init() {
|
||||
const { FirefoxViewNotificationManager } = ChromeUtils.importESModule(
|
||||
"resource:///modules/firefox-view-notification-manager.sys.mjs"
|
||||
);
|
||||
if (
|
||||
AppConstants.NIGHTLY_BUILD &&
|
||||
!Services.prefs.getBoolPref("browser.tabs.firefox-view")
|
||||
) {
|
||||
document.getElementById("menu_openFirefoxView").hidden = true;
|
||||
} else {
|
||||
let shouldShow = FirefoxViewNotificationManager.shouldNotificationDotBeShowing();
|
||||
this.toggleNotificationDot(shouldShow);
|
||||
}
|
||||
Services.obs.addObserver(this, "firefoxview-notification-dot-update");
|
||||
},
|
||||
uninit() {
|
||||
Services.obs.removeObserver(this, "firefoxview-notification-dot-update");
|
||||
},
|
||||
openTab() {
|
||||
if (!this.tab) {
|
||||
this.tab = gBrowser.addTrustedTab("about:firefoxview", { index: 0 });
|
||||
this.tab.addEventListener("TabClose", this, { once: true });
|
||||
gBrowser.tabContainer.addEventListener("TabSelect", this);
|
||||
window.addEventListener("activate", this);
|
||||
gBrowser.hideTab(this.tab);
|
||||
}
|
||||
gBrowser.selectedTab = this.tab;
|
||||
|
@ -9951,25 +9938,6 @@ var FirefoxViewHandler = {
|
|||
this.tab = null;
|
||||
gBrowser.tabContainer.removeEventListener("TabSelect", this);
|
||||
break;
|
||||
case "activate":
|
||||
if (this.tab?.selected) {
|
||||
Services.obs.notifyObservers(
|
||||
null,
|
||||
"firefoxview-notification-dot-update",
|
||||
"false"
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
observe(sub, topic, data) {
|
||||
if (topic === "firefoxview-notification-dot-update") {
|
||||
let shouldShow = data === "true";
|
||||
this.toggleNotificationDot(shouldShow);
|
||||
}
|
||||
},
|
||||
toggleNotificationDot(shouldShow) {
|
||||
let fxViewButton = document.getElementById("firefox-view-button");
|
||||
fxViewButton?.setAttribute("attention", shouldShow);
|
||||
},
|
||||
};
|
||||
|
|
|
@ -472,11 +472,6 @@ const CustomizableWidgets = [
|
|||
return Services.prefs.getBoolPref("browser.tabs.firefox-view");
|
||||
},
|
||||
onCommand(e) {
|
||||
Services.obs.notifyObservers(
|
||||
null,
|
||||
"firefoxview-notification-dot-update",
|
||||
"false"
|
||||
);
|
||||
e.view.FirefoxViewHandler.openTab();
|
||||
},
|
||||
},
|
||||
|
|
|
@ -1,106 +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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* This module exports the FirefoxViewNotificationManager singleton, which manages the notification state
|
||||
* for the Firefox View button
|
||||
*/
|
||||
|
||||
const RECENT_TABS_SYNC = "services.sync.lastTabFetch";
|
||||
const lazy = {};
|
||||
|
||||
const { XPCOMUtils } = ChromeUtils.importESModule(
|
||||
"resource://gre/modules/XPCOMUtils.sys.mjs"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(lazy, {
|
||||
BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
|
||||
SyncedTabs: "resource://services-sync/SyncedTabs.jsm",
|
||||
});
|
||||
|
||||
export const FirefoxViewNotificationManager = new (class {
|
||||
#currentlyShowing;
|
||||
constructor() {
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
this,
|
||||
"lastTabFetch",
|
||||
RECENT_TABS_SYNC,
|
||||
false,
|
||||
() => {
|
||||
this.handleTabSync();
|
||||
}
|
||||
);
|
||||
// Need to access the pref variable for the observer to start observing
|
||||
// See the defineLazyPreferenceGetter function header
|
||||
this.lastTabFetch;
|
||||
|
||||
Services.obs.addObserver(this, "firefoxview-notification-dot-update");
|
||||
|
||||
this.#currentlyShowing = false;
|
||||
}
|
||||
|
||||
async handleTabSync() {
|
||||
let newSyncedTabs = await lazy.SyncedTabs.getRecentTabs(3);
|
||||
this.#currentlyShowing = this.tabsListChanged(newSyncedTabs);
|
||||
this.showNotificationDot();
|
||||
this.syncedTabs = newSyncedTabs;
|
||||
}
|
||||
|
||||
showNotificationDot() {
|
||||
if (this.#currentlyShowing) {
|
||||
Services.obs.notifyObservers(
|
||||
null,
|
||||
"firefoxview-notification-dot-update",
|
||||
"true"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
observe(sub, topic, data) {
|
||||
if (topic === "firefoxview-notification-dot-update" && data === "false") {
|
||||
this.#currentlyShowing = false;
|
||||
}
|
||||
}
|
||||
|
||||
tabsListChanged(newTabs) {
|
||||
// The first time the tabs list is changed this.tabs is undefined because we haven't synced yet.
|
||||
// We don't want to show the badge here because it's not an actual change,
|
||||
// we are just syncing for the first time.
|
||||
if (!this.syncedTabs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We loop through all windows to see if any window has currentURI "about:firefoxview" and
|
||||
// the window is visible because we don't want to show the notification badge in that case
|
||||
for (let window of lazy.BrowserWindowTracker.orderedWindows) {
|
||||
// if the url is "about:firefoxview" and the window visible we don't want to show the notification badge
|
||||
if (
|
||||
window.FirefoxViewHandler.tab?.selected &&
|
||||
!window.isFullyOccluded &&
|
||||
window.windowState !== window.STATE_MINIMIZED
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (newTabs.length > this.syncedTabs.length) {
|
||||
return true;
|
||||
}
|
||||
for (let i = 0; i < newTabs.length; i++) {
|
||||
let newTab = newTabs[i];
|
||||
let oldTab = this.syncedTabs[i];
|
||||
|
||||
if (newTab?.url !== oldTab?.url) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
shouldNotificationDotBeShowing() {
|
||||
return this.#currentlyShowing;
|
||||
}
|
||||
})();
|
|
@ -104,7 +104,19 @@ class TabPickupList extends HTMLElement {
|
|||
}
|
||||
|
||||
async getSyncedTabData() {
|
||||
let tabs = await lazy.SyncedTabs.getRecentTabs(this.maxTabsLength);
|
||||
let tabs = [];
|
||||
let clients = await lazy.SyncedTabs.getTabClients();
|
||||
|
||||
for (let client of clients) {
|
||||
for (let tab of client.tabs) {
|
||||
tab.device = client.name;
|
||||
tab.deviceType = client.clientType;
|
||||
}
|
||||
tabs = [...tabs, ...client.tabs.reverse()];
|
||||
}
|
||||
tabs = tabs
|
||||
.sort((a, b) => b.lastUsed - a.lastUsed)
|
||||
.slice(0, this.maxTabsLength);
|
||||
|
||||
this.updateTabsList(tabs);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ support-files = head.js
|
|||
|
||||
[browser_firefoxview.js]
|
||||
[browser_firefoxview_tab.js]
|
||||
[browser_notification_dot.js]
|
||||
[browser_recently_closed_tabs.js]
|
||||
[browser_setup_state.js]
|
||||
[browser_tab_pickup_list.js]
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const { sinon } = ChromeUtils.import("resource://testing-common/Sinon.jsm");
|
||||
const { BuiltInThemes } = ChromeUtils.import(
|
||||
"resource:///modules/BuiltInThemes.jsm"
|
||||
);
|
||||
|
|
|
@ -1,314 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const tabsList1 = syncedTabsData1[0].tabs;
|
||||
const tabsList2 = syncedTabsData1[1].tabs;
|
||||
const BADGE_TOP_RIGHT = "75% 25%";
|
||||
|
||||
const { SyncedTabs } = ChromeUtils.import(
|
||||
"resource://services-sync/SyncedTabs.jsm"
|
||||
);
|
||||
|
||||
function setupRecentDeviceListMocks() {
|
||||
const sandbox = sinon.createSandbox();
|
||||
sandbox.stub(fxAccounts.device, "recentDeviceList").get(() => [
|
||||
{
|
||||
id: 1,
|
||||
name: "My desktop",
|
||||
isCurrentDevice: true,
|
||||
type: "desktop",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "My iphone",
|
||||
type: "mobile",
|
||||
},
|
||||
]);
|
||||
|
||||
sandbox.stub(UIState, "get").returns({
|
||||
status: UIState.STATUS_SIGNED_IN,
|
||||
syncEnabled: true,
|
||||
});
|
||||
|
||||
return sandbox;
|
||||
}
|
||||
|
||||
function waitForWindowActive(win, active) {
|
||||
return Promise.all([
|
||||
BrowserTestUtils.waitForEvent(win, active ? "focus" : "blur"),
|
||||
BrowserTestUtils.waitForEvent(win, active ? "activate" : "deactivate"),
|
||||
]);
|
||||
}
|
||||
|
||||
async function waitForNotificationBadgeToBeShowing(fxViewButton) {
|
||||
await BrowserTestUtils.waitForMutationCondition(
|
||||
fxViewButton,
|
||||
{ attributes: true },
|
||||
() => fxViewButton.getAttribute("attention") === "true"
|
||||
);
|
||||
return fxViewButton.getAttribute("attention") === "true";
|
||||
}
|
||||
|
||||
async function waitForNotificationBadgeToBeHidden(fxViewButton) {
|
||||
await BrowserTestUtils.waitForMutationCondition(
|
||||
fxViewButton,
|
||||
{ attributes: true },
|
||||
() =>
|
||||
!fxViewButton.getAttribute("attention") ||
|
||||
fxViewButton.getAttribute("attention") === "false"
|
||||
);
|
||||
return (
|
||||
!fxViewButton.getAttribute("attention") ||
|
||||
fxViewButton.getAttribute("attention") === "false"
|
||||
);
|
||||
}
|
||||
|
||||
function getBackgroundPositionForElement(ele) {
|
||||
let style = getComputedStyle(ele);
|
||||
return style.getPropertyValue("background-position");
|
||||
}
|
||||
|
||||
let recentFetchTime = Math.floor(Date.now() / 1000);
|
||||
async function initTabSync() {
|
||||
recentFetchTime += 1;
|
||||
info("updating lastFetch:" + recentFetchTime);
|
||||
Services.prefs.setIntPref("services.sync.lastTabFetch", recentFetchTime);
|
||||
await TestUtils.waitForTick();
|
||||
}
|
||||
|
||||
add_setup(async () => {
|
||||
await window.delayedStartupPromise;
|
||||
await addFirefoxViewButtonToToolbar();
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
BrowserTestUtils.removeTab(FirefoxViewHandler.tab);
|
||||
removeFirefoxViewButtonFromToolbar();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Test that the notification badge will show and hide in the correct cases
|
||||
*/
|
||||
add_task(async function testNotificationDot() {
|
||||
const sandbox = setupRecentDeviceListMocks();
|
||||
const syncedTabsMock = sandbox.stub(SyncedTabs, "getRecentTabs");
|
||||
|
||||
syncedTabsMock.returns(tabsList1);
|
||||
// Initiate a synced tabs update with new tabs
|
||||
await initTabSync();
|
||||
|
||||
let fxViewBtn = document.getElementById("firefox-view-button");
|
||||
ok(fxViewBtn, "Got the Firefox View button");
|
||||
|
||||
ok(
|
||||
BrowserTestUtils.is_visible(fxViewBtn),
|
||||
"The Firefox View button is showing"
|
||||
);
|
||||
|
||||
ok(
|
||||
await waitForNotificationBadgeToBeHidden(fxViewBtn),
|
||||
"The notification badge is not showing initially"
|
||||
);
|
||||
|
||||
syncedTabsMock.returns(tabsList2);
|
||||
// Initiate a synced tabs update with new tabs
|
||||
await initTabSync();
|
||||
|
||||
ok(
|
||||
await waitForNotificationBadgeToBeShowing(fxViewBtn),
|
||||
"The notification badge is showing after first tab sync"
|
||||
);
|
||||
|
||||
// check that switching to the firefoxviewtab removes the badge
|
||||
fxViewBtn.click();
|
||||
|
||||
ok(
|
||||
await waitForNotificationBadgeToBeHidden(fxViewBtn),
|
||||
"The notification badge is not showing after going to Firefox View"
|
||||
);
|
||||
|
||||
syncedTabsMock.returns(tabsList1);
|
||||
// Initiate a synced tabs update with new tabs
|
||||
await initTabSync();
|
||||
|
||||
// The noti badge would show but we are on a Firefox View page so no need to show the noti badge
|
||||
ok(
|
||||
await waitForNotificationBadgeToBeHidden(fxViewBtn),
|
||||
"The notification badge is not showing after tab sync while Firefox View is focused"
|
||||
);
|
||||
|
||||
let newTab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
|
||||
syncedTabsMock.returns(tabsList2);
|
||||
await initTabSync();
|
||||
|
||||
ok(
|
||||
await waitForNotificationBadgeToBeShowing(fxViewBtn),
|
||||
"The notification badge is showing after navigation to a new tab"
|
||||
);
|
||||
|
||||
// check that switching back to the Firefox View tab removes the badge
|
||||
fxViewBtn.click();
|
||||
|
||||
ok(
|
||||
await waitForNotificationBadgeToBeHidden(fxViewBtn),
|
||||
"The notification badge is not showing after focusing the Firefox View tab"
|
||||
);
|
||||
|
||||
await BrowserTestUtils.switchTab(gBrowser, newTab);
|
||||
|
||||
// Initiate a synced tabs update with no new tabs
|
||||
await initTabSync();
|
||||
|
||||
ok(
|
||||
await waitForNotificationBadgeToBeHidden(fxViewBtn),
|
||||
"The notification badge is not showing after a tab sync with the same tabs"
|
||||
);
|
||||
|
||||
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
|
||||
BrowserTestUtils.removeTab(newTab);
|
||||
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests the notification badge with multiple windows
|
||||
*/
|
||||
add_task(async function testNotificationDotOnMultipleWindows() {
|
||||
const sandbox = setupRecentDeviceListMocks();
|
||||
const syncedTabsMock = sandbox.stub(SyncedTabs, "getRecentTabs");
|
||||
|
||||
syncedTabsMock.returns(tabsList1);
|
||||
// Initiate a synced tabs update
|
||||
await initTabSync();
|
||||
|
||||
let fxViewBtn = document.getElementById("firefox-view-button");
|
||||
ok(fxViewBtn, "Got the Firefox View button");
|
||||
|
||||
// Create a new window
|
||||
let win = await BrowserTestUtils.openNewBrowserWindow();
|
||||
await win.delayedStartupPromise;
|
||||
let fxViewBtn2 = win.document.getElementById("firefox-view-button");
|
||||
fxViewBtn2.click();
|
||||
|
||||
// Make sure the badge doesn't shows on all windows
|
||||
ok(
|
||||
await waitForNotificationBadgeToBeHidden(fxViewBtn),
|
||||
"The notification badge is not showing in the inital window"
|
||||
);
|
||||
ok(
|
||||
await waitForNotificationBadgeToBeHidden(fxViewBtn2),
|
||||
"The notification badge is not showing in the second window"
|
||||
);
|
||||
|
||||
// Minimize the window.
|
||||
win.minimize();
|
||||
|
||||
await TestUtils.waitForCondition(
|
||||
() => !win.gBrowser.selectedTab.linkedBrowser.docShellIsActive
|
||||
);
|
||||
|
||||
syncedTabsMock.returns(tabsList2);
|
||||
// Initiate a synced tabs update with new tabs
|
||||
await initTabSync();
|
||||
|
||||
// The badge will show because the View tab is minimized
|
||||
// Make sure the badge shows on all windows
|
||||
ok(
|
||||
await waitForNotificationBadgeToBeShowing(fxViewBtn),
|
||||
"The notification badge is showing in the initial window"
|
||||
);
|
||||
ok(
|
||||
await waitForNotificationBadgeToBeShowing(fxViewBtn2),
|
||||
"The notification badge is showing in the second window"
|
||||
);
|
||||
|
||||
win.restore();
|
||||
await TestUtils.waitForCondition(
|
||||
() => win.gBrowser.selectedTab.linkedBrowser.docShellIsActive
|
||||
);
|
||||
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests the notification badge is in the correct spot and that the badge shows when opening a new window
|
||||
* if another window is showing the badge
|
||||
*/
|
||||
add_task(async function testNotificationDotLocation() {
|
||||
const sandbox = setupRecentDeviceListMocks();
|
||||
const syncedTabsMock = sandbox.stub(SyncedTabs, "getRecentTabs");
|
||||
|
||||
syncedTabsMock.returns(tabsList1);
|
||||
// Initiate a synced tabs update
|
||||
await initTabSync();
|
||||
|
||||
let fxViewBtn = document.getElementById("firefox-view-button");
|
||||
ok(fxViewBtn, "Got the Firefox View button");
|
||||
|
||||
syncedTabsMock.returns(tabsList2);
|
||||
// Initiate a synced tabs update
|
||||
await initTabSync();
|
||||
|
||||
ok(
|
||||
await waitForNotificationBadgeToBeShowing(fxViewBtn),
|
||||
"The notification badge is showing initially"
|
||||
);
|
||||
|
||||
// Create a new window
|
||||
let win = await BrowserTestUtils.openNewBrowserWindow();
|
||||
await win.delayedStartupPromise;
|
||||
// let newTab = await BrowserTestUtils.openNewForegroundTab(win.gBrowser, "");
|
||||
|
||||
// Make sure the badge doesn't showing on the new window
|
||||
let fxViewBtn2 = win.document.getElementById("firefox-view-button");
|
||||
ok(
|
||||
await waitForNotificationBadgeToBeShowing(fxViewBtn2),
|
||||
"The notification badge is showing in the second window after opening"
|
||||
);
|
||||
|
||||
// Make sure the badge is below and center now
|
||||
isnot(
|
||||
getBackgroundPositionForElement(fxViewBtn),
|
||||
BADGE_TOP_RIGHT,
|
||||
"The notification badge is not showing in the top right in the initial window"
|
||||
);
|
||||
isnot(
|
||||
getBackgroundPositionForElement(fxViewBtn2),
|
||||
BADGE_TOP_RIGHT,
|
||||
"The notification badge is not showing in the top right in the second window"
|
||||
);
|
||||
|
||||
CustomizableUI.addWidgetToArea(
|
||||
"firefox-view-button",
|
||||
CustomizableUI.AREA_NAVBAR
|
||||
);
|
||||
|
||||
// Make sure both windows still have the notification badge
|
||||
ok(
|
||||
await waitForNotificationBadgeToBeShowing(fxViewBtn),
|
||||
"The notification badge is showing in the initial window"
|
||||
);
|
||||
ok(
|
||||
await waitForNotificationBadgeToBeShowing(fxViewBtn2),
|
||||
"The notification badge is showing in the second window"
|
||||
);
|
||||
|
||||
// Make sure the badge is in the top right now
|
||||
is(
|
||||
getBackgroundPositionForElement(fxViewBtn),
|
||||
BADGE_TOP_RIGHT,
|
||||
"The notification badge is showing in the top right in the initial window"
|
||||
);
|
||||
is(
|
||||
getBackgroundPositionForElement(fxViewBtn2),
|
||||
BADGE_TOP_RIGHT,
|
||||
"The notification badge is showing in the top right in the second window"
|
||||
);
|
||||
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
|
||||
sandbox.restore();
|
||||
});
|
|
@ -1,6 +1,13 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const { UIState } = ChromeUtils.import("resource://services-sync/UIState.jsm");
|
||||
const { TabsSetupFlowManager } = ChromeUtils.importESModule(
|
||||
"resource:///modules/firefox-view-tabs-setup-manager.sys.mjs"
|
||||
);
|
||||
|
||||
const { sinon } = ChromeUtils.import("resource://testing-common/Sinon.jsm");
|
||||
|
||||
function promiseSyncReady() {
|
||||
let service = Cc["@mozilla.org/weave/service;1"].getService(Ci.nsISupports)
|
||||
.wrappedJSObject;
|
||||
|
|
|
@ -1,9 +1,65 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const { UIState } = ChromeUtils.import("resource://services-sync/UIState.jsm");
|
||||
const { TabsSetupFlowManager } = ChromeUtils.importESModule(
|
||||
"resource:///modules/firefox-view-tabs-setup-manager.sys.mjs"
|
||||
);
|
||||
const { sinon } = ChromeUtils.import("resource://testing-common/Sinon.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(globalThis, {
|
||||
SyncedTabs: "resource://services-sync/SyncedTabs.jsm",
|
||||
});
|
||||
const sandbox = sinon.createSandbox();
|
||||
const syncedTabsData1 = [
|
||||
{
|
||||
id: 1,
|
||||
type: "client",
|
||||
name: "My desktop",
|
||||
clientType: "desktop",
|
||||
lastModified: 1655730486760,
|
||||
tabs: [
|
||||
{
|
||||
type: "tab",
|
||||
title: "Sandboxes - Sinon.JS",
|
||||
url: "https://sinonjs.org/releases/latest/sandbox/",
|
||||
icon: "https://sinonjs.org/assets/images/favicon.png",
|
||||
lastUsed: 1655391592, // Thu Jun 16 2022 14:59:52 GMT+0000
|
||||
},
|
||||
{
|
||||
type: "tab",
|
||||
title: "Internet for people, not profits - Mozilla",
|
||||
url: "https://www.mozilla.org/",
|
||||
icon:
|
||||
"https://www.mozilla.org/media/img/favicons/mozilla/favicon.d25d81d39065.ico",
|
||||
lastUsed: 1655730486, // Mon Jun 20 2022 13:08:06 GMT+0000
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
type: "client",
|
||||
name: "My iphone",
|
||||
clientType: "mobile",
|
||||
lastModified: 1655727832930,
|
||||
tabs: [
|
||||
{
|
||||
type: "tab",
|
||||
title: "The Guardian",
|
||||
url: "https://www.theguardian.com/",
|
||||
icon: "page-icon:https://www.theguardian.com/",
|
||||
lastUsed: 1655291890, // Wed Jun 15 2022 11:18:10 GMT+0000
|
||||
},
|
||||
{
|
||||
type: "tab",
|
||||
title: "The Times",
|
||||
url: "https://www.thetimes.co.uk/",
|
||||
icon: "page-icon:https://www.thetimes.co.uk/",
|
||||
lastUsed: 1655727485, // Mon Jun 20 2022 12:18:05 GMT+0000
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const twoTabs = [
|
||||
{
|
||||
|
@ -66,7 +122,60 @@ const syncedTabsData5 = [
|
|||
},
|
||||
];
|
||||
|
||||
function setupMocks(mockData1, mockData2) {
|
||||
const mockDeviceData = [
|
||||
{
|
||||
id: 1,
|
||||
name: "My desktop",
|
||||
isCurrentDevice: true,
|
||||
type: "desktop",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "My iphone",
|
||||
type: "mobile",
|
||||
},
|
||||
];
|
||||
sandbox.stub(fxAccounts.device, "recentDeviceList").get(() => mockDeviceData);
|
||||
|
||||
sandbox.stub(UIState, "get").returns({
|
||||
status: UIState.STATUS_SIGNED_IN,
|
||||
syncEnabled: true,
|
||||
});
|
||||
|
||||
const syncedTabsMock = sandbox.stub(SyncedTabs, "getTabClients");
|
||||
syncedTabsMock.onFirstCall().returns(mockData1);
|
||||
syncedTabsMock.onSecondCall().returns(mockData2);
|
||||
}
|
||||
|
||||
async function setupListState(browser) {
|
||||
// Skip the synced tabs sign up flow to get to a loaded list state
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["services.sync.engine.tabs", true]],
|
||||
});
|
||||
|
||||
Services.obs.notifyObservers(null, UIState.ON_UPDATE);
|
||||
const recentFetchTime = Math.floor(Date.now() / 1000);
|
||||
info("updating lastFetch:" + recentFetchTime);
|
||||
Services.prefs.setIntPref("services.sync.lastTabFetch", recentFetchTime);
|
||||
|
||||
await waitForElementVisible(browser, "#tabpickup-steps", false);
|
||||
await waitForElementVisible(browser, "#tabpickup-tabs-container", true);
|
||||
|
||||
const tabsContainer = browser.contentWindow.document.querySelector(
|
||||
"#tabpickup-tabs-container"
|
||||
);
|
||||
await BrowserTestUtils.waitForMutationCondition(
|
||||
tabsContainer,
|
||||
{ attributeFilter: ["class"], attributes: true },
|
||||
() => {
|
||||
return !tabsContainer.classList.contains("loading");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
sandbox.restore();
|
||||
Services.prefs.clearUserPref("services.sync.engine.tabs");
|
||||
Services.prefs.clearUserPref("services.sync.lastTabFetch");
|
||||
}
|
||||
|
@ -84,12 +193,7 @@ add_task(async function test_tab_list_ordering() {
|
|||
async browser => {
|
||||
const { document } = browser.contentWindow;
|
||||
|
||||
const sandbox = setupRecentDeviceListMocks();
|
||||
const syncedTabsMock = sandbox.stub(SyncedTabs, "getRecentTabs");
|
||||
let mockTabs1 = getMockTabData(syncedTabsData1);
|
||||
let mockTabs2 = getMockTabData(syncedTabsData2);
|
||||
syncedTabsMock.returns(mockTabs1);
|
||||
|
||||
setupMocks(syncedTabsData1, syncedTabsData2);
|
||||
await setupListState(browser);
|
||||
|
||||
testVisibility(browser, {
|
||||
|
@ -117,7 +221,6 @@ add_task(async function test_tab_list_ordering() {
|
|||
"Last list item in synced-tabs-list is in the correct order"
|
||||
);
|
||||
|
||||
syncedTabsMock.returns(mockTabs2);
|
||||
// Initiate a synced tabs update
|
||||
Services.obs.notifyObservers(null, "services.sync.tabs.changed");
|
||||
|
||||
|
@ -147,8 +250,6 @@ add_task(async function test_tab_list_ordering() {
|
|||
.children[2].textContent.includes("Internet for people, not profits"),
|
||||
"Last list item in synced-tabs-list has been updated"
|
||||
);
|
||||
|
||||
sandbox.restore();
|
||||
cleanup();
|
||||
}
|
||||
);
|
||||
|
@ -163,12 +264,7 @@ add_task(async function test_empty_list_items() {
|
|||
async browser => {
|
||||
const { document } = browser.contentWindow;
|
||||
|
||||
const sandbox = setupRecentDeviceListMocks();
|
||||
const syncedTabsMock = sandbox.stub(SyncedTabs, "getRecentTabs");
|
||||
let mockTabs1 = getMockTabData(syncedTabsData3);
|
||||
let mockTabs2 = getMockTabData(syncedTabsData4);
|
||||
syncedTabsMock.returns(mockTabs1);
|
||||
|
||||
setupMocks(syncedTabsData3, syncedTabsData4);
|
||||
await setupListState(browser);
|
||||
|
||||
testVisibility(browser, {
|
||||
|
@ -203,7 +299,6 @@ add_task(async function test_empty_list_items() {
|
|||
"Last list item in synced-tabs-list should be a placeholder"
|
||||
);
|
||||
|
||||
syncedTabsMock.returns(mockTabs2);
|
||||
// Initiate a synced tabs update
|
||||
Services.obs.notifyObservers(null, "services.sync.tabs.changed");
|
||||
|
||||
|
@ -232,7 +327,6 @@ add_task(async function test_empty_list_items() {
|
|||
"Last list item in synced-tabs-list has been updated"
|
||||
);
|
||||
|
||||
sandbox.restore();
|
||||
cleanup();
|
||||
}
|
||||
);
|
||||
|
@ -247,12 +341,7 @@ add_task(async function test_empty_list() {
|
|||
async browser => {
|
||||
const { document } = browser.contentWindow;
|
||||
|
||||
const sandbox = setupRecentDeviceListMocks();
|
||||
const syncedTabsMock = sandbox.stub(SyncedTabs, "getRecentTabs");
|
||||
let mockTabs1 = getMockTabData([]);
|
||||
let mockTabs2 = getMockTabData(syncedTabsData4);
|
||||
syncedTabsMock.returns(mockTabs1);
|
||||
|
||||
setupMocks([], syncedTabsData4);
|
||||
await setupListState(browser);
|
||||
|
||||
testVisibility(browser, {
|
||||
|
@ -269,7 +358,6 @@ add_task(async function test_empty_list() {
|
|||
"collapsible container should have correct styling when the list is empty"
|
||||
);
|
||||
|
||||
syncedTabsMock.returns(mockTabs2);
|
||||
// Initiate a synced tabs update
|
||||
Services.obs.notifyObservers(null, "services.sync.tabs.changed");
|
||||
|
||||
|
@ -287,7 +375,6 @@ add_task(async function test_empty_list() {
|
|||
},
|
||||
});
|
||||
|
||||
sandbox.restore();
|
||||
cleanup();
|
||||
}
|
||||
);
|
||||
|
@ -306,11 +393,7 @@ add_task(async function test_time_updates_correctly() {
|
|||
async browser => {
|
||||
const { document } = browser.contentWindow;
|
||||
|
||||
const sandbox = setupRecentDeviceListMocks();
|
||||
const syncedTabsMock = sandbox.stub(SyncedTabs, "getRecentTabs");
|
||||
let mockTabs1 = getMockTabData(syncedTabsData5);
|
||||
syncedTabsMock.returns(mockTabs1);
|
||||
|
||||
setupMocks(syncedTabsData5, []);
|
||||
await setupListState(browser);
|
||||
|
||||
ok(
|
||||
|
@ -336,7 +419,6 @@ add_task(async function test_time_updates_correctly() {
|
|||
"synced-tab-li-time text has updated"
|
||||
);
|
||||
|
||||
sandbox.restore();
|
||||
cleanup();
|
||||
await SpecialPowers.popPrefEnv();
|
||||
}
|
||||
|
|
|
@ -1,62 +1,6 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const { UIState } = ChromeUtils.import("resource://services-sync/UIState.jsm");
|
||||
const { sinon } = ChromeUtils.import("resource://testing-common/Sinon.jsm");
|
||||
const { TabsSetupFlowManager } = ChromeUtils.importESModule(
|
||||
"resource:///modules/firefox-view-tabs-setup-manager.sys.mjs"
|
||||
);
|
||||
|
||||
const syncedTabsData1 = [
|
||||
{
|
||||
id: 1,
|
||||
type: "client",
|
||||
name: "My desktop",
|
||||
clientType: "desktop",
|
||||
lastModified: 1655730486760,
|
||||
tabs: [
|
||||
{
|
||||
type: "tab",
|
||||
title: "Sandboxes - Sinon.JS",
|
||||
url: "https://sinonjs.org/releases/latest/sandbox/",
|
||||
icon: "https://sinonjs.org/assets/images/favicon.png",
|
||||
lastUsed: 1655391592, // Thu Jun 16 2022 14:59:52 GMT+0000
|
||||
},
|
||||
{
|
||||
type: "tab",
|
||||
title: "Internet for people, not profits - Mozilla",
|
||||
url: "https://www.mozilla.org/",
|
||||
icon:
|
||||
"https://www.mozilla.org/media/img/favicons/mozilla/favicon.d25d81d39065.ico",
|
||||
lastUsed: 1655730486, // Mon Jun 20 2022 13:08:06 GMT+0000
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
type: "client",
|
||||
name: "My iphone",
|
||||
clientType: "mobile",
|
||||
lastModified: 1655727832930,
|
||||
tabs: [
|
||||
{
|
||||
type: "tab",
|
||||
title: "The Guardian",
|
||||
url: "https://www.theguardian.com/",
|
||||
icon: "page-icon:https://www.theguardian.com/",
|
||||
lastUsed: 1655291890, // Wed Jun 15 2022 11:18:10 GMT+0000
|
||||
},
|
||||
{
|
||||
type: "tab",
|
||||
title: "The Times",
|
||||
url: "https://www.thetimes.co.uk/",
|
||||
icon: "page-icon:https://www.thetimes.co.uk/",
|
||||
lastUsed: 1655727485, // Mon Jun 20 2022 12:18:05 GMT+0000
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
/* eslint-disable no-unused-vars */
|
||||
function testVisibility(browser, expected) {
|
||||
const { document } = browser.contentWindow;
|
||||
|
@ -92,84 +36,3 @@ async function waitForElementVisible(browser, selector, isVisible = true) {
|
|||
}
|
||||
);
|
||||
}
|
||||
|
||||
async function addFirefoxViewButtonToToolbar() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["browser.tabs.firefox-view", true]],
|
||||
});
|
||||
info(Services.prefs.getBoolPref("browser.tabs.firefox-view", false));
|
||||
CustomizableUI.addWidgetToArea(
|
||||
"firefox-view-button",
|
||||
CustomizableUI.AREA_TABSTRIP,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
function removeFirefoxViewButtonFromToolbar() {
|
||||
CustomizableUI.removeWidgetFromArea("firefox-view-button");
|
||||
}
|
||||
|
||||
function setupRecentDeviceListMocks() {
|
||||
const sandbox = sinon.createSandbox();
|
||||
sandbox.stub(fxAccounts.device, "recentDeviceList").get(() => [
|
||||
{
|
||||
id: 1,
|
||||
name: "My desktop",
|
||||
isCurrentDevice: true,
|
||||
type: "desktop",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "My iphone",
|
||||
type: "mobile",
|
||||
},
|
||||
]);
|
||||
|
||||
sandbox.stub(UIState, "get").returns({
|
||||
status: UIState.STATUS_SIGNED_IN,
|
||||
syncEnabled: true,
|
||||
});
|
||||
|
||||
return sandbox;
|
||||
}
|
||||
|
||||
function getMockTabData(clients) {
|
||||
let tabs = [];
|
||||
|
||||
for (let client of clients) {
|
||||
for (let tab of client.tabs) {
|
||||
tab.device = client.name;
|
||||
tab.deviceType = client.clientType;
|
||||
}
|
||||
tabs = [...tabs, ...client.tabs.reverse()];
|
||||
}
|
||||
tabs = tabs.sort((a, b) => b.lastUsed - a.lastUsed).slice(0, 3);
|
||||
|
||||
return tabs;
|
||||
}
|
||||
|
||||
async function setupListState(browser) {
|
||||
// Skip the synced tabs sign up flow to get to a loaded list state
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [["services.sync.engine.tabs", true]],
|
||||
});
|
||||
|
||||
Services.obs.notifyObservers(null, UIState.ON_UPDATE);
|
||||
const recentFetchTime = Math.floor(Date.now() / 1000);
|
||||
info("updating lastFetch:" + recentFetchTime);
|
||||
Services.prefs.setIntPref("services.sync.lastTabFetch", recentFetchTime);
|
||||
|
||||
await waitForElementVisible(browser, "#tabpickup-steps", false);
|
||||
await waitForElementVisible(browser, "#tabpickup-tabs-container", true);
|
||||
|
||||
const tabsContainer = browser.contentWindow.document.querySelector(
|
||||
"#tabpickup-tabs-container"
|
||||
);
|
||||
await BrowserTestUtils.waitForMutationCondition(
|
||||
tabsContainer,
|
||||
{ attributeFilter: ["class"], attributes: true },
|
||||
() => {
|
||||
return !tabsContainer.classList.contains("loading");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
#TabsToolbar:not(:-moz-lwtheme),
|
||||
#TabsToolbar[brighttext]:not(:-moz-lwtheme) {
|
||||
--tab-attention-icon-color: AccentColor;
|
||||
--attention-icon-color: AccentColor;
|
||||
}
|
||||
|
||||
:root:-moz-lwtheme {
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
/* --tabpanel-background-color matches $in-content-page-background in newtab
|
||||
(browser/components/newtab/content-src/styles/_variables.scss) */
|
||||
--tabpanel-background-color: #F9F9FB;
|
||||
--tab-attention-icon-color: var(--lwt-tab-attention-icon-color, rgb(42,195,162));
|
||||
}
|
||||
|
||||
#tabbrowser-tabpanels browser {
|
||||
|
@ -624,14 +623,17 @@
|
|||
|
||||
/* Pinned tabs */
|
||||
|
||||
toolbar[brighttext] {
|
||||
--tab-attention-icon-color: var(--lwt-tab-attention-icon-color, rgb(84,255,189));
|
||||
#TabsToolbar {
|
||||
--attention-icon-color: var(--lwt-tab-attention-icon-color, rgb(42,195,162));
|
||||
}
|
||||
|
||||
#TabsToolbar[brighttext] {
|
||||
--attention-icon-color: var(--lwt-tab-attention-icon-color, rgb(84,255,189));
|
||||
}
|
||||
|
||||
.tabbrowser-tab:is([image], [pinned]) > .tab-stack > .tab-content[attention]:not([selected="true"]),
|
||||
.tabbrowser-tab > .tab-stack > .tab-content[pinned][titlechanged]:not([selected="true"]),
|
||||
#firefox-view-button[attention="true"] {
|
||||
background-image: radial-gradient(circle, var(--tab-attention-icon-color), var(--tab-attention-icon-color) 2px, transparent 2px);
|
||||
.tabbrowser-tab > .tab-stack > .tab-content[pinned][titlechanged]:not([selected="true"]) {
|
||||
background-image: radial-gradient(circle, var(--attention-icon-color), var(--attention-icon-color) 2px, transparent 2px);
|
||||
background-position: center bottom calc(6.5px + var(--tabs-navbar-shadow-size));
|
||||
background-size: 4px 4px;
|
||||
background-repeat: no-repeat;
|
||||
|
@ -691,23 +693,6 @@ toolbar[brighttext] {
|
|||
display: none;
|
||||
}
|
||||
|
||||
toolbar:not(#TabsToolbar) #firefox-view-button {
|
||||
background-position: top 25% right 25%;
|
||||
}
|
||||
|
||||
:is(#widget-overflow-mainView, #widget-overflow-fixed-list) #firefox-view-button {
|
||||
background-position: top 25% left 22px;
|
||||
}
|
||||
|
||||
/* RTL notification dot */
|
||||
toolbar:not(#TabsToolbar) #firefox-view-button:-moz-locale-dir(rtl) {
|
||||
background-position-x: left 25%;
|
||||
}
|
||||
|
||||
:is(#widget-overflow-mainView, #widget-overflow-fixed-list) #firefox-view-button:-moz-locale-dir(rtl) {
|
||||
background-position-x: right 22px;
|
||||
}
|
||||
|
||||
/* Tab bar scroll arrows */
|
||||
|
||||
#tabbrowser-arrowscrollbox::part(scrollbutton-up),
|
||||
|
|
|
@ -292,19 +292,4 @@ var SyncedTabs = {
|
|||
extraOptions
|
||||
);
|
||||
},
|
||||
|
||||
async getRecentTabs(maxCount) {
|
||||
let tabs = [];
|
||||
let clients = await this.getTabClients();
|
||||
|
||||
for (let client of clients) {
|
||||
for (let tab of client.tabs) {
|
||||
tab.device = client.name;
|
||||
tab.deviceType = client.clientType;
|
||||
}
|
||||
tabs = [...tabs, ...client.tabs.reverse()];
|
||||
}
|
||||
tabs = tabs.sort((a, b) => b.lastUsed - a.lastUsed).slice(0, maxCount);
|
||||
return tabs;
|
||||
},
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче