зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1691454 - Hide the Page actions overflow (meatball) menu from the address bar. r=adw
The page actions menu is normally hidden. When the window is smaller than a threshold, and there's more than one action, the single actions are hidden while the menu is shown. This allows for a nicer overflow experience. This patch introduces a pageActions-proton test folder where we'll move proton tests temporarily. The head.js file is just a copy of the original one, we'll clean it up in bug 1700582 after porting the other tests. Differential Revision: https://phabricator.services.mozilla.com/D109606
This commit is contained in:
Родитель
0326b528a5
Коммит
c304d1cd46
|
@ -96,6 +96,7 @@ var BrowserPageActions = {
|
|||
for (let action of urlbarActions) {
|
||||
this.placeActionInUrlbar(action);
|
||||
}
|
||||
this._updateMainButtonAttributes();
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -128,6 +129,7 @@ var BrowserPageActions = {
|
|||
placeAction(action) {
|
||||
this.placeActionInPanel(action);
|
||||
this.placeActionInUrlbar(action);
|
||||
this._updateMainButtonAttributes();
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -213,6 +215,13 @@ var BrowserPageActions = {
|
|||
}
|
||||
},
|
||||
|
||||
_updateMainButtonAttributes() {
|
||||
this.mainButtonNode.toggleAttribute(
|
||||
"multiple-children",
|
||||
PageActions.actions.length > 1
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the node before which an action's node should be inserted.
|
||||
*
|
||||
|
@ -545,6 +554,7 @@ var BrowserPageActions = {
|
|||
this._removeActionFromPanel(action);
|
||||
this._removeActionFromUrlbar(action);
|
||||
action.onRemovedFromWindow(window);
|
||||
this._updateMainButtonAttributes();
|
||||
},
|
||||
|
||||
_removeActionFromUrlbar(action) {
|
||||
|
|
|
@ -762,6 +762,15 @@ toolbar:not(#TabsToolbar) > #personal-bookmarks {
|
|||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@supports -moz-bool-pref("browser.proton.urlbar.enabled") {
|
||||
/* The page actions menu is hidden by default, it is only shown in small
|
||||
windows as the overflow target of multiple page action buttons */
|
||||
#pageActionButton {
|
||||
visibility: collapse;
|
||||
}
|
||||
}
|
||||
|
||||
/* 680px is just below half of popular 1366px wide screens, so when putting two
|
||||
browser windows next to each other on such a screen, they'll be above this
|
||||
threshold. */
|
||||
|
@ -769,9 +778,15 @@ toolbar:not(#TabsToolbar) > #personal-bookmarks {
|
|||
/* Page action buttons are duplicated in the page action menu so we can
|
||||
safely hide them in small windows. */
|
||||
#pageActionSeparator,
|
||||
#pageActionButton ~ .urlbar-page-action {
|
||||
#pageActionButton[multiple-children] ~ .urlbar-page-action {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@supports -moz-bool-pref("browser.proton.urlbar.enabled") {
|
||||
#pageActionButton[multiple-children] {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
@media (max-width: 550px) {
|
||||
#urlbar-container {
|
||||
|
|
|
@ -43,7 +43,7 @@ with Files("test/keyboard/**"):
|
|||
with Files("test/outOfProcess/**"):
|
||||
BUG_COMPONENT = ("Firefox", "General")
|
||||
|
||||
with Files("test/pageActions/**"):
|
||||
with Files("test/pageActions*/**"):
|
||||
BUG_COMPONENT = ("Firefox", "Toolbars and Customization")
|
||||
|
||||
with Files("test/pageinfo/**"):
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
extends: ["plugin:mozilla/browser-test"],
|
||||
};
|
|
@ -0,0 +1,7 @@
|
|||
[DEFAULT]
|
||||
prefs =
|
||||
browser.proton.urlbar.enabled=true
|
||||
support-files =
|
||||
head.js
|
||||
|
||||
[browser_PageActions_overflow.js]
|
|
@ -0,0 +1,90 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* https://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
add_task(async function init() {
|
||||
// We use an extension that shows a page action so that we can test the
|
||||
// "remove extension" item in the context menu.
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
name: "Test contextMenu",
|
||||
page_action: { show_matches: ["<all_urls>"] },
|
||||
},
|
||||
|
||||
useAddonManager: "temporary",
|
||||
});
|
||||
|
||||
await extension.startup();
|
||||
let actionId = ExtensionCommon.makeWidgetId(extension.id);
|
||||
|
||||
let win = await BrowserTestUtils.openNewBrowserWindow();
|
||||
await SimpleTest.promiseFocus(win);
|
||||
let originalWindowWidth = win.outerWidth;
|
||||
Assert.greater(originalWindowWidth, 700, "window is bigger than 700px");
|
||||
BrowserTestUtils.loadURI(win.gBrowser, "data:text/html,<h1>A Page</h1>");
|
||||
await BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
|
||||
|
||||
// The pageAction implementation enables the button at the next animation
|
||||
// frame, so before we look for the button we should wait one animation frame
|
||||
// as well.
|
||||
await promiseAnimationFrame(win);
|
||||
|
||||
registerCleanupFunction(async () => {
|
||||
win.resizeTo(originalWindowWidth, win.outerHeight);
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
});
|
||||
|
||||
info("Check page action buttons are visible, the meatball button is not");
|
||||
let addonButton = win.BrowserPageActions.urlbarButtonNodeForActionID(
|
||||
actionId
|
||||
);
|
||||
Assert.ok(BrowserTestUtils.is_visible(addonButton));
|
||||
let starButton = win.BrowserPageActions.urlbarButtonNodeForActionID(
|
||||
"bookmark"
|
||||
);
|
||||
Assert.ok(BrowserTestUtils.is_visible(starButton));
|
||||
let meatballButton = win.document.getElementById("pageActionButton");
|
||||
Assert.ok(!BrowserTestUtils.is_visible(meatballButton));
|
||||
|
||||
info(
|
||||
"Shrink the window, check page action buttons are not visible, the meatball menu is visible"
|
||||
);
|
||||
await promiseStableResize(500, win);
|
||||
Assert.ok(!BrowserTestUtils.is_visible(addonButton));
|
||||
Assert.ok(!BrowserTestUtils.is_visible(starButton));
|
||||
Assert.ok(BrowserTestUtils.is_visible(meatballButton));
|
||||
|
||||
info(
|
||||
"Remove the extension, check the only page action button is visible, the meatball menu is not visible"
|
||||
);
|
||||
let promiseUninstalled = promiseAddonUninstalled(extension.id);
|
||||
await extension.unload();
|
||||
await promiseUninstalled;
|
||||
Assert.ok(BrowserTestUtils.is_visible(starButton));
|
||||
Assert.ok(!BrowserTestUtils.is_visible(meatballButton));
|
||||
Assert.deepEqual(
|
||||
win.BrowserPageActions.urlbarButtonNodeForActionID(actionId),
|
||||
null
|
||||
);
|
||||
});
|
||||
|
||||
// TODO (Bug 1700780): Why is this necessary? Without this trick the test
|
||||
// fails intermittently on Ubuntu.
|
||||
function promiseStableResize(expectedWidth, win = window) {
|
||||
let deferred = PromiseUtils.defer();
|
||||
let id;
|
||||
function listener() {
|
||||
win.clearTimeout(id);
|
||||
info(`Got resize event: ${win.innerWidth} x ${win.innerHeight}`);
|
||||
if (win.innerWidth <= expectedWidth) {
|
||||
id = win.setTimeout(() => {
|
||||
win.removeEventListener("resize", listener);
|
||||
deferred.resolve();
|
||||
}, 100);
|
||||
}
|
||||
}
|
||||
win.addEventListener("resize", listener);
|
||||
win.resizeTo(expectedWidth, win.outerHeight);
|
||||
return deferred.promise;
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
ExtensionCommon: "resource://gre/modules/ExtensionCommon.jsm",
|
||||
PlacesTestUtils: "resource://testing-common/PlacesTestUtils.jsm",
|
||||
});
|
||||
|
||||
function promisePageActionPanelOpen(eventDict = {}) {
|
||||
let dwu = window.windowUtils;
|
||||
return BrowserTestUtils.waitForCondition(() => {
|
||||
// Wait for the main page action button to become visible. It's hidden for
|
||||
// some URIs, so depending on when this is called, it may not yet be quite
|
||||
// visible. It's up to the caller to make sure it will be visible.
|
||||
info("Waiting for main page action button to have non-0 size");
|
||||
let bounds = dwu.getBoundsWithoutFlushing(
|
||||
BrowserPageActions.mainButtonNode
|
||||
);
|
||||
return bounds.width > 0 && bounds.height > 0;
|
||||
})
|
||||
.then(() => {
|
||||
// Wait for the panel to become open, by clicking the button if necessary.
|
||||
info("Waiting for main page action panel to be open");
|
||||
if (BrowserPageActions.panelNode.state == "open") {
|
||||
return Promise.resolve();
|
||||
}
|
||||
let shownPromise = promisePageActionPanelShown();
|
||||
EventUtils.synthesizeMouseAtCenter(
|
||||
BrowserPageActions.mainButtonNode,
|
||||
eventDict
|
||||
);
|
||||
return shownPromise;
|
||||
})
|
||||
.then(() => {
|
||||
// Wait for items in the panel to become visible.
|
||||
return promisePageActionViewChildrenVisible(
|
||||
BrowserPageActions.mainViewNode
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
async function waitForActivatedActionPanel() {
|
||||
if (!BrowserPageActions.activatedActionPanelNode) {
|
||||
info("Waiting for activated-action panel to be added to mainPopupSet");
|
||||
await new Promise(resolve => {
|
||||
let observer = new MutationObserver(mutations => {
|
||||
if (BrowserPageActions.activatedActionPanelNode) {
|
||||
observer.disconnect();
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
let popupSet = document.getElementById("mainPopupSet");
|
||||
observer.observe(popupSet, { childList: true });
|
||||
});
|
||||
info("Activated-action panel added to mainPopupSet");
|
||||
}
|
||||
if (!BrowserPageActions.activatedActionPanelNode.state == "open") {
|
||||
info("Waiting for activated-action panel popupshown");
|
||||
await promisePanelShown(BrowserPageActions.activatedActionPanelNode);
|
||||
info("Got activated-action panel popupshown");
|
||||
}
|
||||
let panelView = BrowserPageActions.activatedActionPanelNode.querySelector(
|
||||
"panelview"
|
||||
);
|
||||
if (panelView) {
|
||||
await BrowserTestUtils.waitForEvent(
|
||||
BrowserPageActions.activatedActionPanelNode,
|
||||
"ViewShown"
|
||||
);
|
||||
await promisePageActionViewChildrenVisible(panelView);
|
||||
}
|
||||
return panelView;
|
||||
}
|
||||
|
||||
function promisePageActionPanelShown() {
|
||||
return promisePanelShown(BrowserPageActions.panelNode);
|
||||
}
|
||||
|
||||
function promisePageActionPanelHidden() {
|
||||
return promisePanelHidden(BrowserPageActions.panelNode);
|
||||
}
|
||||
|
||||
function promisePanelShown(panelIDOrNode) {
|
||||
return promisePanelEvent(panelIDOrNode, "popupshown");
|
||||
}
|
||||
|
||||
function promisePanelHidden(panelIDOrNode) {
|
||||
return promisePanelEvent(panelIDOrNode, "popuphidden");
|
||||
}
|
||||
|
||||
function promisePanelEvent(panelIDOrNode, eventType) {
|
||||
return new Promise(resolve => {
|
||||
let panel = panelIDOrNode;
|
||||
if (typeof panel == "string") {
|
||||
panel = document.getElementById(panelIDOrNode);
|
||||
if (!panel) {
|
||||
throw new Error(`Panel with ID "${panelIDOrNode}" does not exist.`);
|
||||
}
|
||||
}
|
||||
if (
|
||||
(eventType == "popupshown" && panel.state == "open") ||
|
||||
(eventType == "popuphidden" && panel.state == "closed")
|
||||
) {
|
||||
executeSoon(resolve);
|
||||
return;
|
||||
}
|
||||
panel.addEventListener(
|
||||
eventType,
|
||||
() => {
|
||||
executeSoon(resolve);
|
||||
},
|
||||
{ once: true }
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function promisePageActionViewShown() {
|
||||
info("promisePageActionViewShown waiting for ViewShown");
|
||||
return BrowserTestUtils.waitForEvent(
|
||||
BrowserPageActions.panelNode,
|
||||
"ViewShown"
|
||||
).then(async event => {
|
||||
let panelViewNode = event.originalTarget;
|
||||
await promisePageActionViewChildrenVisible(panelViewNode);
|
||||
return panelViewNode;
|
||||
});
|
||||
}
|
||||
|
||||
function promisePageActionViewChildrenVisible(panelViewNode) {
|
||||
return promiseNodeVisible(panelViewNode.firstElementChild.firstElementChild);
|
||||
}
|
||||
|
||||
function promiseNodeVisible(node) {
|
||||
info(
|
||||
`promiseNodeVisible waiting, node.id=${node.id} node.localeName=${node.localName}\n`
|
||||
);
|
||||
let dwu = window.windowUtils;
|
||||
return BrowserTestUtils.waitForCondition(() => {
|
||||
let bounds = dwu.getBoundsWithoutFlushing(node);
|
||||
if (bounds.width > 0 && bounds.height > 0) {
|
||||
info(
|
||||
`promiseNodeVisible OK, node.id=${node.id} node.localeName=${node.localName}\n`
|
||||
);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
function promiseAddonUninstalled(addonId) {
|
||||
return new Promise(resolve => {
|
||||
let listener = {};
|
||||
listener.onUninstalled = addon => {
|
||||
if (addon.id == addonId) {
|
||||
AddonManager.removeAddonListener(listener);
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
AddonManager.addAddonListener(listener);
|
||||
});
|
||||
}
|
||||
|
||||
async function promiseAnimationFrame(win = window) {
|
||||
await new Promise(resolve => win.requestAnimationFrame(resolve));
|
||||
await win.promiseDocumentFlushed(() => {});
|
||||
}
|
|
@ -33,6 +33,7 @@ BROWSER_CHROME_MANIFESTS += [
|
|||
"content/test/menubar/browser.ini",
|
||||
"content/test/metaTags/browser.ini",
|
||||
"content/test/outOfProcess/browser.ini",
|
||||
"content/test/pageActions-proton/browser.ini",
|
||||
"content/test/pageActions/browser.ini",
|
||||
"content/test/pageinfo/browser.ini",
|
||||
"content/test/pageStyle/browser.ini",
|
||||
|
|
Загрузка…
Ссылка в новой задаче