/** * Kendo UI v2016.1.112 (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: '' + ' #=message#', 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)); }, _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)(); }));