Bug 1463545 - Replace grid layout of <address-option> with a new two line design. r=sfoster

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Matthew Noorenberghe 2018-09-20 21:07:20 +00:00
Родитель b6c0f035ed
Коммит 514f9fcc29
17 изменённых файлов: 408 добавлений и 111 удалений

Просмотреть файл

@ -2,67 +2,28 @@
* 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/. */
address-option {
address-option.rich-option {
grid-row-gap: 5px;
grid-column-gap: 10px;
grid-template-areas:
"name "
"street-address";
}
rich-select[open] > .rich-select-popup-box > address-option {
grid-template-areas:
"name name "
"street-address street-address"
"email tel ";
}
address-picker.payer-related > rich-select address-option {
grid-template-areas:
"name name"
"tel email";
}
address-option > .name {
grid-area: name;
}
address-option > .street-address {
grid-area: street-address;
}
address-option > .email {
grid-area: email;
}
address-option > .tel {
grid-area: tel;
}
address-option > .name,
address-option > .street-address,
address-option > .email,
address-option > .tel {
address-option > .line {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
address-picker.shipping-related address-option > .email,
address-picker.shipping-related address-option.rich-select-selected-option > .tel {
address-option > .line:empty {
/* Hide the 2nd line in cases where it's empty
(e.g. payer field with one or two fields requested) */
display: none;
}
/* for payer contact details:
* display fields selectively based on the contents of the address-fields attribute
*/
address-picker.payer-related address-option > .name,
address-picker.payer-related address-option > .street-address,
address-picker.payer-related address-option > .email,
address-picker.payer-related address-option > .tel {
display: none;
address-option > .line > span {
white-space: nowrap;
}
address-picker[address-fields~='name'].payer-related address-option > .name,
address-picker[address-fields~='email'].payer-related address-option > .email,
address-picker[address-fields~='tel'].payer-related address-option > .tel {
display: inline-block;
address-option > .line > span:empty::before {
/* Show the string for missing fields in grey when the field is empty */
color: GrayText;
content: attr(data-missing-string);
}

Просмотреть файл

@ -2,11 +2,15 @@
* 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/. */
/* import-globals-from ../../../../../browser/extensions/formautofill/content/autofillEditForms.js*/
import ObservedPropertiesMixin from "../mixins/ObservedPropertiesMixin.js";
import RichOption from "./rich-option.js";
/* import-globals-from ../unprivileged-fallbacks.js */
/**
* Up to two-line address display. After bug 1475684 this will also be used for
* the single-line <option> substitute too.
*
* <rich-select>
* <address-option guid="98hgvnbmytfc"
* address-level1="MI"
@ -31,6 +35,7 @@ export default class AddressOption extends ObservedPropertiesMixin(RichOption) {
"email",
"guid",
"name",
"organization",
"postal-code",
"street-address",
"tel",
@ -38,22 +43,34 @@ export default class AddressOption extends ObservedPropertiesMixin(RichOption) {
}
static get observedAttributes() {
return RichOption.observedAttributes.concat(AddressOption.recordAttributes);
return RichOption.observedAttributes.concat(AddressOption.recordAttributes,
"address-fields",
"break-after-nth-field",
"data-field-separator");
}
constructor() {
super();
for (let name of ["name", "street-address", "email", "tel"]) {
this._line1 = document.createElement("div");
this._line1.classList.add("line");
this._line2 = document.createElement("div");
this._line2.classList.add("line");
for (let name of AddressOption.recordAttributes) {
this[`_${name}`] = document.createElement("span");
this[`_${name}`].classList.add(name);
// XXX Bug 1490816: Use appropriate strings
let missingValueString = name.replace(/(-|^)([a-z])/g, ($0, $1, $2) => {
return $1.replace("-", " ") + $2.toUpperCase();
}) + " Missing";
this[`_${name}`].dataset.missingString = missingValueString;
}
}
connectedCallback() {
for (let name of ["name", "street-address", "email", "tel"]) {
this.appendChild(this[`_${name}`]);
}
this.appendChild(this._line1);
this.appendChild(this._line2);
super.connectedCallback();
}
@ -61,14 +78,72 @@ export default class AddressOption extends ObservedPropertiesMixin(RichOption) {
return PaymentDialogUtils.getAddressLabel(address, addressFields);
}
get requiredFields() {
if (this.hasAttribute("address-fields")) {
let names = this.getAttribute("address-fields").trim().split(/\s+/);
if (names.length) {
return names;
}
}
return [
// "address-level1", // TODO: bug 1481481 - not required for some countries e.g. DE
"address-level2",
"country",
"name",
"postal-code",
"street-address",
];
}
render() {
// Clear the lines of the fields so we can append only the ones still
// visible in the correct order below.
this._line1.textContent = "";
this._line2.textContent = "";
// Fill the fields with their text/strings.
// Fall back to empty strings to prevent 'null' from appearing.
this._name.textContent = this.name || "";
this["_street-address"].textContent =
`${this.streetAddress || ""} ${this.addressLevel2 || ""} ` +
`${this.addressLevel1 || ""} ${this.postalCode || ""} ${this.country || ""}`;
this._email.textContent = this.email || "";
this._tel.textContent = this.tel || "";
for (let name of AddressOption.recordAttributes) {
let camelCaseName = super.constructor.kebabToCamelCase(name);
let fieldEl = this[`_${name}`];
fieldEl.textContent = this[camelCaseName] || "";
}
let {fieldsOrder} = PaymentDialogUtils.getFormFormat(this.country);
// A subset of the requested fields may be returned if the fields don't apply to the country.
let requestedVisibleFields = this.addressFields || "mailing-address";
let visibleFields = EditAddress.computeVisibleFields(fieldsOrder, requestedVisibleFields);
let visibleFieldCount = 0;
let requiredFields = this.requiredFields;
// Start by populating line 1
let lineEl = this._line1;
// Which field number to start line 2 after.
let breakAfterNthField = this.breakAfterNthField || 2;
// Now actually place the fields in the proper place on the lines.
for (let field of visibleFields) {
let fieldEl = this[`_${field.fieldId}`];
if (!fieldEl) {
log.warn(`address-option render: '${field.fieldId}' doesn't exist`);
continue;
}
if (!fieldEl.textContent && !requiredFields.includes(field.fieldId)) {
// The field is empty and we don't need to show "Missing …" so don't append.
continue;
}
if (lineEl.children.length > 0) {
lineEl.append(this.dataset.fieldSeparator);
}
lineEl.appendChild(fieldEl);
// Add a break after this field, if requested.
if (++visibleFieldCount == breakAfterNthField) {
lineEl = this._line2;
}
}
}
}

Просмотреть файл

@ -13,8 +13,16 @@ import paymentRequest from "../paymentRequest.js";
*/
export default class AddressPicker extends RichPicker {
static get pickerAttributes() {
return [
"address-fields",
"break-after-nth-field",
"data-field-separator",
];
}
static get observedAttributes() {
return RichPicker.observedAttributes.concat(["address-fields"]);
return RichPicker.observedAttributes.concat(AddressPicker.pickerAttributes);
}
constructor() {
@ -24,7 +32,7 @@ export default class AddressPicker extends RichPicker {
attributeChangedCallback(name, oldValue, newValue) {
super.attributeChangedCallback(name, oldValue, newValue);
if (name == "address-fields" && oldValue !== newValue) {
if (AddressPicker.pickerAttributes.includes(name) && oldValue !== newValue) {
this.render(this.requestStore.getState());
}
}
@ -100,6 +108,20 @@ export default class AddressPicker extends RichPicker {
}
}
optionEl.dataset.fieldSeparator = this.dataset.fieldSeparator;
if (this.hasAttribute("address-fields")) {
optionEl.setAttribute("address-fields", this.getAttribute("address-fields"));
} else {
optionEl.removeAttribute("address-fields");
}
if (this.hasAttribute("break-after-nth-field")) {
optionEl.setAttribute("break-after-nth-field", this.getAttribute("break-after-nth-field"));
} else {
optionEl.removeAttribute("break-after-nth-field");
}
// fieldNames getter is not used here because it returns a default array with
// attributes even when "address-fields" observed attribute is null.
let addressFields = this.getAttribute("address-fields");

Просмотреть файл

@ -265,6 +265,39 @@ export default class PaymentDialog extends PaymentStateSubscriberMixin(HTMLEleme
}
}
_renderPayerFields(state) {
let paymentOptions = state.request.paymentOptions;
let payerRequested = this._isPayerRequested(paymentOptions);
for (let element of this._payerRelatedEls) {
element.hidden = !payerRequested;
}
if (payerRequested) {
let fieldNames = new Set(); // default: ["name", "tel", "email"]
if (paymentOptions.requestPayerName) {
fieldNames.add("name");
}
if (paymentOptions.requestPayerEmail) {
fieldNames.add("email");
}
if (paymentOptions.requestPayerPhone) {
fieldNames.add("tel");
}
this._payerAddressPicker.setAttribute("address-fields", [...fieldNames].join(" "));
// For the payer picker we want to have a line break after the name field (#1)
// if all three fields are requested.
if (fieldNames.size == 3) {
this._payerAddressPicker.setAttribute("break-after-nth-field", 1);
} else {
this._payerAddressPicker.removeAttribute("break-after-nth-field");
}
} else {
this._payerAddressPicker.removeAttribute("address-fields");
}
this._payerAddressPicker.dataset.addAddressTitle = this.dataset.payerTitleAdd;
this._payerAddressPicker.dataset.editAddressTitle = this.dataset.payerTitleEdit;
}
stateChangeCallback(state) {
super.stateChangeCallback(state);
@ -325,28 +358,8 @@ export default class PaymentDialog extends PaymentStateSubscriberMixin(HTMLEleme
for (let element of this._shippingRelatedEls) {
element.hidden = !paymentOptions.requestShipping;
}
let payerRequested = this._isPayerRequested(paymentOptions);
for (let element of this._payerRelatedEls) {
element.hidden = !payerRequested;
}
if (payerRequested) {
let fieldNames = new Set(); // default: ["name", "tel", "email"]
if (paymentOptions.requestPayerName) {
fieldNames.add("name");
}
if (paymentOptions.requestPayerEmail) {
fieldNames.add("email");
}
if (paymentOptions.requestPayerPhone) {
fieldNames.add("tel");
}
this._payerAddressPicker.setAttribute("address-fields", [...fieldNames].join(" "));
} else {
this._payerAddressPicker.removeAttribute("address-fields");
}
this._payerAddressPicker.dataset.addAddressTitle = this.dataset.payerTitleAdd;
this._payerAddressPicker.dataset.editAddressTitle = this.dataset.payerTitleEdit;
this._renderPayerFields(state);
// hide the accepted cards list if the merchant didn't specify a preference
let basicCardMethod = request.paymentMethods

Просмотреть файл

@ -63,8 +63,15 @@ export default class RichPicker extends PaymentStateSubscriberMixin(HTMLElement)
}
get selectedOption() {
return this.dropdown &&
this.dropdown.selectedOption;
return this.dropdown.selectedOption;
}
get selectedRichOption() {
return this.dropdown.selectedRichOption;
}
get requiredFields() {
return this.selectedOption ? this.selectedOption.requiredFields || [] : [];
}
get fieldNames() {
@ -81,7 +88,7 @@ export default class RichPicker extends PaymentStateSubscriberMixin(HTMLElement)
return [];
}
let fieldNames = this.fieldNames;
let fieldNames = this.selectedRichOption.requiredFields;
// Return all field names that are empty or missing from the option.
return fieldNames.filter(name => !selectedOption.getAttribute(name));
}

Просмотреть файл

@ -220,9 +220,26 @@ let ADDRESSES_1 = {
"abcde12345": {
"address-level2": "Mountain View",
"country": "US",
"family-name": "Fields",
"given-name": "Mrs.",
"guid": "abcde12345",
"name": "Mrs. Fields",
},
"german1": {
"additional-name": "Y.",
"address-level1": "",
"address-level2": "Berlin",
"country": "DE",
"email": "de@example.com",
"family-name": "Mouse",
"given-name": "Anon",
"guid": "german1",
"name": "Anon Y. Mouse",
"organization": "Mozilla",
"postal-code": "10997",
"street-address": "Schlesische Str. 27",
"tel": "+49 30 983333002",
},
"missing-country": {
"address-level1": "ON",
"address-level2": "Toronto",

Просмотреть файл

@ -10,6 +10,10 @@
export default function ObservedPropertiesMixin(superClass) {
return class ObservedProperties extends superClass {
static kebabToCamelCase(name) {
return name.replace(/-([a-z])/g, ($0, $1) => $1.toUpperCase());
}
constructor() {
super();
@ -24,7 +28,7 @@ export default function ObservedPropertiesMixin(superClass) {
continue;
}
// Convert attribute names from kebab-case to camelCase properties
Object.defineProperty(this, name.replace(/-([a-z])/g, ($0, $1) => $1.toUpperCase()), {
Object.defineProperty(this, ObservedProperties.kebabToCamelCase(name), {
configurable: true,
get() {
return this.getAttribute(name);

Просмотреть файл

@ -23,6 +23,7 @@
<!ENTITY deliveryGenericError "Cant deliver to this address. Select a different address.">
<!ENTITY pickupGenericError "Cant pick up from this address. Select a different address.">
<!ENTITY paymentMethodsLabel "Payment Method">
<!ENTITY address.fieldSeparator ", ">
<!ENTITY address.addLink.label "Add">
<!ENTITY address.editLink.label "Edit">
<!ENTITY basicCard.addLink.label "Add">
@ -132,6 +133,7 @@
<address-picker class="shipping-related"
data-add-link-label="&address.addLink.label;"
data-edit-link-label="&address.editLink.label;"
data-field-separator="&address.fieldSeparator;"
data-shipping-address-label="&shippingAddressLabel;"
data-delivery-address-label="&deliveryAddressLabel;"
data-pickup-address-label="&pickupAddressLabel;"
@ -155,6 +157,7 @@
label="&payerLabel;"
data-add-link-label="&payer.addLink.label;"
data-edit-link-label="&payer.editLink.label;"
data-field-separator="&address.fieldSeparator;"
data-invalid-label="&invalidOption.label;"
selected-state-key="selectedPayerAddress"></address-picker>
</div>

Просмотреть файл

@ -81,11 +81,11 @@ var PaymentDialogUtils = {
"postalCodeLabel": country == "US" ? "zip" : "postalCode",
"fieldsOrder": [
{fieldId: "name", newLine: true},
{fieldId: "organization", newLine: true},
{fieldId: "street-address", newLine: true},
{fieldId: "address-level2"},
{fieldId: "address-level1"},
{fieldId: "postal-code"},
{fieldId: "organization"},
],
// The following values come from addressReferences.js and should not be changed.
/* eslint-disable-next-line max-len */

Просмотреть файл

@ -13,6 +13,7 @@ skip-if = !e10s
[test_accepted_cards.html]
[test_address_form.html]
[test_address_option.html]
[test_address_picker.html]
[test_basic_card_form.html]
[test_basic_card_option.html]

Просмотреть файл

@ -0,0 +1,179 @@
<!DOCTYPE HTML>
<html>
<!--
Test the address-option component
-->
<head>
<meta charset="utf-8">
<title>Test the address-option component</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/AddTask.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script src="payments_common.js"></script>
<script src="../../res/vendor/custom-elements.min.js"></script>
<script src="../../res/unprivileged-fallbacks.js"></script>
<script src="autofillEditForms.js"></script>
<link rel="stylesheet" type="text/css" href="../../res/components/rich-select.css"/>
<link rel="stylesheet" type="text/css" href="../../res/components/address-option.css"/>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display">
<option id="option1"
data-field-separator=", "
address-level1="MI"
address-level2="Some City"
country="US"
email="foo@bar.com"
name="John Smith"
postal-code="90210"
street-address="123 Sesame Street,&#xA;Apt 40"
tel="+1 519 555-5555"
value="option1"
guid="option1"></option>
<option id="option2"
data-field-separator=", "
value="option2"
guid="option2"></option>
<rich-select id="richSelect1"
option-type="address-option"></rich-select>
</p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
<script type="module">
/** Test the address-option component **/
import "../../res/components/address-option.js";
import "../../res/components/rich-select.js";
let option1 = document.getElementById("option1");
let option2 = document.getElementById("option2");
let richSelect1 = document.getElementById("richSelect1");
add_task(async function test_populated_option_rendering() {
richSelect1.popupBox.appendChild(option1);
richSelect1.value = option1.value;
await asyncElementRendered();
let richOption = richSelect1.selectedRichOption;
is(richOption.name, "John Smith", "Check name getter");
is(richOption.streetAddress, "123 Sesame Street,\nApt 40", "Check streetAddress getter");
is(richOption.addressLevel2, "Some City", "Check addressLevel2 getter");
ok(!richOption.innerText.includes("undefined"), "Check for presence of 'undefined'");
ok(!richOption.innerText.includes("null"), "Check for presence of 'null'");
ok(!richOption._line1.innerText.trim().endsWith(","), "Line 1 should not end with a comma");
ok(!richOption._line2.innerText.trim().endsWith(","), "Line 2 should not end with a comma");
is(richOption._line1.innerText, "John Smith, 123 Sesame Street, Apt 40", "Line 1 text");
is(richOption._line2.innerText, "Some City, MI, 90210, US", "Line 2 text");
// Note that innerText takes visibility into account so that's why it's used over textContent here
is(richOption._name.innerText, "John Smith", "name text");
is(richOption["_street-address"].innerText, "123 Sesame Street, Apt 40", "street-address text");
is(richOption["_address-level2"].innerText, "Some City", "address-level2 text");
is(richOption._email.parentElement, null,
"Check email field isn't in the document for a mailing-address option");
});
// Same option as the last test but with @break-after-nth-field=1
add_task(async function test_breakAfterNthField() {
richSelect1.popupBox.appendChild(option1);
richSelect1.value = option1.value;
await asyncElementRendered();
let richOption = richSelect1.selectedRichOption;
richOption.breakAfterNthField = 1;
await asyncElementRendered();
ok(!richOption.innerText.includes("undefined"), "Check for presence of 'undefined'");
ok(!richOption.innerText.includes("null"), "Check for presence of 'null'");
ok(!richOption._line1.innerText.trim().endsWith(","), "Line 1 should not end with a comma");
ok(!richOption._line2.innerText.trim().endsWith(","), "Line 2 should not end with a comma");
is(richOption._line1.innerText, "John Smith", "Line 1 text with breakAfterNthField = 1");
is(richOption._line2.innerText, "123 Sesame Street, Apt 40, Some City, MI, 90210, US",
"Line 2 text with breakAfterNthField = 1");
});
add_task(async function test_addressField_mailingAddress() {
richSelect1.popupBox.appendChild(option1);
richSelect1.value = option1.value;
await asyncElementRendered();
let richOption = richSelect1.selectedRichOption;
richOption.addressFields = "mailing-address";
await asyncElementRendered();
is(richOption.getAttribute("address-fields"), "mailing-address", "Check @address-fields");
ok(!richOption.innerText.includes("undefined"), "Check for presence of 'undefined'");
ok(!richOption.innerText.includes("null"), "Check for presence of 'null'");
ok(!richOption._line1.innerText.trim().endsWith(","), "Line 1 should not end with a comma");
ok(!richOption._line2.innerText.trim().endsWith(","), "Line 2 should not end with a comma");
is(richOption._line1.innerText, "John Smith, 123 Sesame Street, Apt 40", "Line 1 text");
is(richOption._line2.innerText, "Some City, MI, 90210, US", "Line 2 text");
ok(!isHidden(richOption._line2), "Line 2 should be visible when it's used");
is(richOption._email.parentElement, null,
"Check email field isn't in the document for a mailing-address option");
});
add_task(async function test_addressField_nameEmail() {
richSelect1.popupBox.appendChild(option1);
richSelect1.value = option1.value;
await asyncElementRendered();
let richOption = richSelect1.selectedRichOption;
richOption.addressFields = "name email";
await asyncElementRendered();
is(richOption.getAttribute("address-fields"), "name email", "Check @address-fields");
ok(!richOption.innerText.includes("undefined"), "Check for presence of 'undefined'");
ok(!richOption.innerText.includes("null"), "Check for presence of 'null'");
ok(!richOption._line1.innerText.trim().endsWith(","), "Line 1 should not end with a comma");
ok(!richOption._line2.innerText.trim().endsWith(","), "Line 2 should not end with a comma");
is(richOption._line1.innerText, "John Smith, foo@bar.com", "Line 1 text");
is(richOption._line2.innerText, "", "Line 2 text");
ok(isHidden(richOption._line2), "Line 2 should be hidden when it's not used");
isnot(richOption._email.parentElement, null,
"Check email field is in the document for a 'name email' option");
});
add_task(async function test_missing_fields_option_rendering() {
richSelect1.popupBox.appendChild(option2);
richSelect1.value = option2.value;
await asyncElementRendered();
let richOption = richSelect1.selectedRichOption;
is(richOption.name, null, "Check name getter");
is(richOption.streetAddress, null, "Check streetAddress getter");
is(richOption.addressLevel2, null, "Check addressLevel2 getter");
ok(!richOption.innerText.includes("undefined"), "Check for presence of 'undefined'");
ok(!richOption.innerText.includes("null"), "Check for presence of 'null'");
is(richOption._name.innerText, "", "name text");
is(window.getComputedStyle(richOption._name, "::before").content, "attr(data-missing-string)",
"Check missing field pseudo content");
is(richOption._name.getAttribute("data-missing-string"), "Name Missing",
"Check @data-missing-string");
is(richOption._email.parentElement, null,
"Check email field isn't in the document for a mailing-address option");
});
</script>
</body>
</html>

Просмотреть файл

@ -12,6 +12,7 @@ Test the address-picker component
<script src="payments_common.js"></script>
<script src="../../res/vendor/custom-elements.min.js"></script>
<script src="../../res/unprivileged-fallbacks.js"></script>
<script src="autofillEditForms.js"></script>
<link rel="stylesheet" type="text/css" href="../../res/containers/rich-picker.css"/>
<link rel="stylesheet" type="text/css" href="../../res/components/rich-select.css"/>
@ -21,6 +22,7 @@ Test the address-picker component
<body>
<p id="display">
<address-picker id="picker1"
data-field-separator=", "
selected-state-key="selectedShippingAddress"></address-picker>
</p>
<div id="content" style="display: none">
@ -162,13 +164,13 @@ add_task(async function test_change_selected_address() {
ok(isHidden(picker1.invalidLabel), "The invalid label should be hidden");
});
add_task(async function test_streetAddress_combines_street_level2_level1_postalCode_country() {
add_task(async function test_address_combines_name_street_level2_level1_postalCode_country() {
let options = picker1.dropdown.popupBox.children;
let richoption1 = picker1.dropdown.querySelector(".rich-select-selected-option");
let streetAddress = richoption1.querySelector(".street-address");
/* eslint-disable max-len */
is(streetAddress.textContent,
`${options[1].getAttribute("street-address")} ${options[1].getAttribute("address-level2")} ${options[1].getAttribute("address-level1")} ${options[1].getAttribute("postal-code")} ${options[1].getAttribute("country")}`,
is(richoption1.innerText,
`${options[1].getAttribute("name")}, ${options[1].getAttribute("street-address")}
${options[1].getAttribute("address-level2")}, ${options[1].getAttribute("address-level1")}, ${options[1].getAttribute("postal-code")}, ${options[1].getAttribute("country")}`,
"The address shown should be human readable and include all fields");
/* eslint-enable max-len */
@ -177,8 +179,8 @@ add_task(async function test_streetAddress_combines_street_level2_level1_postalC
await asyncElementRendered();
richoption1 = picker1.dropdown.querySelector(".rich-select-selected-option");
streetAddress = richoption1.querySelector(".street-address");
is(streetAddress.textContent, " Mountain View US",
// "Missing …" text is rendered via a pseudo element content and isn't included in innerText
is(richoption1.innerText, "Mrs. Fields, \nMountain View, , US",
"The address shown should be human readable and include all fields");
picker1.dropdown.popupBox.focus();

Просмотреть файл

@ -12,6 +12,7 @@ Test the paymentOptions address-picker
<script src="../../res/vendor/custom-elements.min.js"></script>
<script src="../../res/unprivileged-fallbacks.js"></script>
<script src="autofillEditForms.js"></script>
<link rel="stylesheet" type="text/css" href="../../res/components/rich-select.css"/>
<link rel="stylesheet" type="text/css" href="../../res/components/address-option.css"/>
@ -19,7 +20,7 @@ Test the paymentOptions address-picker
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display">
<p id="display" style="height: 100vh; margin: 0;">
<iframe id="templateFrame" src="../../res/paymentRequest.xhtml" width="0" height="0"></iframe>
</p>
<div id="content" style="display: none">
@ -126,11 +127,7 @@ add_task(async function setup_once() {
await SimpleTest.promiseFocus(templateFrame.contentWindow);
let displayEl = document.getElementById("display");
// Import the templates from the real shipping dialog to avoid duplication.
for (let template of templateFrame.contentDocument.querySelectorAll("template")) {
let imported = document.importNode(template, true);
displayEl.appendChild(imported);
}
importDialogDependencies(templateFrame, displayEl);
elDialog = new PaymentDialog();
displayEl.appendChild(elDialog);
@ -193,8 +190,7 @@ add_task(async function test_visible_fields() {
ok(elem, `field ${fieldName} exists`);
ok(isVisible(elem), `field ${fieldName} is visible`);
}
ok(!isVisible(closedRichOption.querySelector(".street-address")),
"street-address is not visible");
ok(!closedRichOption.querySelector(".street-address"), "street-address element is not present");
});
add_task(async function test_selective_fields() {
@ -207,6 +203,7 @@ add_task(async function test_selective_fields() {
});
let payerFieldVariations = [
{requestPayerName: true, requestPayerEmail: true, requestPayerPhone: true },
{requestPayerName: true, requestPayerEmail: false, requestPayerPhone: false },
{requestPayerName: false, requestPayerEmail: true, requestPayerPhone: false },
{requestPayerName: false, requestPayerEmail: false, requestPayerPhone: true },
@ -224,12 +221,22 @@ add_task(async function test_selective_fields() {
let elEmail = closedRichOption.querySelector(".email");
let elPhone = closedRichOption.querySelector(".tel");
is(isVisible(elName), payerFields.requestPayerName,
is(!!elName && isVisible(elName), payerFields.requestPayerName,
"name field is correctly toggled");
is(isVisible(elEmail), payerFields.requestPayerEmail,
is(!!elEmail && isVisible(elEmail), payerFields.requestPayerEmail,
"email field is correctly toggled");
is(isVisible(elPhone), payerFields.requestPayerPhone,
is(!!elPhone && isVisible(elPhone), payerFields.requestPayerPhone,
"tel field is correctly toggled");
let numPayerFieldsRequested = [...Object.values(payerFields)].filter(val => val).length;
is(elPicker.getAttribute("break-after-nth-field"), numPayerFieldsRequested == 3 ? "1" : null,
"Check @break-after-nth-field");
if (numPayerFieldsRequested == 3) {
is(closedRichOption.breakAfterNthField, "1",
"Make sure @break-after-nth-field was propagated to <address-option>");
} else {
is(closedRichOption.breakAfterNthField, null, "Make sure @break-after-nth-field was cleared");
}
}
});

Просмотреть файл

@ -13,6 +13,7 @@ Test the payment-dialog custom element
<script src="payments_common.js"></script>
<script src="../../res/vendor/custom-elements.min.js"></script>
<script src="../../res/unprivileged-fallbacks.js"></script>
<script src="autofillEditForms.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<link rel="stylesheet" type="text/css" href="../../res/paymentRequest.css"/>

Просмотреть файл

@ -12,6 +12,7 @@ Test the payment-dialog custom element
<script src="payments_common.js"></script>
<script src="../../res/vendor/custom-elements.min.js"></script>
<script src="../../res/unprivileged-fallbacks.js"></script>
<script src="autofillEditForms.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<link rel="stylesheet" type="text/css" href="../../res/paymentRequest.css"/>

Просмотреть файл

@ -11,6 +11,8 @@ Test the rich-select component
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script src="payments_common.js"></script>
<script src="../../res/vendor/custom-elements.min.js"></script>
<script src="../../res/unprivileged-fallbacks.js"></script>
<script src="autofillEditForms.js"></script>
<link rel="stylesheet" type="text/css" href="../../res/components/rich-select.css"/>
<link rel="stylesheet" type="text/css" href="../../res/components/address-option.css"/>
@ -61,6 +63,7 @@ for (let address of Object.values(addresses)) {
let option = document.createElement("option");
option.textContent = address.name + " " + address["street-address"];
option.setAttribute("value", address.guid);
option.dataset.fieldSeparator = ", ";
for (let field of Object.keys(address)) {
option.setAttribute(field, address[field]);
}

Просмотреть файл

@ -160,10 +160,10 @@ class EditAddress extends EditAutofillForm {
* `mailing-address` is a special attribute token to indicate mailing fields + country.
*
* @param {object[]} mailingFieldsOrder - `fieldsOrder` from `getFormFormat`
* @param {string} addressFields - white-space-separated string of requested address fields to show
* @returns {object[]} in the same structure as `mailingFieldsOrder` but including non-mail fields
*/
computeVisibleFields(mailingFieldsOrder) {
let addressFields = this._elements.form.dataset.addressFields;
static computeVisibleFields(mailingFieldsOrder, addressFields) {
if (addressFields) {
let requestedFieldClasses = addressFields.trim().split(/\s+/);
let fieldClasses = [];
@ -212,7 +212,8 @@ class EditAddress extends EditAutofillForm {
} = this.getFormFormat(country);
this._elements.addressLevel1Label.dataset.localization = addressLevel1Label;
this._elements.postalCodeLabel.dataset.localization = postalCodeLabel;
let fieldClasses = this.computeVisibleFields(mailingFieldsOrder);
let addressFields = this._elements.form.dataset.addressFields;
let fieldClasses = EditAddress.computeVisibleFields(mailingFieldsOrder, addressFields);
this.arrangeFields(fieldClasses);
this.updatePostalCodeValidation(postalCodePattern);
}