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