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