(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);