зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1777343 - Implement simple origin controls attention indicator, r=willdurand,desktop-theme-reviewers,Itiel
Differential Revision: https://phabricator.services.mozilla.com/D158476
This commit is contained in:
Родитель
1778c775fe
Коммит
28b6c5c09f
|
@ -1335,6 +1335,12 @@ customElements.define(
|
|||
|
||||
this.setAttribute("extension-id", this.addon.id);
|
||||
|
||||
let policy = WebExtensionPolicy.getByID(this.addon.id);
|
||||
this.setAttribute(
|
||||
"attention",
|
||||
lazy.OriginControls.getAttention(policy, this.ownerGlobal)
|
||||
);
|
||||
|
||||
this.querySelector(
|
||||
".unified-extensions-item-name"
|
||||
).textContent = this.addon.name;
|
||||
|
|
|
@ -36,6 +36,11 @@ ChromeUtils.defineModuleGetter(
|
|||
"BrowserUsageTelemetry",
|
||||
"resource:///modules/BrowserUsageTelemetry.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"OriginControls",
|
||||
"resource://gre/modules/ExtensionPermissions.jsm"
|
||||
);
|
||||
|
||||
var { DefaultWeakMap } = ExtensionUtils;
|
||||
|
||||
|
@ -249,7 +254,7 @@ this.browserAction = class extends ExtensionAPIPersistent {
|
|||
node.onmouseout = event => this.handleEvent(event);
|
||||
node.onauxclick = event => this.handleEvent(event);
|
||||
|
||||
this.updateButton(node, this.action.getContextData(null), true);
|
||||
this.updateButton(node, this.action.getContextData(null), true, false);
|
||||
},
|
||||
|
||||
onBeforeCommand: event => {
|
||||
|
@ -566,12 +571,14 @@ this.browserAction = class extends ExtensionAPIPersistent {
|
|||
|
||||
// Update the toolbar button |node| with the tab context data
|
||||
// in |tabData|.
|
||||
updateButton(node, tabData, sync = false) {
|
||||
updateButton(node, tabData, sync = false, attention = false) {
|
||||
let title = tabData.title || this.extension.name;
|
||||
let callback = () => {
|
||||
node.setAttribute("tooltiptext", title);
|
||||
node.setAttribute("label", title);
|
||||
|
||||
node.setAttribute("attention", attention);
|
||||
|
||||
if (tabData.badgeText) {
|
||||
node.setAttribute("badge", tabData.badgeText);
|
||||
} else {
|
||||
|
@ -640,7 +647,12 @@ this.browserAction = class extends ExtensionAPIPersistent {
|
|||
let node = this.widget.forWindow(window).node;
|
||||
if (node) {
|
||||
let tab = window.gBrowser.selectedTab;
|
||||
this.updateButton(node, this.action.getContextData(tab));
|
||||
this.updateButton(
|
||||
node,
|
||||
this.action.getContextData(tab),
|
||||
false,
|
||||
OriginControls.getAttention(this.extension.policy, window)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -57,24 +57,27 @@ async function makeExtension({ id, permissions, host_permissions, granted }) {
|
|||
async function testOriginControls(
|
||||
extension,
|
||||
{ win, contextMenuId },
|
||||
{ items, selected, click, granted, revoked }
|
||||
{ items, selected, click, granted, revoked, attention }
|
||||
) {
|
||||
info(
|
||||
`Testing ${extension.id} on ${gBrowser.currentURI.spec} with contextMenuId=${contextMenuId}.`
|
||||
);
|
||||
|
||||
let button;
|
||||
let menu;
|
||||
let manageExtensionClassName;
|
||||
|
||||
switch (contextMenuId) {
|
||||
case "toolbar-context-menu":
|
||||
let target = `#${CSS.escape(makeWidgetId(extension.id))}-browser-action`;
|
||||
button = win.document.querySelector(target);
|
||||
menu = await openChromeContextMenu(contextMenuId, target);
|
||||
manageExtensionClassName = "customize-context-manageExtension";
|
||||
break;
|
||||
|
||||
case "unified-extensions-context-menu":
|
||||
await openExtensionsPanel(win);
|
||||
button = getUnifiedExtensionsItem(win, extension.id);
|
||||
menu = await openUnifiedExtensionsContextMenu(win, extension.id);
|
||||
manageExtensionClassName =
|
||||
"unified-extensions-context-menu-manage-extension";
|
||||
|
@ -102,6 +105,12 @@ async function testOriginControls(
|
|||
"All items accounted for."
|
||||
);
|
||||
|
||||
is(
|
||||
button.getAttribute("attention"),
|
||||
attention ? "true" : "false",
|
||||
"Expected attention badge before clicking."
|
||||
);
|
||||
|
||||
let itemToClick;
|
||||
if (click) {
|
||||
itemToClick = menu.children[click];
|
||||
|
@ -178,18 +187,21 @@ const originControlsInContextMenu = async options => {
|
|||
await testOriginControls(ext2, options, {
|
||||
items: [ACCESS_OPTIONS, WHEN_CLICKED],
|
||||
selected: 1,
|
||||
attention: true,
|
||||
});
|
||||
|
||||
// Could access mochi.test when clicked.
|
||||
await testOriginControls(ext3, options, {
|
||||
items: [ACCESS_OPTIONS, WHEN_CLICKED, ALWAYS_ON],
|
||||
selected: 1,
|
||||
attention: true,
|
||||
});
|
||||
|
||||
// Has <all_urls> granted.
|
||||
await testOriginControls(ext4, options, {
|
||||
items: [ACCESS_OPTIONS, ALL_SITES],
|
||||
selected: 1,
|
||||
attention: false,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -206,16 +218,19 @@ const originControlsInContextMenu = async options => {
|
|||
items: [ACCESS_OPTIONS, WHEN_CLICKED, ALWAYS_ON],
|
||||
selected: 1,
|
||||
click: 1,
|
||||
attention: true,
|
||||
});
|
||||
await testOriginControls(ext3, options, {
|
||||
items: [ACCESS_OPTIONS, WHEN_CLICKED, ALWAYS_ON],
|
||||
selected: 2,
|
||||
click: 2,
|
||||
attention: false,
|
||||
});
|
||||
await testOriginControls(ext4, options, {
|
||||
items: [ACCESS_OPTIONS, ALL_SITES],
|
||||
selected: 1,
|
||||
click: 1,
|
||||
attention: false,
|
||||
});
|
||||
|
||||
// Click the other option, expect example.com permission granted/revoked.
|
||||
|
@ -224,22 +239,26 @@ const originControlsInContextMenu = async options => {
|
|||
selected: 1,
|
||||
click: 2,
|
||||
granted: ["*://example.com/*"],
|
||||
attention: true,
|
||||
});
|
||||
await testOriginControls(ext3, options, {
|
||||
items: [ACCESS_OPTIONS, WHEN_CLICKED, ALWAYS_ON],
|
||||
selected: 2,
|
||||
click: 1,
|
||||
revoked: ["*://example.com/*"],
|
||||
attention: false,
|
||||
});
|
||||
|
||||
// Other option is now selected.
|
||||
await testOriginControls(ext2, options, {
|
||||
items: [ACCESS_OPTIONS, WHEN_CLICKED, ALWAYS_ON],
|
||||
selected: 2,
|
||||
attention: false,
|
||||
});
|
||||
await testOriginControls(ext3, options, {
|
||||
items: [ACCESS_OPTIONS, WHEN_CLICKED, ALWAYS_ON],
|
||||
selected: 1,
|
||||
attention: true,
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -4,11 +4,33 @@
|
|||
|
||||
/* Style for the custom element "unified-extensions-item". */
|
||||
|
||||
:root {
|
||||
--icon-size: 32px;
|
||||
--dot-position: calc(var(--icon-size) / 2 + var(--arrowpanel-menuitem-margin-inline) + var(--arrowpanel-menuitem-padding-inline) - 4px);
|
||||
}
|
||||
|
||||
:root[uidensity="compact"] {
|
||||
--icon-size: 24px;
|
||||
}
|
||||
|
||||
unified-extensions-item {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
/* Larger attention indicator for use below larger icons, see for reference:
|
||||
* https://searchfox.org/mozilla-central/rev/560b7b1b17/browser/themes/shared/tabs.css#624 */
|
||||
unified-extensions-item[attention="true"] {
|
||||
background-image: radial-gradient(circle, var(--tab-attention-icon-color), var(--tab-attention-icon-color) 3px, transparent 3px);
|
||||
background-position: left var(--dot-position) bottom 3px;
|
||||
background-size: 8px 8px;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
unified-extensions-item[attention="true"]:-moz-locale-dir(rtl) {
|
||||
background-position-x: right var(--dot-position);
|
||||
}
|
||||
|
||||
.unified-extensions-item-action {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
@ -33,8 +55,8 @@ unified-extensions-item[secondary-button-hovered="true"] .unified-extensions-ite
|
|||
}
|
||||
|
||||
.unified-extensions-item-icon {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
height: var(--icon-size);
|
||||
width: var(--icon-size);
|
||||
margin-inline-end: 6px;
|
||||
}
|
||||
|
||||
|
|
|
@ -621,13 +621,18 @@ toolbar[brighttext] {
|
|||
|
||||
.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] {
|
||||
#firefox-view-button[attention],
|
||||
.webextension-browser-action[attention="true"] {
|
||||
background-image: radial-gradient(circle, var(--tab-attention-icon-color), var(--tab-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;
|
||||
}
|
||||
|
||||
:root[uidensity="compact"] .webextension-browser-action[attention="true"] {
|
||||
background-position-y: bottom 4.5px;
|
||||
}
|
||||
|
||||
.tabbrowser-tab[image] > .tab-stack > .tab-content[attention]:not([pinned], [selected="true"]) {
|
||||
background-position-x: left 14px;
|
||||
}
|
||||
|
|
|
@ -62,6 +62,11 @@ class PanelActionBase {
|
|||
this.updateOnChange(tab);
|
||||
});
|
||||
|
||||
// eslint-disable-next-line mozilla/balanced-listeners
|
||||
extension.on("add-permissions", () => this.updateOnChange());
|
||||
// eslint-disable-next-line mozilla/balanced-listeners
|
||||
extension.on("remove-permissions", () => this.updateOnChange());
|
||||
|
||||
// When preloading a popup we temporarily grant active tab permissions to
|
||||
// the preloaded popup. If we don't end up opening we need to clear this
|
||||
// permission when clearing the popup.
|
||||
|
|
|
@ -463,6 +463,12 @@ var OriginControls = {
|
|||
};
|
||||
},
|
||||
|
||||
// Whether to show the attention indicator for extension on current tab.
|
||||
getAttention(policy, window) {
|
||||
let state = this.getState(policy, window.gBrowser.currentURI);
|
||||
return !!state.whenClicked && !state.hasAccess;
|
||||
},
|
||||
|
||||
// Grant extension host permission to always run on this host.
|
||||
setAlwaysOn(policy, uri) {
|
||||
if (!policy.active) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче