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