1/* 2 * Inline Form Validation Engine 2.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 var methods = { 16 17 /** 18 * Kind of the constructor, called before any action 19 * @param {Map} user options 20 */ 21 init: function(options) { 22 var form = this; 23 if (!form.data('jqv') || form.data('jqv') == null ) { 24 methods._saveOptions(form, options); 25 26 // bind all formError elements to close on click 27 $(".formError").live("click", function() { 28 $(this).fadeOut(150, function() { 29 30 // remove prompt once invisible 31 $(this).remove(); 32 }); 33 }); 34 } 35 }, 36 /** 37 * Attachs jQuery.validationEngine to form.submit and field.blur events 38 * Takes an optional params: a list of options 39 * ie. jQuery("#formID1").validationEngine('attach', {promptPosition : "centerRight"}); 40 */ 41 attach: function(userOptions) { 42 var form = this; 43 var options; 44 45 if(userOptions) 46 options = methods._saveOptions(form, userOptions); 47 else 48 options = form.data('jqv'); 49 50 if (!options.binded) { 51 if (options.bindMethod == "bind"){ 52 // bind fields 53 form.find("[class*=validate]:not([type=checkbox])").bind(options.validationEventTrigger, methods._onFieldEvent); 54 form.find("[class*=validate][type=checkbox]").bind("click", methods._onFieldEvent); 55 56 // bind form.submit 57 form.bind("submit", methods._onSubmitEvent); 58 } else if (options.bindMethod == "live") { 59 // bind fields with LIVE (for persistant state) 60 form.find("[class*=validate]:not([type=checkbox])").live(options.validationEventTrigger, methods._onFieldEvent); 61 form.find("[class*=validate][type=checkbox]").live("click", methods._onFieldEvent); 62 63 // bind form.submit 64 form.live("submit", methods._onSubmitEvent); 65 } 66 67 options.binded = true; 68 } 69 70 }, 71 /** 72 * Unregisters any bindings that may point to jQuery.validaitonEngine 73 */ 74 detach: function() { 75 var form = this; 76 var options = form.data('jqv'); 77 if (options.binded) { 78 79 // unbind fields 80 form.find("[class*=validate]").not("[type=checkbox]").unbind(options.validationEventTrigger, methods._onFieldEvent); 81 form.find("[class*=validate][type=checkbox]").unbind("click", methods._onFieldEvent); 82 // unbind form.submit 83 form.unbind("submit", methods.onAjaxFormComplete); 84 85 86 // unbind live fields (kill) 87 form.find("[class*=validate]").not("[type=checkbox]").die(options.validationEventTrigger, methods._onFieldEvent); 88 form.find("[class*=validate][type=checkbox]").die("click", methods._onFieldEvent); 89 // unbind form.submit 90 form.die("submit", methods.onAjaxFormComplete); 91 92 form.removeData('jqv'); 93 } 94 }, 95 /** 96 * Validates the form fields, shows prompts accordingly. 97 * Note: There is no ajax form validation with this method, only field ajax validation are evaluated 98 * 99 * @return true if the form validates, false if it fails 100 */ 101 validate: function() { 102 return methods._validateFields(this); 103 }, 104 /** 105 * Validates one field, shows prompt accordingly. 106 * Note: There is no ajax form validation with this method, only field ajax validation are evaluated 107 * 108 * @return true if the form validates, false if it fails 109 */ 110 validateField: function(el) { 111 var options = $(this).data('jqv'); 112 return methods._validateField($(el), options); 113 }, 114 /** 115 * Validates the form fields, shows prompts accordingly. 116 * Note: this methods performs fields and form ajax validations(if setup) 117 * 118 * @return true if the form validates, false if it fails, undefined if ajax is used for form validation 119 */ 120 validateform: function() { 121 return methods._onSubmitEvent.call(this); 122 }, 123 /**
124 * Displays a prompt on a element. 125 * Note that the element needs an id! 126 * 127 * @param {String} promptText html text to display type 128 * @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red) 129 * @param {String} possible values topLeft, topRight, bottomLeft, centerRight, bottomRight 130 */ 131 showPrompt: function(promptText, type, promptPosition, showArrow) { 132 133 var form = this.closest('form'); 134 var options = form.data('jqv'); 135 // No option, take default one 136 if(!options) options = methods._saveOptions(this, options); 137 if(promptPosition) 138 options.promptPosition=promptPosition; 139 options.showArrow = showArrow==true; 140 141 methods._showPrompt(this, promptText, type, false, options); 142 }, 143 /** 144 * Closes all error prompts on the page 145 */ 146 hidePrompt: function() { 147 var promptClass = "."+ methods._getClassName($(this).attr("id")) + "formError" 148 $(promptClass).fadeTo("fast", 0.3, function() { 149 $(this).remove(); 150 }); 151 }, 152 /** 153 * Closes form error prompts, CAN be invidual 154 */ 155 hide: function() { 156 if($(this).is("form")){ 157 var closingtag = "parentForm"+$(this).attr('id'); 158 }else{ 159 160 var closingtag = $(this).attr('id') +"formError" 161 } 162 $('.'+closingtag).fadeTo("fast", 0.3, function() { 163 $(this).remove(); 164 }); 165 }, 166 /** 167 * Closes all error prompts on the page 168 */ 169 hideAll: function() { 170 $('.formError').fadeTo("fast", 0.3, function() { 171 $(this).remove(); 172 }); 173 }, 174 /** 175 * Typically called when user exists a field using tab or a mouse click, triggers a field 176 * validation 177 */ 178 _onFieldEvent: function() { 179 var field = $(this); 180 var form = field.closest('form'); 181 var options = form.data('jqv'); 182 // validate the current field 183 methods._validateField(field, options); 184 }, 185 /** 186 * Called when the form is submited, shows prompts accordingly 187 * 188 * @param {jqObject} 189 * form 190 * @return false if form submission needs to be cancelled 191 */ 192 _onSubmitEvent: function() { 193 var form = $(this); 194 var options = form.data('jqv'); 195 196 // validate each field (- skip field ajax validation, no necessary since we will perform an ajax form validation) 197 var r=methods._validateFields(form, true); 198 199 if (r && options.ajaxFormValidation) { 200 methods._validateFormWithAjax(form, options); 201 return false; 202 } 203 204 if(options.onValidationComplete) { 205 options.onValidationComplete(form, r); 206 return false; 207 } 208 return r; 209 }, 210 211 /** 212 * Return true if the ajax field validations passed so far 213 * @param {Object} options 214 * @return true, is all ajax validation passed so far (remember aja
214x is async) 215 */ 216 _checkAjaxStatus: function(options) { 217 var status = true; 218 $.each(options.ajaxValidCache, function(key, value) { 219 if (!value) { 220 status = false; 221 // break the each 222 return false; 223 } 224 }); 225 return status; 226 }, 227 /** 228 * Validates form fields, shows prompts accordingly 229 * 230 * @param {jqObject} 231 * form 232 * @param {skipAjaxFieldValidation} 233 * boolean - when set to true, ajax field validation is skipped, typically used when the submit button is clicked 234 * 235 * @return true if form is valid, false if not, undefined if ajax form validation is done 236 */ 237 _validateFields: function(form, skipAjaxValidation) { 238 var options = form.data('jqv'); 239 240 // this variable is set to true if an error is found 241 var errorFound = false; 242 243 // Trigger hook, start validation 244 form.trigger("jqv.form.validating") 245 // first, evaluate status of non ajax fields 246 form.find('[class*=validate]').not(':hidden').each( function() { 247 var field = $(this); 248 errorFound |= methods._validateField(field, options, skipAjaxValidation); 249 }); 250 // second, check to see if all ajax calls completed ok 251 // errorFound |= !methods._checkAjaxStatus(options); 252 253 // thrird, check status and scroll the container accordingly 254 form.trigger("jqv.form.result", [errorFound]) 255 256 if (errorFound) { 257 258 if (options.scroll) { 259 260 // get the position of the first error, there should be at least one, no need to check this 261 //var destination = form.find(".formError:not('.greenPopup'):first").offset().top; 262 263 // look for the visually top prompt 264 var destination = Number.MAX_VALUE; 265 266 var lst = $(".formError:not('.greenPopup')"); 267 for (var i = 0; i < lst.length; i++) { 268 var d = $(lst[i]).offset().top; 269 if (d < destination) 270 destination = d; 271 } 272 273 if (!options.isOverflown) 274 $("html:not(:animated),body:not(:animated)").animate({ 275 scrollTop: destination 276 }, 1100); 277 else { 278 var overflowDIV = $(options.overflownDIV); 279 var scrollContainerScroll = overflowDIV.scrollTop(); 280 var scrollContainerPos = -parseInt(overflowDIV.offset().top); 281 282 destination += scrollContainerScroll + scrollContainerPos - 5; 283 var scrollContainer = $(options.overflownDIV + ":not(:animated)"); 284 285 scrollContainer.animate({ 286 scrollTop: destination 287 }, 1100); 288 } 289 } 290 return false; 291 } 292 return true; 293 }, 294 /** 295 * This method is called to perform an ajax form validation. 296 * During this process all the (field, value) pairs are sent to the server which returns a list of invalid fields or true 297 * 298 * @param {jqObject} form 299 * @param {Map} options 300 */ 301 _validateFormWithAjax: function(form, options) { 302 303 var data = form.serialize(); 304 var url = (options.ajaxFormValidationURL) ? options.ajaxFormValidationURL : form.attr("action"); 305 $.ajax({
306 type: "GET", 307 url: url, 308 cache: false, 309 dataType: "json", 310 data: data, 311 form: form, 312 methods: methods, 313 options: options, 314 beforeSend: function() { 315 return options.onBeforeAjaxFormValidation(form, options); 316 }, 317 error: function(data, transport) { 318 methods._ajaxError(data, transport); 319 }, 320 success: function(json) { 321 322 if (json !== true) { 323 324 // getting to this case doesn't necessary means that the form is invalid 325 // the server may return green or closing prompt actions 326 // this flag helps figuring it out 327 var errorInForm=false; 328 for (var i = 0; i < json.length; i++) { 329 var value = json[i]; 330 331 var errorFieldId = value[0]; 332 var errorField = $($("#" + errorFieldId)[0]); 333 334 // make sure we found the element 335 if (errorField.length == 1) { 336 337 // promptText or selector 338 var msg = value[2]; 339 // if the field is valid 340 if (value[1] == true) { 341 342 if (msg == "" || !msg){ 343 // if for some reason, status==true and error="", just close the prompt 344 methods._closePrompt(errorField); 345 } else { 346 // the field is valid, but we are displaying a green prompt 347 if (options.allrules[msg]) { 348 var txt = options.allrules[msg].alertTextOk; 349 if (txt) 350 msg = txt; 351 } 352 methods._showPrompt(errorField, msg, "pass", false, options, true); 353 } 354 355 } else { 356 // the field is invalid, show the red error prompt 357 errorInForm|=true; 358 if (options.allrules[msg]) { 359 var txt = options.allrules[msg].alertText; 360 if (txt) 361 msg = txt; 362 } 363 methods._showPrompt(errorField, msg, "", false, options, true); 364 } 365 } 366 } 367 options.onAjaxFormComplete(!errorInForm, form, json, options); 368 } else 369 options.onAjaxFormComplete(true, form, "", options); 370 } 371 }); 372 373 }, 374 /** 375 * Validates field, shows prompts accordingly 376 * 377 * @param {jqObject} 378 * field 379 * @param {Array[String]} 380 * field's validation rules 381 * @param {Map} 382 * user options 383 * @return true if field is valid 384 */ 385 _validateField: function(field, options, skipAjaxValidation) { 386 if (!field.attr("id")) 387 $.error("jQueryValidate: an ID attribute is required for this field: " + field.attr("name") + " class:" + 388 field.attr("class")); 389 390 var rulesParsing = field.attr('class'); 391 var getRules = /validate\[(.*)\]/.exec(rulesParsing); 392 if (!getRules) 393 return false; 394 var str = getRules[1]; 395 var rules = str.split(/\[|,|\]/); 396
397 // true if we ran the ajax validation, tells the logic to stop messing with prompts 398 var isAjaxValidator = false; 399 var fieldName = field.attr("name"); 400 var promptText = ""; 401 var required = false; 402 options.isError = false; 403 options.showArrow = true; 404 optional = false; 405 406 for (var i = 0; i < rules.length; i++) { 407 408 var errorMsg = undefined; 409 switch (rules[i]) { 410 411 case "optional": 412 optional = true; 413 break; 414 case "required": 415 required = true; 416 errorMsg = methods._required(field, rules, i, options); 417 break; 418 case "custom": 419 errorMsg = methods._customRegex(field, rules, i, options); 420 break; 421 case "ajax": 422 // ajax has its own prompts handling technique 423 if(!skipAjaxValidation){ 424 methods._ajax(field, rules, i, options); 425 isAjaxValidator = true; 426 } 427 break; 428 case "minSize": 429 errorMsg = methods._minSize(field, rules, i, options); 430 break; 431 case "maxSize": 432 errorMsg = methods._maxSize(field, rules, i, options); 433 break; 434 case "min": 435 errorMsg = methods._min(field, rules, i, options); 436 break; 437 case "max": 438 errorMsg = methods._max(field, rules, i, options); 439 break; 440 case "past": 441 errorMsg = methods._past(field, rules, i, options); 442 break; 443 case "future": 444 errorMsg = methods._future(field, rules, i, options); 445 break; 446 case "maxCheckbox": 447 errorMsg = methods._maxCheckbox(field, rules, i, options); 448 field = $($("input[name='" + fieldName + "']")); 449 break; 450 case "minCheckbox": 451 errorMsg = methods._minCheckbox(field, rules, i, options); 452 field = $($("input[name='" + fieldName + "']")); 453 break; 454 case "equals": 455 errorMsg = methods._equals(field, rules, i, options); 456 break; 457 case "funcCall": 458 errorMsg = methods._funcCall(field, rules, i, options); 459 break; 460 461 default: 462 //$.error("jQueryValidator rule not found"+rules[i]); 463 } 464 if (errorMsg !== undefined) { 465 promptText += errorMsg + "<br/>"; 466 options.isError = true; 467 468 } 469 470 } 471 // If the rules required is not added, an empty field is not validated 472 if(!required){ 473 if(field.val() == "") options.isError = false; 474 } 475 // Hack for radio/checkbox group button, the validation go into the 476 // first radio/checkbox of the group 477 var fieldType = field.attr("type"); 478 479 if ((fieldType == "radio" || fieldType == "checkbox") && $("input[name='" + fieldName + "']").size() > 1) { 480 field = $($("input[name='" + fieldName + "'][type!=hidden]:first")); 481 options.showArrow = false; 482 } 483 484 if (options.isError){ 485 486 methods._showPrompt(field, promptText, "", false, options); 487 }else{ 488 if (!isAjaxValidator) methods._closePrompt(field); 489 } 490 field.closest('form').trigger("jqv.field.error", [field, options.isError, promptText]) 491 return options.isError; 492 }, 493 /** 494 * Required validation 495 * 496 * @param {jqObject} field 497 * @param {Array[String]} rules 498 * @param {int} i rules index 499 * @param {Map} 500 * user options 501 * @return an error string if validation failed 502 */ 503 _required: function(field, rules, i, options) { 504 switch (field.attr("type")) { 505 case "text": 506 case "password": 507 case "textarea": 508 case "file": 509 default: 510 if (!field.val()) 511 return options.allrules[rules[i]].alertText; 512 break; 513 case "radio": 514 case "checkbox": 515 var name = field.attr("name"); 516 if ($("input[name='" + name + "']:checked").size() == 0) { 517 518 if ($("input[name='" + name + "']").size() == 1) 519 return options.allrules[rules[i]].alertTextCheckboxe; 520 else 521 return options.allrules[rules[i]].alertTextCheckboxMultiple; 522 } 523 break; 524 // required for <select> 525 case "select-one": 526 // added by [email protected] for select boxes, Thank y
526ou 527 if (!field.val()) 528 return options.allrules[rules[i]].alertText; 529 break; 530 case "select-multiple": 531 // added by [email protected] for select boxes, Thank you 532 if (!field.find("option:selected").val()) 533 return options.allrules[rules[i]].alertText; 534 break; 535 } 536 }, 537 /** 538 * Validate Regex rules 539 * 540 * @param {jqObject} field 541 * @param {Array[String]} rules 542 * @param {int} i rules index 543 * @param {Map} 544 * user options 545 * @return an error string if validation failed 546 */ 547 _customRegex: function(field, rules, i, options) { 548 var customRule = rules[i + 1]; 549 var rule = options.allrules[customRule]; 550 if(!rule) { 551 alert("jqv:custom rule not found "+customRule); 552 return; 553 } 554 555 var ex=rule.regex; 556 if(!ex) { 557 alert("jqv:custom regex not found "+customRule); 558 return; 559 } 560 var pattern = new RegExp(ex); 561 562 if (!pattern.test(field.attr('value'))) 563 return options.allrules[customRule].alertText; 564 }, 565 /** 566 * Validate custom function outside of the engine scope 567 * 568 * @param {jqObject} field 569 * @param {Array[String]} rules 570 * @param {int} i rules index 571 * @param {Map} 572 * user options 573 * @return an error string if validation failed 574 */ 575 _funcCall: function(field, rules, i, options) { 576 var functionName = rules[i + 1]; 577 var fn = window[functionName]; 578 if (typeof(fn) == 'function') 579 return fn(field, rules, i, options); 580 581 }, 582 /** 583 * Field match 584 * 585 * @param {jqObject} field 586 * @param {Array[String]} rules 587 * @param {int} i rules index 588 * @param {Map} 589 * user options 590 * @return an error string if validation failed 591 */ 592 _equals: function(field, rules, i, options) { 593 var equalsField = rules[i + 1]; 594 595 if (field.attr('value') != $("#" + equalsField).attr('value')) 596 return options.allrules.equals.alertText; 597 }, 598 /** 599 * Check the maximum size (in characters) 600 * 601 * @param {jqObject} field 602 * @param {Array[String]} rules 603 * @param {int} i rules index 604 * @param {Map} 605 * user options 606 * @return an error string if validation failed 607 */ 608 _maxSize: function(field, rules, i, options) { 609 var max = rules[i + 1]; 610 var len = field.attr('value').length; 611 612 if (len > max) { 613 var rule = options.allrules.maxSize; 614 return rule.alertText + max + rule.alertText2; 615 } 616 }, 617 /** 618 * Check the minimum size (in characters) 619 * 620 * @param {jqObject} field 621 * @param {Array[String]} rules 622 * @param {int} i rules index 623 * @param {Map} 624 * user options 625 * @return an error string if validation failed 626 */ 627 _minSize: function(field, rules, i, options) { 628 var min = rules[i + 1]; 629 var len = field.attr('value').length; 630 631 if (len < min) { 632 var rule = options.allrules.minSize; 633 return rule.alertText + min + rule.alertText2; 634 } 635 }, 636 /** 637 * Check number minimum value 638 * 639 * @param {jqObject} field 640 * @param {Array[String]} rules 641 * @param {int} i rules index 642 * @param {Map} 643 * user options 644 * @return an error string if validation failed 645 */ 646 _min: function(field, rules, i, options) { 647 var min = parseFloat(rules[i + 1]); 648 var len = parseFloat(field.attr('value')); 649 650 if (len < min) { 651 var rule = options.allrules.min; 652 if (rule.alertText2) return rule.alertText + min + rule.alertText2; 653 return rule.alertText + min; 654 } 655 }, 656 /** 657 * Check number maximum value 658 * 659 * @param {jqObject} field 660 * @param {Array[String]} rules 661 * @param {int} i rules index 662 * @param {Map} 663 * user options 664 * @return an error string if validation failed 665 */ 666 _max: function(field, rules, i, options) { 667 var max = parseFloat(rules[i + 1]); 668 var len = parseFloat(field.attr('value')); 669 670 if (len >max ) { 671 var rule = options.allrules.max; 672 if (rule.alertText2) return rule.alertText + max + rule.alertText2; 673 //orefalo: to review, also do the translations 674 return rule.alertText + max; 675 } 676 }, 677 /** 678 * Checks date is in the past 679 * 680 * @param {jqObject} field 681 * @param {Array[String]} rules 682 * @param {int} i rules index 683 * @param {Map} 684 * user options 685 * @return an error string if validation failed 686 */ 687 _past: function(field, rules, i, options) { 688 689 var p=rules[i + 1];
690 var pdate = (p.toLowerCase() == "now")? new Date():methods._parseDate(p); 691 var vdate = methods._parseDate(field.attr('value')); 692 693 if (vdate > pdate ) { 694 var rule = options.allrules.past; 695 if (rule.alertText2) return rule.alertText + methods._dateToString(pdate) + rule.alertText2; 696 return rule.alertText + methods._dateToString(pdate); 697 } 698 }, 699 /** 700 * Checks date is in the past 701 * 702 * @param {jqObject} field 703 * @param {Array[String]} rules 704 * @param {int} i rules index 705 * @param {Map} 706 * user options 707 * @return an error string if validation failed 708 */ 709 _future: function(field, rules, i, options) { 710 711 var p=rules[i + 1]; 712 var pdate = (p.toLowerCase() == "now")? new Date():methods._parseDate(p); 713 var vdate = methods._parseDate(field.attr('value')); 714 715 if (vdate < pdate ) { 716 var rule = options.allrules.future; 717 if (rule.alertText2) return rule.alertText + methods._dateToString(pdate) + rule.alertText2; 718 return rule.alertText + methods._dateToString(pdate); 719 } 720 }, 721 /** 722 * Max number of checkbox selected 723 * 724 * @param {jqObject} field 725 * @param {Array[String]} rules 726 * @param {int} i rules index 727 * @param {Map} 728 * user options 729 * @return an error string if validation failed 730 */ 731 _maxCheckbox: function(field, rules, i, options) { 732 733 var nbCheck = rules[i + 1]; 734 var groupname = field.attr("name"); 735 var groupSize = $("input[name='" + groupname + "']:checked").size(); 736 if (groupSize > nbCheck) { 737 options.showArrow = false; 738 return options.allrules.maxCheckbox.alertText; 739 } 740 }, 741 /** 742 * Min number of checkbox selected 743 * 744 * @param {jqObject} field 745 * @param {Array[String]} rules 746 * @param {int} i rules index 747 * @param {Map} 748 * user options 749 * @return an error string if validation failed 750 */ 751 _minCheckbox: function(field, rules, i, options) { 752 753 var nbCheck = rules[i + 1]; 754 var groupname = field.attr("name"); 755 var groupSize = $("input[name='" + groupname + "']:checked").size(); 756 if (groupSize < nbCheck) { 757 options.showArrow = false; 758 return options.allrules.minCheckbox.alertText + " " + nbCheck + " " + 759 options.allrules.minCheckbox.alertText2; 760 } 761 }, 762 /** 763 * Ajax field validation 764 * 765 * @param {jqObject} field 766 * @param {Array[String]} rules 767 * @param {int} i rules index 768 * @param {Map} 769 * user options 770 * @return nothing! the ajax validator handles the prompts itself 771 */ 772 _ajax: function(field, rules, i, options) { 773 774 775 var errorSelector = rules[i + 1]; 776 var rule = options.allrules[errorSelector]; 777 var extraData = rule.extraData; 778 779 if (!extraData) 780 extraData = ""; 781 782 if (!options.isError) { 783 $.ajax({
784 type: "GET", 785 url: rule.url, 786 cache: false, 787 dataType: "json", 788 data: "fieldId=" + field.attr("id") + "&fieldValue=" + field.attr("value") + "&extraData=" + extraData, 789 field: field, 790 rule: rule, 791 methods: methods, 792 options: options, 793 beforeSend: function() { 794 // build the loading prompt 795 var loadingText = rule.alertTextLoad; 796 if (loadingText) 797 methods._showPrompt(field, loadingText, "load", true, options); 798 }, 799 error: function(data, transport) { 800 methods._ajaxError(data, transport); 801 }, 802 success: function(json) { 803 804 // asynchronously called on success, data is the json answer from the server 805 var errorFieldId = json[0]; 806 var errorField = $($("#" + errorFieldId)[0]); 807 // make sure we found the element 808 if (errorField.length == 1) { 809 var status = json[1]; 810 if (!status) { 811 // Houston we got a problem 812 options.ajaxValidCache[errorFieldId] = false; 813 options.isError = true; 814 var promptText = rule.alertText; 815 methods._showPrompt(errorField, promptText, "", true, options); 816 } else { 817 if (options.ajaxValidCache[errorFieldId] !== undefined) 818 options.ajaxValidCache[errorFieldId] = true; 819 820 // see if we should display a green prompt 821 var alertTextOk = rule.alertTextOk; 822 if (alertTextOk) 823 methods._showPrompt(errorField, alertTextOk, "pass", true, options); 824 else 825 methods._closePrompt(errorField); 826 } 827 } 828 } 829 }); 830 } 831 }, 832 /** 833 * Common method to handle ajax errors 834 * 835 * @param {Object} data 836 * @param {Object} transport 837 */ 838 _ajaxError: function(data, transport) { 839 if(data.status == 0 && transport == null) 840 alert("The page is not served from a server! ajax call failed"); 841 else if(typeof console != "undefined") 842 console.log("Ajax error: " + data.status + " " + transport); 843 }, 844 /** 845 * date -> string 846 * 847 * @param {Object} date 848 */ 849 _dateToString: function(date) { 850 851 return date.getFullYear()+"-"+(date.getMonth()+1)+"-"+date.getDate(); 852 }, 853 /** 854 * Parses an ISO date 855 * @param {String} d 856 */ 857 _parseDate: function(d) { 858 859 var dateParts = d.split("-"); 860 if(dateParts!==d) 861 dateParts = d.split("/"); 862 return new Date(dateParts[0], (dateParts[1] - 1) ,dateParts[2]); 863 }, 864 /** 865 * Builds or updates a prompt with the given information 866 * 867 * @param {jqObject} field 868 * @param {String} promptText html text to display type 869 * @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red) 870 * @param {boolean} ajaxed - use to mark fields than being validated with ajax 871 * @param {Map} options user options 872 */ 873 _showPrompt: function(field, promptText, type, ajaxed, options, ajaxform) { 874 var prompt = methods._getPrompt(field); 875 // The ajax submit errors are not see has an error in the form, 876 // When the form errors are returned, the engine see 2 bubbles, but those are ebing closed by the engine at the same time 877 // Because no error was found befor submitting 878 if(ajaxform) prompt = false; 879 if (prompt) 880 methods._updatePrompt(field, prompt, promptText, type, ajaxed, options); 881 else 882 methods._buildPrompt(field, promptText, type, ajaxed, options); 883 }, 884 /** 885 * Builds and shades a prompt for the given field. 886 * 887 * @param {jqObject} field 888 * @param {String} promptText html text to display type 889 * @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red) 890 * @param {boolean} ajaxed - use to mark fields than being validated with ajax 891 * @param {Map} options user options 892 */ 893 _buildPrompt: function(field, promptText, type, ajaxed, options) { 894 895 // create the prompt 896 var prompt = $('<div>'); 897 prompt.addClass(methods._getClassName(field.attr("id")) + "formError"); 898 // add a class name to identify the parent form of the prompt 899 if(field.is(":input")) prompt.addClass("parentForm"+methods._getClassName(field.parents('form').attr("id"))); 900 prompt.addClass("formError"); 901 902 switch (type) { 903 case "pass": 904 prompt.addClass("greenPopup"); 905 break; 906 case "load": 907 prompt.addClass("blackPopup"); 908 } 909 if (ajaxed) 910 prompt.addClass("ajaxed"); 911 912 // create the prompt content 913 var promptContent = $('<div>').addClass("formErrorContent").html(promptText).appendTo(prompt); 914 // create the css arrow pointing at the field 915 // note that there is no triangle on max-checkbox and radio 916 if (options.showArrow) { 917 var arrow = $('<div>').addClass("formErrorArrow"); 918 919 switch (options.promptPosition) { 920 case "bottomLeft": 921 case "bottomRight": 922 prompt.find(".formErrorContent").before(arrow); 923 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>'); 924 break; 925 case "topLeft": 926 case "topRight": 927 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>'); 928 prompt.append(arrow); 929 break; 930 } 931 } 932 933 //Cedric: Needed if a container is in position:relative 934 // insert prompt in the form or in the overflown container? 935 if (options.isOverflown) 936 field.before(prompt); 937 else 938 $("body").append(prompt); 939 940 var pos = methods._calculatePosition(field, prompt, options); 941 prompt.css({ 942 "top": pos.callerTopPosition, 943 "left": pos.callerleftPosition, 944 "marginTop": pos.marginTopSize, 945 "opacity": 0 946 }); 947 948 return prompt.animate({ 949 "opacity": 0.87 950 }); 951 952 }, 953 /** 954 * Updates the prompt text field - the field for which the prompt 955 * @param {jqObject} field 956 * @param {String} promptText html text to display type 957 * @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red) 958 * @param {boolean} ajaxed - use to mark fields than being validated with ajax 959 * @param {Map} options user options 960 */ 961 _updatePrompt: function(field, prompt, promptText, type, ajaxed, options) { 962 963 if (prompt) { 964 if (type == "pass") 965 prompt.addClass("greenPopup"); 966 else 967 prompt.removeClass("greenPopup"); 968 969 if (type == "load") 970 prompt.addClass("blackPopup"); 971 else 972 prompt.removeClass("blackPopup"); 973 974 if (ajaxed) 975 prompt.addClass("ajaxed"); 976 else 977 prompt.removeClass("ajaxed"); 978 979 prompt.find(".formErrorContent").html(promptText); 980 981 var pos = methods._calculatePosition(field, prompt, options); 982 prompt.animate({ 983 "top": pos.callerTopPosition, 984 "marginTop": pos.marginTopSize 985 }); 986 } 987 }, 988 /** 989 * Closes the prompt associated with the given field 990 * 991 * @param {jqObject} 992 * field 993 */ 994 _closePrompt: function(field) { 995 996 var prompt = methods._getPrompt(field); 997 if (prompt) 998 prompt.fadeTo("fast", 0, function() { 999 prompt.remove(); 1000 }); 1001 }, 1002 closePrompt: function(field) { 1003 return methods._closePrompt(field); 1004 }, 1005 /** 1006 * Returns the error prompt matching the field if any 1007 * 1008 * @param {jqObject} 1009 * field 1010 * @return undefined or the error prompt (jqObject) 1011 */ 1012 _getPrompt: function(field) { 1013 1014 var className = "." + methods._getClassName(field.attr("id")) + "formError"; 1015 var match = $(className)[0]; 1016 if (match) 1017 return $(match); 1018 }, 1019 /** 1020 * Calculates prompt position 1021 * 1022 * @param {jqObject} 1023 * field 1024 * @param {jqObject} 1025 * the prompt 1026 * @param {Map} 1027 * options 1028 * @return positions 1029 */ 1030 _calculatePosition: function(field, promptElmt, options) { 1031 1032 var promptTopPosition, promptleftPosition, marginTopSize; 1033 var fieldWidth = field.width(); 1034 var promptHeight = promptElmt.height(); 1035 1036 var overflow = options.isOverflown; 1037 if (overflow) { 1038 // is the form contained in an overflown container? 1039 promptTopPosition = promptleftPosition = 0; 1040 // compensation for the arrow 1041 marginTopSize = -promptHeight; 1042 } else { 1043 var offset = field.offset(); 1044 promptTopPosition = offset.top; 1045 promptleftPosition = offset.left; 1046 marginTopSize = 0; 1047 } 1048 1049 switch (options.promptPosition) { 1050 1051 default: 1052 case "topRight": 1053 if (overflow) 1054 // Is the form contained in an overflown container? 1055 promptleftPosition += fieldWidth - 30; 1056 else { 1057 promptleftPosition += fieldWidth - 30; 1058 promptTopPosition += -promptHeight; 1059 } 1060 break; 1061 case "topLeft": 1062 promptTopPosition += -promptHeight - 10; 1063 break; 1064 case "centerRight": 1065 promptleftPosition += fieldWidth + 13; 1066 break; 1067 case "bottomLeft": 1068 promptTopPosition = promptTopPosition + field.height() + 15; 1069 break; 1070 case "bottomRight": 1071 promptleftPosition += fieldWidth - 30; 1072 promptTopPosition += field.height() + 5; 1073 } 1074 1075 return { 1076 "callerTopPosition": promptTopPosition + "px", 1077 "callerleftPosition": promptleftPosition + "px", 1078 "marginTopSize": marginTopSize + "px" 1079 }; 1080 }, 1081 /** 1082 * Saves the user options and variables in the form.data 1083 * 1084 * @param {jqObject} 1085 * form - the form where the user option should be saved 1086 * @param {Map} 1087 * options - the user options 1088 * @return the user options (extended from the defaults) 1089 */ 1090 _saveOptions: function(form, options) { 1091 1092 // is there a language localisation ? 1093 if ($.validationEngineLanguage) 1094 var allRules = $.validationEngineLanguage.allRules; 1095 else 1096 $.error("jQuery.validationEngine rules are not loaded, plz add localization files to the page"); 1097 1098 var userOptions = $.extend({ 1099 1100 // Name of the event triggering field validation 1101 validationEventTrigger: "blur", 1102 // Automatically scroll viewport to the first error 1103 scroll: true, 1104 // Opening box position, possible locations are: topLeft, 1105 // topRight, bottomLeft, centerRight, bottomRight 1106 promptPosition: "topRight", 1107 bindMethod:"bind", 1108 // internal, automatically set to true when it parse a _ajax rule 1109 inlineAjax: false, 1110 // if set to true, the form data is sent asynchronously via ajax to the form.action url (get) 1111 ajaxFormValidation: false, 1112 // Ajax form validation callback method: boolean onComplete(form, status, errors, options) 1113 // retuns false if the form.submit event needs to be canceled. 1114 ajaxFormValidationURL: false, 1115 // The url to send the submit ajax validation (default to action) 1116 onAjaxFormComplete: $.noop, 1117 // called right before the ajax call, may return false to cancel 1118 onBeforeAjaxFormValidation: $.noop, 1119 // Stops form from submitting and execute function assiciated with it 1120 onValidationComplete: false, 1121 1122 // Used when the form is displayed within a scrolling DIV
1123 isOverflown: false, 1124 overflownDIV: "", 1125 1126 // --- Internals DO NOT TOUCH or OVERLOAD --- 1127 // validation rules and i18 1128 allrules: allRules, 1129 // true when form and fields are binded 1130 binded: false, 1131 // set to true, when the prompt arrow needs to be displayed 1132 showArrow: true, 1133 // did one of the validation fail ? kept global to stop further ajax validations 1134 isError: false, 1135 // Caches field validation status, typically only bad status are created. 1136 // the array is used during ajax form validation to detect issues early and prevent an expensive submit 1137 ajaxValidCache: {} 1138 1139 }, options); 1140 1141 form.data('jqv', userOptions); 1142 return userOptions; 1143 }, 1144 1145 /** 1146 * Removes forbidden characters from class name 1147 * @param {String} className 1148 */ 1149 _getClassName: function(className) { 1150 return className.replace(":","_").replace(".","_"); 1151 } 1152 }; 1153 1154 /** 1155 * Plugin entry point. 1156 * You may pass an action as a parameter or a list of options. 1157 * if none, the init and attach methods are being called. 1158 * Remember: if you pass options, the attached method is NOT called automatically 1159 * 1160 * @param {String} 1161 * method (optional) action 1162 */ 1163 $.fn.validationEngine = function(method) { 1164 1165 var form = $(this); 1166 if(!form[0]) return false; // stop here if the form does not exist 1167 1168 if (typeof(method) == 'string' && method.charAt(0) != '_' && methods[method]) { 1169 1170 // make sure init is called once 1171 if(method != "showPrompt" && method != "hidePrompt" && method != "hide" && method != "hideAll") 1172 methods.init.apply(form); 1173 1174 return methods[method].apply(form, Array.prototype.slice.call(arguments, 1)); 1175 } else if (typeof method == 'object' || !method) { 1176 // default constructor with or without arguments 1177 methods.init.apply(form, arguments); 1178 return methods.attach.apply(form); 1179 } else { 1180 $.error('Method ' + method + ' does not exist in jQuery.validationEngine'); 1181 } 1182 }; 1183})(jQuery); 1184
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.