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