Bug 1525174 - Plugin active states for HTML about:addons r=kmag,flod

Differential Revision: https://phabricator.services.mozilla.com/D27967

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Mark Striemer 2019-04-27 00:30:48 +00:00
parent c2c49c5b01
commit cc261e9e4a
6 changed files with 225 additions and 34 deletions

View File

@ -352,6 +352,10 @@ expand-addon-button = More Options
addons-enabled-heading = Enabled
addons-disabled-heading = Disabled
ask-to-activate-button = Ask to Activate
always-activate-button = Always Activate
never-activate-button = Never Activate
addon-detail-author-label = Author
addon-detail-version-label = Version
addon-detail-last-updated-label = Last Updated

View File

@ -14,6 +14,26 @@
<div id="main">
</div>
<template name="addon-options">
<panel-list>
<panel-item action="toggle-disabled"></panel-item>
<panel-item data-l10n-id="remove-addon-button" action="remove"></panel-item>
<panel-item data-l10n-id="install-update-button" action="install-update" badged></panel-item>
<panel-item-separator></panel-item-separator>
<panel-item data-l10n-id="expand-addon-button" action="expand"></panel-item>
</panel-list>
</template>
<template name="plugin-options">
<panel-list>
<panel-item data-l10n-id="ask-to-activate-button" action="ask-to-activate"></panel-item>
<panel-item data-l10n-id="always-activate-button" action="always-activate"></panel-item>
<panel-item data-l10n-id="never-activate-button" action="never-activate"></panel-item>
<panel-item-separator></panel-item-separator>
<panel-item data-l10n-id="expand-addon-button" action="expand"></panel-item>
</panel-list>
</template>
<template name="card">
<div class="card addon">
<img class="card-heading-image">
@ -30,13 +50,6 @@
</div>
<div class="more-options-menu">
<button class="more-options-button ghost-button" action="more-options"></button>
<panel-list>
<panel-item action="toggle-disabled"></panel-item>
<panel-item data-l10n-id="remove-addon-button" action="remove"></panel-item>
<panel-item data-l10n-id="install-update-button" action="install-update" badged></panel-item>
<panel-item-separator></panel-item-separator>
<panel-item data-l10n-id="expand-addon-button" action="expand"></panel-item>
</panel-list>
</div>
</div>
</div>

View File

@ -22,8 +22,11 @@ XPCOMUtils.defineLazyPreferenceGetter(
const PLUGIN_ICON_URL = "chrome://global/skin/plugins/pluginGeneric.svg";
const PERMISSION_MASKS = {
"ask-to-activate": AddonManager.PERM_CAN_ASK_TO_ACTIVATE,
enable: AddonManager.PERM_CAN_ENABLE,
"always-activate": AddonManager.PERM_CAN_ENABLE,
disable: AddonManager.PERM_CAN_DISABLE,
"never-activate": AddonManager.PERM_CAN_DISABLE,
uninstall: AddonManager.PERM_CAN_UNINSTALL,
upgrade: AddonManager.PERM_CAN_UPGRADE,
};
@ -320,10 +323,104 @@ class PanelItem extends HTMLElement {
super();
this.attachShadow({mode: "open"});
this.shadowRoot.appendChild(importTemplate("panel-item"));
this.button = this.shadowRoot.querySelector("button");
}
get disabled() {
return this.button.hasAttribute("disabled");
}
set disabled(val) {
if (val) {
this.button.setAttribute("disabled", "");
} else {
this.button.removeAttribute("disabled");
}
}
get checked() {
return this.hasAttribute("checked");
}
set checked(val) {
if (val) {
this.setAttribute("checked", "");
} else {
this.removeAttribute("checked");
}
}
}
customElements.define("panel-item", PanelItem);
class AddonOptions extends HTMLElement {
connectedCallback() {
if (this.children.length == 0) {
this.render();
}
}
render() {
this.appendChild(importTemplate("addon-options"));
}
update(card, addon, updateInstall) {
// Hide remove button if not allowed.
let removeButton = this.querySelector('[action="remove"]');
removeButton.hidden = !hasPermission(addon, "uninstall");
// Set disable label and hide if not allowed.
let toggleDisabledButton = this.querySelector('[action="toggle-disabled"]');
let toggleDisabledAction = addon.userDisabled ? "enable" : "disable";
document.l10n.setAttributes(
toggleDisabledButton, `${toggleDisabledAction}-addon-button`);
toggleDisabledButton.hidden = !hasPermission(addon, toggleDisabledAction);
// Set the update button and badge the menu if there's an update.
this.querySelector('[action="install-update"]').hidden = !updateInstall;
// The separator isn't needed when expanded (nothing under it) or when the
// remove and disable buttons are hidden (nothing above it).
let separator = this.querySelector("panel-item-separator");
separator.hidden = card.expanded ||
removeButton.hidden && toggleDisabledButton.hidden;
// Hide the expand button if we're expanded.
this.querySelector('[action="expand"]').hidden = card.expanded;
}
}
customElements.define("addon-options", AddonOptions);
class PluginOptions extends HTMLElement {
connectedCallback() {
if (this.children.length == 0) {
this.render();
}
}
render() {
this.appendChild(importTemplate("plugin-options"));
}
update(card, addon) {
let actions = [{
action: "ask-to-activate",
userDisabled: AddonManager.STATE_ASK_TO_ACTIVATE,
}, {
action: "always-activate",
userDisabled: false,
}, {
action: "never-activate",
userDisabled: true,
}];
for (let {action, userDisabled} of actions) {
let el = this.querySelector(`[action="${action}"]`);
el.checked = addon.userDisabled === userDisabled;
el.disabled = !(el.checked || hasPermission(addon, action));
}
}
}
customElements.define("plugin-options", PluginOptions);
class AddonDetails extends HTMLElement {
connectedCallback() {
if (this.children.length == 0) {
@ -589,6 +686,17 @@ class AddonCard extends HTMLElement {
this.querySelector('[action="more-options"]').focus();
}
break;
case "ask-to-activate":
if (hasPermission(addon, "ask-to-activate")) {
addon.userDisabled = AddonManager.STATE_ASK_TO_ACTIVATE;
}
break;
case "always-activate":
addon.userDisabled = false;
break;
case "never-activate":
addon.userDisabled = true;
break;
case "update-check":
let listener = {
onUpdateAvailable(addon, install) {
@ -725,6 +833,8 @@ class AddonCard extends HTMLElement {
onPropertyChanged(addon, changed) {
if (this.details && changed.includes("applyBackgroundUpdates")) {
this.details.update();
} else if (addon.type == "plugin" && changed.includes("userDisabled")) {
this.update();
}
}
@ -767,6 +877,13 @@ class AddonCard extends HTMLElement {
}
name.title = `${addon.name} ${addon.version}`;
// Set the items in the more options menu.
this.options.update(this, addon, this.updateInstall);
// Badge the more options menu if there's an update.
card.querySelector(".more-options-button")
.classList.toggle("more-options-button-badged", !!this.updateInstall);
// Set the private browsing badge visibility.
if (!allowPrivateBrowsingByDefault && addon.type == "extension" &&
addon.incognito != "not_allowed") {
@ -780,32 +897,6 @@ class AddonCard extends HTMLElement {
// Update description.
card.querySelector(".addon-description").textContent = addon.description;
// Hide remove button if not allowed.
let removeButton = card.querySelector('[action="remove"]');
removeButton.hidden = !hasPermission(addon, "uninstall");
// Set disable label and hide if not allowed.
let disableButton = card.querySelector('[action="toggle-disabled"]');
let disableAction = addon.userDisabled ? "enable" : "disable";
document.l10n.setAttributes(
disableButton, `${disableAction}-addon-button`);
disableButton.hidden = !hasPermission(addon, disableAction);
// Set the update button and badge the menu if there's an update.
card.querySelector('[action="install-update"]').hidden =
!this.updateInstall;
card.querySelector(".more-options-button")
.classList.toggle("more-options-button-badged", !!this.updateInstall);
// The separator isn't needed when expanded (nothing under it) or when the
// remove and disable buttons are hidden (nothing above it).
let separator = card.querySelector("panel-item-separator");
separator.hidden = this.expanded ||
removeButton.hidden && disableButton.hidden;
// Hide the expand button if we're expanded.
card.querySelector('[action="expand"]').hidden = this.expanded;
// Update the details if they're shown.
if (this.details) {
this.details.update();
@ -833,6 +924,11 @@ class AddonCard extends HTMLElement {
this.card = importTemplate("card").firstElementChild;
this.setAttribute("addon-id", addon.id);
let panelType = addon.type == "plugin" ? "plugin-options" : "addon-options";
this.options = document.createElement(panelType);
this.options.render();
this.card.querySelector(".more-options-menu").appendChild(this.options);
// Set the contents.
this.update();

View File

@ -27,8 +27,12 @@ button {
left: 28px;
}
:host([checked]) {
--icon: url("chrome://global/skin/icons/check.svg");
}
button:focus,
button:hover {
button:not([disabled]):hover {
background-color: var(--in-content-button-background);
}

View File

@ -77,6 +77,7 @@ skip-if = true # Bug 1449071 - Frequent failures
skip-if = os == 'linux' && !debug # Bug 1398766
[browser_html_detail_view.js]
[browser_html_list_view.js]
[browser_html_plugins.js]
[browser_html_updates.js]
[browser_inlinesettings_browser.js]
skip-if = os == 'mac' || os == 'linux' # Bug 1483347

View File

@ -0,0 +1,73 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const TEST_PLUGIN_DESCRIPTION = "Flash plug-in for testing purposes.";
add_task(async function enableHtmlViews() {
await SpecialPowers.pushPrefEnv({
set: [["extensions.htmlaboutaddons.enabled", true]],
});
});
function checkItems(items, checked) {
for (let item of items) {
let action = item.getAttribute("action");
ok(!item.disabled, `${action} is enabled`);
if (action == checked) {
ok(item.checked, `${action} is checked`);
} else {
ok(!item.checked, `${action} isn't checked`);
}
}
}
add_task(async function testAskToActivate() {
let plugins = await AddonManager.getAddonsByTypes(["plugin"]);
let flash = plugins.find(
plugin => plugin.description == TEST_PLUGIN_DESCRIPTION);
let win = await loadInitialView("plugin");
let doc = win.document;
let card = doc.querySelector(`addon-card[addon-id="${flash.id}"]`);
let panelItems = Array.from(card.querySelectorAll("panel-item"));
let actions = panelItems.map(item => item.getAttribute("action"));
Assert.deepEqual(
actions, ["ask-to-activate", "always-activate", "never-activate", "expand"],
"The panel items are for a plugin");
checkItems(panelItems, "ask-to-activate");
is(flash.userDisabled, AddonManager.STATE_ASK_TO_ACTIVATE,
"Flash is ask-to-activate");
ok(flash.isActive, "Flash is active");
// Switch the plugin to always activate.
let updated = BrowserTestUtils.waitForEvent(card, "update");
panelItems[1].click();
await updated;
checkItems(panelItems, "always-activate");
ok(flash.userDisabled != AddonManager.STATE_ASK_TO_ACTIVATE,
"Flash isn't ask-to-activate");
ok(flash.isActive, "Flash is still active");
// Switch to never activate.
updated = BrowserTestUtils.waitForEvent(card, "update");
panelItems[2].click();
await updated;
checkItems(panelItems, "never-activate");
ok(flash.userDisabled, `Flash is not userDisabled... for some reason`);
ok(!flash.isActive, "Flash isn't active");
// Switch it back to ask to activate.
updated = BrowserTestUtils.waitForEvent(card, "update");
panelItems[0].click();
await updated;
checkItems(panelItems, "ask-to-activate");
is(flash.userDisabled, AddonManager.STATE_ASK_TO_ACTIVATE,
"Flash is ask-to-activate");
ok(flash.isActive, "Flash is active");
await closeView(win);
});