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