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