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