forked from mirrors/gecko-dev
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:
parent
9daee9a3a5
commit
487d770cc3
8 changed files with 196 additions and 25 deletions
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in a new issue