Bug 1485473 - Combine the borders of the name fields on the address form. r=sfoster

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Matthew Noorenberghe 2018-08-24 23:21:30 +00:00
parent 9daee9a3a5
commit 487d770cc3
8 changed files with 196 additions and 25 deletions

View file

@ -26,7 +26,7 @@ body[dir="rtl"] .error-text {
right: 3px;
}
:-moz-any(input, textarea, select):focus + .error-text:not(:empty)::before {
:-moz-any(input, textarea, select):focus ~ .error-text:not(:empty)::before {
background-color: #d70022;
top: -7px;
content: '.';
@ -47,8 +47,8 @@ body[dir=rtl] .error-text::before {
right: 12px
}
:-moz-any(input, textarea, select):not(:focus) + .error-text,
:-moz-any(input, textarea, select):valid + .error-text {
:-moz-any(input, textarea, select):not(:focus) ~ .error-text,
:-moz-any(input, textarea, select):valid ~ .error-text {
display: none;
}

View file

@ -297,6 +297,7 @@ add_task(async function test_restricted_address_fields() {
"tel should be visible");
fillField(form.form.querySelector("#given-name"), "John");
fillField(form.form.querySelector("#family-name"), "Smith");
ok(form.saveButton.disabled, "Save button should be disabled due to empty fields");
fillField(form.form.querySelector("#email"), "john@example.com");
todo(form.saveButton.disabled,

View file

@ -18,57 +18,61 @@
</head>
<body dir="&locale.dir;">
<form id="form" class="editAddressForm" autocomplete="off">
<!--
The <span class="label-text" /> needs to be after the form field in the same element in
order to get proper label styling with :focus and :moz-ui-invalid.
-->
<div>
<div id="name-container">
<label id="given-name-container">
<span data-localization="givenName" class="label-text"/>
<input id="given-name" type="text" required="required"/>
<span data-localization="givenName" class="label-text"/>
</label>
<label id="additional-name-container">
<span data-localization="additionalName" class="label-text"/>
<input id="additional-name" type="text"/>
<span data-localization="additionalName" class="label-text"/>
</label>
<label id="family-name-container">
<input id="family-name" type="text" required="required"/>
<span data-localization="familyName" class="label-text"/>
<input id="family-name" type="text"/>
</label>
</div>
<label id="organization-container">
<span data-localization="organization2" class="label-text"/>
<input id="organization" type="text"/>
<span data-localization="organization2" class="label-text"/>
</label>
<label id="street-address-container">
<span data-localization="streetAddress" class="label-text"/>
<textarea id="street-address" rows="3" required="required"/>
<span data-localization="streetAddress" class="label-text"/>
</label>
<label id="address-level2-container">
<span data-localization="city" class="label-text"/>
<input id="address-level2" type="text" required="required"/>
<span data-localization="city" class="label-text"/>
</label>
<label id="address-level1-container">
<span class="label-text"/>
<input id="address-level1" type="text" required="required"/>
<span class="label-text"/>
</label>
<label id="postal-code-container">
<span class="label-text"/>
<input id="postal-code" type="text" required="required"/>
<span class="label-text"/>
</label>
<div id="country-container">
<label id="country-label">
<span data-localization="country" class="label-text"/>
<select id="country" required="required">
<option/>
</select>
<span data-localization="country" class="label-text"/>
</label>
<p id="country-warning-message" data-localization="countryWarningMessage2"/>
</div>
<label id="tel-container">
<span data-localization="tel" class="label-text"/>
<input id="tel" type="tel"/>
<span data-localization="tel" class="label-text"/>
</label>
<label id="email-container">
<span data-localization="email" class="label-text"/>
<input id="email" type="email" required="required"/>
<span data-localization="email" class="label-text"/>
</label>
</div>
</form>

View file

@ -18,17 +18,20 @@
</head>
<body dir="&locale.dir;">
<form id="form" class="editCreditCardForm" autocomplete="off">
<!--
The <span class="label-text" /> needs to be after the form field in the same element in
order to get proper label styling with :focus and :moz-ui-invalid.
-->
<label>
<span data-localization="cardNumber" class="label-text"/>
<span id="invalidCardNumberString" hidden="hidden" data-localization="invalidCardNumber"></span>
<input id="cc-number" type="text" required="required" minlength="9" pattern="[- 0-9]+"/>
<span data-localization="cardNumber" class="label-text"/>
</label>
<label>
<span data-localization="nameOnCard" class="label-text"/>
<input id="cc-name" type="text" required="required"/>
<span data-localization="nameOnCard" class="label-text"/>
</label>
<label>
<span data-localization="cardExpiresMonth" class="label-text"/>
<select id="cc-exp-month">
<option/>
<option value="1">01</option>
@ -44,17 +47,18 @@
<option value="11">11</option>
<option value="12">12</option>
</select>
<span data-localization="cardExpiresMonth" class="label-text"/>
</label>
<label>
<span data-localization="cardExpiresYear" class="label-text"/>
<select id="cc-exp-year">
<option/>
</select>
<span data-localization="cardExpiresYear" class="label-text"/>
</label>
<label class="billingAddressRow">
<span data-localization="billingAddress" class="label-text"/>
<select id="billingAddressGUID">
</select>
<span data-localization="billingAddress" class="label-text"/>
</label>
</form>
<div id="controls-container">

View file

@ -8,6 +8,12 @@
margin: 0;
}
#name-container,
:root[subdialog] form label,
:root[subdialog] form > p {
margin: 0 0 0.5em !important;
}
#given-name-container,
#additional-name-container,
#address-level1-container,
@ -22,14 +28,74 @@
flex: 0 1 50%;
}
/* Begin name field rules */
#name-container input {
/* Override the default @size="20" on <input>, which acts like a min-width, not
* allowing the fields to shrink with flexbox as small as they need to to match
* the other rows. This is noticeable on narrow viewports e.g. in the
* PaymentRequest dialog on Linux due to the larger font-size. */
width: 0;
}
/* When there is focus within any of the name fields, the border of the inputs
* should be the focused color, except for inner ones which get overriden below. */
#name-container:focus-within input {
border-color: var(--in-content-border-focus);
}
/* Invalid name fields should show the error outline instead of the focus border */
#name-container:focus-within input:-moz-ui-invalid {
border-color: transparent;
}
#given-name-container,
#additional-name-container,
#family-name-container {
display: flex;
/* Remove the bottom margin from the name containers so that the outer
#name-container provides the margin on the outside */
margin-bottom: 0 !important;
margin-left: 0;
margin-right: 0;
}
/* The name fields are placed adjacent to each other.
Remove the border-radius on adjacent fields. */
#given-name:dir(ltr),
#family-name:dir(rtl) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-right-width: 0;
}
#given-name:dir(rtl),
#family-name:dir(ltr) {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
border-left-width: 0;
}
#additional-name {
border-radius: 0;
/* This provides the inner separators between the fields and should never
* change to the focused color. */
border-left-color: var(--in-content-box-border-color) !important;
border-right-color: var(--in-content-box-border-color) !important;
}
/* Since the name fields are adjacent, there isn't room for the -moz-ui-invalid
box-shadow so raise invalid name fields and their labels above the siblings
so the shadow is shown around all 4 sides. */
#name-container input:-moz-ui-invalid,
#name-container input:-moz-ui-invalid ~ .label-text {
z-index: 1;
}
/* End name field rules */
#name-container,
#street-address-container,
#country-container,

View file

@ -13,11 +13,6 @@
padding: 2px;
}
:root[subdialog] form label,
:root[subdialog] form > p {
margin: 0 0 0.5em !important;
}
form input[type="email"],
form input[type="tel"],
form input[type="text"],
@ -55,10 +50,16 @@ form :-moz-any(label, div) > .label-text[field-populated] {
font-size: var(--in-field-label-size);
}
form :-moz-any(label, div):focus-within > .label-text {
form :-moz-any(input, select, textarea):focus ~ .label-text {
color: var(--in-content-item-selected);
}
/* Focused error fields should get a darker text but not the blue one since it
* doesn't look good with the red error outline. */
form :-moz-any(input, select, textarea):focus:-moz-ui-invalid ~ .label-text {
color: var(--in-content-text-color);
}
form div[required] > label > .label-text::after,
form :-moz-any(label, div)[required] > .label-text::after {
content: attr(fieldRequiredSymbol);

View file

@ -208,3 +208,89 @@ add_task(async function test_saveAddressDE() {
}
await removeAllRecords();
});
add_task(async function test_combined_name_fields() {
await testDialog(EDIT_ADDRESS_DIALOG_URL, async win => {
let doc = win.document;
let givenNameField = doc.querySelector("#given-name");
let addtlNameField = doc.querySelector("#additional-name");
let familyNameField = doc.querySelector("#family-name");
function getComputedPropertyValue(field, property) {
return win.getComputedStyle(field).getPropertyValue(property);
}
function checkNameComputedPropertiesMatch(field, property, value, checkFn = is) {
checkFn(getComputedPropertyValue(field, property), value,
`Check ${field.id}'s ${property} is ${value}`);
}
function checkNameFieldBorders(borderColorUnfocused, borderColorFocused) {
info("checking the perimeter colors");
checkNameComputedPropertiesMatch(givenNameField, "border-top-color", borderColorFocused);
checkNameComputedPropertiesMatch(addtlNameField, "border-top-color", borderColorFocused);
checkNameComputedPropertiesMatch(familyNameField, "border-top-color", borderColorFocused);
checkNameComputedPropertiesMatch(familyNameField, "border-right-color", borderColorFocused);
checkNameComputedPropertiesMatch(givenNameField, "border-bottom-color", borderColorFocused);
checkNameComputedPropertiesMatch(addtlNameField, "border-bottom-color", borderColorFocused);
checkNameComputedPropertiesMatch(familyNameField, "border-bottom-color", borderColorFocused);
checkNameComputedPropertiesMatch(givenNameField, "border-left-color", borderColorFocused);
info("checking the internal borders");
checkNameComputedPropertiesMatch(givenNameField, "border-right-width", "0px");
checkNameComputedPropertiesMatch(addtlNameField, "border-left-width", "2px");
checkNameComputedPropertiesMatch(addtlNameField, "border-left-color", borderColorFocused, isnot);
checkNameComputedPropertiesMatch(addtlNameField, "border-right-width", "2px");
checkNameComputedPropertiesMatch(addtlNameField, "border-right-color", borderColorFocused, isnot);
checkNameComputedPropertiesMatch(familyNameField, "border-left-width", "0px");
}
// Set these variables since the test doesn't run from a subdialog and
// therefore doesn't get the additional common CSS files injected.
let borderColor = "rgb(0, 255, 0)";
let borderColorFocused = "rgb(0, 0, 255)";
doc.body.style.setProperty("--in-content-box-border-color", borderColor);
doc.body.style.setProperty("--in-content-border-focus", borderColorFocused);
givenNameField.focus();
checkNameFieldBorders(borderColor, borderColorFocused);
addtlNameField.focus();
checkNameFieldBorders(borderColor, borderColorFocused);
familyNameField.focus();
checkNameFieldBorders(borderColor, borderColorFocused);
info("unfocusing the name fields");
let cancelButton = doc.querySelector("#cancel");
cancelButton.focus();
borderColor = getComputedPropertyValue(givenNameField, "border-top-color");
isnot(borderColor, borderColorFocused, "Check that the border color is different");
checkNameFieldBorders(borderColor, borderColor);
cancelButton.click();
});
});
add_task(async function test_combined_name_fields_error() {
await testDialog(EDIT_ADDRESS_DIALOG_URL, async win => {
let doc = win.document;
let givenNameField = doc.querySelector("#given-name");
info("mark the given name field as invalid");
givenNameField.value = "";
givenNameField.focus();
ok(givenNameField.matches(":-moz-ui-invalid"), "Check field is visually invalid");
let givenNameLabel = doc.querySelector("#given-name-container .label-text");
// Override pointer-events so that we can use elementFromPoint to know if
// the label text is visible.
givenNameLabel.style.pointerEvents = "auto";
let givenNameLabelRect = givenNameLabel.getBoundingClientRect();
// Get the center of the label
let el = doc.elementFromPoint(givenNameLabelRect.left + givenNameLabelRect.width / 2,
givenNameLabelRect.top + givenNameLabelRect.height / 2);
is(el, givenNameLabel, "Check that the label text is visible in the error state");
is(win.getComputedStyle(givenNameField).getPropertyValue("border-top-color"),
"rgba(0, 0, 0, 0)", "Border should be transparent so that only the error outline shows");
doc.querySelector("#cancel").click();
});
});

View file

@ -506,6 +506,15 @@ xul|textbox[focused] {
border-color: var(--in-content-border-focus);
}
/* Don't show the field error outlines and focus borders at the same time */
html|input[type="email"]:-moz-ui-invalid:focus,
html|input[type="tel"]:-moz-ui-invalid:focus,
html|input[type="text"]:-moz-ui-invalid:focus,
html|textarea:-moz-ui-invalid:focus,
xul|textbox[focused] {
border-color: transparent;
}
html|input[type="email"]:disabled,
html|input[type="tel"]:disabled,
html|input[type="text"]:disabled,