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