<form id="change-email-form">
<input type="text"
name="username"
id="username"
placeholder="username"
pattern="[a-zA-Z ]{5,}"
maxlength="30"
required
class="form-control">
<div class="validation-messages">
<span data-rule="valueMissing" class="hide">The username is required.</span>
<span data-rule="patternMismatch" class="hide">Must be a series of alpha
characters only (min 5, max 30).</span>
</div>
<input type="email"
id="email"
placeholder="email address"
title="Email address is required"
required
class="form-control">
<div class="validation-messages">
<span data-rule="valueMissing" class="hide">
An email address is required.</span>
<span data-rule="typeMismatch" class="hide">
Special characters are not allowed.</span>
</div>
<div class="push-down-top">
<button type="button" class="btn btn-link">Cancel</button>
<button type="button" id="login-button" class="btn">Login</button>
</div>
</form>
input:focus:invalid,
textarea:focus:invalid,
select:focus:invalid {
color: #c33;
border-color: #c33;
}
input:focus:invalid:focus,
textarea:focus:invalid:focus,
select:focus:invalid:focus {
border-color: #c33;
-webkit-box-shadow: 0 0 6px #fcc;
-moz-box-shadow: 0 0 6px #fcc;
box-shadow: 0 0 6px #fcc;
}
input:invalid,
textarea:invalid,
select:invalid {
border-bottom: 1px solid #c33;
}
input:valid + .invalid /* Adjacent sibling selector */ {
visibility: hidden;
}
input:invalid + .invalid {
visibility: visible;
}
input:required {
border-left: 4px solid #c33;
}
input:valid {
border-bottom: transparent;
}
.invalid {
color: #999;
}
document.addEventListener('DOMContentLoaded', function(e) {
// Create a container for
// validation rule names.
var ruleNames = [];
var forEach = Array.prototype.forEach;
// Fills array with rule names.
// Looks for all SPANs with the data-rule
// attribute and then adds the rule
// name to the array.
var ruleElements = document.querySelectorAll('span[data-rule]');
forEach.call(ruleElements, function(element) {
var ruleName = element.getAttribute('data-rule');
if (ruleNames.indexOf(ruleNames) < 0) {
ruleNames.push(ruleName);
}
});
// First clear the UI by hiding all
// validation messages. Then run
// validation rules on the selected form.
var validate = function() {
var messages = document.querySelectorAll(".validation-messages span");
forEach.call(messages, function(message){
message.classList.add('hide')
});
document.getElementById('change-email-form').checkValidity();
};
// Check each input element to determine
// which element is invalid. Once an
// invalid state is detected, then loop
// through the validation rules to find
// out which is broken and therefore
// which message to display to the user.
var validationFail = function(e) {
var element, validity;
element = e.currentTarget;
validity = element.validity;
if (!validity.valid) {
ruleNames.forEach(function(ruleName) {
checkRule(validity,ruleName,element);
});
e.preventDefault();
}
};
// Uses the instance of the input element's
// ValidityState object to run a validation
// rule. If the validation rule returns
// 'true' then the rule is broken and
// the appropriate validation message
//is exposed to the user.
var checkRule = function(state, ruleName, element) {
if (state[ruleName]) {
var rules = element
.nextElementSibling
.querySelectorAll('[data-rule="' + ruleName + '"]');
forEach.call(rules, function(rule){
rule.classList.remove('hide');
});
}
};
// Attaches validation event handlers to
// all input elements that are NOT buttons.
var inputElements = document.querySelectorAll('input:not(button)');
forEach.call(inputElements, function(input) {
input.oninvalid = validationFail;
input.onblur = validate;
});
document.getElementById('login-button').addEventListener('click', validate, false);
});