Commit 93bd3dd8 authored by Bryce Johnson's avatar Bryce Johnson

Upgrade gl_field_errors to support more use cases.

parent aba94f65
...@@ -4,18 +4,56 @@ ...@@ -4,18 +4,56 @@
* This class overrides the browser's validation error bubbles, displaying custom * This class overrides the browser's validation error bubbles, displaying custom
* error messages for invalid fields instead. To begin validating any form, add the * error messages for invalid fields instead. To begin validating any form, add the
* class `show-gl-field-errors` to the form element, and ensure error messages are * class `show-gl-field-errors` to the form element, and ensure error messages are
* declared in each inputs' title attribute. * declared in each inputs' `title` attribute. If no title is declared for an invalid
* field the user attempts to submit, "This field is required." will be shown by default.
* *
* Example: * Opt not to validate certain fields by adding the class `gl-field-error-ignore` to the input.
*
* Set a custom error anchor for error message to be injected after with the class `gl-field-error-anchor`
*
* Examples:
*
* Basic:
* *
* <form class='show-gl-field-errors'> * <form class='show-gl-field-errors'>
* <input type='text' name='username' title='Username is required.'/> * <input type='text' name='username' title='Username is required.'/>
*</form> * </form>
*
* Ignore specific inputs (e.g. UsernameValidator):
*
* <form class='show-gl-field-errors'>
* <div class="form-group>
* <input type='text' class='gl-field-errors-ignore' pattern='[a-zA-Z0-9-_]+'/>
* </div>
* <div class="form-group">
* <input type='text' name='username' title='Username is required.'/>
* </div>
* </form>
*
* Custom Error Anchor (allows error message to be injected after specified element):
*
* <form class='show-gl-field-errors'>
* <div class="form-group gl-field-error-anchor">
* <input type='text' name='username' title='Username is required.'/>
* // Error message typically injected here
* </div>
* // Error message now injected here
* </form>
*
* */
/*
* Regex Patterns in use:
*
* Only alphanumeric: : "[a-zA-Z0-9]+"
* No special characters : "[a-zA-Z0-9-_]+",
* *
* */ * */
const errorMessageClass = 'gl-field-error'; const errorMessageClass = 'gl-field-error';
const inputErrorClass = 'gl-field-error-outline'; const inputErrorClass = 'gl-field-error-outline';
const errorAnchorSelector = '.gl-field-error-anchor';
const ignoreInputSelector = '.gl-field-error-ignore';
class GlFieldError { class GlFieldError {
constructor({ input, formErrors }) { constructor({ input, formErrors }) {
...@@ -34,16 +72,18 @@ ...@@ -34,16 +72,18 @@
} }
initFieldValidation() { initFieldValidation() {
const customErrorAnchor = this.inputElement.parents(errorAnchorSelector);
const errorAnchor = customErrorAnchor.length ? customErrorAnchor : this.inputElement;
// hidden when injected into DOM // hidden when injected into DOM
this.inputElement.after(this.fieldErrorElement); errorAnchor.after(this.fieldErrorElement);
this.inputElement.off('invalid').on('invalid', this.handleInvalidSubmit.bind(this)); this.inputElement.off('invalid').on('invalid', this.handleInvalidSubmit.bind(this));
this.scopedSiblings = this.safelySelectSiblings(); this.scopedSiblings = this.safelySelectSiblings();
} }
safelySelectSiblings() { safelySelectSiblings() {
// Apply `ignoreSelector` in markup to siblings whose visibility should not be toggled with input validity // Apply `ignoreSelector` in markup to siblings whose visibility should not be toggled with input validity
const ignoreSelector = '.validation-ignore'; const unignoredSiblings = this.inputElement.siblings(`p:not(${ignoreInputSelector})`);
const unignoredSiblings = this.inputElement.siblings(`p:not(${ignoreSelector})`);
const parentContainer = this.inputElement.parent('.form-group'); const parentContainer = this.inputElement.parent('.form-group');
// Only select siblings when they're scoped within a form-group with one input // Only select siblings when they're scoped within a form-group with one input
...@@ -125,7 +165,7 @@ ...@@ -125,7 +165,7 @@
} }
} }
const customValidationFlag = 'no-gl-field-errors'; const customValidationFlag = 'gl-field-error-ignore';
class GlFieldErrors { class GlFieldErrors {
constructor(form) { constructor(form) {
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
this.inputElement.on('keyup.username_check', () => { this.inputElement.on('keyup.username_check', () => {
const username = this.inputElement.val(); const username = this.inputElement.val();
this.state.valid = this.inputDomElement.validity.valid; this.state.valid = this.inputDomElement.validity.valid;
this.state.empty = !username.length; this.state.empty = !username.length;
......
...@@ -136,3 +136,35 @@ label { ...@@ -136,3 +136,35 @@ label {
color: $red-normal; color: $red-normal;
} }
.show-gl-field-errors {
.gl-field-success-outline {
border: 1px solid $green-normal;
&:focus {
box-shadow: 0 0 0 1px $green-normal inset, 0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 4px 0 $green-normal;
border: 0 none;
}
}
.gl-field-error-outline {
border: 1px solid $red-normal;
&:focus {
box-shadow: 0 0 0 1px $red-normal inset, 0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 4px 0 rgba(210, 40, 82, 0.6);
border: 0 none;
}
}
.gl-field-success-message {
color: $green-normal;
}
.gl-field-error-message {
color: $red-normal;
}
.gl-field-hint {
color: $gl-text-color;
}
}
...@@ -75,43 +75,17 @@ ...@@ -75,43 +75,17 @@
.login-body { .login-body {
font-size: 13px; font-size: 13px;
input + p { input + p {
margin-top: 5px; margin-top: 5px;
} }
.gl-field-success-outline { .username .validation-success {
border: 1px solid $green-normal;
&:focus {
box-shadow: 0 0 0 1px $green-normal inset, 0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 4px 0 $green-normal;
border: 0 none;
}
}
.gl-field-error-outline {
border: 1px solid $red-normal;
&:focus {
box-shadow: 0 0 0 1px $red-normal inset, 0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 4px 0 rgba(210, 40, 82, 0.6);
border: 0 none;
}
}
.username .validation-success,
.gl-field-success-message {
color: $green-normal; color: $green-normal;
} }
.username .validation-error, .username .validation-error {
.gl-field-error-message {
color: $red-normal; color: $red-normal;
} }
.gl-field-hint {
color: $gl-text-color;
}
} }
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
= f.text_field :name, class: "form-control top", required: true, title: "This field is required." = f.text_field :name, class: "form-control top", required: true, title: "This field is required."
%div.username.form-group %div.username.form-group
= f.label :username = f.label :username
= f.text_field :username, class: "form-control middle no-gl-field-error", pattern: "[a-zA-Z0-9]+", required: true, title: 'Please create a username with only alphanumeric characters.' = f.text_field :username, class: "form-control middle", pattern: "[a-zA-Z0-9]+", required: true, title: 'Please create a username with only alphanumeric characters.'
%p.validation-error.hide Username is already taken. %p.validation-error.hide Username is already taken.
%p.validation-success.hide Username is available. %p.validation-success.hide Username is available.
%p.validation-pending.hide Checking username availability... %p.validation-pending.hide Checking username availability...
......
...@@ -10,6 +10,6 @@ ...@@ -10,6 +10,6 @@
.form-group .form-group
%input.hidden{ type:'hidden' } %input.hidden{ type:'hidden' }
.form-group .form-group
%input.custom.no-gl-field-errors{ type:'text' } Custom, do not validate %input.custom.gl-field-error-ignore{ type:'text' } Custom, do not validate
.form-group .form-group
%input.submit{type: 'submit'} Submit %input.submit{type: 'submit'} Submit
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
}); });
it('should ignore elements with custom error handling', function() { it('should ignore elements with custom error handling', function() {
const customErrorFlag = 'no-gl-field-errors'; const customErrorFlag = 'gl-field-error-ignore';
const customErrorElem = $(`.${customErrorFlag}`); const customErrorElem = $(`.${customErrorFlag}`);
expect(customErrorElem.length).toBe(1); expect(customErrorElem.length).toBe(1);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment