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