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