238 lines
6.8 KiB
JavaScript
238 lines
6.8 KiB
JavaScript
(function() {
|
|
// Before using it we must add the parse and format functions
|
|
// Here is a sample implementation using moment.js
|
|
validate.extend(validate.validators.datetime, {
|
|
// The value is guaranteed not to be null or undefined but otherwise it
|
|
// could be anything.
|
|
parse: function(value, options) {
|
|
return +moment.utc(value);
|
|
},
|
|
// Input is a unix timestamp
|
|
format: function(value, options) {
|
|
var format = options.dateOnly ? "YYYY-MM-DD" : "YYYY-MM-DD hh:mm:ss";
|
|
return moment.utc(value).format(format);
|
|
}
|
|
});
|
|
|
|
// These are the constraints used to validate the form
|
|
var constraints = {
|
|
email: {
|
|
// Email is required
|
|
presence: true,
|
|
// and must be an email (duh)
|
|
email: true
|
|
},
|
|
password: {
|
|
// Password is also required
|
|
presence: true,
|
|
// And must be at least 5 characters long
|
|
length: {
|
|
minimum: 5
|
|
}
|
|
},
|
|
"confirm-password": {
|
|
// You need to confirm your password
|
|
presence: true,
|
|
// and it needs to be equal to the other password
|
|
equality: {
|
|
attribute: "password",
|
|
message: "^The passwords does not match"
|
|
}
|
|
},
|
|
username: {
|
|
// You need to pick a username too
|
|
presence: true,
|
|
// And it must be between 3 and 20 characters long
|
|
length: {
|
|
minimum: 3,
|
|
maximum: 20
|
|
},
|
|
format: {
|
|
// We don't allow anything that a-z and 0-9
|
|
pattern: "[a-z0-9]+",
|
|
// but we don't care if the username is uppercase or lowercase
|
|
flags: "i",
|
|
message: "can only contain a-z and 0-9"
|
|
}
|
|
},
|
|
birthdate: {
|
|
// The user needs to give a birthday
|
|
presence: true,
|
|
// and must be born at least 18 years ago
|
|
date: {
|
|
latest: moment().subtract(18, "years"),
|
|
message: "^You must be at least 18 years old to use this service"
|
|
}
|
|
},
|
|
country: {
|
|
// You also need to input where you live
|
|
presence: true,
|
|
// And we restrict the countries supported to Sweden
|
|
inclusion: {
|
|
within: ["SE"],
|
|
// The ^ prevents the field name from being prepended to the error
|
|
message: "^Sorry, this service is for Sweden only"
|
|
}
|
|
},
|
|
zip: {
|
|
// Zip is optional but if specified it must be a 5 digit long number
|
|
format: {
|
|
pattern: "\\d{5}"
|
|
}
|
|
},
|
|
"number-of-children": {
|
|
presence: true,
|
|
// Number of children has to be an integer >= 0
|
|
numericality: {
|
|
onlyInteger: true,
|
|
greaterThanOrEqualTo: 0
|
|
}
|
|
}
|
|
};
|
|
|
|
// Hook up the form so we can prevent it from being posted
|
|
var form = document.querySelector("form#main");
|
|
form.addEventListener("submit", function(ev) {
|
|
ev.preventDefault();
|
|
handleFormSubmit(form);
|
|
});
|
|
|
|
// Hook up the inputs to validate on the fly
|
|
var inputs = document.querySelectorAll("input, textarea, select");
|
|
for (var i = 0; i < inputs.length; ++i) {
|
|
inputs.item(i).addEventListener("change", function(ev) {
|
|
var errors = validate(form, constraints) || {};
|
|
showErrorsForInput(this, errors[this.name]);
|
|
});
|
|
}
|
|
|
|
function handleFormSubmit(form, input) {
|
|
// validate the form against the constraints
|
|
var errors = validate(form, constraints);
|
|
// then we update the form to reflect the results
|
|
showErrors(form, errors || {});
|
|
if (!errors) {
|
|
showSuccess();
|
|
}
|
|
}
|
|
|
|
// Updates the inputs with the validation errors
|
|
function showErrors(form, errors) {
|
|
// We loop through all the inputs and show the errors for that input
|
|
_.each(form.querySelectorAll("input[name], select[name]"), function(input) {
|
|
// Since the errors can be null if no errors were found we need to handle
|
|
// that
|
|
showErrorsForInput(input, errors && errors[input.name]);
|
|
});
|
|
}
|
|
|
|
// Shows the errors for a specific input
|
|
function showErrorsForInput(input, errors) {
|
|
// This is the root of the input
|
|
var formGroup = closestParent(input.parentNode, "form-group"),
|
|
// Find where the error messages will be insert into
|
|
messages = formGroup.querySelector(".messages");
|
|
// First we remove any old messages and resets the classes
|
|
resetFormGroup(formGroup);
|
|
// If we have errors
|
|
if (errors) {
|
|
// we first mark the group has having errors
|
|
formGroup.classList.add("has-error");
|
|
// then we append all the errors
|
|
_.each(errors, function(error) {
|
|
addError(messages, error);
|
|
});
|
|
} else {
|
|
// otherwise we simply mark it as success
|
|
formGroup.classList.add("has-success");
|
|
}
|
|
}
|
|
|
|
// Recusively finds the closest parent that has the specified class
|
|
function closestParent(child, className) {
|
|
if (!child || child == document) {
|
|
return null;
|
|
}
|
|
if (child.classList.contains(className)) {
|
|
return child;
|
|
} else {
|
|
return closestParent(child.parentNode, className);
|
|
}
|
|
}
|
|
|
|
function resetFormGroup(formGroup) {
|
|
// Remove the success and error classes
|
|
formGroup.classList.remove("has-error");
|
|
formGroup.classList.remove("has-success");
|
|
// and remove any old messages
|
|
_.each(formGroup.querySelectorAll(".help-block.error"), function(el) {
|
|
el.parentNode.removeChild(el);
|
|
});
|
|
}
|
|
|
|
// Adds the specified error with the following markup
|
|
// <p class="help-block error">[message]</p>
|
|
function addError(messages, error) {
|
|
var block = document.createElement("p");
|
|
block.classList.add("help-block");
|
|
block.classList.add("error");
|
|
block.innerText = error;
|
|
messages.appendChild(block);
|
|
}
|
|
|
|
function showSuccess() {
|
|
// We made it \:D/
|
|
alert("Success!");
|
|
}
|
|
})();
|
|
/////////////////////////////////////////////////
|
|
const isPresent = $input => {
|
|
return $input && $input!=="" && $input != null;
|
|
}
|
|
|
|
const isNumber = $input => {
|
|
const simpleNumberRegex = /[+-]?(?:\d*[.,])?\d+/;
|
|
return $input && $input.length <250 && simpleNumberRegex.test($input);
|
|
|
|
}
|
|
|
|
const isInteger = $input => {
|
|
const simpleIntegerRegex = /^([+-]?[1-9]\d*|0)$/;
|
|
return $input && $input.length <250 && simpleIntegerRegex.test($input);
|
|
|
|
}
|
|
|
|
const validate = (input) => {
|
|
|
|
const valid;
|
|
const errorMsg;
|
|
const constraint = input.constraint[0];
|
|
|
|
switch (constraint) {
|
|
case "required":
|
|
valid = isPresent ($(`#${input.dbField}`).val());
|
|
errorMsg = ["Ovo je obavezno polje."];
|
|
break;
|
|
case "numerical":
|
|
valid = isNumber ($(`#${input.dbField}`).val());
|
|
errorMsg = ["Unesite brojcanu vrijednost."];
|
|
break;
|
|
case "integer":
|
|
valid = isInteger ($(`#${input.dbField}`).val());
|
|
errorMsg = ["Unesite cijeli broj."];
|
|
|
|
break;
|
|
default :
|
|
valid = true;
|
|
}
|
|
if (!valid) {
|
|
const inputField = document.querySelector(`#${input.dbField}`);
|
|
showErrorsForInput( inputField, errorMsg);
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
|
|
}
|
|
|