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