1/** 2 * Yii validation module. 3 * 4 * This JavaScript module provides the validation methods for the built-in validators. 5 * 6 * @link http://www.yiiframework.com/ 7 * @copyright Copyright (c) 2008 Yii Software LLC 8 * @license http://www.yiiframework.com/license/ 9 * @author Qiang Xue <[email protected]> 10 * @since 2.0 11 */ 12 13yii.validation = (function ($) { 14 var pub = { 15 isEmpty: function (value) { 16 return value === null || value === undefined || ($.isArray(value) && value.length === 0) || value === ''; 17 }, 18 19 addMessage: function (messages, message, value) { 20 messages.push(message.replace(/\{value\}/g, value)); 21 }, 22 23 required: function (value, messages, options) { 24 var valid = false; 25 if (options.requiredValue === undefined) { 26 var isString = typeof value == 'string' || value instanceof String; 27 if (options.strict && value !== undefined || !options.strict && !pub.isEmpty(isString ? $.trim(value) : value)) { 28 valid = true; 29 } 30 } else if (!options.strict && value == options.requiredValue || options.strict && value === options.requiredValue) { 31 valid = true; 32 } 33 34 if (!valid) { 35 pub.addMessage(messages, options.message, value); 36 } 37 }, 38 39 // "boolean" is a reserved keyword in older versions of ES so it's quoted for IE < 9 support 40 'boolean': function (value, messages, options) { 41 if (options.skipOnEmpty && pub.isEmpty(value)) { 42 return; 43 } 44 var valid = !options.strict && (value == options.trueValue || value == options.falseValue) 45 || options.strict && (value === options.trueValue || value === options.falseValue); 46 47 if (!valid) { 48 pub.addMessage(messages, options.message, value); 49 } 50 }, 51 52 string: function (value, messages, options) { 53 if (options.skipOnEmpty && pub.isEmpty(value)) { 54 return; 55 } 56 57 if (typeof value !== 'string') { 58 pub.addMessage(messages, options.message, value); 59 return; 60 } 61 62 if (options.is !== undefined && value.length != options.is) { 63 pub.addMessage(messages, options.notEqual, value); 64 return; 65 } 66 if (options.min !== undefined && value.length < options.min) { 67 pub.addMessage(messages, options.tooShort, value); 68 } 69 if (options.max !== undefined && value.length > options.max) { 70 pub.addMessage(messages, options.tooLong, value); 71 } 72 }, 73 74 file: function (attribute, messages, options) { 75 var files = getUploadedFiles(attribute, messages, options); 76 $.each(files, function (i, file) { 77 validateFile(file, messages, options); 78 }); 79 }, 80 81 image: function (attribute, messages, options, deferredList) { 82 var files = getUploadedFiles(attribute, messages, options); 83 $.each(files, function (i, file) { 84 validateFile(file, messages, options); 85 86 // Skip image validation if FileReader API is not available 87 if (typeof FileReader === "undefined") { 88 return; 89 } 90 91 var deferred = $.Deferred(); 92 pub.validateImage(file, messages, options, deferred, new FileReader(), new Image()); 93 deferredList.push(deferred); 94 }); 95 }, 96 97 validateImage: function (file, messages, options, deferred, fileReader, image) { 98 image.onload = function() { 99 validateImageSize(file, image, messages, options); 100 deferred.resolve(); 101 }; 102 103 image.onerror = function () { 104 messages.push(options.notImage.replace(/\{file\}/g, file.name)); 105 deferred.resolve(); 106 }; 107 108 fileReader.onload = function () { 109 image.src = this.result; 110 }; 111 112 // Resolve deferred if there was error while reading data 113 fileReader.onerror = function () { 114 deferred.resolve(); 115 }; 116
117 fileReader.readAsDataURL(file); 118 }, 119 120 number: function (value, messages, options) { 121 if (options.skipOnEmpty && pub.isEmpty(value)) { 122 return; 123 } 124 125 if (typeof value === 'string' && !options.pattern.test(value)) { 126 pub.addMessage(messages, options.message, value); 127 return; 128 } 129 130 if (options.min !== undefined && value < options.min) { 131 pub.addMessage(messages, options.tooSmall, value); 132 } 133 if (options.max !== undefined && value > options.max) { 134 pub.addMessage(messages, options.tooBig, value); 135 } 136 }, 137 138 range: function (value, messages, options) { 139 if (options.skipOnEmpty && pub.isEmpty(value)) { 140 return; 141 } 142 143 if (!options.allowArray && $.isArray(value)) { 144 pub.addMessage(messages, options.message, value); 145 return; 146 } 147 148 var inArray = true; 149 150 $.each($.isArray(value) ? value : [value], function (i, v) { 151 if ($.inArray(v, options.range) == -1) { 152 inArray = false; 153 return false; 154 } else { 155 return true; 156 } 157 }); 158 159 if (options.not === undefined) { 160 options.not = false; 161 } 162 163 if (options.not === inArray) { 164 pub.addMessage(messages, options.message, value); 165 } 166 }, 167 168 regularExpression: function (value, messages, options) { 169 if (options.skipOnEmpty && pub.isEmpty(value)) { 170 return; 171 } 172 173 if (!options.not && !options.pattern.test(value) || options.not && options.pattern.test(value)) { 174 pub.addMessage(messages, options.message, value); 175 } 176 }, 177 178 email: function (value, messages, options) { 179 if (options.skipOnEmpty && pub.isEmpty(value)) { 180 return; 181 } 182 183 var valid = true, 184 regexp = /^((?:"?([^"]*)"?\s)?)(?:\s+)?(?:(<?)((.+)@([^>]+))(>?))$/, 185 matches = regexp.exec(value); 186 187 if (matches === null) { 188 valid = false; 189 } else { 190 var localPart = matches[5], 191 domain = matches[6]; 192 193 if (options.enableIDN) { 194 localPart = punycode.toASCII(localPart); 195 domain = punycode.toASCII(domain); 196 197 value = matches[1] + matches[3] + localPart + '@' + domain + matches[7]; 198 } 199 200 if (localPart.length > 64) { 201 valid = false; 202 } else if ((localPart + '@' + domain).length > 254) { 203 valid = false; 204 } else { 205 valid = options.pattern.test(value) || (options.allowName && options.fullPattern.test(value)); 206 } 207 } 208 209 if (!valid) { 210 pub.addMessage(messages, options.message, value); 211 } 212 }, 213 214 url: function (value, messages, options) { 215 if (options.skipOnEmpty && pub.isEmpty(value)) { 216 return; 217 } 218 219 if (options.defaultScheme && !/:\/\//.test(value)) { 220 value = options.defaultScheme + '://' + value; 221 } 222 223 var valid = true; 224 225 if (options.enableIDN) { 226 var matches = /^([^:]+):\/\/([^\/]+)(.*)$/.exec(value); 227 if (matches === null) { 228 valid = false; 229 } else { 230 value = matches[1] + '://' + punycode.toASCII(matches[2]) + matches[3]; 231 } 232 } 233 234 if (!valid || !options.pattern.test(value)) { 235 pub.addMessage(messages, options.message, value); 236 } 237 }, 238 239 trim: function ($form, attribute, options, value) { 240 var $input = $form.find(attribute.input); 241 if ($input.is(':checkbox, :radio')) { 242 return value; 243 } 244 245 value = $input.val(); 246 if (!options.skipOnEmpty || !pub.isEmpty(value)) { 247 value = $.trim(value); 248 $input.val(value); 249 } 250 251 return value; 252 }, 253 254 captcha: function (value, messages, options) { 255 if (options.skipOnEmpty && pub.isEmpty(value)) { 256 return; 257 } 258 259 // CAPTCHA may be updated via AJAX and the updated hash is stored in body data 260 var hash = $('body').data(options.hashKey); 261 hash = hash == null ? options.hash : hash[options.caseSensitive ? 0 : 1]; 262 var v = options.caseSensitive ? value : value.toLowerCase(); 263 for (var i = v.length - 1, h = 0; i >= 0; --i) { 264 h += v.charCodeAt(i); 265 } 266 if (h != hash) { 267 pub.addMessage(messages, options.message, value); 268 } 269 }, 270 271 compare: function (value, messages, options, $form) { 272 if (options.skipOnEmpty && pub.isEmpty(value)) { 273 return; 274 } 275 276 var compareValue, 277 valid = true; 278 if (options.compareAttribute === undefined) { 279 compareValue = options.compareValue; 280 } else { 281 var $target = $('#' + options.compareAttribute); 282 if (!$target.length) { 283 $target = $form.find('[name="' + options.compareAttributeName + '"]'); 284 } 285 compareValue = $target.val(); 286 } 287 288 if (options.type === 'number') { 289 value = value ? parseFloat(value) : 0; 290 compareValue = compareValue ? parseFloat(compareValue) : 0; 291 } 292 switch (options.operator) { 293 case '==': 294 valid = value == compareValue; 295 break; 296 case '===': 297 valid = value === compareValue; 298 break; 299 case '!=': 300 valid = value != compareValue; 301 break; 302 case '!==': 303 valid = value !== compareValue; 304 break; 305 case '>': 306 valid = value > compareValue; 307 break; 308 case '>=': 309 valid = value >= compareValue; 310 break; 311 case '<': 312 valid = value < compareValue; 313 break; 314 case '<=': 315 valid = value <= compareValue; 316 break; 317 default: 318 valid = false;
319 break; 320 } 321 322 if (!valid) { 323 pub.addMessage(messages, options.message, value); 324 } 325 }, 326 327 ip: function (value, messages, options) { 328 if (options.skipOnEmpty && pub.isEmpty(value)) { 329 return; 330 } 331 332 var negation = null, 333 cidr = null, 334 matches = new RegExp(options.ipParsePattern).exec(value); 335 if (matches) { 336 negation = matches[1] || null; 337 value = matches[2]; 338 cidr = matches[4] || null; 339 } 340 341 if (options.subnet === true && cidr === null) { 342 pub.addMessage(messages, options.messages.noSubnet, value); 343 return; 344 } 345 if (options.subnet === false && cidr !== null) { 346 pub.addMessage(messages, options.messages.hasSubnet, value); 347 return; 348 } 349 if (options.negation === false && negation !== null) { 350 pub.addMessage(messages, options.messages.message, value); 351 return; 352 } 353 354 var ipVersion = value.indexOf(':') === -1 ? 4 : 6; 355 if (ipVersion == 6) { 356 if (!(new RegExp(options.ipv6Pattern)).test(value)) { 357 pub.addMessage(messages, options.messages.message, value); 358 } 359 if (!options.ipv6) { 360 pub.addMessage(messages, options.messages.ipv6NotAllowed, value); 361 } 362 } else { 363 if (!(new RegExp(options.ipv4Pattern)).test(value)) { 364 pub.addMessage(messages, options.messages.message, value); 365 } 366 if (!options.ipv4) { 367 pub.addMessage(messages, options.messages.ipv4NotAllowed, value); 368 } 369 } 370 } 371 }; 372 373 function getUploadedFiles(attribute, messages, options) { 374 // Skip validation if File API is not available 375 if (typeof File === "undefined") { 376 return []; 377 } 378 379 var fileInput = $(attribute.input, attribute.$form).get(0); 380 381 // Skip validation if file input does not exist 382 // (in case file inputs are added dynamically and no file input has been added to the form) 383 if (typeof fileInput === "undefined") { 384 return []; 385 } 386 387 var files = fileInput.files; 388 if (!files) { 389 messages.push(options.message); 390 return []; 391 } 392 393 if (files.length === 0) { 394 if (!options.skipOnEmpty) { 395 messages.push(options.uploadRequired); 396 } 397 398 return []; 399 } 400 401 if (options.maxFiles && options.maxFiles < files.length) { 402 messages.push(options.tooMany); 403 return []; 404 } 405 406 return files; 407 } 408 409 function validateFile(file, messages, options) { 410 if (options.extensions && options.extensions.length > 0) { 411 var index = file.name.lastIndexOf('.'); 412 var ext = !~index ? '' : file.name.substr(index + 1, file.name.length).toLowerCase(); 413 414 if (!~options.extensions.indexOf(ext)) { 415 messages.push(options.wrongExtension.replace(/\{file\}/g, file.name)); 416 } 417 } 418 419 if (options.mimeTypes && options.mimeTypes.length > 0) { 420 if (!validateMimeType(options.mimeTypes, file.type)) { 421 messages.push(options.wrongMimeType.replace(/\{file\}/g, file.name)); 422 } 423 } 424 425 if (options.maxSize && options.maxSize < file.size) { 426 messages.push(options.tooBig.replace(/\{file\}/g, file.name)); 427 } 428 429 if (options.minSize && options.minSize > file.size) { 430 messages.push(options.tooSmall.replace(/\{file\}/g, file.name)); 431 } 432 } 433 434 function validateMimeType(mimeTypes, fileType) { 435 for (var i = 0, len = mimeTypes.length; i < len; i++) { 436 if (new RegExp(mimeTypes[i]).test(fileType)) { 437 return true; 438 } 439 } 440 441 return false;
442 } 443 444 function validateImageSize(file, image, messages, options) { 445 if (options.minWidth && image.width < options.minWidth) { 446 messages.push(options.underWidth.replace(/\{file\}/g, file.name)); 447 } 448 449 if (options.maxWidth && image.width > options.maxWidth) { 450 messages.push(options.overWidth.replace(/\{file\}/g, file.name)); 451 } 452 453 if (options.minHeight && image.height < options.minHeight) { 454 messages.push(options.underHeight.replace(/\{file\}/g, file.name)); 455 } 456 457 if (options.maxHeight && image.height > options.maxHeight) { 458 messages.push(options.overHeight.replace(/\{file\}/g, file.name)); 459 } 460 } 461 462 return pub; 463})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.