author | Matthew Noorenberghe <mozilla@noorenberghe.ca> |
Wed, 14 Mar 2018 18:12:00 -0700 | |
changeset 408638 | 4e5ce4f1f57901ebaf9d932b41db13b4fe574274 |
parent 408637 | ac23b9ba0603839616105f4fbe7d015ddff28254 |
child 408639 | 6ab0e835a7f4e2823d5ae5a80ffbdeb775ab5591 |
push id | 100996 |
push user | btara@mozilla.com |
push date | Sat, 17 Mar 2018 10:37:43 +0000 |
treeherder | mozilla-inbound@97160a734959 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | sfoster |
bugs | 1427954 |
milestone | 61.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/browser/extensions/formautofill/FormAutofillUtils.jsm +++ b/browser/extensions/formautofill/FormAutofillUtils.jsm @@ -823,34 +823,52 @@ this.FormAutofillUtils = { return { "addressLevel1Label": dataset.state_name_type || "province", "postalCodeLabel": dataset.zip_name_type || "postalCode", "fieldsOrder": this.parseAddressFormat(dataset.fmt || "%N%n%O%n%A%n%C, %S %Z"), }; }, /** + * Localize "data-localization" or "data-localization-region" attributes. + * @param {Element} element + * @param {string} attributeName + */ + localizeAttributeForElement(element, attributeName) { + let bundle = null; + switch (attributeName) { + case "data-localization": { + bundle = this.stringBundle; + break; + } + case "data-localization-region": { + bundle = this.regionsBundle; + break; + } + default: + throw new Error("Unexpected attributeName"); + } + + element.textContent = bundle.GetStringFromName(element.getAttribute(attributeName)); + element.removeAttribute(attributeName); + }, + + /** * Localize elements with "data-localization" or "data-localization-region" attributes. - * @param {DOMElement} root + * @param {Element} root */ localizeMarkup(root) { let elements = root.querySelectorAll("[data-localization]"); for (let element of elements) { - element.textContent = this.stringBundle.GetStringFromName( - element.getAttribute("data-localization") - ); - element.removeAttribute("data-localization"); + this.localizeAttributeForElement(element, "data-localization"); } - let regionElements = root.querySelectorAll("[data-localization-region]"); - for (let element of regionElements) { - element.textContent = this.regionsBundle.GetStringFromName( - element.getAttribute("data-localization-region") - ); - element.removeAttribute("data-localization-region"); + elements = root.querySelectorAll("[data-localization-region]"); + for (let element of elements) { + this.localizeAttributeForElement(element, "data-localization-region"); } }, }; this.log = null; this.FormAutofillUtils.defineLazyLogGetter(this, EXPORTED_SYMBOLS[0]); XPCOMUtils.defineLazyGetter(FormAutofillUtils, "stringBundle", function() {
--- a/browser/extensions/formautofill/content/autofillEditForms.js +++ b/browser/extensions/formautofill/content/autofillEditForms.js @@ -98,17 +98,16 @@ class EditAddress extends EditAutofillFo * Format the form based on country. The address-level1 and postal-code labels * should be specific to the given country. * @param {string} country */ formatForm(country) { const {addressLevel1Label, postalCodeLabel, fieldsOrder} = FormAutofillUtils.getFormFormat(country); this._elements.addressLevel1Label.dataset.localization = addressLevel1Label; this._elements.postalCodeLabel.dataset.localization = postalCodeLabel; - FormAutofillUtils.localizeMarkup(document); this.arrangeFields(fieldsOrder); } arrangeFields(fieldsOrder) { let fields = [ "name", "organization", "street-address", @@ -142,17 +141,16 @@ class EditAddress extends EditAutofillFo let fragment = document.createDocumentFragment(); for (let country of FormAutofillUtils.supportedCountries) { let option = new Option(); option.value = country; option.dataset.localizationRegion = country.toLowerCase(); fragment.appendChild(option); } this._elements.country.appendChild(fragment); - FormAutofillUtils.localizeMarkup(this._elements.country); } handleChange(event) { this.formatForm(event.target.value); } attachEventListeners() { this._elements.country.addEventListener("change", this);
--- a/browser/extensions/formautofill/content/editAddress.xhtml +++ b/browser/extensions/formautofill/content/editAddress.xhtml @@ -7,16 +7,17 @@ %globalDTD; ]> <html xmlns="http://www.w3.org/1999/xhtml" width="620"> <head> <title data-localization="addNewAddressTitle"/> <link rel="stylesheet" href="chrome://formautofill-shared/skin/editDialog.css"/> <link rel="stylesheet" href="chrome://formautofill-shared/skin/editAddress.css"/> <link rel="stylesheet" href="chrome://formautofill/skin/editDialog.css"/> + <script src="chrome://formautofill/content/l10n.js"></script> <script src="chrome://formautofill/content/editDialog.js"></script> <script src="chrome://formautofill/content/autofillEditForms.js"></script> </head> <body dir="&locale.dir;"> <form id="form" autocomplete="off"> <div> <div id="name-container"> <label id="given-name-container">
--- a/browser/extensions/formautofill/content/editCreditCard.xhtml +++ b/browser/extensions/formautofill/content/editCreditCard.xhtml @@ -7,16 +7,17 @@ %globalDTD; ]> <html xmlns="http://www.w3.org/1999/xhtml" width="500" style="width: 500px"> <head> <title data-localization="addNewCreditCardTitle"/> <link rel="stylesheet" href="chrome://formautofill-shared/skin/editDialog.css"/> <link rel="stylesheet" href="chrome://formautofill-shared/skin/editCreditCard.css"/> <link rel="stylesheet" href="chrome://formautofill/skin/editDialog.css"/> + <script src="chrome://formautofill/content/l10n.js"></script> <script src="chrome://formautofill/content/editDialog.js"></script> <script src="chrome://formautofill/content/autofillEditForms.js"></script> </head> <body dir="&locale.dir;"> <form id="form" autocomplete="off"> <label> <span data-localization="cardNumber"/> <input id="cc-number" type="text"/>
--- a/browser/extensions/formautofill/content/editDialog.js +++ b/browser/extensions/formautofill/content/editDialog.js @@ -163,17 +163,16 @@ class EditAddressDialog extends Autofill FormAutofillUtils.supportedCountries.find(supported => supported == FormAutofillUtils.DEFAULT_REGION); super("addresses", elements, record || {country}); } localizeDocument() { if (this._record) { this._elements.title.dataset.localization = "editAddressTitle"; } - FormAutofillUtils.localizeMarkup(document); } async handleSubmit() { await this.saveRecord(this._elements.fieldContainer.buildFormObject(), this._record ? this._record.guid : null); window.close(); } } @@ -181,17 +180,16 @@ class EditCreditCardDialog extends Autof constructor(elements, record) { super("creditCards", elements, record); } localizeDocument() { if (this._record) { this._elements.title.dataset.localization = "editCreditCardTitle"; } - FormAutofillUtils.localizeMarkup(document); } /** * Decrypt cc-number first and fill the form. * @param {object} creditCard */ async loadInitialValues(creditCard) { let decryptedCC = await MasterPassword.decrypt(creditCard["cc-number-encrypted"]);
new file mode 100644 --- /dev/null +++ b/browser/extensions/formautofill/content/l10n.js @@ -0,0 +1,36 @@ +/* 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/. */ + +"use strict"; + +/** + * This file will be replaced by Fluent but it's a middle ground so we can share + * the edit dialog code with the unprivileged PaymentRequest dialog before the + * Fluent conversion + */ + +ChromeUtils.import("resource://formautofill/FormAutofillUtils.jsm"); + +const L10N_ATTRIBUTES = ["data-localization", "data-localization-region"]; + +let mutationObserver = new MutationObserver(function onMutation(mutations) { + for (let mutation of mutations) { + if (!mutation.target.hasAttribute(mutation.attributeName)) { + // The attribute was removed in the meantime. + continue; + } + FormAutofillUtils.localizeAttributeForElement(mutation.target, mutation.attributeName); + } +}); + +document.addEventListener("DOMContentLoaded", function onDCL() { + FormAutofillUtils.localizeMarkup(document); + mutationObserver.observe(document, { + attributes: true, + attributeFilter: L10N_ATTRIBUTES, + subtree: true, + }); +}, { + once: true, +});
--- a/browser/extensions/formautofill/test/browser/browser_editAddressDialog.js +++ b/browser/extensions/formautofill/test/browser/browser_editAddressDialog.js @@ -106,21 +106,25 @@ add_task(async function test_editAddress is(addresses[0]["given-name"], TEST_ADDRESS_1["given-name"] + "test", "given-name changed"); await removeAddresses([addresses[0].guid]); addresses = await getAddresses(); is(addresses.length, 0, "Address storage is empty"); }); add_task(async function test_saveAddressCA() { - await testDialog(EDIT_ADDRESS_DIALOG_URL, win => { + await testDialog(EDIT_ADDRESS_DIALOG_URL, async win => { let doc = win.document; // Change country to verify labels doc.querySelector("#country").focus(); EventUtils.synthesizeKey("Canada", {}, win); + + await TestUtils.waitForCondition(() => { + return doc.querySelector("#address-level1-container > span").textContent == "Province"; + }, "Wait for the mutation observer to change the labels"); is(doc.querySelector("#address-level1-container > span").textContent, "Province", "CA address-level1 label should be 'Province'"); is(doc.querySelector("#postal-code-container > span").textContent, "Postal Code", "CA postal-code label should be 'Postal Code'"); // Input address info and verify move through form with tab keys doc.querySelector("#given-name").focus(); const keyInputs = [ TEST_ADDRESS_CA_1["given-name"], @@ -153,21 +157,24 @@ add_task(async function test_saveAddress let addresses = await getAddresses(); for (let [fieldName, fieldValue] of Object.entries(TEST_ADDRESS_CA_1)) { is(addresses[0][fieldName], fieldValue, "check " + fieldName); } await removeAllRecords(); }); add_task(async function test_saveAddressDE() { - await testDialog(EDIT_ADDRESS_DIALOG_URL, win => { + await testDialog(EDIT_ADDRESS_DIALOG_URL, async win => { let doc = win.document; // Change country to verify labels doc.querySelector("#country").focus(); EventUtils.synthesizeKey("Germany", {}, win); + await TestUtils.waitForCondition(() => { + return doc.querySelector("#postal-code-container > span").textContent == "Postal Code"; + }, "Wait for the mutation observer to change the labels"); is(doc.querySelector("#postal-code-container > span").textContent, "Postal Code", "DE postal-code label should be 'Postal Code'"); is(doc.querySelector("#address-level1-container").style.display, "none", "DE address-level1 should be hidden"); // Input address info and verify move through form with tab keys doc.querySelector("#given-name").focus(); const keyInputs = [ TEST_ADDRESS_DE_1["given-name"],
--- a/browser/extensions/formautofill/test/browser/head.js +++ b/browser/extensions/formautofill/test/browser/head.js @@ -334,16 +334,16 @@ async function removeAllRecords() { async function waitForFocusAndFormReady(win) { return Promise.all([ new Promise(resolve => waitForFocus(resolve, win)), BrowserTestUtils.waitForEvent(win, "FormReady"), ]); } async function testDialog(url, testFn, arg) { - let win = window.openDialog(url, null, null, arg); + let win = window.openDialog(url, null, "width=600,height=600", arg); await waitForFocusAndFormReady(win); let unloadPromise = BrowserTestUtils.waitForEvent(win, "unload"); - testFn(win); + await testFn(win); return unloadPromise; } registerCleanupFunction(removeAllRecords);