1(function ($) { 2 $.fn.validationEngineLanguage = function () { }; 3 $.validationEngineLanguage = { 4 newLang: function () { 5 $.validationEngineLanguage.allRules = { 6 "required": { // Add your regex rules here, you can take telephone as an example 7 "regex": "none", 8 "alertText": "* æ¤å¤ä¸ºå¿ 填项", 9 "alertTextCheckboxMultiple": "* è¯·éæ©", 10 "alertTextCheckboxe": "* æ¨å¿ é¡»é©éæ¤æ ", 11 "alertTextDateRange": "* æ¥æèå´ä¸å¯ç©ºç½" 12 }, 13 "requiredInFunction": { 14 "func": function (field, rules, i, options) { 15 return (field.val() == "test") ? true : false; 16 }, 17 "alertText": "* Field must equal test" 18 }, 19 "dateRange": { 20 "regex": "none", 21 "alertText": "* æ æç ", 22 "alertText2": " æ¥æèå´" 23 }, 24 "dateTimeRange": { 25 "regex": "none", 26 "alertText": "* æ æç ", 27 "alertText2": " æ¶é´èå´" 28 }, 29 "minSize": { 30 "regex": "none", 31 "alertText": "* æå° ", 32 "alertText2": " 个å符" 33 }, 34 "maxSize": { 35 "regex": "none", 36 "alertText": "* æå¤ ", 37 "alertText2": " 个å符" 38 }, 39 "groupRequired": { 40 "regex": "none", 41 "alertText": "* ä½ å¿ ééå¡«å ¶ä¸ä¸ä¸ªæ ä½" 42 }, 43 "min": { 44 "regex": "none", 45 "alertText": "* æå°å¼çº " 46 }, 47 "max": { 48 "regex": "none", 49 "alertText": "* æå¤§å¼ä¸º " 50 }, 51 "past": { 52 "regex": "none", 53 "alertText": "* æ¥æå¿ éæ©äº " 54 }, 55 "future": { 56 "regex": "none", 57 "alertText": "* æ¥æå¿ éæäº " 58 }, 59 "maxCheckbox": { 60 "regex": "none", 61 "alertText": "* æå¤éå ", 62 "alertText2": " 个项ç®" 63 }, 64 "minCheckbox": { 65 "regex": "none", 66 "alertText": "* æå°éæ© ", 67 "alertText2": " 个项ç®" 68 }, 69 "equals": { 70 "regex": "none", 71 "alertText": "* 请è¾å ¥ä¸ä¸é¢ç¸åçå¯ç " 72 }, 73 "creditCard": { 74 "regex": "none", 75 "alertText": "* æ æçä¿¡ç¨å¡å·ç " 76 }, 77 "phone": { 78 // credit: jquery.h5validate.js / orefalo 79 "regex": /^([\+][0-9]{1,3}([ \.\-])?)?([\(][0-9]{1,6}[\)])?([0-9 \.\-]{1,32})(([A-Za-z \:]{1,11})?[0-9]{1,4}?)$/, 80 "alertText": "* æ æççµè¯å·ç " 81 }, 82 "email": { 83 // Shamelessly lifted from Scott Gonzalez via the Bassistance Validation plugin http://projects.scottsplayground.com/email_address_validation/ 84 "regex": /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i, 85 "alertText": "* é®ä»¶å°åæ æ" 86 }, 87 "integer": { 88 "regex": /^[\-\+]?\d+$/, 89 "alertText": "* 䏿¯ææçæ´æ°" 90 }, 91 "number": { 92 // Number, including positive, negative, and floating decimal. credit: orefalo 93 "regex": /^[\-\+]?((([0-9]{1,3})([,][0-9]{3})*)|([0-9]+))?([\.]([0-9]+))?$/, 94 "alertText": "* æ æçæ°å" 95 }, 96 "date": { 97 "regex": /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/, 98 "alertText": "* æ æçæ¥æï¼æ ¼å¼å¿ é为 YYYY-MM-DD" 99 }, 100 "ipv4": { 101 "regex": /^((([01]?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5]))[.]){3}(([0-1]?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5]))$/, 102 "alertText": "* æ æç IP å°å" 103 }, 104 "url": { 105 "regex": /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i, 106 "alertText": "* å¿ é¡»ä»¥ http:// å¼å§" 107 }, 108 "onlyNumberSp": { 109 "regex": /^[0-9\ ]+$/,
110 "alertText": "* åªè½å¡«æ°å" 111 }, 112 "onlyLetterSp": { 113 "regex": /^[a-zA-Z\ \']+$/, 114 "alertText": "* åªæ¥åè±æåæ¯å¤§å°å" 115 }, 116 "onlyLetterAccentSp": { 117 "regex": /^[a-z\u00C0-\u017F\ ]+$/i, 118 "alertText": "* åªæ¥åè±æåæ¯å¤§å°å" 119 }, 120 "onlyLetterNumber": { 121 "regex": /^[0-9a-zA-Z]+$/, 122 "alertText": "* 䏿¥åç¹æ®å符" 123 }, 124 // --- CUSTOM RULES -- Those are specific to the demos, they can be removed or changed to your likings 125 "ajaxUserCall": { 126 "url": "ajaxValidateFieldUser", 127 // you may want to pass extra data on the ajax call 128 "extraData": "name=eric", 129 "alertText": "* æ¤åç§°å·²è¢«å ¶ä»äººä½¿ç¨", 130 "alertTextLoad": "* æ£å¨ç¡®è®¤åç§°æ¯å¦æå ¶ä»äººä½¿ç¨ï¼è¯·ç¨çã" 131 }, 132 "mobilephone":{ 133 "regex": /^(13|14|15|16|17|18|19)\d{9}$/, 134 "alertText":"* ææºå·ç æè¯¯", 135 "alertTextOk": "* ææºå·ç ä¹å", 136 }, 137 "ajaxNameCallPhp": { 138 // remote json service location 139 "url": "phpajax/ajaxValidateFieldName.php", 140 // error 141 "alertText": "* æ¤åç§°å·²è¢«å ¶ä»äººä½¿ç¨", 142 // speaks by itself 143 "alertTextLoad": "* æ£å¨ç¡®è®¤åç§°æ¯å¦æå ¶ä»äººä½¿ç¨ï¼è¯·ç¨çã" 144 }, 145 "validate2fields": { 146 "alertText": "* 请è¾å ¥ HELLO" 147 }, 148 //tls warning:homegrown not fielded 149 "dateFormat": { 150 "regex": /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$|^(?:(?:(?:0?[13578]|1[02])(\/|-)31)|(?:(?:0?[1,3-9]|1[0-2])(\/|-)(?:29|30)))(\/|-)(?:[1-9]\d\d\d|\d[1-9]\d\d|\d\d[1-9]\d|\d\d\d[1-9])$|^(?:(?:0?[1-9]|1[0-2])(\/|-)(?:0?[1-9]|1\d|2[0-8]))(\/|-)(?:[1-9]\d\d\d|\d[1-9]\d\d|\d\d[1-9]\d|\d\d\d[1-9])$|^(0?2(\/|-)29)(\/|-)(?:(?:0[48]00|[13579][26]00|[2468][048]00)|(?:\d\d)?(?:0[48]|[2468][048]|[13579][26]))$/, 151 "alertText": "* æ æçæ¥ææ ¼å¼" 152 }, 153 //tls warning:homegrown not fielded 154 "dateTimeFormat": { 155 "regex": /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])\s+(1[012]|0?[1-9]){1}:(0?[1-5]|[0-6][0-9]){1}:(0?[0-6]|[0-6][0-9]){1}\s+(am|pm|AM|PM){1}$|^(?:(?:(?:0?[13578]|1[02])(\/|-)31)|(?:(?:0?[1,3-9]|1[0-2])(\/|-)(?:29|30)))(\/|-)(?:[1-9]\d\d\d|\d[1-9]\d\d|\d\d[1-9]\d|\d\d\d[1-9])$|^((1[012]|0?[1-9]){1}\/(0?[1-9]|[12][0-9]|3[01]){1}\/\d{2,4}\s+(1[012]|0?[1-9]){1}:(0?[1-5]|[0-6][0-9]){1}:(0?[0-6]|[0-6][0-9]){1}\s+(am|pm|AM|PM){1})$/, 156 "alertText": "* æ æçæ¥æææ¶é´æ ¼å¼", 157 "alertText2": "坿¥åçæ ¼å¼ï¼ ", 158 "alertText3": "mm/dd/yyyy hh:mm:ss AM|PM æ ", 159 "alertText4": "yyyy-mm-dd hh:mm:ss AM|PM" 160 } 161 }; 162 163 } 164 }; 165 $.validationEngineLanguage.newLang(); 166})(jQuery); 167 168 169/* 170 * Inline Form Validation Engine 2.6.2, jQuery plugin 171 * 172 * Copyright(c) 2010, Cedric Dugas 173 * http://www.position-absolute.com 174 * 175 * 2.0 Rewrite by Olivier Refalo 176 * http://www.crionics.com 177 * 178 * Form validation engine allowing custom regex rules to be added. 179 * Licensed under the MIT License 180 */ 181 (function($) { 182 183 "use strict"; 184 185 var methods = { 186 187 /** 188 * Kind of the constructor, called before any action 189 * @param {Map} user options 190 */ 191 init: function(options) { 192 var form = this; 193 if (!form.data('jqv') || form.data('jqv') == null ) { 194 options = methods._saveOptions(form, options); 195 // bind all formError elements to close on click 196 $(document).on("click", ".formError", function() { 197 $(this).fadeOut(150, function() { 198 // remove prompt once invisible 199 $(this).closest('.formError').remove(); 200 }); 201 }); 202 } 203 return this; 204 }, 205 /** 206 * Attachs jQuery.validationEngine to form.submit and field.blur events 207 * Takes an optional params: a list of options 208 * ie. jQuery("#formID1").validationEngine('attach', {promptPosition : "centerRight"}); 209 */ 210 attach: function(userOptions) { 211 212 var form = this; 213 var options; 214 215 if(userOptions) 216 options = methods._saveOptions(form, userOptions); 217 else 218 options = form.data('jqv'); 219 220 options.validateAttribute = (form.find("[data-validation-engine*=validate]").length) ? "data-validation-engine" : "class"; 221 if (options.binded) { 222 223 // delegate fields 224 form.on(options.validationEventTrigger, "["+options.validateAttribute+"*=validate]:not([type=checkbox]):not([type=radio]):not(.datepicker)", methods._onFieldEvent); 225 form.on("click", "["+options.validateAttribute+"*=validate][type=c
225heckbox],["+options.validateAttribute+"*=validate][type=radio]", methods._onFieldEvent); 226 form.on(options.validationEventTrigger,"["+options.validateAttribute+"*=validate][class*=datepicker]", {"delay": 300}, methods._onFieldEvent); 227 } 228 if (options.autoPositionUpdate) { 229 $(window).bind("resize", { 230 "noAnimation": true, 231 "formElem": form 232 }, methods.updatePromptsPosition); 233 } 234 form.on("click","a[data-validation-engine-skip], a[class*='validate-skip'], button[data-validation-engine-skip], button[class*='validate-skip'], input[data-validation-engine-skip], input[class*='validate-skip']", methods._submitButtonClick); 235 form.removeData('jqv_submitButton'); 236 237 // bind form.submit 238 form.on("submit", methods._onSubmitEvent); 239 return this; 240 }, 241 /** 242 * Unregisters any bindings that may point to jQuery.validaitonEngine 243 */ 244 detach: function() { 245 246 var form = this; 247 var options = form.data('jqv'); 248 249 // unbind fields 250 form.off(options.validationEventTrigger, "["+options.validateAttribute+"*=validate]:not([type=checkbox]):not([type=radio]):not(.datepicker)", methods._onFieldEvent); 251 form.off("click", "["+options.validateAttribute+"*=validate][type=checkbox],["+options.validateAttribute+"*=validate][type=radio]", methods._onFieldEvent); 252 form.off(options.validationEventTrigger,"["+options.validateAttribute+"*=validate][class*=datepicker]", methods._onFieldEvent); 253 254 // unbind form.submit 255 form.off("submit", methods._onSubmitEvent); 256 form.removeData('jqv'); 257 258 form.off("click", "a[data-validation-engine-skip], a[class*='validate-skip'], button[data-validation-engine-skip], button[class*='validate-skip'], input[data-validation-engine-skip], input[class*='validate-skip']", methods._submitButtonClick); 259 form.removeData('jqv_submitButton'); 260 261 if (options.autoPositionUpdate) 262 $(window).off("resize", methods.updatePromptsPosition); 263 264 return this; 265 }, 266 /** 267 * Validates either a form or a list of fields, shows prompts accordingly. 268 * Note: There is no ajax form validation with this method, only field ajax validation are evaluated 269 * 270 * @return true if the form validates, false if it fails 271 */ 272 validate: function(userOptions) { 273 var element = $(this); 274 var valid = null; 275 var options; 276
277 if (element.is("form") || element.hasClass("validationEngineContainer")) { 278 if (element.hasClass('validating')) { 279 // form is already validating. 280 // Should abort old validation and start new one. I don't know how to implement it. 281 return false; 282 } else { 283 element.addClass('validating'); 284 if(userOptions) 285 options = methods._saveOptions(element, userOptions); 286 else 287 options = element.data('jqv'); 288 var valid = methods._validateFields(this); 289 290 // If the form doesn't validate, clear the 'validating' class before the user has a chance to submit again 291 setTimeout(function(){ 292 element.removeClass('validating'); 293 }, 100); 294 if (valid && options.onSuccess) { 295 options.onSuccess(); 296 } else if (!valid && options.onFailure) { 297 options.onFailure(); 298 } 299 } 300 } else if (element.is('form') || element.hasClass('validationEngineContainer')) { 301 element.removeClass('validating'); 302 } else { 303 // field validation 304 var form = element.closest('form, .validationEngineContainer'); 305 options = (form.data('jqv')) ? form.data('jqv') : $.validationEngine.defaults; 306 valid = methods._validateField(element, options); 307 308 if (valid && options.onFieldSuccess) 309 options.onFieldSuccess(); 310 else if (options.onFieldFailure && options.InvalidFields.length > 0) { 311 options.onFieldFailure(); 312 } 313 314 return !valid; 315 } 316 if(options.onValidationComplete) { 317 // !! ensures that an undefined return is interpreted as return false but allows a onValidationComplete() to possibly return true and have form continue processing 318 return !!options.onValidationComplete(form, valid); 319 } 320 return valid; 321 }, 322 /** 323 * Redraw prompts position, useful when you change the DOM state when validating 324 */ 325 updatePromptsPosition: function(event) { 326 327 if (event && this == window) { 328 var form = event.data.formElem; 329 var noAnimation = event.data.noAnimation; 330 } 331 else 332 var form = $(this.closest('form, .validationEngineContainer')); 333 334 var options = form.data('jqv'); 335 // No option, take default one 336 if (!options) 337 options = methods._saveOptions(form, options); 338 form.find('['+options.validateAttribute+'*=validate]').not(":disabled").each(function(){ 339 var field = $(this); 340 if (options.prettySelect && field.is(":hidden")) 341 field = form.find("#" + options.usePrefix + field.attr('id') + options.useSuffix); 342 var prompt = methods._getPrompt(field); 343 var promptText = $(prompt).find(".formErrorContent").html(); 344 345 if(prompt) 346 methods._updatePrompt(field, $(prompt), promptText, undefined, false, options, noAnimation); 347 }); 348 return this; 349 }, 350 /** 351 * Displays a prompt on a element. 352 * Note that the element needs an id! 353 * 354 * @param {String} promptText html text to display type 355 * @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red) 356 * @param {String} possible values topLeft, topRight, bottomLeft, centerRight, bottomRight 357 */ 358 showPrompt: function(promptText, type, promptPosition, showArrow) { 359 var form = this.closest('form, .validationEngineContainer'); 360 var options = form.data('jqv'); 361 // No option, take default one 362 if(!options) 363 options = methods._saveOptions(this, options); 364 if(promptPosition) 365 options.promptPosition=promptPosition; 366 options.showArrow = showArrow==true; 367 368 methods._showPrompt(this, promptText, type, false, options); 369 return this; 370 }, 371 /** 372 * Closes form error prompts, CAN be invidual 373 */ 374 hide: function() { 375 var form = $(this).closest('form, .validationEngineContainer'); 376 var options = form.data('jqv'); 377 // No option, take default one 378 if (!options) 379 options = methods._saveOptions(form, options); 380 var fadeDuration = (options && options.fadeDuration) ? options.fadeDuration : 0.3; 381 var closingtag; 382
383 if(form.is("form") || form.hasClass("validationEngineContainer")) { 384 closingtag = "parentForm"+methods._getClassName($(form).attr("id")); 385 } else { 386 closingtag = methods._getClassName($(form).attr("id")) +"formError"; 387 } 388 $('.'+closingtag).fadeTo(fadeDuration, 0, function() { 389 $(this).closest('.formError').remove(); 390 }); 391 return this; 392 }, 393 /** 394 * Closes all error prompts on the page 395 */ 396 hideAll: function() { 397 var form = this; 398 var options = form.data('jqv'); 399 var duration = options ? options.fadeDuration:300; 400 $('.formError').fadeTo(duration, 0, function() { 401 $(this).closest('.formError').remove(); 402 }); 403 return this; 404 }, 405 /** 406 * Typically called when user exists a field using tab or a mouse click, triggers a field 407 * validation 408 */ 409 _onFieldEvent: function(event) { 410 var field = $(this); 411 var form = field.closest('form, .validationEngineContainer'); 412 var options = form.data('jqv'); 413 // No option, take default one 414 if (!options) 415 options = methods._saveOptions(form, options); 416 options.eventTrigger = "field"; 417 418 if (options.notEmpty == true){ 419 420 if(field.val().length > 0){ 421 // validate the current field 422 window.setTimeout(function() { 423 methods._validateField(field, options); 424 }, (event.data) ? event.data.delay : 0); 425 426 } 427 428 }else{ 429 430 // validate the current field 431 window.setTimeout(function() { 432 methods._validateField(field, options); 433 }, (event.data) ? event.data.delay : 0); 434 435 } 436 437 438 439 440 }, 441 /** 442 * Called when the form is submited, shows prompts accordingly 443 * 444 * @param {jqObject} 445 * form 446 * @return false if form submission needs to be cancelled 447 */ 448 _onSubmitEvent: function() { 449 var form = $(this); 450 var options = form.data('jqv'); 451 452 //check if it is trigger from skipped button 453 if (form.data("jqv_submitButton")){ 454 var submitButton = $("#" + form.data("jqv_submitButton")); 455 if (submitButton){ 456 if (submitButton.length > 0){
457 if (submitButton.hasClass("validate-skip") || submitButton.attr("data-validation-engine-skip") == "true") 458 return true; 459 } 460 } 461 } 462 463 options.eventTrigger = "submit"; 464 465 // validate each field 466 // (- skip field ajax validation, not necessary IF we will perform an ajax form validation) 467 var r=methods._validateFields(form); 468 469 if (r && options.ajaxFormValidation) { 470 methods._validateFormWithAjax(form, options); 471 // cancel form auto-submission - process with async call onAjaxFormComplete 472 return false; 473 } 474 475 if(options.onValidationComplete) { 476 // !! ensures that an undefined return is interpreted as return false but allows a onValidationComplete() to possibly return true and have form continue processing 477 return !!options.onValidationComplete(form, r); 478 } 479 return r; 480 }, 481 /** 482 * Return true if the ajax field validations passed so far 483 * @param {Object} options 484 * @return true, is all ajax validation passed so far (remember ajax is async) 485 */ 486 _checkAjaxStatus: function(options) { 487 var status = true; 488 $.each(options.ajaxValidCache, function(key, value) { 489 if (!value) { 490 status = false; 491 // break the each 492 return false; 493 } 494 }); 495 return status; 496 }, 497 498 /** 499 * Return true if the ajax field is validated 500 * @param {String} fieldid 501 * @param {Object} options 502 * @return true, if validation passed, false if false or doesn't exist 503 */ 504 _checkAjaxFieldStatus: function(fieldid, options) { 505 return options.ajaxValidCache[fieldid] == true; 506 }, 507 /** 508 * Validates form fields, shows prompts accordingly 509 * 510 * @param {jqObject} 511 * form 512 * @param {skipAjaxFieldValidation} 513 * boolean - when set to true, ajax field validation is skipped, typically used when the submit button is clicked 514 * 515 * @return true if form is valid, false if not, undefined if ajax form validation is done 516 */ 517 _validateFields: function(form) { 518 var options = form.data('jqv'); 519 520 // this variable is set to true if an error is found 521 var errorFound = false; 522 523 // Trigger hook, start validation 524 form.trigger("jqv.form.validating"); 525 // first, evaluate status of non ajax fields 526 var first_err=null; 527 form.find('['+options.validateAttribute+'*=validate]').not(":disabled").each( function() { 528 var field = $(this); 529 var names = []; 530 if ($.inArray(field.attr('name'), names) < 0) { 531 errorFound |= methods._validateField(field, options); 532 if (errorFound && first_err==null) 533 if (field.is(":hidden") && options.prettySelect) 534 first_err = field = form.find("#" + options.usePrefix + methods._jqSelector(field.attr('id')) + options.useSuffix); 535 else { 536 537 //Check if we need to adjust what element to show the prompt on 538 //and and such scroll to instead 539 if(field.data('jqv-prompt-at') instanceof jQuery ){ 540 field = field.data('jqv-prompt-at'); 541 } else if(field.data('jqv-prompt-at')) { 542 field = $(field.data('jqv-prompt-at')); 543 } 544 first_err=field; 545 } 546 if (options.doNotShowAllErrosOnSubmit) 547 return false; 548 names.push(field.attr('name')); 549 550 //if option set, stop checking validation rules after one error is found 551 if(options.showOneMessage == true && errorFound){ 552 return false; 553 } 554 } 555 }); 556 557 // second, check to see if all ajax calls completed ok 558 // errorFound |= !methods._checkAjaxStatus(options); 559 560 // third, check status and scroll the container accordingly 561 form.trigger("jqv.form.result", [errorFound]); 562 563 if (errorFound) { 564 if (options.scroll) { 565 var destination=first_err.offset().top; 566 var fixleft = first_err.offset().left; 567 568 //prompt positioning adjustment support. Usage: positionType:Xshift,Yshift (for ex.: bottomLeft:+20 or bottomLeft:-20,+10) 569 var positionType=options.promptPosition; 570 if (typeof(positionType)=='string' && positionType.indexOf(":")!=-1) 571 positionType=positionType.substring(0,positionType.indexOf(":")); 572 573 if (positionType!="bottomRight" && positionType!="bottomLeft") { 574 var prompt_err= methods._getPrompt(first_err); 575 if (prompt_err) { 576 destination=prompt_err.offset().top; 577 } 578 } 579 580 // Offset the amount the page scrolls by an amount in px to accomodate fixed elements at top of page 581 if (options.scrollOffset) { 582 destination -= options.scrollOffset; 583 } 584 585 // get the position of the first error, there should be at least one, no need to check this 586 //var destination = form.find(".formError:not('.greenPopup'):first").offset().top; 587 if (options.isOverflown) { 588 var overflowDIV = $(options.overflownDIV); 589 if(!overflowDIV.length) return false;
590 var scrollContainerScroll = overflowDIV.scrollTop(); 591 var scrollContainerPos = -parseInt(overflowDIV.offset().top); 592 593 destination += scrollContainerScroll + scrollContainerPos - 5; 594 var scrollContainer = $(options.overflownDIV).filter(":not(:animated)"); 595 596 scrollContainer.animate({ scrollTop: destination }, 1100, function(){ 597 if(options.focusFirstField) first_err.focus(); 598 }); 599 600 } else { 601 $("html, body").animate({ 602 scrollTop: destination 603 }, 1100, function(){ 604 if(options.focusFirstField) first_err.focus(); 605 }); 606 $("html, body").animate({scrollLeft: fixleft},1100) 607 } 608 609 } else if(options.focusFirstField) 610 first_err.focus(); 611 return false; 612 } 613 return true; 614 }, 615 /** 616 * This method is called to perform an ajax form validation. 617 * During this process all the (field, value) pairs are sent to the server which returns a list of invalid fields or true 618 * 619 * @param {jqObject} form 620 * @param {Map} options 621 */ 622 _validateFormWithAjax: function(form, options) { 623 624 var data = form.serialize(); 625 var type = (options.ajaxFormValidationMethod) ? options.ajaxFormValidationMethod : "GET"; 626 var url = (options.ajaxFormValidationURL) ? options.ajaxFormValidationURL : form.attr("action"); 627 var dataType = (options.dataType) ? options.dataType : "json"; 628 $.ajax({ 629 type: type, 630 url: url, 631 cache: false, 632 dataType: dataType, 633 data: data, 634 form: form, 635 methods: methods, 636 options: options, 637 beforeSend: function() { 638 return options.onBeforeAjaxFormValidation(form, options); 639 }, 640 error: function(data, transport) { 641 if (options.onFailure) { 642 options.onFailure(data, transport); 643 } else { 644 methods._ajaxError(data, transport); 645 } 646 }, 647 success: function(json) { 648 if ((dataType == "json") && (json !== true)) { 649 // getting to this case doesn't necessary means that the form is invalid 650 // the server may return green or closing prompt actions 651 // this flag helps figuring it out 652 var errorInForm=false; 653 for (var i = 0; i < json.length; i++) { 654 var value = json[i]; 655 656 var errorFieldId = value[0]; 657 var errorField = $($("#" + errorFieldId)[0]); 658 659 // make sure we found the element 660 if (errorField.length == 1) { 661 662 // promptText or selector 663 var msg = value[2]; 664 // if the field is valid 665 if (value[1] == true) { 666 667 if (msg == "" || !msg){ 668 // if for some reason, status==true and error="", just close the prompt 669 methods._closePrompt(errorField); 670 } else { 671 // the field is valid, but we are displaying a green prompt 672 if (options.allrules[msg]) { 673 var txt = options.allrules[msg].alertTextOk; 674 if (txt) 675 msg = txt; 676 } 677 if (options.showPrompts) methods._showPrompt(errorField, msg, "pass", false, options, true); 678 } 679 } else { 680 // the field is invalid, show the red error prompt 681 errorInForm|=true; 682 if (options.allrules[msg]) { 683 var txt = options.allrules[msg].alertText; 684 if (txt) 685 msg = txt; 686 } 687 if(options.showPrompts) methods._showPrompt(errorField, msg, "", false, options, true); 688 } 689 } 690 } 691 options.onAjaxFormComplete(!errorInForm, form, json, options); 692 } else 693 options.onAjaxFormComplete(true, form, json, options); 694 695 } 696 }); 697 698 }, 699 /** 700 * Validates field, shows prompts accordingly 701 * 702 * @param {jqObject} 703 * field 704 * @param {Array[String]} 705 * field's validation rules 706 * @param {Map} 707 * user options 708 * @return false if field is valid (It is inversed for *fields*, it return false on validate and true on errors.) 709 */ 710 _validateField: function(field, options, skipAjaxValidation) { 711 if (!field.attr("id")) { 712 field.attr("id", "form-validation-field-" + $.validationEngine.fieldIdCounter); 713 ++$.validationEngine.fieldIdCounter; 714 } 715 716 if(field.hasClass(options.ignoreFieldsWithClass)) 717 return false;
718 719 if (!options.validateNonVisibleFields && (field.is(":hidden") && !options.prettySelect || field.parent().is(":hidden"))) 720 return false; 721 722 var rulesParsing = field.attr(options.validateAttribute); 723 var getRules = /validate\[(.*)\]/.exec(rulesParsing); 724 725 if (!getRules) 726 return false; 727 var str = getRules[1]; 728 var rules = str.split(/\[|,|\]/); 729 730 // true if we ran the ajax validation, tells the logic to stop messing with prompts 731 var isAjaxValidator = false; 732 var fieldName = field.attr("name"); 733 var promptText = ""; 734 var promptType = ""; 735 var required = false; 736 var limitErrors = false; 737 options.isError = false; 738 options.showArrow = true; 739 740 // If the programmer wants to limit the amount of error messages per field, 741 if (options.maxErrorsPerField > 0) { 742 limitErrors = true; 743 } 744 745 var form = $(field.closest("form, .validationEngineContainer")); 746 // Fix for adding spaces in the rules 747 for (var i = 0; i < rules.length; i++) { 748 rules[i] = rules[i].toString().replace(" ", "");//.toString to worked on IE8 749 // Remove any parsing errors 750 if (rules[i] === '') { 751 delete rules[i]; 752 } 753 } 754 755 for (var i = 0, field_errors = 0; i < rules.length; i++) { 756 757 // If we are limiting errors, and have hit the max, break 758 if (limitErrors && field_errors >= options.maxErrorsPerField) { 759 // If we haven't hit a required yet, check to see if there is one in the validation rules for this 760 // field and that it's index is greater or equal to our current index 761 if (!required) { 762 var have_required = $.inArray('required', rules); 763 required = (have_required != -1 && have_required >= i); 764 } 765 break; 766 } 767 768 769 var errorMsg = undefined; 770 switch (rules[i]) { 771 772 case "required": 773 required = true; 774 errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._required); 775 break; 776 case "custom": 777 errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._custom); 778 break; 779 case "groupRequired": 780 // Check is its the first of group, if not, reload validation with first field 781 // AND continue normal validation on present field 782 var classGroup = "["+options.validateAttribute+"*=" +rules[i + 1] +"]"; 783 var firstOfGroup = form.find(classGroup).eq(0); 784 if(firstOfGroup[0] != field[0]){ 785 786 methods._validateField(firstOfGroup, options, skipAjaxValidation); 787 options.showArrow = true; 788 789 } 790 errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._groupRequired); 791 if(errorMsg) required = true; 792 options.showArrow = false; 793 break; 794 case "ajax": 795 // AJAX defaults to returning it's loading message 796 errorMsg = methods._ajax(field, rules, i, options); 797 if (errorMsg) { 798 promptType = "load"; 799 } 800 break; 801 case "minSize": 802 errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._minSize); 803 break; 804 case "maxSize": 805 errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._maxSize); 806 break; 807 case "min": 808 errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._min); 809 break; 810 case "max": 811 errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._max); 812 break; 813 case "past": 814 errorMsg = methods._getErrorMessage(form, field,rules[i], rules, i, options, methods._past); 815 break; 816 case "future": 817 errorMsg = methods._getErrorMessage(form, field,rules[i], rules, i, options, methods._future); 818 break; 819 case "dateRange": 820 var classGroup = "["+options.validateAttribute+"*=" + rules[i + 1] + "]"; 821 options.firstOfGroup = form.find(classGroup).eq(0); 822 options.secondOfGroup = form.find(classGroup).eq(1); 823 824 //if one entry out of the pair has value then proceed to run through validation 825 if (options.firstOfGroup[0].value || options.secondOfGroup[0].value) { 826 errorMsg = methods._getErrorMessage(form, field,rules[i], rules, i, options, methods._dateRange); 827 } 828 if (errorMsg) required = true; 829 options.showArrow = false;
830 break; 831 832 case "dateTimeRange": 833 var classGroup = "["+options.validateAttribute+"*=" + rules[i + 1] + "]"; 834 options.firstOfGroup = form.find(classGroup).eq(0); 835 options.secondOfGroup = form.find(classGroup).eq(1); 836 837 //if one entry out of the pair has value then proceed to run through validation 838 if (options.firstOfGroup[0].value || options.secondOfGroup[0].value) { 839 errorMsg = methods._getErrorMessage(form, field,rules[i], rules, i, options, methods._dateTimeRange); 840 } 841 if (errorMsg) required = true; 842 options.showArrow = false; 843 break; 844 case "maxCheckbox": 845 field = $(form.find("input[name='" + fieldName + "']")); 846 errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._maxCheckbox); 847 break; 848 case "minCheckbox": 849 field = $(form.find("input[name='" + fieldName + "']")); 850 errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._minCheckbox); 851 break; 852 case "equals": 853 errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._equals); 854 break; 855 case "funcCall": 856 errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._funcCall); 857 break; 858 case "creditCard": 859 errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._creditCard); 860 break; 861 case "condRequired": 862 errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._condRequired); 863 if (errorMsg !== undefined) { 864 required = true; 865 } 866 break; 867 case "funcCallRequired": 868 errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._funcCallRequired); 869 if (errorMsg !== undefined) { 870 required = true; 871 } 872 break; 873 874 default: 875 } 876 877 var end_validation = false; 878 879 // If we were passed back an message object, check what the status was to determine what to do 880 if (typeof errorMsg == "object") { 881 switch (errorMsg.status) { 882 case "_break": 883 end_validation = true; 884 break; 885 // If we have an error message, set errorMsg to the error message 886 case "_error": 887 errorMsg = errorMsg.message; 888 break; 889 // If we want to throw an error, but not show a prompt, return early with true 890 case "_error_no_prompt": 891 return true; 892 break; 893 // Anything else we continue on 894 default: 895 break; 896 } 897 } 898 899 //funcCallRequired, first in rules, and has error, skip anything else 900 if( i==0 && str.indexOf('funcCallRequired')==0 && errorMsg !== undefined ){ 901 if(promptText != '') { 902 promptText += "<br/>"; 903 } 904 promptText += errorMsg; 905 options.isError=true; 906 field_errors++; 907 end_validation=true; 908 } 909 910 // If it has been specified that validation should end now, break 911 if (end_validation) { 912 break; 913 } 914 915 // If we have a string, that means that we have an error, so add it to the error message. 916 if (typeof errorMsg == 'string') { 917 if(promptText != '') { 918 promptText += "<br/>"; 919 } 920 promptText += errorMsg; 921 options.isError = true; 922 field_errors++; 923 } 924 } 925 // If the rules required is not added, an empty field is not validated 926 //the 3rd condition is added so that even empty password fields should be equal 927 //otherwise if one is filled and another left empty, the "equal" condition would fail 928 //which does not make any sense 929 if(!required && !(field.val()) && field.val().length < 1 && $.inArray('equals', rules) < 0) options.isError = false; 930 931 // Hack for radio/checkbox group button, the validation go into the 932 // first radio/checkbox of the group 933 var fieldType = field.prop("type"); 934 var positionType=field.data("promptPosition") || options.promptPosition; 935 936 if ((fieldType == "radio" || fieldType == "checkbox") && form.find("input[name='" + fieldName + "']").size() > 1) { 937 if(positionType === 'inline') { 938 field = $(form.find("input[name='" + fieldName + "'][type!=hidden]:last")); 939 } else { 940 field = $(form.find("input[name='" + fieldName + "'][type!=hidden]:first")); 941 } 942 options.showArrow = options.showArrowOnRadioAndCheckbox; 943 } 944 945 if(field.is(":hidden") && options.prettySelect) { 946 field = form.find("#" + options.usePrefix + methods._jqSelector(field.attr('id')) + options.useSuffix); 947 } 948 949 if (options.isError && options.showPrompts){ 950 methods._showPrompt(field, promptText, promptType, false, options); 951 }else{ 952 if (!isAjaxValidator) methods._closePrompt(field); 953 } 954 955 if (!isAjaxValidator) { 956 field.trigger("jqv.field.result", [field, options.isError, promptText]); 957 } 958 959 /* Record error */ 960 var errindex = $.inArray(field[0], options.InvalidFields); 961 if (errindex == -1) { 962 if (options.isError) 963 options.InvalidFields.push(field[0]); 964 } else if (!options.isError) { 965 options.InvalidFields.splice(errindex, 1); 966 } 967
968 methods._handleStatusCssClasses(field, options); 969 970 /* run callback function for each field */ 971 if (options.isError && options.onFieldFailure) 972 options.onFieldFailure(field); 973 974 if (!options.isError && options.onFieldSuccess) 975 options.onFieldSuccess(field); 976 977 return options.isError; 978 }, 979 /** 980 * Handling css classes of fields indicating result of validation 981 * 982 * @param {jqObject} 983 * field 984 * @param {Array[String]} 985 * field's validation rules 986 * @private 987 */ 988 _handleStatusCssClasses: function(field, options) { 989 /* remove all classes */ 990 if(options.addSuccessCssClassToField) 991 field.removeClass(options.addSuccessCssClassToField); 992 993 if(options.addFailureCssClassToField) 994 field.removeClass(options.addFailureCssClassToField); 995 996 /* Add classes */ 997 if (options.addSuccessCssClassToField && !options.isError) 998 field.addClass(options.addSuccessCssClassToField); 999 1000 if (options.addFailureCssClassToField && options.isError) 1001 field.addClass(options.addFailureCssClassToField); 1002 }, 1003 1004 /******************** 1005 * _getErrorMessage 1006 * 1007 * @param form 1008 * @param field 1009 * @param rule 1010 * @param rules 1011 * @param i 1012 * @param options 1013 * @param originalValidationMethod 1014 * @return {*} 1015 * @private 1016 */ 1017 _getErrorMessage:function (form, field, rule, rules, i, options, originalValidationMethod) { 1018 // If we are using the custon validation type, build the index for the rule. 1019 // Otherwise if we are doing a function call, make the call and return the object 1020 // that is passed back. 1021 var rule_index = jQuery.inArray(rule, rules); 1022 if (rule === "custom" || rule === "funcCall" || rule === "funcCallRequired") { 1023 var custom_validation_type = rules[rule_index + 1]; 1024 rule = rule + "[" + custom_validation_type + "]"; 1025 // Delete the rule from the rules array so that it doesn't try to call the 1026 // same rule over again 1027 delete(rules[rule_index]); 1028 } 1029 // Change the rule to the composite rule, if it was different from the original 1030 var alteredRule = rule; 1031 1032 1033 var element_classes = (field.attr("data-validation-engine")) ? field.attr("data-validation-engine") : field.attr("class"); 1034 var element_classes_array = element_classes.split(" "); 1035 1036 // Call the original validation method. If we are dealing with dates or checkboxes, also pass the form 1037 var errorMsg; 1038 if (rule == "future" || rule == "past" || rule == "maxCheckbox" || rule == "minCheckbox") { 1039 errorMsg = originalValidationMethod(form, field, rules, i, options); 1040 } else { 1041 errorMsg = originalValidationMethod(field, rules, i, options); 1042 } 1043 1044 // If the original validation method returned an error and we have a custom error message, 1045 // return the custom message instead. Otherwise return the original error message. 1046 if (errorMsg != undefined) { 1047 var custom_message = methods._getCustomErrorMessage($(field), element_classes_array, alteredRule, options); 1048 if (custom_message) errorMsg = custom_message; 1049 } 1050 return errorMsg; 1051 1052 }, 1053 _getCustomErrorMessage:function (field, classes, rule, options) { 1054 var custom_message = false; 1055 var validityProp = /^custom\[.*\]$/.test(rule) ? methods._validityProp["custom"] : methods._validityProp[rule]; 1056 // If there is a validityProp for this rule, check to see if the field has an attribute for it 1057 if (validityProp != undefined) { 1058 custom_message = field.attr("data-errormessage-"+validityProp); 1059 // If there was an error message for it, return the message 1060 if (custom_message != undefined) 1061 return custom_message; 1062 } 1063 custom_message = field.attr("data-errormessage"); 1064 // If there is an inline custom error message, return it 1065 if (custom_message != undefined) 1066 return custom_message; 1067 var id = '#' + field.attr("id"); 1068 // If we have custom messages for the element's id, get the message for the rule from the id. 1069 // Otherwise, if we have custom messages for the element's classes, use the first class message we find instead. 1070 if (typeof options.custom_error_messages[id] != "undefined" && 1071 typeof options.custom_error_messages[id][rule] != "undefined" ) { 1072 custom_message = options.custom_error_messages[id][rule]['message']; 1073 } else if (classes.length > 0) { 1074 for (var i = 0; i < classes.length && classes.length > 0; i++) { 1075 var element_class = "." + classes[i]; 1076 if (typeof options.custom_error_messages[element_class] != "undefined" && 1077 typeof options.custom_error_messages[element_class][rule] != "undefined") { 1078 custom_message = options.custom_error_messages[element_class][rule]['message']; 1079 break; 1080 } 1081 } 1082 } 1083 if (!custom_message && 1084 typeof options.custom_error_messages[rule] != "undefined" && 1085 typeof options.custom_error_messages[rule]['message'] != "undefined"){ 1086 custom_message = options.custom_error_messages[rule]['message']; 1087 } 1088 return custom_message; 1089 }, 1090 _validityProp: { 1091 "required": "value-missing",
1092 "custom": "custom-error", 1093 "groupRequired": "value-missing", 1094 "ajax": "custom-error", 1095 "minSize": "range-underflow", 1096 "maxSize": "range-overflow", 1097 "min": "range-underflow", 1098 "max": "range-overflow", 1099 "past": "type-mismatch", 1100 "future": "type-mismatch", 1101 "dateRange": "type-mismatch", 1102 "dateTimeRange": "type-mismatch", 1103 "maxCheckbox": "range-overflow", 1104 "minCheckbox": "range-underflow", 1105 "equals": "pattern-mismatch", 1106 "funcCall": "custom-error", 1107 "funcCallRequired": "custom-error", 1108 "creditCard": "pattern-mismatch", 1109 "condRequired": "value-missing" 1110 }, 1111 /** 1112 * Required validation 1113 * 1114 * @param {jqObject} field 1115 * @param {Array[String]} rules 1116 * @param {int} i rules index 1117 * @param {Map} 1118 * user options 1119 * @param {bool} condRequired flag when method is used for internal purpose in condRequired check 1120 * @return an error string if validation failed 1121 */ 1122 _required: function(field, rules, i, options, condRequired) { 1123 switch (field.prop("type")) { 1124 case "radio": 1125 case "checkbox": 1126 // new validation style to only check dependent field 1127 if (condRequired) { 1128 if (!field.prop('checked')) { 1129 return options.allrules[rules[i]].alertTextCheckboxMultiple; 1130 } 1131 break; 1132 } 1133 // old validation style 1134 var form = field.closest("form, .validationEngineContainer"); 1135 var name = field.attr("name"); 1136 if (form.find("input[name='" + name + "']:checked").size() == 0) { 1137 if (form.find("input[name='" + name + "']:visible").size() == 1) 1138 return options.allrules[rules[i]].alertTextCheckboxe; 1139 else 1140 return options.allrules[rules[i]].alertTextCheckboxMultiple; 1141 } 1142 break; 1143 case "text": 1144 case "password": 1145 case "textarea": 1146 case "file": 1147 case "select-one": 1148 case "select-multiple": 1149 default: 1150 var field_val = $.trim( field.val() ); 1151 var dv_placeholder = $.trim( field.attr("data-validation-placeholder") ); 1152 var placeholder = $.trim( field.attr("placeholder") ); 1153 if ( 1154 ( !field_val ) 1155 || ( dv_placeholder && field_val == dv_placeholder ) 1156 || ( placeholder && field_val == placeholder ) 1157 ) { 1158 return options.allrules[rules[i]].alertText; 1159 } 1160 break; 1161 } 1162 }, 1163 /** 1164 * Validate that 1 from the group field is required 1165 * 1166 * @param {jqObject} field 1167 * @param {Array[String]} rules 1168 * @param {int} i rules index 1169 * @param {Map} 1170 * user options 1171 * @return an error string if validation failed 1172 */ 1173 _groupRequired: function(field, rules, i, options) { 1174 var classGroup = "["+options.validateAttribute+"*=" +rules[i + 1] +"]"; 1175 var isValid = false; 1176 // Check all fields from the group 1177 field.closest("form, .validationEngineContainer").find(classGroup).each(function(){ 1178 if(!methods._required($(this), rules, i, options)){ 1179 isValid = true; 1180 return false; 1181 } 1182 }); 1183 1184 if(!isValid) { 1185 return options.allrules[rules[i]].alertText; 1186 } 1187 }, 1188 /** 1189 * Validate rules 1190 * 1191 * @param {jqObject} field 1192 * @param {Array[String]} rules 1193 * @param {int} i rules index 1194 * @param {Map} 1195 * user options 1196 * @return an error string if validation failed 1197 */ 1198 _custom: function(field, rules, i, options) { 1199 var customRule = rules[i + 1]; 1200 var rule = options.allrules[customRule]; 1201 var fn; 1202 if(!rule) { 1203 alert("jqv:custom rule not found - "+customRule); 1204 return; 1205 } 1206 1207 if(rule["regex"]) { 1208 var ex=rule.regex; 1209 if(!ex) { 1210 alert("jqv:custom regex not found - "+customRule); 1211 return; 1212 } 1213 var pattern = new RegExp(ex); 1214 1215 if (!pattern.test(field.val())) return options.allrules[customRule].alertText; 1216 1217 } else if(rule["func"]) { 1218 fn = rule["func"]; 1219 1220 if (typeof(fn) !== "function") { 1221 alert("jqv:custom parameter 'function' is no function - "+customRule); 1222 return; 1223 } 1224 1225 if (!fn(field, rules, i, options)) 1226 return options.allrules[customRule].alertText; 1227 } else { 1228 alert("jqv:custom type not allowed "+customRule); 1229 return; 1230 } 1231 }, 1232 /** 1233 * Validate custom function outside of the engine scope 1234 * 1235 * @param {jqObject} field 1236 * @param {Array[String]} rules 1237 * @param {int} i rules index 1238 * @param {Map} 1239 * user options 1240 * @return an error string if validation failed 1241 */ 1242 _funcCall: function(field, rules, i, options) { 1243 var functionName = rules[i + 1]; 1244 var fn; 1245 if(functionName.indexOf('.') >-1) 1246 { 1247 var namespaces = functionName.split('.'); 1248 var scope = window; 1249 while(namespaces.length) 1250 { 1251 scope = scope[namespaces.shift()]; 1252 } 1253 fn = scope; 1254 } 1255 else 1256 fn = window[functionName] || options.customFunctions[functionName]; 1257 if (typeof(fn) == 'function') 1258 return fn(field, rules, i, options); 1259 1260 }, 1261 _funcCallRequired: function(field, rules, i, options) { 1262 return methods._funcCall(field,rules,i,options); 1263 }, 1264 /** 1265 * Field match 1266 * 1267 * @param {jqObject} field 1268 * @param {Array[String]} rules 1269 * @param {int} i rules index 1270 * @param {Map} 1271 * user options 1272 * @return an error string if validation failed 1273 */ 1274 _equals: function(field, rules, i, options) { 1275 var equalsField = rules[i + 1]; 1276 1277 if (field.val() != $("#" + equalsField).val()) 1278 return options.allrules.equals.alertText; 1279 }, 1280 /** 1281 * Check the maximum size (in characters) 1282 * 1283 * @param {jqObject} field 1284 * @param {Array[String]} rules 1285 * @param {int} i rules index 1286 * @param {Map} 1287 * user options 1288 * @return an error string if validation failed 1289 */ 1290 _maxSize: function(field, rules, i, options) { 1291 var max = rules[i + 1]; 1292 var len = field.val().length; 1293 1294 if (len > max) { 1295 var rule = options.allrules.maxSize; 1296 return rule.alertText + max + rule.alertText2; 1297 } 1298 }, 1299 /** 1300 * Check the minimum size (in characters) 1301 * 1302 * @param {jqObject} field 1303 * @param {Array[String]} rules 1304 * @param {int} i rules index 1305 * @param {Map} 1306 * user options 1307 * @return an error string if validation failed 1308 */ 1309 _minSize: function(field, rules, i, options) { 1310 var min = rules[i + 1]; 1311 var len = field.val().length; 1312 1313 if (len < min) { 1314 var rule = options.allrules.minSize; 1315 return rule.alertText + min + rule.alertText2; 1316 } 1317 }, 1318 /** 1319 * Check number minimum value 1320 * 1321 * @param {jqObject} field 1322 * @param {Array[String]} rules 1323 * @param {int} i rules index 1324 * @param {Map} 1325 * user options 1326 * @return an error string if validation failed 1327 */ 1328 _min: function(field, rules, i, options) { 1329 var min = parseFloat(rules[i + 1]); 1330 var len = parseFloat(field.val()); 1331 1332 if (len < min) { 1333 var rule = options.allrules.min; 1334 if (rule.alertText2) return rule.alertText + min + rule.alertText2; 1335 return rule.alertText + min; 1336 } 1337 }, 1338 /** 1339 * Check number maximum value 1340 * 1341 * @param {jqObject} field 1342 * @param {Array[String]} rules 1343 * @param {int} i rules index 1344 * @param {Map} 1345 * user options 1346 * @return an error string if validation failed 1347 */ 1348 _max: function(field, rules, i, options) { 1349 var max = parseFloat(rules[i + 1]); 1350 var len = parseFloat(field.val()); 1351 1352 if (len >max ) { 1353 var rule = options.allrules.max; 1354 if (rule.alertText2) return rule.alertText + max + rule.alertText2; 1355 //orefalo: to review, also do the translations 1356 return rule.alertText + max; 1357 } 1358 }, 1359 /** 1360 * Checks date is in the past 1361 * 1362 * @param {jqObject} field 1363 * @param {Array[String]} rules 1364 * @param {int} i rules index 1365 * @param {Map} 1366 * user options 1367 * @return an error string if validation failed 1368 */ 1369 _past: function(form, field, rules, i, options) { 1370 1371 var p=rules[i + 1]; 1372 var fieldAlt = $(form.find("*[name='" + p.replace(/^#+/, '') + "']")); 1373 var pdate; 1374 1375 if (p.toLowerCase() == "now") { 1376 pdate = new Date(); 1377 } else if (undefined != fieldAlt.val()) { 1378 if (fieldAlt.is(":disabled")) 1379 return; 1380 pdate = methods._parseDate(fieldAlt.val()); 1381 } else { 1382 pdate = methods._parseDate(p); 1383 } 1384 var vdate = methods._parseDate(field.val()); 1385 1386 if (vdate > pdate ) { 1387 var rule = options.allrules.past; 1388 if (rule.alertText2) return rule.alertText + methods._dateToString(pdate) + rule.alertText2; 1389 return rule.alertText + methods._dateToString(pdate); 1390 } 1391 }, 1392 /** 1393 * Checks date is in the future 1394 * 1395 * @param {jqObject} field 1396 * @param {Array[String]} rules 1397 * @param {int} i rules index 1398 * @param {Map} 1399 * user options 1400 * @return an error string if validation failed 1401 */ 1402 _future: function(form, field, rules, i, options) { 1403 1404 var p=rules[i + 1]; 1405 var fieldAlt = $(form.find("*[name='" + p.replace(/^#+/, '') + "']")); 1406 var pdate; 1407 1408 if (p.toLowerCase() == "now") { 1409 pdate = new Date(); 1410 } else if (undefined != fieldAlt.val()) { 1411 if (fieldAlt.is(":disabled")) 1412 return; 1413 pdate = methods._parseDate(fieldAlt.val()); 1414 } else { 1415 pdate = methods._parseDate(p); 1416 } 1417 var vdate = methods._parseDate(field.val()); 1418 1419 if (vdate < pdate ) { 1420 var rule = options.allrules.future; 1421 if (rule.alertText2) 1422 return rule.alertText + methods._dateToString(pdate) + rule.alertText2; 1423 return rule.alertText + methods._dateToString(pdate); 1424 } 1425 }, 1426 /** 1427 * Checks if valid date 1428 * 1429 * @param {string} date string 1430 * @return a bool based on determination of valid date 1431 */ 1432 _isDate: function (value) { 1433 var dateRegEx = new RegExp(/^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$|^(?:(?:(?
1433:0?[13578]|1[02])(\/|-)31)|(?:(?:0?[1,3-9]|1[0-2])(\/|-)(?:29|30)))(\/|-)(?:[1-9]\d\d\d|\d[1-9]\d\d|\d\d[1-9]\d|\d\d\d[1-9])$|^(?:(?:0?[1-9]|1[0-2])(\/|-)(?:0?[1-9]|1\d|2[0-8]))(\/|-)(?:[1-9]\d\d\d|\d[1-9]\d\d|\d\d[1-9]\d|\d\d\d[1-9])$|^(0?2(\/|-)29)(\/|-)(?:(?:0[48]00|[13579][26]00|[2468][048]00)|(?:\d\d)?(?:0[48]|[2468][048]|[13579][26]))$/); 1434 return dateRegEx.test(value); 1435 }, 1436 /** 1437 * Checks if valid date time 1438 * 1439 * @param {string} date string 1440 * @return a bool based on determination of valid date time 1441 */ 1442 _isDateTime: function (value){ 1443 var dateTimeRegEx = new RegExp(/^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])\s+(1[012]|0?[1-9]){1}:(0?[1-5]|[0-6][0-9]){1}:(0?[0-6]|[0-6][0-9]){1}\s+(am|pm|AM|PM){1}$|^(?:(?:(?:0?[13578]|1[02])(\/|-)31)|(?:(?:0?[1,3-9]|1[0-2])(\/|-)(?:29|30)))(\/|-)(?:[1-9]\d\d\d|\d[1-9]\d\d|\d\d[1-9]\d|\d\d\d[1-9])$|^((1[012]|0?[1-9]){1}\/(0?[1-9]|[12][0-9]|3[01]){1}\/\d{2,4}\s+(1[012]|0?[1-9]){1}:(0?[1-5]|[0-6][0-9]){1}:(0?[0-6]|[0-6][0-9]){1}\s+(am|pm|AM|PM){1})$/); 1444 return dateTimeRegEx.test(value); 1445 }, 1446 //Checks if the start date is before the end date 1447 //returns true if end is later than start 1448 _dateCompare: function (start, end) { 1449 return (new Date(start.toString()) < new Date(end.toString())); 1450 }, 1451 /** 1452 * Checks date range 1453 * 1454 * @param {jqObject} first field name 1455 * @param {jqObject} second field name 1456 * @return an error string if validation failed 1457 */ 1458 _dateRange: function (field, rules, i, options) { 1459 //are not both populated 1460 if ((!options.firstOfGroup[0].value && options.secondOfGroup[0].value) || (options.firstOfGroup[0].value && !options.secondOfGroup[0].value)) { 1461 return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2; 1462 } 1463 1464 //are not both dates 1465 if (!methods._isDate(options.firstOfGroup[0].value) || !methods._isDate(options.secondOfGroup[0].value)) { 1466 return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2; 1467 } 1468 1469 //are both dates but range is off 1470 if (!methods._dateCompare(options.firstOfGroup[0].value, options.secondOfGroup[0].value)) { 1471 return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2; 1472 } 1473 }, 1474 /** 1475 * Checks date time range 1476 * 1477 * @param {jqObject} first field name 1478 * @param {jqObject} second field name 1479 * @return an error string if validation failed 1480 */ 1481 _dateTimeRange: function (field, rules, i, options) { 1482 //are not both populated 1483 if ((!options.firstOfGroup[0].value && options.secondOfGroup[0].value) || (options.firstOfGroup[0].value && !options.secondOfGroup[0].value)) { 1484 return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2; 1485 } 1486 //are not both dates 1487 if (!methods._isDateTime(options.firstOfGroup[0].value) || !methods._isDateTime(options.secondOfGroup[0].value)) { 1488 return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2; 1489 } 1490 //are both dates but range is off 1491 if (!methods._dateCompare(options.firstOfGroup[0].value, options.secondOfGroup[0].value)) { 1492 return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2; 1493 } 1494 }, 1495 /** 1496 * Max number of checkbox selected 1497 * 1498 * @param {jqObject} field 1499 * @param {Array[String]} rules 1500 * @param {int} i rules index 1501 * @param {Map} 1502 * user options 1503 * @return an error string if validation failed 1504 */ 1505 _maxCheckbox: function(form, field, rules, i, options) { 1506 1507 var nbCheck = rules[i + 1]; 1508 var groupname = field.attr("name"); 1509 var groupSize = form.find("input[name='" + groupname + "']:checked").size(); 1510 if (groupSize > nbCheck) { 1511 options.showArrow = false; 1512 if (options.allrules.maxCheckbox.alertText2) 1513 return options.allrules.maxCheckbox.alertText + " " + nbCheck + " " + options.allrules.maxCheckbox.alertText2; 1514 return options.allrules.maxCheckbox.alertText; 1515 } 1516 }, 1517 /** 1518 * Min number of checkbox selected 1519 * 1520 * @param {jqObject} field 1521 * @param {Array[String]} rules 1522 * @param {int} i rules index 1523 * @param {Map} 1524 * user options 1525 * @return an error string if validation failed 1526 */ 1527 _minCheckbox: function(form, field, rules, i, options) { 1528 1529 var nbCheck = rules[i + 1]; 1530 var groupname = field.attr("name"); 1531 var groupSize = form.find("input[name='" + groupname + "']:checked").size(); 1532 if (groupSize < nbCheck) { 1533 options.showArrow = false;
1534 return options.allrules.minCheckbox.alertText + " " + nbCheck + " " + options.allrules.minCheckbox.alertText2; 1535 } 1536 }, 1537 /** 1538 * Checks that it is a valid credit card number according to the 1539 * Luhn checksum algorithm. 1540 * 1541 * @param {jqObject} field 1542 * @param {Array[String]} rules 1543 * @param {int} i rules index 1544 * @param {Map} 1545 * user options 1546 * @return an error string if validation failed 1547 */ 1548 _creditCard: function(field, rules, i, options) { 1549 //spaces and dashes may be valid characters, but must be stripped to calculate the checksum. 1550 var valid = false, cardNumber = field.val().replace(/ +/g, '').replace(/-+/g, ''); 1551 1552 var numDigits = cardNumber.length; 1553 if (numDigits >= 14 && numDigits <= 16 && parseInt(cardNumber) > 0) { 1554 1555 var sum = 0, i = numDigits - 1, pos = 1, digit, luhn = new String(); 1556 do { 1557 digit = parseInt(cardNumber.charAt(i)); 1558 luhn += (pos++ % 2 == 0) ? digit * 2 : digit; 1559 } while (--i >= 0) 1560 1561 for (i = 0; i < luhn.length; i++) { 1562 sum += parseInt(luhn.charAt(i)); 1563 } 1564 valid = sum % 10 == 0; 1565 } 1566 if (!valid) return options.allrules.creditCard.alertText; 1567 }, 1568 /** 1569 * Ajax field validation 1570 * 1571 * @param {jqObject} field 1572 * @param {Array[String]} rules 1573 * @param {int} i rules index 1574 * @param {Map} 1575 * user options 1576 * @return nothing! the ajax validator handles the prompts itself 1577 */ 1578 _ajax: function(field, rules, i, options) { 1579 1580 var errorSelector = rules[i + 1]; 1581 var rule = options.allrules[errorSelector]; 1582 var extraData = rule.extraData; 1583 var extraDataDynamic = rule.extraDataDynamic; 1584 var data = { 1585 "fieldId" : field.attr("id"), 1586 "fieldValue" : field.val() 1587 }; 1588 1589 if (typeof extraData === "object") { 1590 $.extend(data, extraData); 1591 } else if (typeof extraData === "string") { 1592 var tempData = extraData.split("&"); 1593 for(var i = 0; i < tempData.length; i++) { 1594 var values = tempData[i].split("="); 1595 if (values[0] && values[0]) { 1596 data[values[0]] = values[1]; 1597 } 1598 } 1599 } 1600 1601 if (extraDataDynamic) { 1602 var tmpData = []; 1603 var domIds = String(extraDataDynamic).split(","); 1604 for (var i = 0; i < domIds.length; i++) { 1605 var id = domIds[i]; 1606 if ($(id).length) { 1607 var inputValue = field.closest("form, .validationEngineContainer").find(id).val(); 1608 var keyValue = id.replace('#', '') + '=' + escape(inputValue); 1609 data[id.replace('#', '')] = inputValue; 1610 } 1611 } 1612 } 1613 1614 // If a field change event triggered this we want to clear the cache for this ID 1615 if (options.eventTrigger == "field") { 1616 delete(options.ajaxValidCache[field.attr("id")]); 1617 } 1618 1619 // If there is an error or if the the field is already validated, do not re-execute AJAX 1620 if (!options.isError && !methods._checkAjaxFieldStatus(field.attr("id"), options)) { 1621 $.ajax({ 1622 type: options.ajaxFormValidationMethod, 1623 url: rule.url, 1624 cache: false, 1625 dataType: "json", 1626 data: data, 1627 field: field, 1628 rule: rule, 1629 methods: methods, 1630 options: options, 1631 beforeSend: function() {}, 1632 error: function(data, transport) { 1633 if (options.onFailure) { 1634 options.onFailure(data, transport); 1635 } else { 1636 methods._ajaxError(data, transport); 1637 } 1638 }, 1639 success: function(json) { 1640 1641 // asynchronously called on success, data is the json answer from the server 1642 var errorFieldId = json[0]; 1643 //var errorField = $($("#" + errorFieldId)[0]); 1644 var errorField = $("#"+ errorFieldId).eq(0); 1645 1646 // make sure we found the element 1647 if (errorField.length == 1) { 1648 var status = json[1]; 1649 // read the optional msg from the server 1650 var msg = json[2]; 1651 if (!status) { 1652 // Houston we got a problem - display an red prompt 1653 options.ajaxValidCache[errorFieldId] = false; 1654 options.isError = true; 1655 1656 // resolve the msg prompt 1657 if(msg) { 1658 if (options.allrules[msg]) { 1659 var txt = options.allrules[msg].alertText; 1660 if (txt) { 1661 msg = txt; 1662 } 1663 } 1664 } 1665 else 1666 msg = rule.alertText; 1667 1668 if (options.showPrompts) methods._showPrompt(errorField, msg, "", true, options); 1669 } else { 1670 options.ajaxValidCache[errorFieldId] = true; 1671 1672 // resolves the msg prompt 1673 if(msg) { 1674 if (options.allrules[msg]) { 1675 var txt = options.allrules[msg].alertTextOk; 1676 if (txt) { 1677 msg = txt; 1678 } 1679 } 1680 } 1681 else 1682 msg = rule.alertTextOk; 1683 1684 if (options.showPrompts) { 1685 // see if we should display a green prompt 1686 if (msg) 1687 methods._showPrompt(errorField, msg, "pass", true, options); 1688 else 1689 methods._closePrompt(errorField); 1690 } 1691 1692 // If a submit form triggered this, we want to re-submit the form 1693 if (options.eventTrigger == "submit") 1694 field.closest("form").submit(); 1695 } 1696 } 1697 errorField.trigger("jqv.field.result", [errorField, options.isError, msg]); 1698 } 1699 }); 1700 1701 return rule.alertTextLoad; 1702 } 1703 }, 1704 /** 1705 * Common method to handle ajax errors 1706 * 1707 * @param {Object} data 1708 * @param {Object} transport 1709 */ 1710 _ajaxError: function(data, transport) { 1711 if(data.status == 0 && transport == null) 1712 alert("The page is not served from a server! ajax call failed"); 1713 else if(typeof console != "undefined") 1714 console.log("Ajax error: " + data.status + " " + transport); 1715 }, 1716 /** 1717 * date -> string 1718 * 1719 * @param {Object} date 1720 */ 1721 _dateToString: function(date) { 1722 return date.getFullYear()+"-"+(date.getMonth()+1)+"-"+date.getDate(); 1723 }, 1724 /** 1725 * Parses an ISO date 1726 * @param {String} d 1727 */ 1728 _parseDate: function(d) { 1729 1730 var dateParts = d.split("-"); 1731 if(dateParts==d) 1732 dateParts = d.split("/"); 1733 if(dateParts==d) { 1734 dateParts = d.split("."); 1735 return new Date(dateParts[2], (dateParts[1] - 1), dateParts[0]); 1736 } 1737 return new Date(dateParts[0], (dateParts[1] - 1) ,dateParts[2]); 1738 }, 1739 /** 1740 * Builds or updates a prompt with the given information 1741 * 1742 * @param {jqObject} field 1743 * @param {String} promptText html text to display type 1744 * @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red) 1745 * @param {boolean} ajaxed - use to mark fields than being validated with ajax 1746 * @param {Map} options user options 1747 */ 1748 _showPrompt: function(field, promptText, type, ajaxed, options, ajaxform) { 1749 //Check if we need to adjust what element to show the prompt on 1750 if(field.data('jqv-prompt-at') instanceof jQuery ){ 1751 field = field.data('jqv-prompt-at'); 1752 } else if(field.data('jqv-prompt-at')) { 1753 field = $(field.data('jqv-prompt-at')); 1754 } 1755 1756 var prompt = methods._getPrompt(field); 1757 // The ajax submit errors are not see has an error in the form, 1758 // When the form errors are returned, the engine see 2 bubbles, but those are ebing closed by the engine at the same time 1759 // Because no error was found befor submitting 1760 if(ajaxform) prompt = false;
1761 // Check that there is indded text 1762 if($.trim(promptText)){ 1763 if (prompt) 1764 methods._updatePrompt(field, prompt, promptText, type, ajaxed, options); 1765 else 1766 methods._buildPrompt(field, promptText, type, ajaxed, options); 1767 } 1768 }, 1769 /** 1770 * Builds and shades a prompt for the given field. 1771 * 1772 * @param {jqObject} field 1773 * @param {String} promptText html text to display type 1774 * @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red) 1775 * @param {boolean} ajaxed - use to mark fields than being validated with ajax 1776 * @param {Map} options user options 1777 */ 1778 _buildPrompt: function(field, promptText, type, ajaxed, options) { 1779 1780 // create the prompt 1781 var prompt = $('<div>'); 1782 prompt.addClass(methods._getClassName(field.attr("id")) + "formError"); 1783 // add a class name to identify the parent form of the prompt 1784 prompt.addClass("parentForm"+methods._getClassName(field.closest('form, .validationEngineContainer').attr("id"))); 1785 prompt.addClass("formError"); 1786 1787 switch (type) { 1788 case "pass": 1789 prompt.addClass("greenPopup"); 1790 break; 1791 case "load": 1792 prompt.addClass("blackPopup"); 1793 break; 1794 default: 1795 /* it has error */ 1796 //alert("unknown popup type:"+type); 1797 }
1798 if (ajaxed) 1799 prompt.addClass("ajaxed"); 1800 1801 // create the prompt content 1802 var promptContent = $('<div>').addClass("formErrorContent").html(promptText).appendTo(prompt); 1803 1804 // determine position type 1805 var positionType=field.data("promptPosition") || options.promptPosition; 1806 1807 // create the css arrow pointing at the field 1808 // note that there is no triangle on max-checkbox and radio 1809 if (options.showArrow) { 1810 var arrow = $('<div>').addClass("formErrorArrow"); 1811 1812 //prompt positioning adjustment support. Usage: positionType:Xshift,Yshift (for ex.: bottomLeft:+20 or bottomLeft:-20,+10) 1813 if (typeof(positionType)=='string') 1814 { 1815 var pos=positionType.indexOf(":"); 1816 if(pos!=-1) 1817 positionType=positionType.substring(0,pos); 1818 } 1819 1820 switch (positionType) { 1821 case "bottomLeft": 1822 case "bottomRight": 1823 prompt.find(".formErrorContent").before(arrow); 1824 arrow.addClass("formErrorArrowBottom").html('<div class="line1"><!-- --></div><div class="line2"><!-- --></div><div class="line3"><!-- --></div><div class="line4"><!-- --></div><div class="line5"><!-- --></div><div class="line6"><!-- --></div><div class="line7"><!-- --></div><div class="line8"><!-- --></div><div class="line9"><!-- --></div><div class="line10"><!-- --></div>'); 1825 break; 1826 case "topLeft": 1827 case "topRight": 1828 arrow.html('<div class="line10"><!-- --></div><div class="line9"><!-- --></div><div class="line8"><!-- --></div><div class="line7"><!-- --></div><div class="line6"><!-- --></div><div class="line5"><!-- --></div><div class="line4"><!-- --></div><div class="line3"><!-- --></div><div class="line2"><!-- --></div><div class="line1"><!-- --></div>'); 1829 prompt.append(arrow); 1830 break; 1831 } 1832 } 1833 // Add custom prompt class 1834 if (options.addPromptClass) 1835 prompt.addClass(options.addPromptClass); 1836 1837 // Add custom prompt class defined in element 1838 var requiredOverride = field.attr('data-required-class'); 1839 if(requiredOverride !== undefined) { 1840 prompt.addClass(requiredOverride); 1841 } else { 1842 if(options.prettySelect) { 1843 if($('#' + field.attr('id')).next().is('select')) { 1844 var prettyOverrideClass = $('#' + field.attr('id').substr(options.usePrefix.length).substring(options.useSuffix.length)).attr('data-required-class'); 1845 if(prettyOverrideClass !== undefined) { 1846 prompt.addClass(prettyOverrideClass); 1847 } 1848 } 1849 } 1850 } 1851 1852 prompt.css({ 1853 "opacity": 0 1854 }); 1855 if(positionType === 'inline') { 1856 prompt.addClass("inline"); 1857 if(typeof field.attr('data-prompt-target') !== 'undefined' && $('#'+field.attr('data-prompt-target')).length > 0) { 1858 prompt.appendTo($('#'+field.attr('data-prompt-target'))); 1859 } else { 1860 field.after(prompt); 1861 } 1862 } else { 1863 field.before(prompt); 1864 } 1865 1866 var pos = methods._calculatePosition(field, prompt, options); 1867 // Support RTL layouts by @yasser_lotfy ( Yasser Lotfy ) 1868 if ($('body').hasClass('rtl')) { 1869 prompt.css({ 1870 'position': positionType === 'inline' ? 'relative' : 'absolute', 1871 "top": pos.callerTopPosition, 1872 "left": "initial", 1873 "right": pos.callerleftPosition, 1874 "marginTop": pos.marginTopSize, 1875 "opacity": 0 1876 }).data("callerField", field); 1877 } else { 1878 prompt.css({ 1879 'position': positionType === 'inline' ? 'relative' : 'absolute', 1880 "top": pos.callerTopPosition, 1881 "left": pos.callerleftPosition, 1882 "right": "initial", 1883 "marginTop": pos.marginTopSize, 1884 "opacity": 0 1885 }).data("callerField", field); 1886 } 1887 1888 1889 if (options.autoHidePrompt) { 1890 setTimeout(function(){ 1891 prompt.animate({ 1892 "opacity": 0 1893 },function(){ 1894 prompt.closest('.formError').remove(); 1895 }); 1896 }, options.autoHideDelay); 1897 } 1898 return prompt.animate({ 1899 "opacity": 0.87 1900 }); 1901 }, 1902 /** 1903 * Updates the prompt text field - the field for which the prompt 1904 * @param {jqObject} field 1905 * @param {String} promptText html text to display type 1906 * @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red) 1907 * @param {boolean} ajaxed - use to mark fields than being validated with ajax 1908 * @param {Map} options user options 1909 */ 1910 _updatePrompt: function(field, prompt, promptText, type, ajaxed, options, noAnimation) { 1911 1912 if (prompt) { 1913 if (typeof type !== "undefined") { 1914 if (type == "pass") 1915 prompt.addClass("greenPopup"); 1916 else 1917 prompt.removeClass("greenPopup"); 1918 1919 if (type == "load") 1920 prompt.addClass("blackPopup"); 1921 else 1922 prompt.removeClass("blackPopup"); 1923 } 1924 if (ajaxed) 1925 prompt.addClass("ajaxed"); 1926 else 1927 prompt.removeClass("ajaxed"); 1928 1929 prompt.find(".formErrorContent").html(promptText); 1930 1931 var pos = methods._calculatePosition(field, prompt, options);
1932 // Support RTL layouts by @yasser_lotfy ( Yasser Lotfy ) 1933 if ($('body').hasClass('rtl')) { 1934 var css = {"top": pos.callerTopPosition, 1935 "left": "initial", 1936 "right": pos.callerleftPosition, 1937 "marginTop": pos.marginTopSize, 1938 "opacity": 0.87}; 1939 } else { 1940 var css = {"top": pos.callerTopPosition, 1941 "left": pos.callerleftPosition, 1942 "right": "initial", 1943 "marginTop": pos.marginTopSize, 1944 "opacity": 0.87}; 1945 } 1946 1947 prompt.css({ 1948 "opacity": 0, 1949 "display": "block" 1950 }); 1951 1952 if (noAnimation) 1953 prompt.css(css); 1954 else 1955 prompt.animate(css); 1956 } 1957 }, 1958 /** 1959 * Closes the prompt associated with the given field 1960 * 1961 * @param {jqObject} 1962 * field 1963 */ 1964 _closePrompt: function(field) { 1965 var prompt = methods._getPrompt(field); 1966 if (prompt) 1967 prompt.fadeTo("fast", 0, function() { 1968 prompt.closest('.formError').remove(); 1969 }); 1970 }, 1971 closePrompt: function(field) { 1972 return methods._closePrompt(field); 1973 }, 1974 /** 1975 * Returns the error prompt matching the field if any 1976 * 1977 * @param {jqObject} 1978 * field 1979 * @return undefined or the error prompt (jqObject) 1980 */ 1981 _getPrompt: function(field) { 1982 var formId = $(field).closest('form, .validationEngineContainer').attr('id'); 1983 var className = methods._getClassName(field.attr("id")) + "formError"; 1984 var match = $("." + methods._escapeExpression(className) + '.parentForm' + methods._getClassName(formId))[0]; 1985 if (match) 1986 return $(match); 1987 }, 1988 /** 1989 * Returns the escapade classname 1990 * 1991 * @param {selector} 1992 * className 1993 */ 1994 _escapeExpression: function (selector) { 1995 return selector.replace(/([#;&,\.\+\*\~':"\!\^$\[\]\(\)=>\|])/g, "\\$1"); 1996 }, 1997 /** 1998 * returns true if we are in a RTLed document 1999 * 2000 * @param {jqObject} field 2001 */ 2002 isRTL: function(field) 2003 { 2004 var $document = $(document); 2005 var $body = $('body'); 2006 var rtl = 2007 (field && field.hasClass('rtl')) || 2008 (field && (field.attr('dir') || '').toLowerCase()==='rtl') || 2009 $document.hasClass('rtl') || 2010 ($document.attr('dir') || '').toLowerCase()==='rtl' || 2011 $body.hasClass('rtl') || 2012 ($body.attr('dir') || '').toLowerCase()==='rtl'; 2013 return Boolean(rtl); 2014 }, 2015 /** 2016 * Calculates prompt position 2017 * 2018 * @param {jqObject} 2019 * field 2020 * @param {jqObject} 2021 * the prompt 2022 * @param {Map} 2023 * options 2024 * @return positions 2025 */ 2026 _calculatePosition: function (field, promptElmt, options) { 2027 2028 var promptTopPosition, promptleftPosition, marginTopSize; 2029 var fieldWidth = field.width(); 2030 var fieldLeft = field.position().left; 2031 var fieldTop = field.position().top; 2032 var fieldHeight = field.height(); 2033 var promptHeight = promptElmt.height(); 2034 2035 2036 // is the form contained in an overflown container? 2037 promptTopPosition = promptleftPosition = 0; 2038 // compensation for the arrow 2039 marginTopSize = -promptHeight; 2040 2041 2042 //prompt positioning adjustment support 2043 //now you can adjust prompt position 2044 //usage: positionType:Xshift,Yshift 2045 //for example: 2046 // bottomLeft:+20 means bottomLeft position shifted by 20 pixels right horizontally 2047 // topRight:20, -15 means topRight position shifted by 20 pixels to right and 15 pixels to top 2048 //You can use +pixels, - pixels. If no sign is provided than + is default. 2049 var positionType=field.data("promptPosition") || options.promptPosition; 2050 var shift1=""; 2051 var shift2=""; 2052 var shiftX=0; 2053 var shiftY=0; 2054 if (typeof(positionType)=='string') { 2055 //do we have any position adjustments ? 2056 if (positionType.indexOf(":")!=-1) { 2057 shift1=positionType.substring(positionType.indexOf(":")+1); 2058 positionType=positionType.substring(0,positionType.indexOf(":")); 2059 2060 //if any advanced positioning will be needed (percents or something else) - parser should be added here 2061 //for now we use simple parseInt() 2062 2063 //do we have second parameter? 2064 if (shift1.indexOf(",") !=-1) { 2065 shift2=shift1.substring(shift1.indexOf(",") +1); 2066 shift1=shift1.substring(0,shift1.indexOf(",")); 2067 shiftY=parseInt(shift2); 2068 if (isNaN(shiftY)) shiftY=0; 2069 }; 2070 2071 shiftX=parseInt(shift1); 2072 if (isNaN(shift1)) shift1=0; 2073 2074 }; 2075 }; 2076 2077 2078 switch (positionType) { 2079 default: 2080 case "topRight": 2081 promptleftPosition += fieldLeft + fieldWidth - 27; 2082 promptTopPosition += fieldTop; 2083 break; 2084
2085 case "topLeft": 2086 promptTopPosition += fieldTop; 2087 promptleftPosition += fieldLeft; 2088 break; 2089 2090 case "centerRight": 2091 promptTopPosition = fieldTop+4; 2092 marginTopSize = 0; 2093 promptleftPosition= fieldLeft + field.outerWidth(true)+5; 2094 break; 2095 case "centerLeft": 2096 promptleftPosition = fieldLeft - (promptElmt.width() + 2); 2097 promptTopPosition = fieldTop+4; 2098 marginTopSize = 0; 2099 2100 break; 2101 2102 case "bottomLeft": 2103 promptTopPosition = fieldTop + field.height() + 5; 2104 marginTopSize = 0; 2105 promptleftPosition = fieldLeft; 2106 break; 2107 case "bottomRight": 2108 promptleftPosition = fieldLeft + fieldWidth - 27; 2109 promptTopPosition = fieldTop + field.height() + 5; 2110 marginTopSize = 0; 2111 break; 2112 case "inline": 2113 promptleftPosition = 0; 2114 promptTopPosition = 0; 2115 marginTopSize = 0; 2116 }; 2117 2118 2119 2120 //apply adjusments if any 2121 promptleftPosition += shiftX; 2122 promptTopPosition += shiftY; 2123 2124 return { 2125 "callerTopPosition": promptTopPosition + "px", 2126 "callerleftPosition": promptleftPosition + "px", 2127 "marginTopSize": marginTopSize + "px" 2128 }; 2129 }, 2130 /** 2131 * Saves the user options and variables in the form.data 2132 * 2133 * @param {jqObject} 2134 * form - the form where the user option should be saved 2135 * @param {Map} 2136 * options - the user options 2137 * @return the user options (extended from the defaults) 2138 */ 2139 _saveOptions: function(form, options) { 2140 2141 // is there a language localisation ? 2142 if ($.validationEngineLanguage) 2143 var allRules = $.validationEngineLanguage.allRules; 2144 else 2145 $.error("jQuery.validationEngine rules are not loaded, plz add localization files to the page"); 2146 // --- Internals DO NOT TOUCH or OVERLOAD --- 2147 // validation rules and i18 2148 $.validationEngine.defaults.allrules = allRules; 2149 2150 var userOptions = $.extend(true,{},$.validationEngine.defaults,options); 2151 2152 form.data('jqv', userOptions); 2153 return userOptions; 2154 }, 2155 2156 /** 2157 * Removes forbidden characters from class name 2158 * @param {String} className 2159 */ 2160 _getClassName: function(className) { 2161 if(className) 2162 return className.replace(/:/g, "_").replace(/\./g, "_"); 2163 }, 2164 /** 2165 * Escape special character for jQuery selector 2166 * http://totaldev.com/content/escaping-characters-get-valid-jquery-id 2167 * @param {String} selector 2168 */ 2169 _jqSelector: function(str){ 2170 return str.replace(/([;&,\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g, '\\$1'); 2171 }, 2172 /** 2173 * Conditionally required field 2174 * 2175 * @param {jqObject} field 2176 * @param {Array[String]} rules 2177 * @param {int} i rules index 2178 * @param {Map} 2179 * user options 2180 * @return an error string if validation failed 2181 */ 2182 _condRequired: function(field, rules, i, options) { 2183 var idx, dependingField; 2184 2185 for(idx = (i + 1); idx < rules.length; idx++) { 2186 dependingField = jQuery("#" + rules[idx]).first(); 2187 2188 /* Use _required for determining wether dependingField has a value. 2189 * There is logic there for handling all field types, and default value; so we won't replicate that here 2190 * Indicate this special use by setting the last parameter to true so we only validate the dependingField on chackboxes and radio buttons (#462) 2191 */ 2192 if (dependingField.length && methods._required(dependingField, ["required"], 0, options, true) == undefined) { 2193 /* We now know any of the depending fields has a value, 2194 * so we can validate this field as per normal required code 2195 */ 2196 return methods._required(field, ["required"], 0, options); 2197 } 2198 } 2199 }, 2200 2201 _submitButtonClick: function(event) { 2202 var button = $(this); 2203 var form = button.closest('form, .validationEngineContainer'); 2204 form.data("jqv_submitButton", button.attr("id")); 2205 } 2206 }; 2207 2208 /** 2209 * Plugin entry point. 2210 * You may pass an action as a parameter or a list of options. 2211 * if none, the init and attach methods are being called. 2212 * Remember: if you pass options, the attached method is NOT called automatically 2213 * 2214 * @param {String} 2215 * method (optional) action 2216 */ 2217 $.fn.validationEngine = function(method) { 2218 2219 var form = $(this); 2220 if(!form[0]) return form; // stop here if the form does not exist 2221 2222 if (typeof(method) == 'string' && method.charAt(0) != '_' && methods[method]) { 2223 2224 // make sure init is called once 2225 if(method != "showPrompt" && method != "hide" && method != "hideAll") 2226 methods.init.apply(form); 2227 2228 return methods[method].apply(form, Array.prototype.slice.call(arguments, 1)); 2229 } else if (typeof method == 'object' || !method) { 2230 2231 // default constructor with or without arguments 2232 methods.init.apply(form, arguments); 2233 return methods.attach.apply(form); 2234 } else { 2235 $.error('Method ' + method + ' does not exist in jQuery.validationEngine'); 2236 } 2237 }; 2238 2239 2240 2241 // LEAK GLOBAL OPTIONS 2242 $.validationEngine= {fieldIdCounter: 0,defaults:{ 2243 2244 // Name of the event triggering field validation 2245 validationEventTrigger: "blur", 2246 // Automatically scroll viewport to the first error 2247 scroll: true, 2248 // Focus on the first input 2249 focusFirstField:true, 2250 // Show prompts, set to false to disable prompts 2251 showPrompts: true, 2252 // Should we attempt to validate non-visible input fields contained in the form? (Useful in cases of tabbed containers, e.g. jQuery-UI tabs) 2253 validateNonVisibleFields: false, 2254 // ignore the validation for fields with this specific class (Useful in cases of tabbed containers AND hidden fields we don't want to validate) 2255 ignoreFieldsWithClass: 'ignoreMe', 2256 // Opening box position, possible locations are: topLeft, 2257 // topRight, bottomLeft, centerRight, bottomRight, inline 2258 // inline gets inserted after the validated field or into an element specified in data-prompt-target 2259 promptPosition: "topRight", 2260 bindMethod:"bind", 2261 // internal, automatically set to true when it parse a _ajax rule
2262 inlineAjax: false, 2263 // if set to true, the form data is sent asynchronously via ajax to the form.action url (get) 2264 ajaxFormValidation: false, 2265 // The url to send the submit ajax validation (default to action) 2266 ajaxFormValidationURL: false, 2267 // HTTP method used for ajax validation 2268 ajaxFormValidationMethod: 'get', 2269 // Ajax form validation callback method: boolean onComplete(form, status, errors, options) 2270 // retuns false if the form.submit event needs to be canceled. 2271 onAjaxFormComplete: $.noop, 2272 // called right before the ajax call, may return false to cancel 2273 onBeforeAjaxFormValidation: $.noop, 2274 // Stops form from submitting and execute function assiciated with it 2275 onValidationComplete: false, 2276 2277 // Used when you have a form fields too close and the errors messages are on top of other disturbing viewing messages 2278 doNotShowAllErrosOnSubmit: false, 2279 // Object where you store custom messages to override the default error messages 2280 custom_error_messages:{}, 2281 // true if you want to validate the input fields on blur event 2282 binded: true, 2283 // set to true if you want to validate the input fields on blur only if the field it's not empty 2284 notEmpty: false, 2285 // set to true, when the prompt arrow needs to be displayed 2286 showArrow: true, 2287 // set to false, determines if the prompt arrow should be displayed when validating 2288 // checkboxes and radio buttons 2289 showArrowOnRadioAndCheckbox: false, 2290 // did one of the validation fail ? kept global to stop further ajax validations 2291 isError: false, 2292 // Limit how many displayed errors a field can have 2293 maxErrorsPerField: false, 2294 2295 // Caches field validation status, typically only bad status are created. 2296 // the array is used during ajax form validation to detect issues early and prevent an expensive submit 2297 ajaxValidCache: {}, 2298 // Auto update prompt position after window resize 2299 autoPositionUpdate: false, 2300 2301 InvalidFields: [], 2302 onFieldSuccess: false, 2303 onFieldFailure: false, 2304 onSuccess: false, 2305 onFailure: false, 2306 validateAttribute: "class", 2307 addSuccessCssClassToField: "", 2308 addFailureCssClassToField: "", 2309 2310 // Auto-hide prompt 2311 autoHidePrompt: false, 2312 // Delay before auto-hide 2313 autoHideDelay: 10000, 2314 // Fade out duration while hiding the validations 2315 fadeDuration: 300, 2316 // Use Prettify select library 2317 prettySelect: false, 2318 // Add css class on prompt 2319 addPromptClass : "", 2320 // Custom ID uses prefix 2321 usePrefix: "", 2322 // Custom ID uses suffix 2323 useSuffix: "", 2324 // Only show one message per error prompt 2325 showOneMessage: false 2326 }}; 2327 $(function(){$.validationEngine.defaults.promptPosition = methods.isRTL()?'topLeft':"topRight"}); 2328})(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.