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