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