/** * Yii validation module. * * This JavaScript module provides the validation methods for the built-in validators. * * @link http://www.yiiframework.com/ * @copyright Copyright (c) 2008 Yii Software LLC * @license http://www.yiiframework.com/license/ * @author Qiang Xue * @since 2.0 */ yii.validation = (function ($) { var pub = { isEmpty: function (value) { return value === null || value === undefined || ($.isArray(value) && value.length === 0) || value === ''; }, addMessage: function (messages, message, value) { messages.push(message.replace(/\{value\}/g, value)); }, required: function (value, messages, options) { var valid = false; if (options.requiredValue === undefined) { var isString = typeof value == 'string' || value instanceof String; if (options.strict && value !== undefined || !options.strict && !pub.isEmpty(isString ? $.trim(value) : value)) { valid = true; } } else if (!options.strict && value == options.requiredValue || options.strict && value === options.requiredValue) { valid = true; } if (!valid) { pub.addMessage(messages, options.message, value); } }, // "boolean" is a reserved keyword in older versions of ES so it's quoted for IE < 9 support 'boolean': function (value, messages, options) { if (options.skipOnEmpty && pub.isEmpty(value)) { return; } var valid = !options.strict && (value == options.trueValue || value == options.falseValue) || options.strict && (value === options.trueValue || value === options.falseValue); if (!valid) { pub.addMessage(messages, options.message, value); } }, string: function (value, messages, options) { if (options.skipOnEmpty && pub.isEmpty(value)) { return; } if (typeof value !== 'string') { pub.addMessage(messages, options.message, value); return; } if (options.is !== undefined && value.length != options.is) { pub.addMessage(messages, options.notEqual, value); return; } if (options.min !== undefined && value.length < options.min) { pub.addMessage(messages, options.tooShort, value); } if (options.max !== undefined && value.length > options.max) { pub.addMessage(messages, options.tooLong, value); } }, file: function (attribute, messages, options) { var files = getUploadedFiles(attribute, messages, options); $.each(files, function (i, file) { validateFile(file, messages, options); }); }, image: function (attribute, messages, options, deferredList) { var files = getUploadedFiles(attribute, messages, options); $.each(files, function (i, file) { validateFile(file, messages, options); // Skip image validation if FileReader API is not available if (typeof FileReader === "undefined") { return; } var deferred = $.Deferred(); pub.validateImage(file, messages, options, deferred, new FileReader(), new Image()); deferredList.push(deferred); }); }, validateImage: function (file, messages, options, deferred, fileReader, image) { image.onload = function() { validateImageSize(file, image, messages, options); deferred.resolve(); }; image.onerror = function () { messages.push(options.notImage.replace(/\{file\}/g, file.name)); deferred.resolve(); }; fileReader.onload = function () { image.src = this.result; }; // Resolve deferred if there was error while reading data fileReader.onerror = function () { deferred.resolve(); }; fileReader.readAsDataURL(file); }, number: function (value, messages, options) { if (options.skipOnEmpty && pub.isEmpty(value)) { return; } if (typeof value === 'string' && !options.pattern.test(value)) { pub.addMessage(messages, options.message, value); return; } if (options.min !== undefined && value < options.min) { pub.addMessage(messages, options.tooSmall, value); } if (options.max !== undefined && value > options.max) { pub.addMessage(messages, options.tooBig, value); } }, range: function (value, messages, options) { if (options.skipOnEmpty && pub.isEmpty(value)) { return; } if (!options.allowArray && $.isArray(value)) { pub.addMessage(messages, options.message, value); return; } var inArray = true; $.each($.isArray(value) ? value : [value], function (i, v) { if ($.inArray(v, options.range) == -1) { inArray = false; return false; } else { return true; } }); if (options.not === undefined) { options.not = false; } if (options.not === inArray) { pub.addMessage(messages, options.message, value); } }, regularExpression: function (value, messages, options) { if (options.skipOnEmpty && pub.isEmpty(value)) { return; } if (!options.not && !options.pattern.test(value) || options.not && options.pattern.test(value)) { pub.addMessage(messages, options.message, value); } }, email: function (value, messages, options) { if (options.skipOnEmpty && pub.isEmpty(value)) { return; } var valid = true, regexp = /^((?:"?([^"]*)"?\s)?)(?:\s+)?(?:(]+))(>?))$/, matches = regexp.exec(value); if (matches === null) { valid = false; } else { var localPart = matches[5], domain = matches[6]; if (options.enableIDN) { localPart = punycode.toASCII(localPart); domain = punycode.toASCII(domain); value = matches[1] + matches[3] + localPart + '@' + domain + matches[7]; } if (localPart.length > 64) { valid = false; } else if ((localPart + '@' + domain).length > 254) { valid = false; } else { valid = options.pattern.test(value) || (options.allowName && options.fullPattern.test(value)); } } if (!valid) { pub.addMessage(messages, options.message, value); } }, url: function (value, messages, options) { if (options.skipOnEmpty && pub.isEmpty(value)) { return; } if (options.defaultScheme && !/:\/\//.test(value)) { value = options.defaultScheme + '://' + value; } var valid = true; if (options.enableIDN) { var matches = /^([^:]+):\/\/([^\/]+)(.*)$/.exec(value); if (matches === null) { valid = false; } else { value = matches[1] + '://' + punycode.toASCII(matches[2]) + matches[3]; } } if (!valid || !options.pattern.test(value)) { pub.addMessage(messages, options.message, value); } }, trim: function ($form, attribute, options, value) { var $input = $form.find(attribute.input); if ($input.is(':checkbox, :radio')) { return value; } value = $input.val(); if (!options.skipOnEmpty || !pub.isEmpty(value)) { value = $.trim(value); $input.val(value); } return value; }, captcha: function (value, messages, options) { if (options.skipOnEmpty && pub.isEmpty(value)) { return; } // CAPTCHA may be updated via AJAX and the updated hash is stored in body data var hash = $('body').data(options.hashKey); hash = hash == null ? options.hash : hash[options.caseSensitive ? 0 : 1]; var v = options.caseSensitive ? value : value.toLowerCase(); for (var i = v.length - 1, h = 0; i >= 0; --i) { h += v.charCodeAt(i); } if (h != hash) { pub.addMessage(messages, options.message, value); } }, compare: function (value, messages, options, $form) { if (options.skipOnEmpty && pub.isEmpty(value)) { return; } var compareValue, valid = true; if (options.compareAttribute === undefined) { compareValue = options.compareValue; } else { var $target = $('#' + options.compareAttribute); if (!$target.length) { $target = $form.find('[name="' + options.compareAttributeName + '"]'); } compareValue = $target.val(); } if (options.type === 'number') { value = value ? parseFloat(value) : 0; compareValue = compareValue ? parseFloat(compareValue) : 0; } switch (options.operator) { case '==': valid = value == compareValue; break; case '===': valid = value === compareValue; break; case '!=': valid = value != compareValue; break; case '!==': valid = value !== compareValue; break; case '>': valid = value > compareValue; break; case '>=': valid = value >= compareValue; break; case '<': valid = value < compareValue; break; case '<=': valid = value <= compareValue; break; default: valid = false; break; } if (!valid) { pub.addMessage(messages, options.message, value); } }, ip: function (value, messages, options) { if (options.skipOnEmpty && pub.isEmpty(value)) { return; } var negation = null, cidr = null, matches = new RegExp(options.ipParsePattern).exec(value); if (matches) { negation = matches[1] || null; value = matches[2]; cidr = matches[4] || null; } if (options.subnet === true && cidr === null) { pub.addMessage(messages, options.messages.noSubnet, value); return; } if (options.subnet === false && cidr !== null) { pub.addMessage(messages, options.messages.hasSubnet, value); return; } if (options.negation === false && negation !== null) { pub.addMessage(messages, options.messages.message, value); return; } var ipVersion = value.indexOf(':') === -1 ? 4 : 6; if (ipVersion == 6) { if (!(new RegExp(options.ipv6Pattern)).test(value)) { pub.addMessage(messages, options.messages.message, value); } if (!options.ipv6) { pub.addMessage(messages, options.messages.ipv6NotAllowed, value); } } else { if (!(new RegExp(options.ipv4Pattern)).test(value)) { pub.addMessage(messages, options.messages.message, value); } if (!options.ipv4) { pub.addMessage(messages, options.messages.ipv4NotAllowed, value); } } } }; function getUploadedFiles(attribute, messages, options) { // Skip validation if File API is not available if (typeof File === "undefined") { return []; } var fileInput = $(attribute.input, attribute.$form).get(0); // Skip validation if file input does not exist // (in case file inputs are added dynamically and no file input has been added to the form) if (typeof fileInput === "undefined") { return []; } var files = fileInput.files; if (!files) { messages.push(options.message); return []; } if (files.length === 0) { if (!options.skipOnEmpty) { messages.push(options.uploadRequired); } return []; } if (options.maxFiles && options.maxFiles < files.length) { messages.push(options.tooMany); return []; } return files; } function validateFile(file, messages, options) { if (options.extensions && options.extensions.length > 0) { var found = false; var filename = file.name.toLowerCase(); for (var index=0; index < options.extensions.length; index++) { var ext = options.extensions[index].toLowerCase(); if ((ext === '' && filename.indexOf('.') === -1) || (filename.substr(filename.length - options.extensions[index].length - 1) === ('.' + ext))) { found = true; break; } } if (!found) { messages.push(options.wrongExtension.replace(/\{file\}/g, file.name)); } } if (options.mimeTypes && options.mimeTypes.length > 0) { if (!validateMimeType(options.mimeTypes, file.type)) { messages.push(options.wrongMimeType.replace(/\{file\}/g, file.name)); } } if (options.maxSize && options.maxSize < file.size) { messages.push(options.tooBig.replace(/\{file\}/g, file.name)); } if (options.minSize && options.minSize > file.size) { messages.push(options.tooSmall.replace(/\{file\}/g, file.name)); } } function validateMimeType(mimeTypes, fileType) { for (var i = 0, len = mimeTypes.length; i < len; i++) { if (new RegExp(mimeTypes[i]).test(fileType)) { return true; } } return false; } function validateImageSize(file, image, messages, options) { if (options.minWidth && image.width < options.minWidth) { messages.push(options.underWidth.replace(/\{file\}/g, file.name)); } if (options.maxWidth && image.width > options.maxWidth) { messages.push(options.overWidth.replace(/\{file\}/g, file.name)); } if (options.minHeight && image.height < options.minHeight) { messages.push(options.underHeight.replace(/\{file\}/g, file.name)); } if (options.maxHeight && image.height > options.maxHeight) { messages.push(options.overHeight.replace(/\{file\}/g, file.name)); } } return pub; })(jQuery);