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