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