зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1550137 - Import button for migrator in the about:logins menu. r=Gijs,fluent-reviewers,flod
Differential Revision: https://phabricator.services.mozilla.com/D34600 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
ee27782e07
Коммит
5c01e14fcb
|
@ -87,6 +87,7 @@ let LEGACY_ACTORS = {
|
||||||
events: {
|
events: {
|
||||||
"AboutLoginsCreateLogin": {wantUntrusted: true},
|
"AboutLoginsCreateLogin": {wantUntrusted: true},
|
||||||
"AboutLoginsDeleteLogin": {wantUntrusted: true},
|
"AboutLoginsDeleteLogin": {wantUntrusted: true},
|
||||||
|
"AboutLoginsImport": {wantUntrusted: true},
|
||||||
"AboutLoginsInit": {wantUntrusted: true},
|
"AboutLoginsInit": {wantUntrusted: true},
|
||||||
"AboutLoginsOpenPreferences": {wantUntrusted: true},
|
"AboutLoginsOpenPreferences": {wantUntrusted: true},
|
||||||
"AboutLoginsOpenSite": {wantUntrusted: true},
|
"AboutLoginsOpenSite": {wantUntrusted: true},
|
||||||
|
@ -583,6 +584,7 @@ const listeners = {
|
||||||
mm: {
|
mm: {
|
||||||
"AboutLogins:CreateLogin": ["AboutLoginsParent"],
|
"AboutLogins:CreateLogin": ["AboutLoginsParent"],
|
||||||
"AboutLogins:DeleteLogin": ["AboutLoginsParent"],
|
"AboutLogins:DeleteLogin": ["AboutLoginsParent"],
|
||||||
|
"AboutLogins:Import": ["AboutLoginsParent"],
|
||||||
"AboutLogins:OpenPreferences": ["AboutLoginsParent"],
|
"AboutLogins:OpenPreferences": ["AboutLoginsParent"],
|
||||||
"AboutLogins:OpenSite": ["AboutLoginsParent"],
|
"AboutLogins:OpenSite": ["AboutLoginsParent"],
|
||||||
"AboutLogins:Subscribe": ["AboutLoginsParent"],
|
"AboutLogins:Subscribe": ["AboutLoginsParent"],
|
||||||
|
|
|
@ -42,6 +42,10 @@ class AboutLoginsChild extends ActorChild {
|
||||||
this.mm.sendAsyncMessage("AboutLogins:DeleteLogin", {login: event.detail});
|
this.mm.sendAsyncMessage("AboutLogins:DeleteLogin", {login: event.detail});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case "AboutLoginsImport": {
|
||||||
|
this.mm.sendAsyncMessage("AboutLogins:Import");
|
||||||
|
break;
|
||||||
|
}
|
||||||
case "AboutLoginsOpenPreferences": {
|
case "AboutLoginsOpenPreferences": {
|
||||||
this.mm.sendAsyncMessage("AboutLogins:OpenPreferences");
|
this.mm.sendAsyncMessage("AboutLogins:OpenPreferences");
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -13,6 +13,8 @@ ChromeUtils.defineModuleGetter(this, "Localization",
|
||||||
"resource://gre/modules/Localization.jsm");
|
"resource://gre/modules/Localization.jsm");
|
||||||
ChromeUtils.defineModuleGetter(this, "LoginHelper",
|
ChromeUtils.defineModuleGetter(this, "LoginHelper",
|
||||||
"resource://gre/modules/LoginHelper.jsm");
|
"resource://gre/modules/LoginHelper.jsm");
|
||||||
|
ChromeUtils.defineModuleGetter(this, "MigrationUtils",
|
||||||
|
"resource:///modules/MigrationUtils.jsm");
|
||||||
ChromeUtils.defineModuleGetter(this, "Services",
|
ChromeUtils.defineModuleGetter(this, "Services",
|
||||||
"resource://gre/modules/Services.jsm");
|
"resource://gre/modules/Services.jsm");
|
||||||
|
|
||||||
|
@ -96,6 +98,15 @@ var AboutLoginsParent = {
|
||||||
Services.logins.removeLogin(login);
|
Services.logins.removeLogin(login);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case "AboutLogins:Import": {
|
||||||
|
try {
|
||||||
|
MigrationUtils.showMigrationWizard(message.target.ownerGlobal,
|
||||||
|
[MigrationUtils.MIGRATION_ENTRYPOINT_PASSWORDS]);
|
||||||
|
} catch (ex) {
|
||||||
|
Cu.reportError(ex);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case "AboutLogins:OpenPreferences": {
|
case "AboutLogins:OpenPreferences": {
|
||||||
message.target.ownerGlobal.openPreferences("privacy-logins");
|
message.target.ownerGlobal.openPreferences("privacy-logins");
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -61,6 +61,7 @@ master-password-reload-button-accesskey = L
|
||||||
|
|
||||||
menu-button =
|
menu-button =
|
||||||
.button-title = Open menu
|
.button-title = Open menu
|
||||||
|
.menuitem-import = Import Passwords…
|
||||||
.menuitem-preferences =
|
.menuitem-preferences =
|
||||||
{ PLATFORM() ->
|
{ PLATFORM() ->
|
||||||
[windows] Options
|
[windows] Options
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
<button id="create-login-button" data-l10n-id="create-login-button"></button>
|
<button id="create-login-button" data-l10n-id="create-login-button"></button>
|
||||||
<menu-button data-l10n-id="menu-button"
|
<menu-button data-l10n-id="menu-button"
|
||||||
data-l10n-attrs="button-title,
|
data-l10n-attrs="button-title,
|
||||||
|
menuitem-import,
|
||||||
menuitem-preferences"></menu-button>
|
menuitem-preferences"></menu-button>
|
||||||
</header>
|
</header>
|
||||||
<login-list data-l10n-id="login-list"
|
<login-list data-l10n-id="login-list"
|
||||||
|
@ -141,7 +142,12 @@
|
||||||
<link rel="stylesheet" href="chrome://browser/content/aboutlogins/components/menu-button.css">
|
<link rel="stylesheet" href="chrome://browser/content/aboutlogins/components/menu-button.css">
|
||||||
<button class="menu-button alternate-button"></button>
|
<button class="menu-button alternate-button"></button>
|
||||||
<ul class="menu" role="menu" aria-hidden="true">
|
<ul class="menu" role="menu" aria-hidden="true">
|
||||||
<li role="menuitem" class="menuitem"><button class="menuitem-button menuitem-preferences alternate-button"></button></li>
|
<li role="menuitem" class="menuitem windows-only">
|
||||||
|
<button class="menuitem-button menuitem-import alternate-button" data-event-name="AboutLoginsImport"></button>
|
||||||
|
</li>
|
||||||
|
<li role="menuitem" class="menuitem">
|
||||||
|
<button class="menuitem-button menuitem-preferences alternate-button" data-event-name="AboutLoginsOpenPreferences"></button>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,10 @@
|
||||||
left: 0;
|
left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.menuitem {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
.menuitem-button {
|
.menuitem-button {
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
/* 32px = 8px (padding) + 16px (icon) + 8px (padding) */
|
/* 32px = 8px (padding) + 16px (icon) + 8px (padding) */
|
||||||
|
@ -52,12 +56,22 @@
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
/* Override common.inc.css box-shadow on these buttons */
|
/* Override common.inc.css box-shadow on these buttons */
|
||||||
box-shadow: none !important;
|
box-shadow: none !important;
|
||||||
|
flex-grow: 1;
|
||||||
|
text-align: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.menuitem-button:dir(rtl) {
|
.menuitem-button:dir(rtl) {
|
||||||
background-position: right 8px center;
|
background-position: right 8px center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.menuitem-import {
|
||||||
|
background-image: url("chrome://browser/skin/save.svg");
|
||||||
|
}
|
||||||
|
|
||||||
.menuitem-preferences {
|
.menuitem-preferences {
|
||||||
background-image: url("chrome://browser/skin/settings.svg");
|
background-image: url("chrome://browser/skin/settings.svg");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:host(:not(.Win32)) .windows-only {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
|
@ -16,11 +16,22 @@ export default class MenuButton extends ReflectedFluentElement {
|
||||||
|
|
||||||
this.reflectFluentStrings();
|
this.reflectFluentStrings();
|
||||||
|
|
||||||
|
if (navigator.platform == "Win32") {
|
||||||
|
// We can't add navigator.platform in all cases
|
||||||
|
// because some platforms, such as Ubuntu 64-bit,
|
||||||
|
// use "Linux x86_64" which is an invalid className.
|
||||||
|
this.classList.add(navigator.platform);
|
||||||
|
}
|
||||||
|
|
||||||
this.shadowRoot.querySelector(".menu-button").addEventListener("click", this);
|
this.shadowRoot.querySelector(".menu-button").addEventListener("click", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
static get reflectedFluentIDs() {
|
static get reflectedFluentIDs() {
|
||||||
return ["button-title", "menuitem-preferences"];
|
return [
|
||||||
|
"button-title",
|
||||||
|
"menuitem-import",
|
||||||
|
"menuitem-preferences",
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
static get observedAttributes() {
|
static get observedAttributes() {
|
||||||
|
@ -46,12 +57,15 @@ export default class MenuButton extends ReflectedFluentElement {
|
||||||
event.originalTarget == this.shadowRoot.querySelector(".menu-button")) {
|
event.originalTarget == this.shadowRoot.querySelector(".menu-button")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (event.originalTarget.classList.contains("menuitem-preferences")) {
|
let classList = event.originalTarget.classList;
|
||||||
document.dispatchEvent(new CustomEvent("AboutLoginsOpenPreferences", {
|
if (classList.contains("menuitem-import") ||
|
||||||
|
classList.contains("menuitem-preferences")) {
|
||||||
|
let eventName = event.originalTarget.dataset.eventName;
|
||||||
|
document.dispatchEvent(new CustomEvent(eventName, {
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
}));
|
}));
|
||||||
this.hideMenu();
|
this.hideMenu();
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
this.toggleMenu();
|
this.toggleMenu();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -12,6 +12,8 @@ skip-if = asan || debug
|
||||||
[browser_loginListChanges.js]
|
[browser_loginListChanges.js]
|
||||||
[browser_masterPassword.js]
|
[browser_masterPassword.js]
|
||||||
[browser_openFiltered.js]
|
[browser_openFiltered.js]
|
||||||
|
[browser_openImport.js]
|
||||||
|
skip-if = (os != "win") # import is only available on Windows
|
||||||
[browser_openPreferences.js]
|
[browser_openPreferences.js]
|
||||||
[browser_openSite.js]
|
[browser_openSite.js]
|
||||||
[browser_updateLogin.js]
|
[browser_updateLogin.js]
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
add_task(async function setup() {
|
||||||
|
let aboutLoginsTab = await BrowserTestUtils.openNewForegroundTab({gBrowser, url: "about:logins"});
|
||||||
|
registerCleanupFunction(() => {
|
||||||
|
BrowserTestUtils.removeTab(aboutLoginsTab);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
add_task(async function test_open_import() {
|
||||||
|
let promiseImportWindow = BrowserTestUtils.domWindowOpened();
|
||||||
|
|
||||||
|
let browser = gBrowser.selectedBrowser;
|
||||||
|
await BrowserTestUtils.synthesizeMouseAtCenter("menu-button", {}, browser);
|
||||||
|
await ContentTask.spawn(browser, null, async () => {
|
||||||
|
return ContentTaskUtils.waitForCondition(() => {
|
||||||
|
let menuButton = Cu.waiveXrays(content.document.querySelector("menu-button"));
|
||||||
|
return menuButton.shadowRoot
|
||||||
|
.querySelector(".menu")
|
||||||
|
.getAttribute("aria-hidden") == "false";
|
||||||
|
}, "waiting for menu to open");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Not using synthesizeMouseAtCenter here because the element we want clicked on
|
||||||
|
// is in the shadow DOM. BrowserTestUtils.synthesizeMouseAtCenter/AsyncUtilsContent
|
||||||
|
// thinks that the shadow DOM element is in another document and throws an exception
|
||||||
|
// when trying to call element.ownerGlobal on the targeted shadow DOM node. This is
|
||||||
|
// on file as bug 1557489. As a workaround, this manually calculates the position to click.
|
||||||
|
let {x, y} = await ContentTask.spawn(browser, null, async () => {
|
||||||
|
let menuButton = Cu.waiveXrays(content.document.querySelector("menu-button"));
|
||||||
|
let prefsItem = menuButton.shadowRoot.querySelector(".menuitem-import");
|
||||||
|
return prefsItem.getBoundingClientRect();
|
||||||
|
});
|
||||||
|
await BrowserTestUtils.synthesizeMouseAtPoint(x + 5, y + 5, {}, browser);
|
||||||
|
|
||||||
|
info("waiting for Import to get opened");
|
||||||
|
let importWindow = await promiseImportWindow;
|
||||||
|
ok(true, "Import opened");
|
||||||
|
|
||||||
|
importWindow.close();
|
||||||
|
});
|
|
@ -52,7 +52,12 @@ add_task(async function test_menu_open_close() {
|
||||||
|
|
||||||
let preferencesItem = gMenuButton.shadowRoot.querySelector(".menuitem-preferences");
|
let preferencesItem = gMenuButton.shadowRoot.querySelector(".menuitem-preferences");
|
||||||
ok(!preferencesItem.matches(":focus"), ".menuitem-preferences should not be focused before tabbing to it");
|
ok(!preferencesItem.matches(":focus"), ".menuitem-preferences should not be focused before tabbing to it");
|
||||||
sendKey("TAB");
|
// The Import menuitem is only visible on Windows, where we will need a second Tab
|
||||||
|
// press to get to the Preferences item.
|
||||||
|
let tabs = navigator.platform == "Win32" ? 2 : 1;
|
||||||
|
while (tabs--) {
|
||||||
|
sendKey("TAB");
|
||||||
|
}
|
||||||
await SimpleTest.promiseWaitForCondition(() => preferencesItem.matches(":focus"),
|
await SimpleTest.promiseWaitForCondition(() => preferencesItem.matches(":focus"),
|
||||||
"waiting for preferencesItem to get focus");
|
"waiting for preferencesItem to get focus");
|
||||||
ok(preferencesItem.matches(":focus"), ".menuitem-preferences should be focused after tabbing to it");
|
ok(preferencesItem.matches(":focus"), ".menuitem-preferences should be focused after tabbing to it");
|
||||||
|
|
Загрузка…
Ссылка в новой задаче