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