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