c401d6411b
Improves the create account modal for screen readers by doing the following:
* Making the `modal-alert` section into an `aria-role="alert"` region and making it show and hide using height instead of display:none so screen readers pick it up. Made a change so the field-related error messages are always shown beneath the field.
* Add `aria-invalid` and `aria-describedby` attributes to each field in the modal, so the screen reader will read out the error hint on error. This necessitated an Ember component extension to allow both the `aria-*` attributes to be bound and to render on `{{input}}`.
* Moved the social login buttons to the right in the HTML structure so they are not read out first.
* Added `aria-label` attributes to the login buttons so they can have different content for screen readers.
* In some cases for modals, the title that should be used for the `aria-labelledby` attribute is within the modal content and not the discourse-modal-title title. This introduces a new titleAriaElementId property to the d-modal component that is then used by the create-account modal to read out the title
------
This is the same as e0d2de73d8 but
fixes the Ember-input-component-extension to use the public
Ember components TextField and TextArea instead of the private
TextSupport so the extension works in both normal Ember and
Ember CLI.
112 lines
2.7 KiB
JavaScript
112 lines
2.7 KiB
JavaScript
import EmberObject from "@ember/object";
|
|
import I18n from "I18n";
|
|
import Mixin from "@ember/object/mixin";
|
|
import discourseComputed from "discourse-common/utils/decorators";
|
|
import { isEmpty } from "@ember/utils";
|
|
|
|
export default Mixin.create({
|
|
rejectedPasswords: null,
|
|
|
|
init() {
|
|
this._super(...arguments);
|
|
this.set("rejectedPasswords", []);
|
|
this.set("rejectedPasswordsMessages", new Map());
|
|
},
|
|
|
|
@discourseComputed("passwordMinLength")
|
|
passwordInstructions() {
|
|
return I18n.t("user.password.instructions", {
|
|
count: this.passwordMinLength,
|
|
});
|
|
},
|
|
|
|
@discourseComputed("isDeveloper", "admin")
|
|
passwordMinLength(isDeveloper, admin) {
|
|
return isDeveloper || admin
|
|
? this.siteSettings.min_admin_password_length
|
|
: this.siteSettings.min_password_length;
|
|
},
|
|
|
|
@discourseComputed(
|
|
"accountPassword",
|
|
"passwordRequired",
|
|
"rejectedPasswords.[]",
|
|
"accountUsername",
|
|
"accountEmail",
|
|
"passwordMinLength",
|
|
"forceValidationReason"
|
|
)
|
|
passwordValidation(
|
|
password,
|
|
passwordRequired,
|
|
rejectedPasswords,
|
|
accountUsername,
|
|
accountEmail,
|
|
passwordMinLength,
|
|
forceValidationReason
|
|
) {
|
|
const failedAttrs = {
|
|
failed: true,
|
|
ok: false,
|
|
element: document.querySelector("#new-account-password"),
|
|
};
|
|
|
|
if (!passwordRequired) {
|
|
return EmberObject.create({ ok: true });
|
|
}
|
|
|
|
if (rejectedPasswords.includes(password)) {
|
|
return EmberObject.create(
|
|
Object.assign(failedAttrs, {
|
|
reason:
|
|
this.rejectedPasswordsMessages.get(password) ||
|
|
I18n.t("user.password.common"),
|
|
})
|
|
);
|
|
}
|
|
|
|
// If blank, fail without a reason
|
|
if (isEmpty(password)) {
|
|
return EmberObject.create(
|
|
Object.assign(failedAttrs, {
|
|
message: I18n.t("user.password.required"),
|
|
reason: forceValidationReason
|
|
? I18n.t("user.password.required")
|
|
: null,
|
|
})
|
|
);
|
|
}
|
|
|
|
// If too short
|
|
if (password.length < passwordMinLength) {
|
|
return EmberObject.create(
|
|
Object.assign(failedAttrs, {
|
|
reason: I18n.t("user.password.too_short"),
|
|
})
|
|
);
|
|
}
|
|
|
|
if (!isEmpty(accountUsername) && password === accountUsername) {
|
|
return EmberObject.create(
|
|
Object.assign(failedAttrs, {
|
|
reason: I18n.t("user.password.same_as_username"),
|
|
})
|
|
);
|
|
}
|
|
|
|
if (!isEmpty(accountEmail) && password === accountEmail) {
|
|
return EmberObject.create(
|
|
Object.assign(failedAttrs, {
|
|
reason: I18n.t("user.password.same_as_email"),
|
|
})
|
|
);
|
|
}
|
|
|
|
// Looks good!
|
|
return EmberObject.create({
|
|
ok: true,
|
|
reason: I18n.t("user.password.ok"),
|
|
});
|
|
},
|
|
});
|