Bug 1570792 - Toggle extension enabled state on the card r=rpl,fluent-reviewers,Gijs

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

--HG--
extra : source : cf2f28971e644574fec25c268044bde692511c08
This commit is contained in:
Mark Striemer 2019-11-21 22:04:55 +00:00
parent ecb3c6477f
commit 8ff9fdc060
12 changed files with 152 additions and 59 deletions

View File

@ -53,7 +53,7 @@ function assertDisabledSideloadedAddonElement(managerWindow, addonElement) {
const enableBtn = addonElement.querySelector('[action="toggle-disabled"]');
is(
doc.l10n.getAttributes(enableBtn).id,
"enable-addon-button",
"enable-addon-button-label",
"The button has the enable label"
);
}

View File

@ -12,9 +12,7 @@ async function isExtensionLocked(win, addonID) {
await win.htmlBrowserLoaded;
return doc.querySelector(`addon-card[addon-id="${addonID}"]`);
}, `Get addon-card for "${addonID}"`);
let disableBtn = addonCard.querySelector(
'panel-item[action="toggle-disabled"]'
);
let disableBtn = addonCard.querySelector('[action="toggle-disabled"]');
let removeBtn = addonCard.querySelector('panel-item[action="remove"]');
ok(removeBtn.disabled, "Remove button should be disabled");
ok(disableBtn.hidden, "Disable button should be hidden");

View File

@ -0,0 +1,29 @@
# coding=utf8
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
from __future__ import absolute_import
import fluent.syntax.ast as FTL
from fluent.migrate.helpers import transforms_from
from fluent.migrate import COPY_PATTERN
TARGET_FILE = "toolkit/toolkit/about/aboutAddons.ftl"
SOURCE_FILE = TARGET_FILE
def migrate(ctx):
"""Bug 1570792 - Add a toggle to extension cards, part {index}"""
ctx.add_transforms(
TARGET_FILE,
SOURCE_FILE,
transforms_from(
"""
disable-addon-button-label =
.aria-label = {COPY_PATTERN(from_path, "disable-addon-button")}
enable-addon-button-label =
.aria-label = {COPY_PATTERN(from_path, "enable-addon-button")}
""",
from_path=SOURCE_FILE),
)

View File

@ -367,6 +367,10 @@ remove-addon-button = Remove
remove-addon-disabled-button = Cant Be Removed <a data-l10n-name="link">Why?</a>
disable-addon-button = Disable
enable-addon-button = Enable
disable-addon-button-label =
.aria-label = Disable
enable-addon-button-label =
.aria-label = Enable
preferences-addon-button =
{ PLATFORM() ->
[windows] Options

View File

@ -14,6 +14,7 @@
<link rel="stylesheet" href="chrome://global/skin/in-content/common.css">
<link rel="stylesheet" href="chrome://mozapps/content/extensions/aboutaddons.css">
<link rel="stylesheet" href="chrome://mozapps/content/extensions/toggle-button.css">
<link rel="stylesheet" href="chrome://mozapps/content/extensions/shortcuts.css">
<link rel="localization" href="branding/brand.ftl">
@ -77,7 +78,6 @@
<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 data-l10n-id="preferences-addon-button" action="preferences"></panel-item>
@ -121,6 +121,7 @@
</a>
<div class="spacer"></div>
<button class="theme-enable-button" action="toggle-disabled" hidden></button>
<input type="checkbox" class="toggle-button extension-enable-button" action="toggle-disabled" hidden>
<button
class="more-options-button"
action="more-options"

View File

@ -1639,18 +1639,6 @@ class AddonOptions extends HTMLElement {
case "report":
el.hidden = !isAbuseReportSupported(addon);
break;
case "toggle-disabled":
if (addon.type == "theme") {
el.remove();
} else {
let toggleDisabledAction = addon.userDisabled ? "enable" : "disable";
document.l10n.setAttributes(
el,
`${toggleDisabledAction}-addon-button`
);
el.hidden = !hasPermission(addon, toggleDisabledAction);
}
break;
case "install-update":
el.hidden = !updateInstall;
break;
@ -2452,8 +2440,8 @@ class AddonCard extends HTMLElement {
await addon.disable();
}
if (e.mozInputSource == MouseEvent.MOZ_SOURCE_KEYBOARD) {
// Refocus the open menu button so it's clear where the focus is.
this.querySelector('[action="more-options"]').focus();
// Refocus the button, since the card might've moved and lost focus.
e.target.focus();
}
break;
case "ask-to-activate":
@ -2747,6 +2735,12 @@ class AddonCard extends HTMLElement {
toggleDisabledButton,
`${toggleDisabledAction}-addon-button`
);
} else if (addon.type === "extension") {
toggleDisabledButton.checked = !addon.userDisabled;
document.l10n.setAttributes(
toggleDisabledButton,
`${toggleDisabledAction}-addon-button-label`
);
}
}
@ -2847,6 +2841,9 @@ class AddonCard extends HTMLElement {
if (addon.type != "theme") {
this.card.querySelector(".theme-enable-button").remove();
}
if (addon.type != "extension") {
this.card.querySelector(".extension-enable-button").remove();
}
let nameContainer = this.card.querySelector(".addon-name-container");
let headingLevel = this.expanded ? "h1" : "h3";

View File

@ -0,0 +1,72 @@
/* 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/. */
input[type="checkbox"].toggle-button {
--button-height: 16px;
--button-half-height: 8px;
--button-width: 26px;
--button-border-width: 1px;
/* dot-size = button-height - 2*dot-margin - 2*button-border-width */
--dot-size: 10px;
--dot-margin: 2px;
/* --dot-transform-x = button-width - 2*dot-margin - dot-size - 2*button-border-width */
--dot-transform-x: 10px;
--border-color: hsla(210,4%,10%,.14);
}
input[type="checkbox"].toggle-button {
-moz-appearance: none;
padding: 0;
margin: 0;
outline: 0;
border: var(--button-border-width) solid var(--border-color);
height: var(--button-height);
width: var(--button-width);
border-radius: var(--button-half-height);
background: var(--in-content-button-background);
box-sizing: border-box;
}
input[type="checkbox"].toggle-button:hover {
background: var(--in-content-button-background-hover);
border-color: var(--border-color);
}
input[type="checkbox"].toggle-button:active {
background: var(--in-content-button-background-active);
border-color: var(--border-color);
}
input[type="checkbox"].toggle-button:focus {
box-shadow: 0 0 0 1px var(--border-color), 0 0 0 4px rgba(10, 132, 255, 0.3);
}
input[type="checkbox"].toggle-button:checked:focus {
box-shadow: 0 0 0 1px var(--in-content-border-active), 0 0 0 4px rgba(10, 132, 255, 0.3);
}
input[type="checkbox"].toggle-button:checked {
background: var(--in-content-primary-button-background);
border-color: var(--in-content-primary-button-background-hover);
}
input[type="checkbox"].toggle-button:checked:hover {
background: var(--in-content-primary-button-background-hover);
border-color: var(--in-content-primary-button-background-active);
}
input[type="checkbox"].toggle-button:checked:active {
background: var(--in-content-primary-button-background-active);
border-color: var(--in-content-primary-button-background-active);
}
input[type="checkbox"].toggle-button::before {
display: block;
content: "";
background: #fff;
height: var(--dot-size);
width: var(--dot-size);
margin: var(--dot-margin);
border-radius: 50%;
outline: 1px solid var(--border-color);
-moz-outline-radius: 50%;
transition: transform 100ms;
}
input[type="checkbox"].toggle-button:checked::before {
transform: translateX(var(--dot-transform-x));
}

View File

@ -33,4 +33,5 @@ toolkit.jar:
content/mozapps/extensions/rating-star.css (content/rating-star.css)
content/mozapps/extensions/shortcuts.css (content/shortcuts.css)
content/mozapps/extensions/shortcuts.js (content/shortcuts.js)
content/mozapps/extensions/toggle-button.css (content/toggle-button.css)
#endif

View File

@ -19,7 +19,7 @@ function assertDisabledSideloadedExtensionElement(managerWindow, addonElement) {
);
is(
doc.l10n.getAttributes(toggleDisabled).id,
"enable-addon-button",
"enable-addon-button-label",
"Addon toggle-disabled action has the enable label"
);
}
@ -31,7 +31,7 @@ function assertEnabledSideloadedExtensionElement(managerWindow, addonElement) {
);
is(
doc.l10n.getAttributes(toggleDisabled).id,
"enable-addon-button",
"enable-addon-button-label",
"Addon toggle-disabled action has the enable label"
);
}

View File

@ -293,7 +293,7 @@ add_task(async function testDetailOperations() {
let panel = card.querySelector("panel-list");
// Check button visibility.
let disableButton = panel.querySelector('[action="toggle-disabled"]');
let disableButton = card.querySelector('[action="toggle-disabled"]');
ok(!disableButton.hidden, "The disable button is visible");
let removeButton = panel.querySelector('[action="remove"]');

View File

@ -106,15 +106,18 @@ add_task(async function testExtensionList() {
ok(icon.src.endsWith("/test-icon.png"), "The icon is set");
// Disable the extension.
let disableButton = card.querySelector('[action="toggle-disabled"]');
let disableToggle = card.querySelector('[action="toggle-disabled"]');
ok(disableToggle.checked, "The disable toggle is checked");
is(
doc.l10n.getAttributes(disableButton).id,
"disable-addon-button",
"The button has the disable label"
doc.l10n.getAttributes(disableToggle).id,
"disable-addon-button-label",
"The toggle has the disable label"
);
ok(disableToggle.getAttribute("aria-label"), "There's an aria-label");
ok(!disableToggle.hidden, "The toggle is visible");
let disabled = BrowserTestUtils.waitForEvent(list, "move");
disableButton.click();
disableToggle.click();
await disabled;
is(
card.parentNode,
@ -123,11 +126,13 @@ add_task(async function testExtensionList() {
);
// The disable button is now enable.
ok(!disableToggle.checked, "The disable toggle is unchecked");
is(
doc.l10n.getAttributes(disableButton).id,
"enable-addon-button",
doc.l10n.getAttributes(disableToggle).id,
"enable-addon-button-label",
"The button has the enable label"
);
ok(disableToggle.getAttribute("aria-label"), "There's an aria-label");
// Remove the add-on.
let removeButton = card.querySelector('[action="remove"]');
@ -395,63 +400,47 @@ add_task(async function testKeyboardSupport() {
// Test opening and closing the menu.
let moreOptionsMenu = card.querySelector("panel-list");
let expandButton = moreOptionsMenu.querySelector('[action="expand"]');
let toggleDisableButton = card.querySelector('[action="toggle-disabled"]');
let removeButton = card.querySelector('[action="remove"]');
is(moreOptionsMenu.open, false, "The menu is closed");
let shown = BrowserTestUtils.waitForEvent(moreOptionsMenu, "shown");
space();
await shown;
is(moreOptionsMenu.open, true, "The menu is open");
isFocused(toggleDisableButton, "The disable button is now focused");
EventUtils.synthesizeKey("Escape", {});
is(moreOptionsMenu.open, false, "The menu is closed");
isFocused(moreOptionsButton, "The more options button is focused");
// Test tabbing out of the menu.
space();
shown = BrowserTestUtils.waitForEvent(moreOptionsMenu, "shown");
is(moreOptionsMenu.open, true, "The menu is open");
await shown;
isFocused(removeButton, "The remove button is now focused");
tab({ shiftKey: true });
is(moreOptionsMenu.open, true, "The menu stays open");
isFocused(expandButton, "The focus has looped to the bottom");
tab();
is(moreOptionsMenu.open, true, "The menu stays open");
isFocused(toggleDisableButton, "The focus has looped to the top");
isFocused(removeButton, "The focus has looped to the top");
let hidden = BrowserTestUtils.waitForEvent(moreOptionsMenu, "hidden");
EventUtils.synthesizeKey("Escape", {});
await hidden;
isFocused(moreOptionsButton, "Escape closed the menu");
// Open the menu to test contents.
shown = BrowserTestUtils.waitForEvent(moreOptionsMenu, "shown");
space();
is(moreOptionsMenu.open, true, "The menu is open");
// Wait for the panel to be shown.
await shown;
// Disable the add-on.
isFocused(toggleDisableButton, "The disable button is focused");
let disableButton = card.querySelector('[action="toggle-disabled"]');
tab({ shiftKey: true });
isFocused(disableButton, "The disable toggle is focused");
is(card.parentNode, enabledSection, "The card is in the enabled section");
let disabled = BrowserTestUtils.waitForEvent(list, "move");
space();
await disabled;
is(moreOptionsMenu.open, false, "The menu is closed");
is(
card.parentNode,
disabledSection,
"The card is now in the disabled section"
);
// Open the menu again.
shown = BrowserTestUtils.waitForEvent(moreOptionsMenu, "shown");
isFocused(moreOptionsButton, "The more options button is focused");
space();
await shown;
isFocused(disableButton, "The disable button is still focused");
// Remove the add-on.
tab();
let removeButton = card.querySelector('[action="remove"]');
isFocused(moreOptionsButton, "The more options button is focused again");
shown = BrowserTestUtils.waitForEvent(moreOptionsMenu, "shown");
space();
is(moreOptionsMenu.open, true, "The menu is open");
await shown;
isFocused(removeButton, "The remove button is focused");
let removed = BrowserTestUtils.waitForEvent(list, "remove");
space();
@ -763,8 +752,9 @@ add_task(async function testSideloadRemoveButton() {
let card = getCardByAddonId(doc, id);
let moreOptionsPanel = card.querySelector("panel-list");
let moreOptionsButton = card.querySelector('[action="more-options"]');
let panelOpened = BrowserTestUtils.waitForEvent(moreOptionsPanel, "shown");
moreOptionsPanel.show();
EventUtils.synthesizeMouseAtCenter(moreOptionsButton, {}, win);
await panelOpened;
// Verify the remove button is visible with a SUMO link.

View File

@ -16,7 +16,8 @@ async function getUpdateButton(item) {
let button = item.querySelector('[action="install-update"]');
let panel = button.closest("panel-list");
let shown = BrowserTestUtils.waitForEvent(panel, "shown");
panel.show();
let moreOptionsButton = item.querySelector('[action="more-options"]');
EventUtils.synthesizeMouseAtCenter(moreOptionsButton, {}, item.ownerGlobal);
await shown;
return button;
}