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