(function ($) { var $jQval = $.validator, adapters, data_validation = "unobtrusiveValidation"; var prevGetLengthFunction = $.validator.prototype.getLength; $.validator.prototype.getLength = function (value, element) { switch (element.nodeName.toLowerCase()) { case "textarea": var count = 0; for (var i = value.length - 1; i >= 0; --i) { if (value[i] === '\n') count += 2; else if (value[i] !== '\r')++count; } return count; } return prevGetLengthFunction.call(this, value, element); }; function setValidationValues(options, ruleName, value) { options.rules[ruleName] = value; if (options.message) { options.messages[ruleName] = options.message; } } function splitAndTrim(value) { return value.replace(/^\s+|\s+$/g, "").split(/\s*,\s*/g); } function escapeAttributeValue(value) { // As mentioned on http://api.jquery.com/category/selectors/ return value.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g, "\\$1"); } function getModelPrefix(fullFieldName) { return fullFieldName.substr(0, fullFieldName.lastIndexOf(".") + 1); } function appendModelPrefix(fieldName, prefix) { if (prefix && prefix !== '') { fieldName = prefix + fieldName; } return fieldName; } function onError(error, inputElement) { // 'this' is the form element var element = inputElement[0]; var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(element.name) + "']"); var validator = $(this).data('validator'); if (!validator.optional(element) || !isTipsEnabled.call(this) || validator.cbrInitializationMode) { container.removeClass("field-validation-valid").addClass("field-validation-error"); error.data("unobtrusiveContainer", container); container.empty(); error.removeClass("input-validation-error").appendTo(container); } else { container.empty().addClass("field-validation-valid").removeClass("field-validation-error"); error.hide(); } updateTips.call(this); } function onErrors(event, validator) { // 'this' is the form element updateTips.call(this); } function onSuccess(error) { // 'this' is the form element var container = error.data("unobtrusiveContainer"); if (container) { container.empty().addClass("field-validation-valid").removeClass("field-validation-error"); error.removeData("unobtrusiveContainer"); } updateTips.call(this); } function isTipsEnabled() { // 'this' is the form element return $("[data-valmsg-tips=true]", this).length !== 0; } function updateTips() { // 'this' is the form element var info = validationInfo(this); var validator = $(this).data("validator"); var tips = []; for (var fieldName in validator.invalid) { var element = $('[name="' + escapeAttributeValue(fieldName) + '"]', this); if (element.length !== 0 && validator.optional(element[0])) { tips.push({ element: element, title: getElementTitle(element) }); } } var tipsContainer = $("[data-valmsg-tips=true] .invalid-tips", this); var tipsFieldsContainer = $('.field-tips', tipsContainer); var validContainer = $("[data-valmsg-tips=true] .valid-tips", this); $('[data-valmsg-submit]', this).prop('disabled', tips.length !== 0); if (info.tipsTimeoutId) { clearTimeout(info.tipsTimeoutId); } info.tipsTimeoutId = setTimeout(function () { if (tips.length !== 0) { tipsFieldsContainer.empty(); $.each(tips, function (index) { var element = this.element; var title = this.title; if (index !== 0) tipsFieldsContainer.append(', '); var obj = $('') .text(title) .click(function () { element.focus(); cbrTools.scrollToElement(element); //var scrollTop = element.offset().top - 35; //$(document).scrollTop(scrollTop > 0 ? scrollTop : 0); }); obj.appendTo(tipsFieldsContainer); }); tipsContainer.show(); validContainer.hide(); } else { tipsFieldsContainer.empty(); tipsContainer.hide(); validContainer.show(); } }, 200); function getElementTitle(element) { var inputName = element[0].name; var inputId = element[0].id; var title = null; if (!title) title = element.attr('data-title'); if (!title) title = $('label[for="' + escapeAttributeValue(inputId) + '"]').text(); if (!title) title = $(element).closest('.input_label').find('.input_placeholder').text(); if (!title) title = element.attr('title'); if (!title) title = inputName; return title; } } function initCbrValidation() { // 'this' is the form element var $form = $(this); var validator = $form.data('validator'); var isTipsEnabledFlag = isTipsEnabled.call(this); //mark fields with values or server errors as validator.submitted var initialErrors = {}; var hasInitialErrors = false; $.each(validator.elements(), function () { var element = this; if (!validator.checkable(element) && validator.elementValue(element) !== '') { validator.submitted[element.name] = "SUBMITTED"; } var $error = $form.find('[data-valmsg-for="' + escapeAttributeValue(element.name) + '"]'); if (/[^\s]/.test($error.text())) { validator.submitted[element.name] = $error.text(); initialErrors[element.name] = $error.text(); hasInitialErrors = true; } }); validator.refreshTips = function () { if (isTipsEnabledFlag) { validator.form(); } } //show validation tips for required fields if (isTipsEnabledFlag) { var submittedSaved = validator.submitted; validator.submitted = {}; validator.refreshTips(); $.extend(validator.submitted, submittedSaved); //reshow server validation messages validator.cbrInitializationMode = true; validator.showErrors(initialErrors); validator.cbrInitializationMode = false; } if (initialErrors) validator.focusInvalid(); } function onReset(event) { // 'this' is the form element var $form = $(this); $form.data("validator").resetForm(); $form.find(".validation-summary-errors") .addClass("validation-summary-valid") .removeClass("validation-summary-errors"); $form.find(".field-validation-error") .addClass("field-validation-valid") .removeClass("field-validation-error") .removeData("unobtrusiveContainer") .find(">*") // If we were using valmsg-replace, get the underlying error .removeData("unobtrusiveContainer"); } function validationInfo(form) { var $form = $(form), result = $form.data(data_validation), onResetProxy = $.proxy(onReset, form), defaultOptions = $jQval.unobtrusive.options || {}, execInContext = function (name, args) { var func = defaultOptions[name]; func && $.isFunction(func) && func.apply(form, args); } if (!result) { result = { options: { // options structure passed to jQuery Validate's validate() method //onkeyup: false, errorClass: defaultOptions.errorClass || "input-validation-error", errorElement: defaultOptions.errorElement || "span", errorPlacement: function (error, inputElement) { onError.apply(form, arguments); }, invalidHandler: function (event, validator) { onErrors.apply(form, arguments); }, messages: {}, rules: {}, success: function (error) { onSuccess.apply(form, arguments); } }, attachValidation: function () { $form .off("reset." + data_validation, onResetProxy) .on("reset." + data_validation, onResetProxy) .validate(this.options); initCbrValidation.call(form); }, validate: function () { // a validation function that is called by unobtrusive Ajax $form.validate(); return $form.valid(); } }; $form.data(data_validation, result); } return result; } $.validator.unobtrusive.parseElement = function (element, skipAttach) { /// /// Parses a single HTML element for unobtrusive validation attributes. /// /// The HTML element to be parsed. /// [Optional] true to skip attaching the /// validation to the form. If parsing just this single element, you should specify true. /// If parsing several elements, you should specify false, and manually attach the validation /// to the form when you are finished. The default is false. var $element = $(element), form = $element.parents("form")[0], valInfo, rules, messages; if (!form) { // Cannot do client-side validation without a form return; } valInfo = validationInfo(form); valInfo.options.rules[element.name] = rules = {}; valInfo.options.messages[element.name] = messages = {}; $.each(this.adapters, function () { var prefix = "data-val-" + this.name, message = $element.attr(prefix), paramValues = {}; if (message !== undefined) { // Compare against undefined, because an empty message is legal (and falsy) prefix += "-"; $.each(this.params, function () { paramValues[this] = $element.attr(prefix + this); }); this.adapt({ element: element, form: form, message: message, params: paramValues, rules: rules, messages: messages }); } }); $.extend(rules, { "__dummy__": true }); if (!skipAttach) { valInfo.attachValidation(); } } $.validator.unobtrusive.parse = function (selector) { /// /// Parses all the HTML elements in the specified selector. It looks for input elements decorated /// with the [data-val=true] attribute value and enables validation according to the data-val-* /// attribute values. /// /// Any valid jQuery selector. // $forms includes all forms in selector's DOM hierarchy (parent, children and self) that have at least one // element with data-val=true var $selector = $(selector), $forms = $selector.parents() .addBack() .filter("form") .add($selector.find("form")) .has("[data-val=true]"); $selector.find("[data-val=true]").each(function () { $jQval.unobtrusive.parseElement(this, true); }); $forms.each(function () { var info = validationInfo(this); if (info) { info.attachValidation(); } }); } adapters = $jQval.unobtrusive.adapters; $.validator.unobtrusive.adapters.add('conditionalrequired', ['dependson', 'targetvalues'], function (options) { var prefix = getModelPrefix(options.element.name), dependson = options.params.dependson, fullOtherName = appendModelPrefix(dependson, prefix), dependsOnElement = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(fullOtherName) + "']"), targetValues = $.parseJSON(options.params.targetvalues); var isTipsEnabledFlag = isTipsEnabled.call(options.form); if (isTipsEnabledFlag) { dependsOnElement .unbind('blur.unobtrusive.' + options.element.name) .bind('blur.unobtrusive.' + options.element.name, function () { var validator = $(options.form).data('validator'); validator.element(options.element); }); switch (dependsOnElement.attr('type')) { case 'radio': case 'checkbox': dependsOnElement .unbind('click.unobtrusive.' + options.element.name) .bind('click.unobtrusive.' + options.element.name, function () { $(this).blur(); }); break; case 'select': dependsOnElement .unbind('change.unobtrusive.' + options.element.name) .bind('change.unobtrusive.' + options.element.name, function () { $(this).blur(); }); break; } } setValidationValues(options, 'required', function (element) { if (dependsOnElement.length === 0) return true; var controlType = dependsOnElement.attr('type'); var actualValue = ""; switch (controlType) { case 'checkbox': actualValue = dependsOnElement.is(':checked') ? 'true' : 'false'; break; case 'radio': actualValue = dependsOnElement.filter(':checked').val(); break; default: actualValue = dependsOnElement.val(); break; } if (actualValue === null || typeof (actualValue) === 'undefined') actualValue = ''; var res = false; for (var i in targetValues) { if (actualValue.toLowerCase() === targetValues[i].toLowerCase()) { res = true; break; } } return res; }); }); $.validator.unobtrusive.adapters.addBool('snilsvalidation'); $.validator.addMethod('snilsvalidation', function (value, element, params) { if (this.optional(element)) return true; var digits = value.replace(/[^0-9]/g, ''); if (digits.length !== 11) return false; var formattedValue = digits.substring(0, 3) + '-' + digits.substring(3, 6) + '-' + digits.substring(6, 9) + ' ' + digits.substring(9, 11); if (document.activeElement !== element) { if (value !== formattedValue) { element.value = formattedValue; } } return true; /*value = formattedValue; if (!/(\d\d\d)-(\d\d\d)-(\d\d\d)\s+(\d\d)/.exec(value)) return false; var numbers = RegExp.$1 + RegExp.$2 + RegExp.$3; var checkControlSum = parseInt(RegExp.$4, 10); if (numbers <= '001001998') return true; var controlSum = 0; for (var i = 1; i <= numbers.length; ++i) { var n = parseInt(numbers[numbers.length - i]); controlSum += n * i; } controlSum = controlSum % 101; if (controlSum >= 100) controlSum = 0; return checkControlSum == controlSum;*/ }); $.validator.unobtrusive.adapters.addBool('innvalidation'); $.validator.addMethod('innvalidation', function (value, element, params) { if (this.optional(element)) return true; var parse, n; //Разрешаем использовать пробельные символы в номере //number = number.replace(/\s/g, ''); //Проверка длины //if (!/^([0-9]{10}|[0-9]{12})$/.test(number)) { return false; } //Проверка контрольных цифр //if (number.length == 10) { // parse = number.match(/^(.{9})(.)$/); // n = parse[1].split(''); // var controlCode = parse[2], // checkCode = ((2 * n[0] + 4 * n[1] + 10 * n[2] + 3 * n[3] + 5 * n[4] + 9 * n[5] + 4 * n[6] + 6 * n[7] + 8 * n[8]) % 11) % 10; // if (checkCode != controlCode) // { // return false; // } //} //else //{ // parse = number.match(/^(.{10})(.)(.)$/); // n = parse[1].split(''); // var controlCode1 = parse[2], // controlCode2 = parse[3], // checkCode1 = ((7 * n[0] + 2 * n[1] + 4 * n[2] + 10 * n[3] + 3 * n[4] + 5 * n[5] + 9 * n[6] + 4 * n[7] + 6 * n[8] + 8 * n[9]) % 11) % 10, // checkCode2 = ((3 * n[0] + 7 * n[1] + 2 * n[2] + 4 * n[3] + 10 * n[4] + 3 * n[5] + 5 * n[6] + 9 * n[7] + 4 * n[8] + 6 * n[9] + 8 * checkCode1) % 11) % 10; // if (checkCode1 != controlCode1 || checkCode2 != controlCode2) { // return false; // } //} return true; }); $.validator.unobtrusive.adapters.add('datemask', ['min', 'max'], function (options) { var value = { min: options.params.min, max: options.params.max } setValidationValues(options, 'datemask', value); }); $.validator.addMethod('datemask', function (value, element, params) { if (this.optional(element)) return true; var d = _parseDate(value); if (d === null) return false; if (params.min) { var d1 = new Date(params.min); if (!(d1 <= d)) return false; } if (params.max) { var d2 = params.max === "current" ? new Date() : new Date(params.max); if (!(d <= d2)) return false; } return true; }); $.validator.methods.date = function (value, element) { var val = _parseDate(value); return this.optional(element) || (val instanceof Date); }; function _parseDate(value) { var m = /(\d\d)\.(\d\d)\.(\d\d\d\d)/.exec(value); if (m === null) return false; var year = parseInt(m[3]); var month = parseInt(m[2]) - 1; var date = parseInt(m[1]); var d = new Date(year, month, date); if (d.getFullYear() === year && d.getMonth() === month && d.getDate() == date) return d; else return null; } })(jQuery);