345 lines
22 KiB
JavaScript
345 lines
22 KiB
JavaScript
/**
|
|
* Kendo UI v2016.1.226 (http://www.telerik.com/kendo-ui)
|
|
* Copyright 2016 Telerik AD. All rights reserved.
|
|
*
|
|
* Kendo UI commercial licenses may be obtained at
|
|
* http://www.telerik.com/purchase/license-agreement/kendo-ui-complete
|
|
* If you do not own a commercial license, this file shall be governed by the trial license terms.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/
|
|
(function (f, define) {
|
|
define('kendo.validator', ['kendo.core'], f);
|
|
}(function () {
|
|
var __meta__ = {
|
|
id: 'validator',
|
|
name: 'Validator',
|
|
category: 'web',
|
|
description: 'The Validator offers an easy way to do a client-side form validation.',
|
|
depends: ['core']
|
|
};
|
|
(function ($, undefined) {
|
|
var kendo = window.kendo, Widget = kendo.ui.Widget, NS = '.kendoValidator', INVALIDMSG = 'k-invalid-msg', invalidMsgRegExp = new RegExp(INVALIDMSG, 'i'), INVALIDINPUT = 'k-invalid', VALIDINPUT = 'k-valid', emailRegExp = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i, urlRegExp = /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i, INPUTSELECTOR = ':input:not(:button,[type=submit],[type=reset],[disabled],[readonly])', CHECKBOXSELECTOR = ':checkbox:not([disabled],[readonly])', NUMBERINPUTSELECTOR = '[type=number],[type=range]', BLUR = 'blur', NAME = 'name', FORM = 'form', NOVALIDATE = 'novalidate', proxy = $.proxy, patternMatcher = function (value, pattern) {
|
|
if (typeof pattern === 'string') {
|
|
pattern = new RegExp('^(?:' + pattern + ')$');
|
|
}
|
|
return pattern.test(value);
|
|
}, matcher = function (input, selector, pattern) {
|
|
var value = input.val();
|
|
if (input.filter(selector).length && value !== '') {
|
|
return patternMatcher(value, pattern);
|
|
}
|
|
return true;
|
|
}, hasAttribute = function (input, name) {
|
|
if (input.length) {
|
|
return input[0].attributes[name] != null;
|
|
}
|
|
return false;
|
|
};
|
|
if (!kendo.ui.validator) {
|
|
kendo.ui.validator = {
|
|
rules: {},
|
|
messages: {}
|
|
};
|
|
}
|
|
function resolveRules(element) {
|
|
var resolvers = kendo.ui.validator.ruleResolvers || {}, rules = {}, name;
|
|
for (name in resolvers) {
|
|
$.extend(true, rules, resolvers[name].resolve(element));
|
|
}
|
|
return rules;
|
|
}
|
|
function decode(value) {
|
|
return value.replace(/&/g, '&').replace(/"/g, '"').replace(/'/g, '\'').replace(/</g, '<').replace(/>/g, '>');
|
|
}
|
|
function numberOfDecimalDigits(value) {
|
|
value = (value + '').split('.');
|
|
if (value.length > 1) {
|
|
return value[1].length;
|
|
}
|
|
return 0;
|
|
}
|
|
function parseHtml(text) {
|
|
if ($.parseHTML) {
|
|
return $($.parseHTML(text));
|
|
}
|
|
return $(text);
|
|
}
|
|
function searchForMessageContainer(elements, fieldName) {
|
|
var containers = $(), element, attr;
|
|
for (var idx = 0, length = elements.length; idx < length; idx++) {
|
|
element = elements[idx];
|
|
if (invalidMsgRegExp.test(element.className)) {
|
|
attr = element.getAttribute(kendo.attr('for'));
|
|
if (attr === fieldName) {
|
|
containers = containers.add(element);
|
|
}
|
|
}
|
|
}
|
|
return containers;
|
|
}
|
|
var Validator = Widget.extend({
|
|
init: function (element, options) {
|
|
var that = this, resolved = resolveRules(element), validateAttributeSelector = '[' + kendo.attr('validate') + '!=false]';
|
|
options = options || {};
|
|
options.rules = $.extend({}, kendo.ui.validator.rules, resolved.rules, options.rules);
|
|
options.messages = $.extend({}, kendo.ui.validator.messages, resolved.messages, options.messages);
|
|
Widget.fn.init.call(that, element, options);
|
|
that._errorTemplate = kendo.template(that.options.errorTemplate);
|
|
if (that.element.is(FORM)) {
|
|
that.element.attr(NOVALIDATE, NOVALIDATE);
|
|
}
|
|
that._inputSelector = INPUTSELECTOR + validateAttributeSelector;
|
|
that._checkboxSelector = CHECKBOXSELECTOR + validateAttributeSelector;
|
|
that._errors = {};
|
|
that._attachEvents();
|
|
that._isValidated = false;
|
|
},
|
|
events: [
|
|
'validate',
|
|
'change'
|
|
],
|
|
options: {
|
|
name: 'Validator',
|
|
errorTemplate: '<span class="k-widget k-tooltip k-tooltip-validation">' + '<span class="k-icon k-warning"> </span> #=message#</span>',
|
|
messages: {
|
|
required: '{0} is required',
|
|
pattern: '{0} is not valid',
|
|
min: '{0} should be greater than or equal to {1}',
|
|
max: '{0} should be smaller than or equal to {1}',
|
|
step: '{0} is not valid',
|
|
email: '{0} is not valid email',
|
|
url: '{0} is not valid URL',
|
|
date: '{0} is not valid date',
|
|
dateCompare: 'End date should be greater than or equal to the start date'
|
|
},
|
|
rules: {
|
|
required: function (input) {
|
|
var checkbox = input.filter('[type=checkbox]').length && !input.is(':checked'), value = input.val();
|
|
return !(hasAttribute(input, 'required') && (value === '' || !value || checkbox));
|
|
},
|
|
pattern: function (input) {
|
|
if (input.filter('[type=text],[type=email],[type=url],[type=tel],[type=search],[type=password]').filter('[pattern]').length && input.val() !== '') {
|
|
return patternMatcher(input.val(), input.attr('pattern'));
|
|
}
|
|
return true;
|
|
},
|
|
min: function (input) {
|
|
if (input.filter(NUMBERINPUTSELECTOR + ',[' + kendo.attr('type') + '=number]').filter('[min]').length && input.val() !== '') {
|
|
var min = parseFloat(input.attr('min')) || 0, val = kendo.parseFloat(input.val());
|
|
return min <= val;
|
|
}
|
|
return true;
|
|
},
|
|
max: function (input) {
|
|
if (input.filter(NUMBERINPUTSELECTOR + ',[' + kendo.attr('type') + '=number]').filter('[max]').length && input.val() !== '') {
|
|
var max = parseFloat(input.attr('max')) || 0, val = kendo.parseFloat(input.val());
|
|
return max >= val;
|
|
}
|
|
return true;
|
|
},
|
|
step: function (input) {
|
|
if (input.filter(NUMBERINPUTSELECTOR + ',[' + kendo.attr('type') + '=number]').filter('[step]').length && input.val() !== '') {
|
|
var min = parseFloat(input.attr('min')) || 0, step = parseFloat(input.attr('step')) || 1, val = parseFloat(input.val()), decimals = numberOfDecimalDigits(step), raise;
|
|
if (decimals) {
|
|
raise = Math.pow(10, decimals);
|
|
return Math.floor((val - min) * raise) % (step * raise) / Math.pow(100, decimals) === 0;
|
|
}
|
|
return (val - min) % step === 0;
|
|
}
|
|
return true;
|
|
},
|
|
email: function (input) {
|
|
return matcher(input, '[type=email],[' + kendo.attr('type') + '=email]', emailRegExp);
|
|
},
|
|
url: function (input) {
|
|
return matcher(input, '[type=url],[' + kendo.attr('type') + '=url]', urlRegExp);
|
|
},
|
|
date: function (input) {
|
|
if (input.filter('[type^=date],[' + kendo.attr('type') + '=date]').length && input.val() !== '') {
|
|
return kendo.parseDate(input.val(), input.attr(kendo.attr('format'))) !== null;
|
|
}
|
|
return true;
|
|
}
|
|
},
|
|
validateOnBlur: true
|
|
},
|
|
destroy: function () {
|
|
Widget.fn.destroy.call(this);
|
|
this.element.off(NS);
|
|
},
|
|
value: function () {
|
|
if (!this._isValidated) {
|
|
return false;
|
|
}
|
|
return this.errors().length === 0;
|
|
},
|
|
_submit: function (e) {
|
|
if (!this.validate()) {
|
|
e.stopPropagation();
|
|
e.stopImmediatePropagation();
|
|
e.preventDefault();
|
|
return false;
|
|
}
|
|
return true;
|
|
},
|
|
_checkElement: function (element) {
|
|
var state = this.value();
|
|
this.validateInput(element);
|
|
if (this.value() !== state) {
|
|
this.trigger('change');
|
|
}
|
|
},
|
|
_attachEvents: function () {
|
|
var that = this;
|
|
if (that.element.is(FORM)) {
|
|
that.element.on('submit' + NS, proxy(that._submit, that));
|
|
}
|
|
if (that.options.validateOnBlur) {
|
|
if (!that.element.is(INPUTSELECTOR)) {
|
|
that.element.on(BLUR + NS, that._inputSelector, function () {
|
|
that._checkElement($(this));
|
|
});
|
|
that.element.on('click' + NS, that._checkboxSelector, function () {
|
|
that._checkElement($(this));
|
|
});
|
|
} else {
|
|
that.element.on(BLUR + NS, function () {
|
|
that._checkElement(that.element);
|
|
});
|
|
if (that.element.is(CHECKBOXSELECTOR)) {
|
|
that.element.on('click' + NS, function () {
|
|
that._checkElement(that.element);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
},
|
|
validate: function () {
|
|
var inputs;
|
|
var idx;
|
|
var result = false;
|
|
var length;
|
|
var isValid = this.value();
|
|
this._errors = {};
|
|
if (!this.element.is(INPUTSELECTOR)) {
|
|
var invalid = false;
|
|
inputs = this.element.find(this._inputSelector);
|
|
for (idx = 0, length = inputs.length; idx < length; idx++) {
|
|
if (!this.validateInput(inputs.eq(idx))) {
|
|
invalid = true;
|
|
}
|
|
}
|
|
result = !invalid;
|
|
} else {
|
|
result = this.validateInput(this.element);
|
|
}
|
|
this.trigger('validate', { valid: result });
|
|
if (isValid !== result) {
|
|
this.trigger('change');
|
|
}
|
|
return result;
|
|
},
|
|
validateInput: function (input) {
|
|
input = $(input);
|
|
this._isValidated = true;
|
|
var that = this, template = that._errorTemplate, result = that._checkValidity(input), valid = result.valid, className = '.' + INVALIDMSG, fieldName = input.attr(NAME) || '', lbl = that._findMessageContainer(fieldName).add(input.next(className).filter(function () {
|
|
var element = $(this);
|
|
if (element.filter('[' + kendo.attr('for') + ']').length) {
|
|
return element.attr(kendo.attr('for')) === fieldName;
|
|
}
|
|
return true;
|
|
})).hide(), messageText;
|
|
input.removeAttr('aria-invalid');
|
|
if (!valid) {
|
|
messageText = that._extractMessage(input, result.key);
|
|
that._errors[fieldName] = messageText;
|
|
var messageLabel = parseHtml(template({ message: decode(messageText) }));
|
|
var lblId = lbl.attr('id');
|
|
that._decorateMessageContainer(messageLabel, fieldName);
|
|
if (lblId) {
|
|
messageLabel.attr('id', lblId);
|
|
}
|
|
if (!lbl.replaceWith(messageLabel).length) {
|
|
messageLabel.insertAfter(input);
|
|
}
|
|
messageLabel.show();
|
|
input.attr('aria-invalid', true);
|
|
} else {
|
|
delete that._errors[fieldName];
|
|
}
|
|
input.toggleClass(INVALIDINPUT, !valid);
|
|
input.toggleClass(VALIDINPUT, valid);
|
|
return valid;
|
|
},
|
|
hideMessages: function () {
|
|
var that = this, className = '.' + INVALIDMSG, element = that.element;
|
|
if (!element.is(INPUTSELECTOR)) {
|
|
element.find(className).hide();
|
|
} else {
|
|
element.next(className).hide();
|
|
}
|
|
},
|
|
_findMessageContainer: function (fieldName) {
|
|
var locators = kendo.ui.validator.messageLocators, name, containers = $();
|
|
for (var idx = 0, length = this.element.length; idx < length; idx++) {
|
|
containers = containers.add(searchForMessageContainer(this.element[idx].getElementsByTagName('*'), fieldName));
|
|
}
|
|
for (name in locators) {
|
|
containers = containers.add(locators[name].locate(this.element, fieldName));
|
|
}
|
|
return containers;
|
|
},
|
|
_decorateMessageContainer: function (container, fieldName) {
|
|
var locators = kendo.ui.validator.messageLocators, name;
|
|
container.addClass(INVALIDMSG).attr(kendo.attr('for'), fieldName || '');
|
|
for (name in locators) {
|
|
locators[name].decorate(container, fieldName);
|
|
}
|
|
container.attr('role', 'alert');
|
|
},
|
|
_extractMessage: function (input, ruleKey) {
|
|
var that = this, customMessage = that.options.messages[ruleKey], fieldName = input.attr(NAME);
|
|
customMessage = kendo.isFunction(customMessage) ? customMessage(input) : customMessage;
|
|
return kendo.format(input.attr(kendo.attr(ruleKey + '-msg')) || input.attr('validationMessage') || input.attr('title') || customMessage || '', fieldName, input.attr(ruleKey) || input.attr(kendo.attr(ruleKey)));
|
|
},
|
|
_checkValidity: function (input) {
|
|
var rules = this.options.rules, rule;
|
|
for (rule in rules) {
|
|
if (!rules[rule].call(this, input)) {
|
|
return {
|
|
valid: false,
|
|
key: rule
|
|
};
|
|
}
|
|
}
|
|
return { valid: true };
|
|
},
|
|
errors: function () {
|
|
var results = [], errors = this._errors, error;
|
|
for (error in errors) {
|
|
results.push(errors[error]);
|
|
}
|
|
return results;
|
|
}
|
|
});
|
|
kendo.ui.plugin(Validator);
|
|
}(window.kendo.jQuery));
|
|
return window.kendo;
|
|
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
|
|
(a3 || a2)();
|
|
})); |