metro4
Version:
The front-end framework for Build responsive, mobile-first projects on the web with the first front-end component library in Metro Style
454 lines (397 loc) • 15.9 kB
JavaScript
/* global Metro, Datetime, datetime */
(function(Metro, $) {
'use strict';
var Utils = Metro.utils;
var ValidatorFuncs = {
required: function(val){
if (Array.isArray(val)) {
return val.length > 0 ? val : false;
} else {
return Utils.isValue(val) ? val.trim() : false;
}
},
length: function(val, len){
if (Array.isArray(val)) {return val.length === parseInt(len);}
if (!Utils.isValue(len) || isNaN(len) || len <= 0) {
return false;
}
return val.trim().length === parseInt(len);
},
minlength: function(val, len){
if (Array.isArray(val)) {return val.length >= parseInt(len);}
if (!Utils.isValue(len) || isNaN(len) || len <= 0) {
return false;
}
return val.trim().length >= parseInt(len);
},
maxlength: function(val, len){
if (Array.isArray(val)) {return val.length <= parseInt(len);}
if (!Utils.isValue(len) || isNaN(len) || len <= 0) {
return false;
}
return val.trim().length <= parseInt(len);
},
min: function(val, min_value){
if (!Utils.isValue(min_value) || isNaN(min_value)) {
return false;
}
if (!this.number(val)) {
return false;
}
if (isNaN(val)) {
return false;
}
return Number(val) >= Number(min_value);
},
max: function(val, max_value){
if (!Utils.isValue(max_value) || isNaN(max_value)) {
return false;
}
if (!this.number(val)) {
return false;
}
if (isNaN(val)) {
return false;
}
return Number(val) <= Number(max_value);
},
email: function(val){
/* eslint-disable-next-line */
return /^[a-z0-9\u007F-\uffff!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9\u007F-\uffff!#$%&'*+\/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z]{2,}$/i.test(val);
},
domain: function(val){
/* eslint-disable-next-line */
return /^((xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$/.test(val);
},
url: function(val){
/* eslint-disable-next-line */
var regexp = /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z0-9\u00a1-\uffff][a-z0-9\u00a1-\uffff_-]{0,62})?[a-z0-9\u00a1-\uffff]\.)+(?:[a-z\u00a1-\uffff]{2,}\.?))(?::\d{2,5})?(?:[/?#]\S*)?$/i;
return regexp.test(val);
},
date: function(val, format, locale){
try {
if (!format) {
datetime(val);
} else {
Datetime.from(val, format, locale);
}
return true;
} catch (e) {
return false;
}
},
number: function(val){
return !isNaN(val);
},
integer: function(val){
return Utils.isInt(val);
},
float: function(val){
return Utils.isFloat(val);
},
digits: function(val){
return /^\d+$/.test(val);
},
hexcolor: function(val){
/* eslint-disable-next-line */
return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(val);
},
color: function(val){
if (!Utils.isValue(val)) return false;
return Metro.colors.color(val, Metro.colors.PALETTES.STANDARD) !== false || Metro.colors.isColor(Metro.colors.parse(val));
},
pattern: function(val, pat){
if (!Utils.isValue(val)) return false;
if (!Utils.isValue(pat)) return false;
var reg = new RegExp(pat);
return reg.test(val);
},
compare: function(val, val2){
return val === val2;
},
not: function(val, not_this){
return val !== not_this;
},
notequals: function(val, val2){
if (Utils.isNull(val)) return false;
if (Utils.isNull(val2)) return false;
return val.trim() !== val2.trim();
},
equals: function(val, val2){
if (Utils.isNull(val)) return false;
if (Utils.isNull(val2)) return false;
return val.trim() === val2.trim();
},
custom: function(val, func){
if (Utils.isFunc(func) === false) {
return false;
}
return Utils.exec(func, [val]);
},
is_control: function(el){
return el.parent().hasClass("input")
|| el.parent().hasClass("select")
|| el.parent().hasClass("textarea")
|| el.parent().hasClass("checkbox")
|| el.parent().hasClass("switch")
|| el.parent().hasClass("radio")
|| el.parent().hasClass("spinner")
;
},
reset_state: function(el){
var input = $(el);
var is_control = ValidatorFuncs.is_control(input);
if (is_control) {
input.parent().removeClass("invalid valid");
} else {
input.removeClass("invalid valid");
}
},
set_valid_state: function(el){
var input = $(el);
var is_control = ValidatorFuncs.is_control(input);
if (is_control) {
input.parent().addClass("valid");
} else {
input.addClass("valid");
}
},
set_invalid_state: function(el){
var input = $(el);
var is_control = ValidatorFuncs.is_control(input);
if (is_control) {
input.parent().addClass("invalid");
} else {
input.addClass("invalid");
}
},
reset: function(form){
var that = this;
$.each($(form).find("[data-validate]"), function(){
that.reset_state(this);
});
return this;
},
validate: function(el, result, cb_ok, cb_error, required_mode){
var this_result = true;
var input = $(el);
var funcs = input.data('validate') !== undefined ? String(input.data('validate')).split(" ").map(function(s){return s.trim();}) : [];
var errors = [];
var hasForm = input.closest('form').length > 0;
var attr_name, radio_checked;
if (funcs.length === 0) {
return true;
}
this.reset_state(input);
if (input.attr('type') && input.attr('type').toLowerCase() === "checkbox") {
if (funcs.indexOf('required') === -1) {
this_result = true;
} else {
this_result = input.is(":checked");
}
if (this_result === false) {
errors.push('required');
}
if (result !== undefined) {
result.val += this_result ? 0 : 1;
}
} else if (input.attr('type') && input.attr('type').toLowerCase() === "radio") {
attr_name = input.attr('name');
if (typeof attr_name === undefined) {
this_result = true;
} else {
/*
* Fix with escaped name by nlared https://github.com/nlared
* */
radio_checked = $("input[name=" + attr_name.replace("[", "\\\[").replace("]", "\\\]") + "]:checked"); // eslint-disable-line
this_result = radio_checked.length > 0;
}
if (result !== undefined) {
result.val += this_result ? 0 : 1;
}
} else {
$.each(funcs, function(){
if (this_result === false) return;
var rule = this.split("=");
var f, a, b;
f = rule[0]; rule.shift();
a = rule.join("=");
if (['compare', 'equals', 'notequals'].indexOf(f) > -1) {
a = hasForm ? input[0].form.elements[a].value : $("[name="+a+"]").val();
}
if (f === 'date') {
a = input.attr("data-value-format");
b = input.attr("data-value-locale");
}
if (Utils.isFunc(ValidatorFuncs[f]) === false) {
this_result = true;
} else {
if (required_mode === true || f === "required") {
this_result = ValidatorFuncs[f](input.val(), a, b);
} else {
if (input.val().trim() !== "") {
this_result = ValidatorFuncs[f](input.val(), a, b);
} else {
this_result = true;
}
}
}
if (this_result === false) {
errors.push(f);
}
if (result !== undefined) {
result.val += this_result ? 0 : 1;
}
});
}
if (this_result === false) {
this.set_invalid_state(input);
if (result !== undefined) {
result.log.push({
input: input[0],
name: input.attr("name"),
value: input.val(),
funcs: funcs,
errors: errors
});
}
if (cb_error !== undefined) Utils.exec(cb_error, [input, input.val()], input[0]);
} else {
this.set_valid_state(input);
if (cb_ok !== undefined) Utils.exec(cb_ok, [input, input.val()], input[0]);
}
return this_result;
}
};
Metro['validator'] = ValidatorFuncs;
var ValidatorDefaultConfig = {
validatorDeferred: 0,
submitTimeout: 200,
interactiveCheck: false,
clearInvalid: 0,
requiredMode: true,
useRequiredClass: true,
onBeforeSubmit: Metro.noop_true,
onSubmit: Metro.noop,
onError: Metro.noop,
onValidate: Metro.noop,
onErrorForm: Metro.noop,
onValidateForm: Metro.noop,
onValidatorCreate: Metro.noop
};
Metro.validatorSetup = function (options) {
ValidatorDefaultConfig = $.extend({}, ValidatorDefaultConfig, options);
};
if (typeof window["metroValidatorSetup"] !== undefined) {
Metro.validatorSetup(window["metroValidatorSetup"]);
}
Metro.Component('validator', {
name: "Validator",
init: function( options, elem ) {
this._super(elem, options, ValidatorDefaultConfig, {
_onsubmit: null,
_onreset: null,
result: []
});
return this;
},
_create: function(){
var that = this, element = this.element, o = this.options;
var inputs = element.find("[data-validate]");
element
.attr("novalidate", 'novalidate');
$.each(inputs, function(){
var input = $(this);
var funcs = input.data("validate");
var required = funcs.indexOf("required") > -1;
if (required && o.useRequiredClass === true) {
if (ValidatorFuncs.is_control(input)) {
input.parent().addClass("required");
} else {
input.addClass("required");
}
}
if (o.interactiveCheck === true) {
input.on(Metro.events.inputchange, function () {
ValidatorFuncs.validate(this, undefined, undefined, undefined, o.requiredMode);
});
}
});
this._onsubmit = null;
this._onreset = null;
if (element[0].onsubmit !== null) {
this._onsubmit = element[0].onsubmit;
element[0].onsubmit = null;
}
if (element[0].onreset !== null) {
this._onreset = element[0].onreset;
element[0].onreset = null;
}
element[0].onsubmit = function(){
return that._submit();
};
element[0].onreset = function(){
return that._reset();
};
this._fireEvent("validator-create", {
element: element
});
},
_reset: function(){
ValidatorFuncs.reset(this.element);
if (this._onreset !== null) Utils.exec(this._onreset, null, this.element[0]);
},
_submit: function(){
var that = this, element = this.element, o = this.options;
var form = this.elem;
var inputs = element.find("[data-validate]");
var submit = element.find("input[type=submit], button[type=submit]");
var result = {
val: 0,
log: []
};
var formData = $.serializeToArray(element);
if (submit.length > 0) {
submit.attr('disabled', 'disabled').addClass('disabled');
}
$.each(inputs, function(){
ValidatorFuncs.validate(this, result, o.onValidate, o.onError, o.requiredMode);
});
submit.removeAttr("disabled").removeClass("disabled");
result.val += Utils.exec(o.onBeforeSubmit, [formData], this.elem) === false ? 1 : 0;
if (result.val === 0) {
this._fireEvent("validate-form", {
data: formData
});
setTimeout(function(){
// TODO need fix event name to equivalent
Utils.exec(o.onSubmit, [formData], form);
element.fire("formsubmit", {
data: formData
});
if (that._onsubmit !== null) Utils.exec(that._onsubmit, null, form);
}, o.submitTimeout);
} else {
this._fireEvent("error-form", {
log: result.log,
data: formData
});
if (o.clearInvalid > 0) {
setTimeout(function(){
$.each(inputs, function(){
var inp = $(this);
if (ValidatorFuncs.is_control(inp)) {
inp.parent().removeClass("invalid");
} else {
inp.removeClass("invalid");
}
})
}, o.clearInvalid);
}
}
return result.val === 0;
},
changeAttribute: function(){
}
});
}(Metro, m4q));