/* * jQuery UI Datepicker 1.8.18 * * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * http://docs.jquery.com/UI/Datepicker * * Depends: * jquery.ui.core.js */(function($,undefined){function isArray(a){return a&&($.browser.safari&&typeof a=="object"&&a.length||a.constructor&&a.constructor.toString().match(/\Array\(\)/))}function extendRemove(a,b){$.extend(a,b);for(var c in b)if(b[c]==null||b[c]==undefined)a[c]=b[c];return a}function bindHover(a){var b="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return a.bind("mouseout",function(a){var c=$(a.target).closest(b);!c.length||c.removeClass("ui-state-hover ui-datepicker-prev-hover ui-datepicker-next-hover")}).bind("mouseover",function(c){var d=$(c.target).closest(b);!$.datepicker._isDisabledDatepicker(instActive.inline?a.parent()[0]:instActive.input[0])&&!!d.length&&(d.parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"),d.addClass("ui-state-hover"),d.hasClass("ui-datepicker-prev")&&d.addClass("ui-datepicker-prev-hover"),d.hasClass("ui-datepicker-next")&&d.addClass("ui-datepicker-next-hover"))})}function Datepicker(){this.debug=!1,this._curInst=null,this._keyEvent=!1,this._disabledInputs=[],this._datepickerShowing=!1,this._inDialog=!1,this._mainDivId="ui-datepicker-div",this._inlineClass="ui-datepicker-inline",this._appendClass="ui-datepicker-append",this._triggerClass="ui-datepicker-trigger",this._dialogClass="ui-datepicker-dialog",this._disableClass="ui-datepicker-disabled",this._unselectableClass="ui-datepicker-unselectable",this._currentClass="ui-datepicker-current-day",this._dayOverClass="ui-datepicker-days-cell-over",this.regional=[],this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:!1,hideIfNoPrevNext:!1,navigationAsDateFormat:!1,gotoCurrent:!1,changeMonth:!1,changeYear:!1,yearRange:"c-10:c+10",showOtherMonths:!1,selectOtherMonths:!1,showWeek:!1,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:!0,showButtonPanel:!1,autoSize:!1,disabled:!1},$.extend(this._defaults,this.regional[""]),this.dpDiv=bindHover($('
'))}$.extend($.ui,{datepicker:{version:"1.8.18"}});var PROP_NAME="datepicker",dpuuid=(new Date).getTime(),instActive;$.extend(Datepicker.prototype,{markerClassName:"hasDatepicker",maxRows:4,log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(a){extendRemove(this._defaults,a||{});return this},_attachDatepicker:function(target,settings){var inlineSettings=null;for(var attrName in this._defaults){var attrValue=target.getAttribute("date:"+attrName);if(attrValue){inlineSettings=inlineSettings||{};try{inlineSettings[attrName]=eval(attrValue)}catch(err){inlineSettings[attrName]=attrValue}}}var nodeName=target.nodeName.toLowerCase(),inline=nodeName=="div"||nodeName=="span";target.id||(this.uuid+=1,target.id="dp"+this.uuid);var inst=this._newInst($(target),inline);inst.settings=$.extend({},settings||{},inlineSettings||{}),nodeName=="input"?this._connectDatepicker(target,inst):inline&&this._inlineDatepicker(target,inst)},_newInst:function(a,b){var c=a[0].id.replace(/([^A-Za-z0-9_-])/g,"\\\\$1");return{id:c,input:a,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:b,dpDiv:b?bindHover($('
')):this.dpDiv}},_connectDatepicker:function(a,b){var c=$(a);b.append=$([]),b.trigger=$([]);c.hasClass(this.markerClassName)||(this._attachments(c,b),c.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker",function(a,c,d){b.settings[c]=d}).bind("getData.datepicker",function(a,c){return this._get(b,c)}),this._autoSize(b),$.data(a,PROP_NAME,b),b.settings.disabled&&this._disableDatepicker(a))},_attachments:function(a,b){var c=this._get(b,"appendText"),d=this._get(b,"isRTL");b.append&&b.append.remove(),c&&(b.append=$(''+c+""),a[d?"before":"after"](b.append)),a.unbind("focus",this._showDatepicker),b.trigger&&b.trigger.remove();var e=this._get(b,"showOn");(e=="focus"||e=="both")&&a.focus(this._showDatepicker);if(e=="button"||e=="both"){var f=this._get(b,"buttonText"),g=this._get(b,"buttonImage");b.trigger=$(this._get(b,"buttonImageOnly")?$("").addClass(this._triggerClass).attr({src:g,alt:f,title:f}):$('').addClass(this._triggerClass).html(g==""?f:$("").attr({src:g,alt:f,title:f}))),a[d?"before":"after"](b.trigger),b.trigger.click(function(){$.datepicker._datepickerShowing&&$.datepicker._lastInput==a[0]?$.datepicker._hideDatepicker():$.datepicker._datepickerShowing&&$.datepicker._lastInput!=a[0]?($.datepicker._hideDatepicker(),$.datepicker._showDatepicker(a[0])):$.datepicker._showDatepicker(a[0]);return!1})}},_autoSize:function(a){if(this._get(a,"autoSize")&&!a.inline){var b=new Date(2009,11,20),c=this._get(a,"dateFormat");if(c.match(/[DM]/)){var d=function(a){var b=0,c=0;for(var d=0;db&&(b=a[d].length,c=d);return c};b.setMonth(d(this._get(a,c.match(/MM/)?"monthNames":"monthNamesShort"))),b.setDate(d(this._get(a,c.match(/DD/)?"dayNames":"dayNamesShort"))+20-b.getDay())}a.input.attr("size",this._formatDate(a,b).length)}},_inlineDatepicker:function(a,b){var c=$(a);c.hasClass(this.markerClassName)||(c.addClass(this.markerClassName).append(b.dpDiv).bind("setData.datepicker",function(a,c,d){b.settings[c]=d}).bind("getData.datepicker",function(a,c){return this._get(b,c)}),$.data(a,PROP_NAME,b),this._setDate(b,this._getDefaultDate(b),!0),this._updateDatepicker(b),this._updateAlternate(b),b.settings.disabled&&this._disableDatepicker(a),b.dpDiv.css("display","block"))},_dialogDatepicker:function(a,b,c,d,e){var f=this._dialogInst;if(!f){this.uuid+=1;var g="dp"+this.uuid;this._dialogInput=$(''),this._dialogInput.keydown(this._doKeyDown),$("body").append(this._dialogInput),f=this._dialogInst=this._newInst(this._dialogInput,!1),f.settings={},$.data(this._dialogInput[0],PROP_NAME,f)}extendRemove(f.settings,d||{}),b=b&&b.constructor==Date?this._formatDate(f,b):b,this._dialogInput.val(b),this._pos=e?e.length?e:[e.pageX,e.pageY]:null;if(!this._pos){var h=document.documentElement.clientWidth,i=document.documentElement.clientHeight,j=document.documentElement.scrollLeft||document.body.scrollLeft,k=document.documentElement.scrollTop||document.body.scrollTop;this._pos=[h/2-100+j,i/2-150+k]}this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px"),f.settings.onSelect=c,this._inDialog=!0,this.dpDiv.addClass(this._dialogClass),this._showDatepicker(this._dialogInput[0]),$.blockUI&&$.blockUI(this.dpDiv),$.data(this._dialogInput[0],PROP_NAME,f);return this},_destroyDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!!b.hasClass(this.markerClassName)){var d=a.nodeName.toLowerCase();$.removeData(a,PROP_NAME),d=="input"?(c.append.remove(),c.trigger.remove(),b.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)):(d=="div"||d=="span")&&b.removeClass(this.markerClassName).empty()}},_enableDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!!b.hasClass(this.markerClassName)){var d=a.nodeName.toLowerCase();if(d=="input")a.disabled=!1,c.trigger.filter("button").each(function(){this.disabled=!1}).end().filter("img").css({opacity:"1.0",cursor:""});else if(d=="div"||d=="span"){var e=b.children("."+this._inlineClass);e.children().removeClass("ui-state-disabled"),e.find("select.ui-datepicker-month, select.ui-datepicker-year").removeAttr("disabled")}this._disabledInputs=$.map(this._disabledInputs,function(b){return b==a?null:b})}},_disableDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!!b.hasClass(this.markerClassName)){var d=a.nodeName.toLowerCase();if(d=="input")a.disabled=!0,c.trigger.filter("button").each(function(){this.disabled=!0}).end().filter("img").css({opacity:"0.5",cursor:"default"});else if(d=="div"||d=="span"){var e=b.children("."+this._inlineClass);e.children().addClass("ui-state-disabled"),e.find("select.ui-datepicker-month, select.ui-datepicker-year").attr("disabled","disabled")}this._disabledInputs=$.map(this._disabledInputs,function(b){return b==a?null:b}),this._disabledInputs[this._disabledInputs.length]=a}},_isDisabledDatepicker:function(a){if(!a)return!1;for(var b=0;b-1}},_doKeyUp:function(a){var b=$.datepicker._getInst(a.target);if(b.input.val()!=b.lastVal)try{var c=$.datepicker.parseDate($.datepicker._get(b,"dateFormat"),b.input?b.input.val():null,$.datepicker._getFormatConfig(b));c&&($.datepicker._setDateFromField(b),$.datepicker._updateAlternate(b),$.datepicker._updateDatepicker(b))}catch(a){$.datepicker.log(a)}return!0},_showDatepicker:function(a){a=a.target||a,a.nodeName.toLowerCase()!="input"&&(a=$("input",a.parentNode)[0]);if(!$.datepicker._isDisabledDatepicker(a)&&$.datepicker._lastInput!=a){var b=$.datepicker._getInst(a);$.datepicker._curInst&&$.datepicker._curInst!=b&&($.datepicker._curInst.dpDiv.stop(!0,!0),b&&$.datepicker._datepickerShowing&&$.datepicker._hideDatepicker($.datepicker._curInst.input[0]));var c=$.datepicker._get(b,"beforeShow"),d=c?c.apply(a,[a,b]):{};if(d===!1)return;extendRemove(b.settings,d),b.lastVal=null,$.datepicker._lastInput=a,$.datepicker._setDateFromField(b),$.datepicker._inDialog&&(a.value=""),$.datepicker._pos||($.datepicker._pos=$.datepicker._findPos(a),$.datepicker._pos[1]+=a.offsetHeight);var e=!1;$(a).parents().each(function(){e|=$(this).css("position")=="fixed";return!e}),e&&$.browser.opera&&($.datepicker._pos[0]-=document.documentElement.scrollLeft,$.datepicker._pos[1]-=document.documentElement.scrollTop);var f={left:$.datepicker._pos[0],top:$.datepicker._pos[1]};$.datepicker._pos=null,b.dpDiv.empty(),b.dpDiv.css({position:"absolute",display:"block",top:"-1000px"}),$.datepicker._updateDatepicker(b),f=$.datepicker._checkOffset(b,f,e),b.dpDiv.css({position:$.datepicker._inDialog&&$.blockUI?"static":e?"fixed":"absolute",display:"none",left:f.left+"px",top:f.top+"px"});if(!b.inline){var g=$.datepicker._get(b,"showAnim"),h=$.datepicker._get(b,"duration"),i=function(){var a=b.dpDiv.find("iframe.ui-datepicker-cover");if(!!a.length){var c=$.datepicker._getBorders(b.dpDiv);a.css({left:-c[0],top:-c[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})}};b.dpDiv.zIndex($(a).zIndex()+1),$.datepicker._datepickerShowing=!0,$.effects&&$.effects[g]?b.dpDiv.show(g,$.datepicker._get(b,"showOptions"),h,i):b.dpDiv[g||"show"](g?h:null,i),(!g||!h)&&i(),b.input.is(":visible")&&!b.input.is(":disabled")&&b.input.focus(),$.datepicker._curInst=b}}},_updateDatepicker:function(a){var b=this;b.maxRows=4;var c=$.datepicker._getBorders(a.dpDiv);instActive=a,a.dpDiv.empty().append(this._generateHTML(a));var d=a.dpDiv.find("iframe.ui-datepicker-cover");!d.length||d.css({left:-c[0],top:-c[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()}),a.dpDiv.find("."+this._dayOverClass+" a").mouseover();var e=this._getNumberOfMonths(a),f=e[1],g=17;a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""),f>1&&a.dpDiv.addClass("ui-datepicker-multi-"+f).css("width",g*f+"em"),a.dpDiv[(e[0]!=1||e[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi"),a.dpDiv[(this._get(a,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl"),a==$.datepicker._curInst&&$.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&&!a.input.is(":disabled")&&a.input[0]!=document.activeElement&&a.input.focus();if(a.yearshtml){var h=a.yearshtml;setTimeout(function(){h===a.yearshtml&&a.yearshtml&&a.dpDiv.find("select.ui-datepicker-year:first").replaceWith(a.yearshtml),h=a.yearshtml=null},0)}},_getBorders:function(a){var b=function(a){return{thin:1,medium:2,thick:3}[a]||a};return[parseFloat(b(a.css("border-left-width"))),parseFloat(b(a.css("border-top-width")))]},_checkOffset:function(a,b,c){var d=a.dpDiv.outerWidth(),e=a.dpDiv.outerHeight(),f=a.input?a.input.outerWidth():0,g=a.input?a.input.outerHeight():0,h=document.documentElement.clientWidth+$(document).scrollLeft(),i=document.documentElement.clientHeight+$(document).scrollTop();b.left-=this._get(a,"isRTL")?d-f:0,b.left-=c&&b.left==a.input.offset().left?$(document).scrollLeft():0,b.top-=c&&b.top==a.input.offset().top+g?$(document).scrollTop():0,b.left-=Math.min(b.left,b.left+d>h&&h>d?Math.abs(b.left+d-h):0),b.top-=Math.min(b.top,b.top+e>i&&i>e?Math.abs(e+g):0);return b},_findPos:function(a){var b=this._getInst(a),c=this._get(b,"isRTL");while(a&&(a.type=="hidden"||a.nodeType!=1||$.expr.filters.hidden(a)))a=a[c?"previousSibling":"nextSibling"];var d=$(a).offset();return[d.left,d.top]},_hideDatepicker:function(a){var b=this._curInst;if(!(!b||a&&b!=$.data(a,PROP_NAME))&&this._datepickerShowing){var c=this._get(b,"showAnim"),d=this._get(b,"duration"),e=this,f=function(){$.datepicker._tidyDialog(b),e._curInst=null};$.effects&&$.effects[c]?b.dpDiv.hide(c,$.datepicker._get(b,"showOptions"),d,f):b.dpDiv[c=="slideDown"?"slideUp":c=="fadeIn"?"fadeOut":"hide"](c?d:null,f),c||f(),this._datepickerShowing=!1;var g=this._get(b,"onClose");g&&g.apply(b.input?b.input[0]:null,[b.input?b.input.val():"",b]),this._lastInput=null,this._inDialog&&(this._dialogInput.css({position:"absolute",left:"0",top:"-100px"}),$.blockUI&&($.unblockUI(),$("body").append(this.dpDiv))),this._inDialog=!1}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(a){if(!!$.datepicker._curInst){var b=$(a.target),c=$.datepicker._getInst(b[0]);(b[0].id!=$.datepicker._mainDivId&&b.parents("#"+$.datepicker._mainDivId).length==0&&!b.hasClass($.datepicker.markerClassName)&&!b.closest("."+$.datepicker._triggerClass).length&&$.datepicker._datepickerShowing&&(!$.datepicker._inDialog||!$.blockUI)||b.hasClass($.datepicker.markerClassName)&&$.datepicker._curInst!=c)&&$.datepicker._hideDatepicker()}},_adjustDate:function(a,b,c){var d=$(a),e=this._getInst(d[0]);this._isDisabledDatepicker(d[0])||(this._adjustInstDate(e,b+(c=="M"?this._get(e,"showCurrentAtPos"):0),c),this._updateDatepicker(e))},_gotoToday:function(a){var b=$(a),c=this._getInst(b[0]);if(this._get(c,"gotoCurrent")&&c.currentDay)c.selectedDay=c.currentDay,c.drawMonth=c.selectedMonth=c.currentMonth,c.drawYear=c.selectedYear=c.currentYear;else{var d=new Date;c.selectedDay=d.getDate(),c.drawMonth=c.selectedMonth=d.getMonth(),c.drawYear=c.selectedYear=d.getFullYear()}this._notifyChange(c),this._adjustDate(b)},_selectMonthYear:function(a,b,c){var d=$(a),e=this._getInst(d[0]);e["selected"+(c=="M"?"Month":"Year")]=e["draw"+(c=="M"?"Month":"Year")]=parseInt(b.options[b.selectedIndex].value,10),this._notifyChange(e),this._adjustDate(d)},_selectDay:function(a,b,c,d){var e=$(a);if(!$(d).hasClass(this._unselectableClass)&&!this._isDisabledDatepicker(e[0])){var f=this._getInst(e[0]);f.selectedDay=f.currentDay=$("a",d).html(),f.selectedMonth=f.currentMonth=b,f.selectedYear=f.currentYear=c,this._selectDate(a,this._formatDate(f,f.currentDay,f.currentMonth,f.currentYear))}},_clearDate:function(a){var b=$(a),c=this._getInst(b[0]);this._selectDate(b,"")},_selectDate:function(a,b){var c=$(a),d=this._getInst(c[0]);b=b!=null?b:this._formatDate(d),d.input&&d.input.val(b),this._updateAlternate(d);var e=this._get(d,"onSelect");e?e.apply(d.input?d.input[0]:null,[b,d]):d.input&&d.input.trigger("change"),d.inline?this._updateDatepicker(d):(this._hideDatepicker(),this._lastInput=d.input[0],typeof d.input[0]!="object"&&d.input.focus(),this._lastInput=null)},_updateAlternate:function(a){var b=this._get(a,"altField");if(b){var c=this._get(a,"altFormat")||this._get(a,"dateFormat"),d=this._getDate(a),e=this.formatDate(c,d,this._getFormatConfig(a));$(b).each(function(){$(this).val(e)})}},noWeekends:function(a){var b=a.getDay();return[b>0&&b<6,""]},iso8601Week:function(a){var b=new Date(a.getTime());b.setDate(b.getDate()+4-(b.getDay()||7));var c=b.getTime();b.setMonth(0),b.setDate(1);return Math.floor(Math.round((c-b)/864e5)/7)+1},parseDate:function(a,b,c){if(a==null||b==null)throw"Invalid arguments";b=typeof b=="object"?b.toString():b+"";if(b=="")return null;var d=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff;d=typeof d!="string"?d:(new Date).getFullYear()%100+parseInt(d,10);var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?c.dayNames:null)||this._defaults.dayNames,g=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,h=(c?c.monthNames:null)||this._defaults.monthNames,i=-1,j=-1,k=-1,l=-1,m=!1,n=function(b){var c=s+1-1){j=1,k=l;for(;;){var u=this._getDaysInMonth(i,j-1);if(k<=u)break;j++,k-=u}}var t=this._daylightSavingAdjust(new Date(i,j-1,k));if(t.getFullYear()!=i||t.getMonth()+1!=j||t.getDate()!=k)throw"Invalid date";return t},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1e7,formatDate:function(a,b,c){if(!b)return"";var d=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,e=(c?c.dayNames:null)||this._defaults.dayNames,f=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,g=(c?c.monthNames:null)||this._defaults.monthNames,h=function(b){var c=m+112?a.getHours()+2:0);return a},_setDate:function(a,b,c){var d=!b,e=a.selectedMonth,f=a.selectedYear,g=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay=a.currentDay=g.getDate(),a.drawMonth=a.selectedMonth=a.currentMonth=g.getMonth(),a.drawYear=a.selectedYear=a.currentYear=g.getFullYear(),(e!=a.selectedMonth||f!=a.selectedYear)&&!c&&this._notifyChange(a),this._adjustInstDate(a),a.input&&a.input.val(d?"":this._formatDate(a))},_getDate:function(a){var b=!a.currentYear||a.input&&a.input.val()==""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return b},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(),b.getMonth(),b.getDate()));var c=this._get(a,"isRTL"),d=this._get(a,"showButtonPanel"),e=this._get(a,"hideIfNoPrevNext"),f=this._get(a,"navigationAsDateFormat"),g=this._getNumberOfMonths(a),h=this._get(a,"showCurrentAtPos"),i=this._get(a,"stepMonths"),j=g[0]!=1||g[1]!=1,k=this._daylightSavingAdjust(a.currentDay?new Date(a.currentYear,a.currentMonth,a.currentDay):new Date(9999,9,9)),l=this._getMinMaxDate(a,"min"),m=this._getMinMaxDate(a,"max"),n=a.drawMonth-h,o=a.drawYear;n<0&&(n+=12,o--);if(m){var p=this._daylightSavingAdjust(new Date(m.getFullYear(),m.getMonth()-g[0]*g[1]+1,m.getDate()));p=l&&pp)n--,n<0&&(n=11,o--)}a.drawMonth=n,a.drawYear=o;var q=this._get(a,"prevText");q=f?this.formatDate(q,this._daylightSavingAdjust(new Date(o,n-i,1)),this._getFormatConfig(a)):q;var r=this._canAdjustMonth(a,-1,o,n)?''+q+"":e?"":''+q+"",s=this._get(a,"nextText");s=f?this.formatDate(s,this._daylightSavingAdjust(new Date(o,n+i,1)),this._getFormatConfig(a)):s;var t=this._canAdjustMonth(a,1,o,n)?''+s+"":e?"":''+s+"",u=this._get(a,"currentText"),v=this._get(a,"gotoCurrent")&&a.currentDay?k:b;u=f?this.formatDate(u,v,this._getFormatConfig(a)):u;var w=a.inline?"":'",x=d?'
'+(c?w:"")+(this._isInRange(a,v)?'":"")+(c?"":w)+"
":"",y=parseInt(this._get(a,"firstDay"),10);y=isNaN(y)?0:y;var z=this._get(a,"showWeek"),A=this._get(a,"dayNames"),B=this._get(a,"dayNamesShort"),C=this._get(a,"dayNamesMin"),D=this._get(a,"monthNames"),E=this._get(a,"monthNamesShort"),F=this._get(a,"beforeShowDay"),G=this._get(a,"showOtherMonths"),H=this._get(a,"selectOtherMonths"),I=this._get(a,"calculateWeek")||this.iso8601Week,J=this._getDefaultDate(a),K="";for(var L=0;L1)switch(N){case 0:Q+=" ui-datepicker-group-first",P=" ui-corner-"+(c?"right":"left");break;case g[1]-1:Q+=" ui-datepicker-group-last",P=" ui-corner-"+(c?"left":"right");break;default:Q+=" ui-datepicker-group-middle",P=""}Q+='">'}Q+='
'+(/all|left/.test(P)&&L==0?c?t:r:"")+(/all|right/.test(P)&&L==0?c?r:t:"")+this._generateMonthYearHeader(a,n,o,l,m,L>0||N>0,D,E)+'
'+"";var R=z?'":"";for(var S=0;S<7;S++){var T=(S+y)%7;R+="=5?' class="ui-datepicker-week-end"':"")+">"+''+C[T]+""}Q+=R+"";var U=this._getDaysInMonth(o,n);o==a.selectedYear&&n==a.selectedMonth&&(a.selectedDay=Math.min(a.selectedDay,U));var V=(this._getFirstDayOfMonth(o,n)-y+7)%7,W=Math.ceil((V+U)/7),X=j?this.maxRows>W?this.maxRows:W:W;this.maxRows=X;var Y=this._daylightSavingAdjust(new Date(o,n,1-V));for(var Z=0;Z";var _=z?'":"";for(var S=0;S<7;S++){var ba=F?F.apply(a.input?a.input[0]:null,[Y]):[!0,""],bb=Y.getMonth()!=n,bc=bb&&!H||!ba[0]||l&&Ym;_+='",Y.setDate(Y.getDate()+1),Y=this._daylightSavingAdjust(Y)}Q+=_+""}n++,n>11&&(n=0,o++),Q+="
'+this._get(a,"weekHeader")+"
'+this._get(a,"calculateWeek")(Y)+""+(bb&&!G?" ":bc?''+Y.getDate()+"":''+Y.getDate()+"")+"
"+(j?""+(g[0]>0&&N==g[1]-1?'
':""):""),M+=Q}K+=M}K+=x+($.browser.msie&&parseInt($.browser.version,10)<7&&!a.inline?'':""), a._keyEvent=!1;return K},_generateMonthYearHeader:function(a,b,c,d,e,f,g,h){var i=this._get(a,"changeMonth"),j=this._get(a,"changeYear"),k=this._get(a,"showMonthAfterYear"),l='
',m="";if(f||!i)m+=''+g[b]+"";else{var n=d&&d.getFullYear()==c,o=e&&e.getFullYear()==c;m+='"}k||(l+=m+(f||!i||!j?" ":""));if(!a.yearshtml){a.yearshtml="";if(f||!j)l+=''+c+"";else{var q=this._get(a,"yearRange").split(":"),r=(new Date).getFullYear(),s=function(a){var b=a.match(/c[+-].*/)?c+parseInt(a.substring(1),10):a.match(/[+-].*/)?r+parseInt(a,10):parseInt(a,10);return isNaN(b)?r:b},t=s(q[0]),u=Math.max(t,s(q[1]||""));t=d?Math.max(t,d.getFullYear()):t,u=e?Math.min(u,e.getFullYear()):u,a.yearshtml+='",l+=a.yearshtml,a.yearshtml=null}}l+=this._get(a,"yearSuffix"),k&&(l+=(f||!i||!j?" ":"")+m),l+="
";return l},_adjustInstDate:function(a,b,c){var d=a.drawYear+(c=="Y"?b:0),e=a.drawMonth+(c=="M"?b:0),f=Math.min(a.selectedDay,this._getDaysInMonth(d,e))+(c=="D"?b:0),g=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(d,e,f)));a.selectedDay=g.getDate(),a.drawMonth=a.selectedMonth=g.getMonth(),a.drawYear=a.selectedYear=g.getFullYear(),(c=="M"||c=="Y")&&this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min"),d=this._getMinMaxDate(a,"max"),e=c&&bd?d:e;return e},_notifyChange:function(a){var b=this._get(a,"onChangeMonthYear");b&&b.apply(a.input?a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){var b=this._get(a,"numberOfMonths");return b==null?[1,1]:typeof b=="number"?[1,b]:b},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-this._daylightSavingAdjust(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,d){var e=this._getNumberOfMonths(a),f=this._daylightSavingAdjust(new Date(c,d+(b<0?b:e[0]*e[1]),1));b<0&&f.setDate(this._getDaysInMonth(f.getFullYear(),f.getMonth()));return this._isInRange(a,f)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min"),d=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!d||b.getTime()<=d.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10);return{shortYearCutoff:b,dayNamesShort:this._get(a,"dayNamesShort"),dayNames:this._get(a,"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,d){b||(a.currentDay=a.selectedDay,a.currentMonth=a.selectedMonth,a.currentYear=a.selectedYear);var e=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(d,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),e,this._getFormatConfig(a))}}),$.fn.datepicker=function(a){if(!this.length)return this;$.datepicker.initialized||($(document).mousedown($.datepicker._checkExternalClick).find("body").append($.datepicker.dpDiv),$.datepicker.initialized=!0);var b=Array.prototype.slice.call(arguments,1);if(typeof a=="string"&&(a=="isDisabled"||a=="getDate"||a=="widget"))return $.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this[0]].concat(b));if(a=="option"&&arguments.length==2&&typeof arguments[1]=="string")return $.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this[0]].concat(b));return this.each(function(){typeof a=="string"?$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this].concat(b)):$.datepicker._attachDatepicker(this,a)})},$.datepicker=new Datepicker,$.datepicker.initialized=!1,$.datepicker.uuid=(new Date).getTime(),$.datepicker.version="1.8.18",window["DP_jQuery_"+dpuuid]=$})(jQuery); /** * This file is modified for powermail localization */ (function($){ $.fn.validationEngineLanguage = function(){ }; $.validationEngineLanguage = { newLang: function(){ $.validationEngineLanguage.allRules = { "required": { // Add your regex rules here, you can take telephone as an example "regex": "none", // "alertText": "* This field is required", "alertText": JsValidationCheckRequired, // "alertTextCheckboxMultiple": "* Please select an option", "alertTextCheckboxMultiple": JsValidationCheckRequiredOption, "alertTextCheckboxe": "Bitte diese Checkbox anhaken", "alertTextDateRange": "* Both date range fields are required" }, "dateRange": { "regex": "none", "alertText": "* Invalid ", "alertText2": "Date Range" }, "dateTimeRange": { "regex": "none", "alertText": "* Invalid ", "alertText2": "Date Time Range" }, "minSize": { "regex": "none", "alertText": "* Minimum ", "alertText2": " characters allowed" }, "maxSize": { "regex": "none", "alertText": "* Maximum ", "alertText2": " characters allowed" }, "groupRequired": { "regex": "none", "alertText": "* You must fill one of the following fields" }, "min": { "regex": "none", "alertText": "* Minimum value is " }, "max": { "regex": "none", "alertText": "* Maximum value is " }, "past": { "regex": "none", "alertText": "* Date prior to " }, "future": { "regex": "none", "alertText": "* Date past " }, "maxCheckbox": { "regex": "none", "alertText": "* Maximum ", "alertText2": " options allowed" }, "minCheckbox": { "regex": "none", "alertText": "* Please select ", "alertText2": " options" }, "equals": { "regex": "none", "alertText": "* Fields do not match" }, "creditCard": { "regex": "none", "alertText": "* Invalid credit card number" }, "phone": { // credit: jquery.h5validate.js / orefalo "regex": /^([\+][0-9]{1,3}[ \.\-])?([\(]{1}[0-9]{2,6}[\)])?([0-9 \.\-\/]{3,20})((x|ext|extension)[ ]?[0-9]{1,4})?$/, // "alertText": "* Invalid phone number" "alertText": JsValidationCheckPhone }, "email": { // Shamelessly lifted from Scott Gonzalez via the Bassistance Validation plugin http://projects.scottsplayground.com/email_address_validation/ "regex": /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i, // "alertText": "* Invalid email address" "alertText": JsValidationCheckEmail }, "integer": { "regex": /^[\-\+]?\d+$/, // "alertText": "* Not a valid integer" "alertText": JsValidationCheckInteger }, "number": { // Number, including positive, negative, and floating decimal. credit: orefalo "regex": /^[\-\+]?(([0-9]+)([\.,]([0-9]+))?|([\.,]([0-9]+))?)$/, "alertText": "* Invalid floating decimal number" }, "date": { "regex": /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/, "alertText": "* Invalid date, must be in YYYY-MM-DD format" }, "ipv4": { "regex": /^((([01]?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5]))[.]){3}(([0-1]?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5]))$/, "alertText": "* Invalid IP address" }, "url": { "regex": /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i, // "alertText": "* Invalid URL" "alertText": JsValidationCheckUrl }, "onlyNumberSp": { "regex": /^[0-9\ ]+$/, "alertText": "* Numbers only" }, "onlyLetterSp": { "regex": /^[a-zA-Z-äöüÄÖÜß\ \']+$/, // "alertText": "* Letters only" "alertText": JsValidationCheckLetters }, "onlyLetterNumber": { "regex": /^[0-9a-zA-Z]+$/, "alertText": "* No special characters allowed" }, // --- CUSTOM RULES -- Those are specific to the demos, they can be removed or changed to your likings "ajaxUserCall": { "url": "ajaxValidateFieldUser", // you may want to pass extra data on the ajax call "extraData": "name=eric", "alertText": "* This user is already taken", "alertTextLoad": "* Validating, please wait" }, "ajaxUserCallPhp": { "url": "phpajax/ajaxValidateFieldUser.php", // you may want to pass extra data on the ajax call "extraData": "name=eric", // if you provide an "alertTextOk", it will show as a green prompt when the field validates "alertTextOk": "* This username is available", "alertText": "* This user is already taken", "alertTextLoad": "* Validating, please wait" }, "ajaxNameCall": { // remote json service location "url": "ajaxValidateFieldName", // error "alertText": "* This name is already taken", // if you provide an "alertTextOk", it will show as a green prompt when the field validates "alertTextOk": "* This name is available", // speaks by itself "alertTextLoad": "* Validating, please wait" }, "ajaxNameCallPhp": { // remote json service location "url": "phpajax/ajaxValidateFieldName.php", // error "alertText": "* This name is already taken", // speaks by itself "alertTextLoad": "* Validating, please wait" }, "validate2fields": { "alertText": "* Please input HELLO" }, //tls warning:homegrown not fielded "dateFormat":{ "regex": /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$|^(?:(?:(?:0?[13578]|1[02])(\/|-)31)|(?:(?:0?[1,3-9]|1[0-2])(\/|-)(?:29|30)))(\/|-)(?:[1-9]\d\d\d|\d[1-9]\d\d|\d\d[1-9]\d|\d\d\d[1-9])$|^(?:(?:0?[1-9]|1[0-2])(\/|-)(?:0?[1-9]|1\d|2[0-8]))(\/|-)(?:[1-9]\d\d\d|\d[1-9]\d\d|\d\d[1-9]\d|\d\d\d[1-9])$|^(0?2(\/|-)29)(\/|-)(?:(?:0[48]00|[13579][26]00|[2468][048]00)|(?:\d\d)?(?:0[48]|[2468][048]|[13579][26]))$/, "alertText": "* Invalid Date" }, //tls warning:homegrown not fielded "dateTimeFormat": { "regex": /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])\s+(1[012]|0?[1-9]){1}:(0?[1-5]|[0-6][0-9]){1}:(0?[0-6]|[0-6][0-9]){1}\s+(am|pm|AM|PM){1}$|^(?:(?:(?:0?[13578]|1[02])(\/|-)31)|(?:(?:0?[1,3-9]|1[0-2])(\/|-)(?:29|30)))(\/|-)(?:[1-9]\d\d\d|\d[1-9]\d\d|\d\d[1-9]\d|\d\d\d[1-9])$|^((1[012]|0?[1-9]){1}\/(0?[1-9]|[12][0-9]|3[01]){1}\/\d{2,4}\s+(1[012]|0?[1-9]){1}:(0?[1-5]|[0-6][0-9]){1}:(0?[0-6]|[0-6][0-9]){1}\s+(am|pm|AM|PM){1})$/, "alertText": "* Invalid Date or Date Format", "alertText2": "Expected Format: ", "alertText3": "mm/dd/yyyy hh:mm:ss AM|PM or ", "alertText4": "yyyy-mm-dd hh:mm:ss AM|PM" }, "creditCardNr": { "regex": /^(?:3[47][0-9]{13})|(?:4[0-9]{12}(?:[0-9]{3})?)|(?:5[1-5][0-9]{14})$/, "alertText": "Bitte geben Sie eine gültige Kartennummer ein" // "alertText": JsValidationCheckLetters }, "expirationDate": { //"regex": /^[Januar]|[Februar]|[März]|[April]|[Mai]|[Juni]|[Juli]|[August]|[September]|[Oktober]|[November]|[Dezember]$/, "regex": /^(Januar|Februar|M\ärz|April|Mai|Juni|Juli|August|September|Oktober|November|Dezember)\s+[0-9]{4}$/, "alertText": "Bitte geben Sie das Ablaufdatum an" // "alertText": JsValidationCheckLetters }, /* powermail new */ "checkCheckboxes": { "alertText": JsValidationCheckCheckboxes } /* powermail new end */ }; } }; $.validationEngineLanguage.newLang(); })(jQuery); /* * Inline Form Validation Engine 2.6, jQuery plugin * * Copyright(c) 2010, Cedric Dugas * http://www.position-absolute.com * * 2.0 Rewrite by Olivier Refalo * http://www.crionics.com * * Form validation engine allowing custom regex rules to be added. * Licensed under the MIT License */ (function($) { "use strict"; var methods = { /** * Kind of the constructor, called before any action * @param {Map} user options */ init: function(options) { var form = this; if (!form.data('jqv') || form.data('jqv') == null ) { options = methods._saveOptions(form, options); // bind all formError elements to close on click $(".formError").live("click", function() { $(this).fadeOut(150, function() { // remove prompt once invisible $(this).parent('.formErrorOuter').remove(); $(this).remove(); }); }); } return this; }, /** * Attachs jQuery.validationEngine to form.submit and field.blur events * Takes an optional params: a list of options * ie. jQuery("#formID1").validationEngine('attach', {promptPosition : "centerRight"}); */ attach: function(userOptions) { if(!$(this).is("form")) { alert("Sorry, jqv.attach() only applies to a form"); return this; } var form = this; var options; if(userOptions) options = methods._saveOptions(form, userOptions); else options = form.data('jqv'); options.validateAttribute = (form.find("[data-validation-engine*=validate]").length) ? "data-validation-engine" : "class"; if (options.binded) { // bind fields form.find("["+options.validateAttribute+"*=validate]").not("[type=checkbox]").not("[type=radio]").not(".datepicker").bind(options.validationEventTrigger, methods._onFieldEvent); form.find("["+options.validateAttribute+"*=validate][type=checkbox],["+options.validateAttribute+"*=validate][type=radio]").bind("click", methods._onFieldEvent); form.find("["+options.validateAttribute+"*=validate][class*=datepicker]").bind(options.validationEventTrigger,{"delay": 300}, methods._onFieldEvent); } if (options.autoPositionUpdate) { $(window).bind("resize", { "noAnimation": true, "formElem": form }, methods.updatePromptsPosition); } // bind form.submit form.bind("submit", methods._onSubmitEvent); return this; }, /** * Unregisters any bindings that may point to jQuery.validaitonEngine */ detach: function() { if(!$(this).is("form")) { alert("Sorry, jqv.detach() only applies to a form"); return this; } var form = this; var options = form.data('jqv'); // unbind fields form.find("["+options.validateAttribute+"*=validate]").not("[type=checkbox]").unbind(options.validationEventTrigger, methods._onFieldEvent); form.find("["+options.validateAttribute+"*=validate][type=checkbox],[class*=validate][type=radio]").unbind("click", methods._onFieldEvent); // unbind form.submit form.unbind("submit", methods.onAjaxFormComplete); // unbind live fields (kill) form.find("["+options.validateAttribute+"*=validate]").not("[type=checkbox]").die(options.validationEventTrigger, methods._onFieldEvent); form.find("["+options.validateAttribute+"*=validate][type=checkbox]").die("click", methods._onFieldEvent); // unbind form.submit form.die("submit", methods.onAjaxFormComplete); form.removeData('jqv'); if (options.autoPositionUpdate) $(window).unbind("resize", methods.updatePromptsPosition); return this; }, /** * Validates either a form or a list of fields, shows prompts accordingly. * Note: There is no ajax form validation with this method, only field ajax validation are evaluated * * @return true if the form validates, false if it fails */ validate: function() { if($(this).is("form")) return methods._validateFields(this); else { // field validation var form = $(this).closest('form'); var options = form.data('jqv'); var r = methods._validateField($(this), options); if (options.onSuccess && options.InvalidFields.length == 0) options.onSuccess(); else if (options.onFailure && options.InvalidFields.length > 0) options.onFailure(); return r; } }, /** * Redraw prompts position, useful when you change the DOM state when validating */ updatePromptsPosition: function(event) { if (event && this == window) { var form = event.data.formElem; var noAnimation = event.data.noAnimation; } else var form = $(this.closest('form')); var options = form.data('jqv'); // No option, take default one form.find('['+options.validateAttribute+'*=validate]').not(":disabled").each(function(){ var field = $(this); var prompt = methods._getPrompt(field); var promptText = $(prompt).find(".formErrorContent").html(); if(prompt) methods._updatePrompt(field, $(prompt), promptText, undefined, false, options, noAnimation); }); return this; }, /** * Displays a prompt on a element. * Note that the element needs an id! * * @param {String} promptText html text to display type * @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red) * @param {String} possible values topLeft, topRight, bottomLeft, centerRight, bottomRight */ showPrompt: function(promptText, type, promptPosition, showArrow) { var form = this.closest('form'); var options = form.data('jqv'); // No option, take default one if(!options) options = methods._saveOptions(this, options); if(promptPosition) options.promptPosition=promptPosition; options.showArrow = showArrow==true; methods._showPrompt(this, promptText, type, false, options); return this; }, /** * Closes form error prompts, CAN be invidual */ hide: function() { var form = $(this).closest('form'); if(form.length == 0) return this; var options = form.data('jqv'); var closingtag; if($(this).is("form")) { closingtag = "parentForm"+methods._getClassName($(this).attr("id")); } else { closingtag = methods._getClassName($(this).attr("id")) +"formError"; } $('.'+closingtag).fadeTo(options.fadeDuration, 0.3, function() { $(this).parent('.formErrorOuter').remove(); $(this).remove(); }); return this; }, /** * Closes all error prompts on the page */ hideAll: function() { var form = this; var options = form.data('jqv'); var duration = options ? options.fadeDuration:0.3; $('.formError').fadeTo(duration, 0.3, function() { $(this).parent('.formErrorOuter').remove(); $(this).remove(); }); return this; }, /** * Typically called when user exists a field using tab or a mouse click, triggers a field * validation */ _onFieldEvent: function(event) { var field = $(this); var form = field.closest('form'); var options = form.data('jqv'); options.eventTrigger = "field"; // validate the current field window.setTimeout(function() { methods._validateField(field, options); if (options.InvalidFields.length == 0 && options.onSuccess) { options.onSuccess(); } else if (options.InvalidFields.length > 0 && options.onFailure) { options.onFailure(); } }, (event.data) ? event.data.delay : 0); }, /** * Called when the form is submited, shows prompts accordingly * * @param {jqObject} * form * @return false if form submission needs to be cancelled */ _onSubmitEvent: function() { var form = $(this); var options = form.data('jqv'); options.eventTrigger = "submit"; // validate each field // (- skip field ajax validation, not necessary IF we will perform an ajax form validation) var r=methods._validateFields(form); if (r && options.ajaxFormValidation) { methods._validateFormWithAjax(form, options); // cancel form auto-submission - process with async call onAjaxFormComplete return false; } if(options.onValidationComplete) { // !! ensures that an undefined return is interpreted as return false but allows a onValidationComplete() to possibly return true and have form continue processing return !!options.onValidationComplete(form, r); } return r; }, /** * Return true if the ajax field validations passed so far * @param {Object} options * @return true, is all ajax validation passed so far (remember ajax is async) */ _checkAjaxStatus: function(options) { var status = true; $.each(options.ajaxValidCache, function(key, value) { if (!value) { status = false; // break the each return false; } }); return status; }, /** * Return true if the ajax field is validated * @param {String} fieldid * @param {Object} options * @return true, if validation passed, false if false or doesn't exist */ _checkAjaxFieldStatus: function(fieldid, options) { return options.ajaxValidCache[fieldid] == true; }, /** * Validates form fields, shows prompts accordingly * * @param {jqObject} * form * @param {skipAjaxFieldValidation} * boolean - when set to true, ajax field validation is skipped, typically used when the submit button is clicked * * @return true if form is valid, false if not, undefined if ajax form validation is done */ _validateFields: function(form) { var options = form.data('jqv'); // this variable is set to true if an error is found var errorFound = false; // Trigger hook, start validation form.trigger("jqv.form.validating"); // first, evaluate status of non ajax fields var first_err=null; form.find('['+options.validateAttribute+'*=validate]').not(":disabled").each( function() { var field = $(this); var names = []; if ($.inArray(field.attr('name'), names) < 0) { errorFound |= methods._validateField(field, options); if (errorFound && first_err==null) if (field.is(":hidden") && options.prettySelect) first_err = field = form.find("#" + options.usePrefix + field.attr('id') + options.useSuffix); else first_err=field; if (options.doNotShowAllErrosOnSubmit) return false; names.push(field.attr('name')); } }); // second, check to see if all ajax calls completed ok // errorFound |= !methods._checkAjaxStatus(options); // third, check status and scroll the container accordingly form.trigger("jqv.form.result", [errorFound]); if (errorFound) { if (options.scroll) { var destination=first_err.offset().top; var fixleft = first_err.offset().left; //prompt positioning adjustment support. Usage: positionType:Xshift,Yshift (for ex.: bottomLeft:+20 or bottomLeft:-20,+10) var positionType=options.promptPosition; if (typeof(positionType)=='string' && positionType.indexOf(":")!=-1) positionType=positionType.substring(0,positionType.indexOf(":")); if (positionType!="bottomRight" && positionType!="bottomLeft") { var prompt_err= methods._getPrompt(first_err); destination=prompt_err.offset().top; } // get the position of the first error, there should be at least one, no need to check this //var destination = form.find(".formError:not('.greenPopup'):first").offset().top; if (options.isOverflown) { var overflowDIV = $(options.overflownDIV); if(!overflowDIV.length) return false; var scrollContainerScroll = overflowDIV.scrollTop(); var scrollContainerPos = -parseInt(overflowDIV.offset().top); destination += scrollContainerScroll + scrollContainerPos - 5; var scrollContainer = $(options.overflownDIV + ":not(:animated)"); scrollContainer.animate({ scrollTop: destination }, 1100, function(){ if(options.focusFirstField) first_err.focus(); }); } else { $("html:not(:animated),body:not(:animated)").animate({ scrollTop: destination, scrollLeft: fixleft }, 1100, function(){ if(options.focusFirstField) first_err.focus(); }); } } else if(options.focusFirstField) first_err.focus(); return false; } return true; }, /** * This method is called to perform an ajax form validation. * During this process all the (field, value) pairs are sent to the server which returns a list of invalid fields or true * * @param {jqObject} form * @param {Map} options */ _validateFormWithAjax: function(form, options) { var data = form.serialize(); var type = (options.ajaxmethod) ? options.ajaxmethod : "GET"; var url = (options.ajaxFormValidationURL) ? options.ajaxFormValidationURL : form.attr("action"); var dataType = (options.dataType) ? options.dataType : "json"; $.ajax({ type: type, url: url, cache: false, dataType: dataType, data: data, form: form, methods: methods, options: options, beforeSend: function() { return options.onBeforeAjaxFormValidation(form, options); }, error: function(data, transport) { methods._ajaxError(data, transport); }, success: function(json) { if (json !== true) { // getting to this case doesn't necessary means that the form is invalid // the server may return green or closing prompt actions // this flag helps figuring it out var errorInForm=false; for (var i = 0; i < json.length; i++) { var value = json[i]; var errorFieldId = value[0]; var errorField = $($("#" + errorFieldId)[0]); // make sure we found the element if (errorField.length == 1) { // promptText or selector var msg = value[2]; // if the field is valid if (value[1] == true) { if (msg == "" || !msg){ // if for some reason, status==true and error="", just close the prompt methods._closePrompt(errorField); } else { // the field is valid, but we are displaying a green prompt if (options.allrules[msg]) { var txt = options.allrules[msg].alertTextOk; if (txt) msg = txt; } methods._showPrompt(errorField, msg, "pass", false, options, true); } } else { // the field is invalid, show the red error prompt errorInForm|=true; if (options.allrules[msg]) { var txt = options.allrules[msg].alertText; if (txt) msg = txt; } methods._showPrompt(errorField, msg, "", false, options, true); } } } options.onAjaxFormComplete(!errorInForm, form, json, options); } else options.onAjaxFormComplete(true, form, "", options); } }); }, /** * Validates field, shows prompts accordingly * * @param {jqObject} * field * @param {Array[String]} * field's validation rules * @param {Map} * user options * @return false if field is valid (It is inversed for *fields*, it return false on validate and true on errors.) */ _validateField: function(field, options, skipAjaxValidation) { if (!field.attr("id")) { field.attr("id", "form-validation-field-" + $.validationEngine.fieldIdCounter); ++$.validationEngine.fieldIdCounter; } if (field.is(":hidden") && !options.prettySelect || field.parent().is(":hidden")) return false; var rulesParsing = field.attr(options.validateAttribute); var getRules = /validate\[(.*)\]/.exec(rulesParsing); if (!getRules) return false; var str = getRules[1]; var rules = str.split(/\[|,|\]/); // true if we ran the ajax validation, tells the logic to stop messing with prompts var isAjaxValidator = false; var fieldName = field.attr("name"); var promptText = ""; var promptType = ""; var required = false; options.isError = false; options.showArrow = true; var form = $(field.closest("form")); for (var i = 0; i < rules.length; i++) { // Fix for adding spaces in the rules rules[i] = rules[i].replace(" ", ""); var errorMsg = undefined; switch (rules[i]) { case "required": required = true; errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._required); break; case "custom": errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._custom); break; case "groupRequired": // Check is its the first of group, if not, reload validation with first field // AND continue normal validation on present field var classGroup = "["+options.validateAttribute+"*=" +rules[i + 1] +"]"; var firstOfGroup = form.find(classGroup).eq(0); if(firstOfGroup[0] != field[0]){ methods._validateField(firstOfGroup, options, skipAjaxValidation); options.showArrow = true; continue; } errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._groupRequired); if(errorMsg) required = true; options.showArrow = false; break; case "ajax": // AJAX defaults to returning it's loading message errorMsg = methods._ajax(field, rules, i, options); if (errorMsg) { promptType = "load"; } break; case "minSize": errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._minSize); break; case "maxSize": errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._maxSize); break; case "min": errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._min); break; case "max": errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._max); break; case "past": errorMsg = methods._getErrorMessage(form, field,rules[i], rules, i, options, methods._past); break; case "future": errorMsg = methods._getErrorMessage(form, field,rules[i], rules, i, options, methods._future); break; case "dateRange": var classGroup = "["+options.validateAttribute+"*=" + rules[i + 1] + "]"; options.firstOfGroup = form.find(classGroup).eq(0); options.secondOfGroup = form.find(classGroup).eq(1); //if one entry out of the pair has value then proceed to run through validation if (options.firstOfGroup[0].value || options.secondOfGroup[0].value) { errorMsg = methods._getErrorMessage(form, field,rules[i], rules, i, options, methods._dateRange); } if (errorMsg) required = true; options.showArrow = false; break; case "dateTimeRange": var classGroup = "["+options.validateAttribute+"*=" + rules[i + 1] + "]"; options.firstOfGroup = form.find(classGroup).eq(0); options.secondOfGroup = form.find(classGroup).eq(1); //if one entry out of the pair has value then proceed to run through validation if (options.firstOfGroup[0].value || options.secondOfGroup[0].value) { errorMsg = methods._getErrorMessage(form, field,rules[i], rules, i, options, methods._dateTimeRange); } if (errorMsg) required = true; options.showArrow = false; break; case "maxCheckbox": field = $(form.find("input[name='" + fieldName + "']")); errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._maxCheckbox); break; case "minCheckbox": field = $(form.find("input[name='" + fieldName + "']")); errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._minCheckbox); break; case "equals": errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._equals); break; case "funcCall": errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._funcCall); break; case "creditCard": errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._creditCard); break; case "condRequired": errorMsg = methods._getErrorMessage(form, field, rules[i], rules, i, options, methods._condRequired); if (errorMsg !== undefined) { required = true; } break; default: } if (errorMsg !== undefined) { promptText += errorMsg + "
"; options.isError = true; } //if option set, stop checking validation rules after one error is found if(options.showOneMessage === true && options.isError === true) break; } // If the rules required is not added, an empty field is not validated if(!required && field.val().length < 1) options.isError = false; // Hack for radio/checkbox group button, the validation go into the // first radio/checkbox of the group var fieldType = field.prop("type"); if ((fieldType == "radio" || fieldType == "checkbox") && form.find("input[name='" + fieldName + "']").size() > 1) { field = $(form.find("input[name='" + fieldName + "'][type!=hidden]:first")); options.showArrow = false; } if(field.is(":hidden") && options.prettySelect) { field = form.find("#" + options.usePrefix + field.attr('id') + options.useSuffix); } if (options.isError){ methods._showPrompt(field, promptText, promptType, false, options); }else{ if (!isAjaxValidator) methods._closePrompt(field); } if (!isAjaxValidator) { field.trigger("jqv.field.result", [field, options.isError, promptText]); } /* Record error */ var errindex = $.inArray(field[0], options.InvalidFields); if (errindex == -1) { if (options.isError) options.InvalidFields.push(field[0]); } else if (!options.isError) { options.InvalidFields.splice(errindex, 1); } return options.isError; }, /******************** * _getErrorMessage * * @param form * @param field * @param rule * @param rules * @param i * @param options * @param originalValidationMethod * @return {*} * @private */ _getErrorMessage:function (form, field, rule, rules, i, options, originalValidationMethod) { // If we are using the custon validation type, build the index for the rule. // Otherwise if we are doing a function call, make the call and return the object // that is passed back. var beforeChangeRule = rule; if (rule == "custom") { var custom_validation_type_index = jQuery.inArray(rule, rules)+ 1; var custom_validation_type = rules[custom_validation_type_index]; rule = "custom[" + custom_validation_type + "]"; } var element_classes = (field.attr("data-validation-engine")) ? field.attr("data-validation-engine") : field.attr("class"); var element_classes_array = element_classes.split(" "); // Call the original validation method. If we are dealing with dates, also pass the form var errorMsg; if (rule == "future" || rule == "past" || rule == "maxCheckbox" || rule == "minCheckbox") { errorMsg = originalValidationMethod(form, field, rules, i, options); } else { errorMsg = originalValidationMethod(field, rules, i, options); } // If the original validation method returned an error and we have a custom error message, // return the custom message instead. Otherwise return the original error message. if (errorMsg != undefined) { var custom_message = methods._getCustomErrorMessage($(field), element_classes_array, beforeChangeRule, options); if (custom_message) return custom_message; } return errorMsg; }, _getCustomErrorMessage:function (field, classes, rule, options) { var custom_message = false; var validityProp = methods._validityProp[rule]; if (validityProp != undefined) { custom_message = field.attr("data-errormessage-"+validityProp); if (custom_message != undefined) return custom_message; } custom_message = field.attr("data-errormessage"); if (custom_message != undefined) return custom_message; var id = '#' + field.attr("id"); // If we have custom messages for the element's id, get the message for the rule from the id. // Otherwise, if we have custom messages for the element's classes, use the first class message we find instead. if (typeof options.custom_error_messages[id] != "undefined" && typeof options.custom_error_messages[id][rule] != "undefined" ) { custom_message = options.custom_error_messages[id][rule]['message']; } else if (classes.length > 0) { for (var i = 0; i < classes.length && classes.length > 0; i++) { var element_class = "." + classes[i]; if (typeof options.custom_error_messages[element_class] != "undefined" && typeof options.custom_error_messages[element_class][rule] != "undefined") { custom_message = options.custom_error_messages[element_class][rule]['message']; break; } } } if (!custom_message && typeof options.custom_error_messages[rule] != "undefined" && typeof options.custom_error_messages[rule]['message'] != "undefined"){ custom_message = options.custom_error_messages[rule]['message']; } return custom_message; }, _validityProp: { "required": "value-missing", "custom": "custom-error", "groupRequired": "value-missing", "ajax": "custom-error", "minSize": "range-underflow", "maxSize": "range-overflow", "min": "range-underflow", "max": "range-overflow", "past": "type-mismatch", "future": "type-mismatch", "dateRange": "type-mismatch", "dateTimeRange": "type-mismatch", "maxCheckbox": "range-overflow", "minCheckbox": "range-underflow", "equals": "pattern-mismatch", "funcCall": "custom-error", "creditCard": "pattern-mismatch", "condRequired": "value-missing" }, /** * Required validation * * @param {jqObject} field * @param {Array[String]} rules * @param {int} i rules index * @param {Map} * user options * @return an error string if validation failed */ _required: function(field, rules, i, options) { switch (field.prop("type")) { case "text": case "password": case "textarea": case "file": case "select-one": case "select-multiple": default: if (! $.trim(field.val()) || field.val() == field.attr("data-validation-placeholder") || field.val() == field.attr("placeholder")) return options.allrules[rules[i]].alertText; break; case "radio": case "checkbox": var form = field.closest("form"); var name = field.attr("name"); if (form.find("input[name='" + name + "']:checked").size() == 0) { if (form.find("input[name='" + name + "']:visible").size() == 1) return options.allrules[rules[i]].alertTextCheckboxe; else return options.allrules[rules[i]].alertTextCheckboxMultiple; } break; } }, /** * Validate that 1 from the group field is required * * @param {jqObject} field * @param {Array[String]} rules * @param {int} i rules index * @param {Map} * user options * @return an error string if validation failed */ _groupRequired: function(field, rules, i, options) { var classGroup = "["+options.validateAttribute+"*=" +rules[i + 1] +"]"; var isValid = false; // Check all fields from the group field.closest("form").find(classGroup).each(function(){ if(!methods._required($(this), rules, i, options)){ isValid = true; return false; } }); if(!isValid) { return options.allrules[rules[i]].alertText; } }, /** * Validate rules * * @param {jqObject} field * @param {Array[String]} rules * @param {int} i rules index * @param {Map} * user options * @return an error string if validation failed */ _custom: function(field, rules, i, options) { var customRule = rules[i + 1]; var rule = options.allrules[customRule]; var fn; if(!rule) { alert("jqv:custom rule not found - "+customRule); return; } if(rule["regex"]) { var ex=rule.regex; if(!ex) { alert("jqv:custom regex not found - "+customRule); return; } var pattern = new RegExp(ex); if (!pattern.test(field.val())) return options.allrules[customRule].alertText; } else if(rule["func"]) { fn = rule["func"]; if (typeof(fn) !== "function") { alert("jqv:custom parameter 'function' is no function - "+customRule); return; } if (!fn(field, rules, i, options)) return options.allrules[customRule].alertText; } else { alert("jqv:custom type not allowed "+customRule); return; } }, /** * Validate custom function outside of the engine scope * * @param {jqObject} field * @param {Array[String]} rules * @param {int} i rules index * @param {Map} * user options * @return an error string if validation failed */ _funcCall: function(field, rules, i, options) { var functionName = rules[i + 1]; var fn; if(functionName.indexOf('.') >-1) { var namespaces = functionName.split('.'); var scope = window; while(namespaces.length) { scope = scope[namespaces.shift()]; } fn = scope; } else fn = window[functionName] || options.customFunctions[functionName]; if (typeof(fn) == 'function') return fn(field, rules, i, options); }, /** * Field match * * @param {jqObject} field * @param {Array[String]} rules * @param {int} i rules index * @param {Map} * user options * @return an error string if validation failed */ _equals: function(field, rules, i, options) { var equalsField = rules[i + 1]; if (field.val() != $("#" + equalsField).val()) return options.allrules.equals.alertText; }, /** * Check the maximum size (in characters) * * @param {jqObject} field * @param {Array[String]} rules * @param {int} i rules index * @param {Map} * user options * @return an error string if validation failed */ _maxSize: function(field, rules, i, options) { var max = rules[i + 1]; var len = field.val().length; if (len > max) { var rule = options.allrules.maxSize; return rule.alertText + max + rule.alertText2; } }, /** * Check the minimum size (in characters) * * @param {jqObject} field * @param {Array[String]} rules * @param {int} i rules index * @param {Map} * user options * @return an error string if validation failed */ _minSize: function(field, rules, i, options) { var min = rules[i + 1]; var len = field.val().length; if (len < min) { var rule = options.allrules.minSize; return rule.alertText + min + rule.alertText2; } }, /** * Check number minimum value * * @param {jqObject} field * @param {Array[String]} rules * @param {int} i rules index * @param {Map} * user options * @return an error string if validation failed */ _min: function(field, rules, i, options) { var min = parseFloat(rules[i + 1]); var len = parseFloat(field.val()); if (len < min) { var rule = options.allrules.min; if (rule.alertText2) return rule.alertText + min + rule.alertText2; return rule.alertText + min; } }, /** * Check number maximum value * * @param {jqObject} field * @param {Array[String]} rules * @param {int} i rules index * @param {Map} * user options * @return an error string if validation failed */ _max: function(field, rules, i, options) { var max = parseFloat(rules[i + 1]); var len = parseFloat(field.val()); if (len >max ) { var rule = options.allrules.max; if (rule.alertText2) return rule.alertText + max + rule.alertText2; //orefalo: to review, also do the translations return rule.alertText + max; } }, /** * Checks date is in the past * * @param {jqObject} field * @param {Array[String]} rules * @param {int} i rules index * @param {Map} * user options * @return an error string if validation failed */ _past: function(form, field, rules, i, options) { var p=rules[i + 1]; var fieldAlt = $(form.find("input[name='" + p.replace(/^#+/, '') + "']")); var pdate; if (p.toLowerCase() == "now") { pdate = new Date(); } else if (undefined != fieldAlt.val()) { if (fieldAlt.is(":disabled")) return; pdate = methods._parseDate(fieldAlt.val()); } else { pdate = methods._parseDate(p); } var vdate = methods._parseDate(field.val()); if (vdate > pdate ) { var rule = options.allrules.past; if (rule.alertText2) return rule.alertText + methods._dateToString(pdate) + rule.alertText2; return rule.alertText + methods._dateToString(pdate); } }, /** * Checks date is in the future * * @param {jqObject} field * @param {Array[String]} rules * @param {int} i rules index * @param {Map} * user options * @return an error string if validation failed */ _future: function(form, field, rules, i, options) { var p=rules[i + 1]; var fieldAlt = $(form.find("input[name='" + p.replace(/^#+/, '') + "']")); var pdate; if (p.toLowerCase() == "now") { pdate = new Date(); } else if (undefined != fieldAlt.val()) { if (fieldAlt.is(":disabled")) return; pdate = methods._parseDate(fieldAlt.val()); } else { pdate = methods._parseDate(p); } var vdate = methods._parseDate(field.val()); if (vdate < pdate ) { var rule = options.allrules.future; if (rule.alertText2) return rule.alertText + methods._dateToString(pdate) + rule.alertText2; return rule.alertText + methods._dateToString(pdate); } }, /** * Checks if valid date * * @param {string} date string * @return a bool based on determination of valid date */ _isDate: function (value) { var dateRegEx = new RegExp(/^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$|^(?:(?:(?:0?[13578]|1[02])(\/|-)31)|(?:(?:0?[1,3-9]|1[0-2])(\/|-)(?:29|30)))(\/|-)(?:[1-9]\d\d\d|\d[1-9]\d\d|\d\d[1-9]\d|\d\d\d[1-9])$|^(?:(?:0?[1-9]|1[0-2])(\/|-)(?:0?[1-9]|1\d|2[0-8]))(\/|-)(?:[1-9]\d\d\d|\d[1-9]\d\d|\d\d[1-9]\d|\d\d\d[1-9])$|^(0?2(\/|-)29)(\/|-)(?:(?:0[48]00|[13579][26]00|[2468][048]00)|(?:\d\d)?(?:0[48]|[2468][048]|[13579][26]))$/); return dateRegEx.test(value); }, /** * Checks if valid date time * * @param {string} date string * @return a bool based on determination of valid date time */ _isDateTime: function (value){ var dateTimeRegEx = new RegExp(/^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])\s+(1[012]|0?[1-9]){1}:(0?[1-5]|[0-6][0-9]){1}:(0?[0-6]|[0-6][0-9]){1}\s+(am|pm|AM|PM){1}$|^(?:(?:(?:0?[13578]|1[02])(\/|-)31)|(?:(?:0?[1,3-9]|1[0-2])(\/|-)(?:29|30)))(\/|-)(?:[1-9]\d\d\d|\d[1-9]\d\d|\d\d[1-9]\d|\d\d\d[1-9])$|^((1[012]|0?[1-9]){1}\/(0?[1-9]|[12][0-9]|3[01]){1}\/\d{2,4}\s+(1[012]|0?[1-9]){1}:(0?[1-5]|[0-6][0-9]){1}:(0?[0-6]|[0-6][0-9]){1}\s+(am|pm|AM|PM){1})$/); return dateTimeRegEx.test(value); }, //Checks if the start date is before the end date //returns true if end is later than start _dateCompare: function (start, end) { return (new Date(start.toString()) < new Date(end.toString())); }, /** * Checks date range * * @param {jqObject} first field name * @param {jqObject} second field name * @return an error string if validation failed */ _dateRange: function (field, rules, i, options) { //are not both populated if ((!options.firstOfGroup[0].value && options.secondOfGroup[0].value) || (options.firstOfGroup[0].value && !options.secondOfGroup[0].value)) { return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2; } //are not both dates if (!methods._isDate(options.firstOfGroup[0].value) || !methods._isDate(options.secondOfGroup[0].value)) { return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2; } //are both dates but range is off if (!methods._dateCompare(options.firstOfGroup[0].value, options.secondOfGroup[0].value)) { return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2; } }, /** * Checks date time range * * @param {jqObject} first field name * @param {jqObject} second field name * @return an error string if validation failed */ _dateTimeRange: function (field, rules, i, options) { //are not both populated if ((!options.firstOfGroup[0].value && options.secondOfGroup[0].value) || (options.firstOfGroup[0].value && !options.secondOfGroup[0].value)) { return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2; } //are not both dates if (!methods._isDateTime(options.firstOfGroup[0].value) || !methods._isDateTime(options.secondOfGroup[0].value)) { return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2; } //are both dates but range is off if (!methods._dateCompare(options.firstOfGroup[0].value, options.secondOfGroup[0].value)) { return options.allrules[rules[i]].alertText + options.allrules[rules[i]].alertText2; } }, /** * Max number of checkbox selected * * @param {jqObject} field * @param {Array[String]} rules * @param {int} i rules index * @param {Map} * user options * @return an error string if validation failed */ _maxCheckbox: function(form, field, rules, i, options) { var nbCheck = rules[i + 1]; var groupname = field.attr("name"); var groupSize = form.find("input[name='" + groupname + "']:checked").size(); if (groupSize > nbCheck) { options.showArrow = false; if (options.allrules.maxCheckbox.alertText2) return options.allrules.maxCheckbox.alertText + " " + nbCheck + " " + options.allrules.maxCheckbox.alertText2; return options.allrules.maxCheckbox.alertText; } }, /** * Min number of checkbox selected * * @param {jqObject} field * @param {Array[String]} rules * @param {int} i rules index * @param {Map} * user options * @return an error string if validation failed */ _minCheckbox: function(form, field, rules, i, options) { var nbCheck = rules[i + 1]; var groupname = field.attr("name"); var groupSize = form.find("input[name='" + groupname + "']:checked").size(); if (groupSize < nbCheck) { options.showArrow = false; return options.allrules.minCheckbox.alertText + " " + nbCheck + " " + options.allrules.minCheckbox.alertText2; } }, /** * Checks that it is a valid credit card number according to the * Luhn checksum algorithm. * * @param {jqObject} field * @param {Array[String]} rules * @param {int} i rules index * @param {Map} * user options * @return an error string if validation failed */ _creditCard: function(field, rules, i, options) { //spaces and dashes may be valid characters, but must be stripped to calculate the checksum. var valid = false, cardNumber = field.val().replace(/ +/g, '').replace(/-+/g, ''); var numDigits = cardNumber.length; if (numDigits >= 14 && numDigits <= 16 && parseInt(cardNumber) > 0) { var sum = 0, i = numDigits - 1, pos = 1, digit, luhn = new String(); do { digit = parseInt(cardNumber.charAt(i)); luhn += (pos++ % 2 == 0) ? digit * 2 : digit; } while (--i >= 0) for (i = 0; i < luhn.length; i++) { sum += parseInt(luhn.charAt(i)); } valid = sum % 10 == 0; } if (!valid) return options.allrules.creditCard.alertText; }, /** * Ajax field validation * * @param {jqObject} field * @param {Array[String]} rules * @param {int} i rules index * @param {Map} * user options * @return nothing! the ajax validator handles the prompts itself */ _ajax: function(field, rules, i, options) { var errorSelector = rules[i + 1]; var rule = options.allrules[errorSelector]; var extraData = rule.extraData; var extraDataDynamic = rule.extraDataDynamic; var data = { "fieldId" : field.attr("id"), "fieldValue" : field.val() }; if (typeof extraData === "object") { $.extend(data, extraData); } else if (typeof extraData === "string") { var tempData = extraData.split("&"); for(var i = 0; i < tempData.length; i++) { var values = tempData[i].split("="); if (values[0] && values[0]) { data[values[0]] = values[1]; } } } if (extraDataDynamic) { var tmpData = []; var domIds = String(extraDataDynamic).split(","); for (var i = 0; i < domIds.length; i++) { var id = domIds[i]; if ($(id).length) { var inputValue = field.closest("form").find(id).val(); var keyValue = id.replace('#', '') + '=' + escape(inputValue); data[id.replace('#', '')] = inputValue; } } } // If a field change event triggered this we want to clear the cache for this ID if (options.eventTrigger == "field") { delete(options.ajaxValidCache[field.attr("id")]); } // If there is an error or if the the field is already validated, do not re-execute AJAX if (!options.isError && !methods._checkAjaxFieldStatus(field.attr("id"), options)) { $.ajax({ type: options.ajaxFormValidationMethod, url: rule.url, cache: false, dataType: "json", data: data, field: field, rule: rule, methods: methods, options: options, beforeSend: function() {}, error: function(data, transport) { methods._ajaxError(data, transport); }, success: function(json) { // asynchronously called on success, data is the json answer from the server var errorFieldId = json[0]; //var errorField = $($("#" + errorFieldId)[0]); var errorField = $($("input[id='" + errorFieldId +"']")[0]); // make sure we found the element if (errorField.length == 1) { var status = json[1]; // read the optional msg from the server var msg = json[2]; if (!status) { // Houston we got a problem - display an red prompt options.ajaxValidCache[errorFieldId] = false; options.isError = true; // resolve the msg prompt if(msg) { if (options.allrules[msg]) { var txt = options.allrules[msg].alertText; if (txt) { msg = txt; } } } else msg = rule.alertText; methods._showPrompt(errorField, msg, "", true, options); } else { options.ajaxValidCache[errorFieldId] = true; // resolves the msg prompt if(msg) { if (options.allrules[msg]) { var txt = options.allrules[msg].alertTextOk; if (txt) { msg = txt; } } } else msg = rule.alertTextOk; // see if we should display a green prompt if (msg) methods._showPrompt(errorField, msg, "pass", true, options); else methods._closePrompt(errorField); // If a submit form triggered this, we want to re-submit the form if (options.eventTrigger == "submit") field.closest("form").submit(); } } errorField.trigger("jqv.field.result", [errorField, options.isError, msg]); } }); return rule.alertTextLoad; } }, /** * Common method to handle ajax errors * * @param {Object} data * @param {Object} transport */ _ajaxError: function(data, transport) { if(data.status == 0 && transport == null) alert("The page is not served from a server! ajax call failed"); else if(typeof console != "undefined") console.log("Ajax error: " + data.status + " " + transport); }, /** * date -> string * * @param {Object} date */ _dateToString: function(date) { return date.getFullYear()+"-"+(date.getMonth()+1)+"-"+date.getDate(); }, /** * Parses an ISO date * @param {String} d */ _parseDate: function(d) { var dateParts = d.split("-"); if(dateParts==d) dateParts = d.split("/"); return new Date(dateParts[0], (dateParts[1] - 1) ,dateParts[2]); }, /** * Builds or updates a prompt with the given information * * @param {jqObject} field * @param {String} promptText html text to display type * @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red) * @param {boolean} ajaxed - use to mark fields than being validated with ajax * @param {Map} options user options */ _showPrompt: function(field, promptText, type, ajaxed, options, ajaxform) { var prompt = methods._getPrompt(field); // The ajax submit errors are not see has an error in the form, // When the form errors are returned, the engine see 2 bubbles, but those are ebing closed by the engine at the same time // Because no error was found befor submitting if(ajaxform) prompt = false; if (prompt) methods._updatePrompt(field, prompt, promptText, type, ajaxed, options); else methods._buildPrompt(field, promptText, type, ajaxed, options); }, /** * Builds and shades a prompt for the given field. * * @param {jqObject} field * @param {String} promptText html text to display type * @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red) * @param {boolean} ajaxed - use to mark fields than being validated with ajax * @param {Map} options user options */ _buildPrompt: function(field, promptText, type, ajaxed, options) { // create the prompt var prompt = $('
'); prompt.addClass(methods._getClassName(field.attr("id")) + "formError"); // add a class name to identify the parent form of the prompt prompt.addClass("parentForm"+methods._getClassName(field.parents('form').attr("id"))); prompt.addClass("formError"); switch (type) { case "pass": prompt.addClass("greenPopup"); break; case "load": prompt.addClass("blackPopup"); break; default: /* it has error */ //alert("unknown popup type:"+type); } if (ajaxed) prompt.addClass("ajaxed"); // create the prompt content var promptContent = $('
').addClass("formErrorContent").html(promptText).appendTo(prompt); // create the css arrow pointing at the field // note that there is no triangle on max-checkbox and radio if (options.showArrow) { var arrow = $('
').addClass("formErrorArrow"); //prompt positioning adjustment support. Usage: positionType:Xshift,Yshift (for ex.: bottomLeft:+20 or bottomLeft:-20,+10) var positionType=field.data("promptPosition") || options.promptPosition; if (typeof(positionType)=='string') { var pos=positionType.indexOf(":"); if(pos!=-1) positionType=positionType.substring(0,pos); } switch (positionType) { case "bottomLeft": case "bottomRight": prompt.find(".formErrorContent").before(arrow); arrow.addClass("formErrorArrowBottom").html('
'); break; case "topLeft": case "topRight": arrow.html('
'); prompt.append(arrow); break; } } // Modify z-indexes for jquery ui if (field.closest('.ui-dialog').length) prompt.addClass('formErrorInsideDialog'); prompt.css({ "opacity": 0, 'position':'absolute' }); field.before(prompt); var pos = methods._calculatePosition(field, prompt, options); prompt.css({ "top": pos.callerTopPosition, "left": pos.callerleftPosition, "marginTop": pos.marginTopSize, "opacity": 0 }).data("callerField", field); if (options.autoHidePrompt) { setTimeout(function(){ prompt.animate({ "opacity": 0 },function(){ prompt.closest('.formErrorOuter').remove(); prompt.remove(); }); }, options.autoHideDelay); } return prompt.animate({ "opacity": 0.87 }); }, /** * Updates the prompt text field - the field for which the prompt * @param {jqObject} field * @param {String} promptText html text to display type * @param {String} type the type of bubble: 'pass' (green), 'load' (black) anything else (red) * @param {boolean} ajaxed - use to mark fields than being validated with ajax * @param {Map} options user options */ _updatePrompt: function(field, prompt, promptText, type, ajaxed, options, noAnimation) { if (prompt) { if (typeof type !== "undefined") { if (type == "pass") prompt.addClass("greenPopup"); else prompt.removeClass("greenPopup"); if (type == "load") prompt.addClass("blackPopup"); else prompt.removeClass("blackPopup"); } if (ajaxed) prompt.addClass("ajaxed"); else prompt.removeClass("ajaxed"); prompt.find(".formErrorContent").html(promptText); var pos = methods._calculatePosition(field, prompt, options); var css = {"top": pos.callerTopPosition, "left": pos.callerleftPosition, "marginTop": pos.marginTopSize}; if (noAnimation) prompt.css(css); else prompt.animate(css); } }, /** * Closes the prompt associated with the given field * * @param {jqObject} * field */ _closePrompt: function(field) { var prompt = methods._getPrompt(field); if (prompt) prompt.fadeTo("fast", 0, function() { prompt.parent('.formErrorOuter').remove(); prompt.remove(); }); }, closePrompt: function(field) { return methods._closePrompt(field); }, /** * Returns the error prompt matching the field if any * * @param {jqObject} * field * @return undefined or the error prompt (jqObject) */ _getPrompt: function(field) { var formId = $(field).closest('form').attr('id'); var className = methods._getClassName(field.attr("id")) + "formError"; var match = $("." + methods._escapeExpression(className) + '.parentForm' + formId)[0]; if (match) return $(match); }, /** * Returns the escapade classname * * @param {selector} * className */ _escapeExpression: function (selector) { return selector.replace(/([#;&,\.\+\*\~':"\!\^$\[\]\(\)=>\|])/g, "\\$1"); }, /** * returns true if we are in a RTLed document * * @param {jqObject} field */ isRTL: function(field) { var $document = $(document); var $body = $('body'); var rtl = (field && field.hasClass('rtl')) || (field && (field.attr('dir') || '').toLowerCase()==='rtl') || $document.hasClass('rtl') || ($document.attr('dir') || '').toLowerCase()==='rtl' || $body.hasClass('rtl') || ($body.attr('dir') || '').toLowerCase()==='rtl'; return Boolean(rtl); }, /** * Calculates prompt position * * @param {jqObject} * field * @param {jqObject} * the prompt * @param {Map} * options * @return positions */ _calculatePosition: function (field, promptElmt, options) { var promptTopPosition, promptleftPosition, marginTopSize; var fieldWidth = field.width(); var fieldLeft = field.position().left; var fieldTop = field.position().top; var fieldHeight = field.height(); var promptHeight = promptElmt.height(); // is the form contained in an overflown container? promptTopPosition = promptleftPosition = 0; // compensation for the arrow marginTopSize = -promptHeight; //prompt positioning adjustment support //now you can adjust prompt position //usage: positionType:Xshift,Yshift //for example: // bottomLeft:+20 means bottomLeft position shifted by 20 pixels right horizontally // topRight:20, -15 means topRight position shifted by 20 pixels to right and 15 pixels to top //You can use +pixels, - pixels. If no sign is provided than + is default. var positionType=field.data("promptPosition") || options.promptPosition; var shift1=""; var shift2=""; var shiftX=0; var shiftY=0; if (typeof(positionType)=='string') { //do we have any position adjustments ? if (positionType.indexOf(":")!=-1) { shift1=positionType.substring(positionType.indexOf(":")+1); positionType=positionType.substring(0,positionType.indexOf(":")); //if any advanced positioning will be needed (percents or something else) - parser should be added here //for now we use simple parseInt() //do we have second parameter? if (shift1.indexOf(",") !=-1) { shift2=shift1.substring(shift1.indexOf(",") +1); shift1=shift1.substring(0,shift1.indexOf(",")); shiftY=parseInt(shift2); if (isNaN(shiftY)) shiftY=0; }; shiftX=parseInt(shift1); if (isNaN(shift1)) shift1=0; }; }; switch (positionType) { default: case "topRight": promptleftPosition += fieldLeft + fieldWidth - 30; promptTopPosition += fieldTop; break; case "topLeft": promptTopPosition += fieldTop; promptleftPosition += fieldLeft; break; case "centerRight": promptTopPosition = fieldTop+4; marginTopSize = 0; promptleftPosition= fieldLeft + field.outerWidth(true)+5; break; case "centerLeft": promptleftPosition = fieldLeft - (promptElmt.width() + 2); promptTopPosition = fieldTop+4; marginTopSize = 0; break; case "bottomLeft": promptTopPosition = fieldTop + field.height() + 5; marginTopSize = 0; promptleftPosition = fieldLeft; break; case "bottomRight": promptleftPosition = fieldLeft + fieldWidth - 30; promptTopPosition = fieldTop + field.height() + 5; marginTopSize = 0; }; //apply adjusments if any promptleftPosition += shiftX; promptTopPosition += shiftY; return { "callerTopPosition": promptTopPosition + "px", "callerleftPosition": promptleftPosition + "px", "marginTopSize": marginTopSize + "px" }; }, /** * Saves the user options and variables in the form.data * * @param {jqObject} * form - the form where the user option should be saved * @param {Map} * options - the user options * @return the user options (extended from the defaults) */ _saveOptions: function(form, options) { // is there a language localisation ? if ($.validationEngineLanguage) var allRules = $.validationEngineLanguage.allRules; else $.error("jQuery.validationEngine rules are not loaded, plz add localization files to the page"); // --- Internals DO NOT TOUCH or OVERLOAD --- // validation rules and i18 $.validationEngine.defaults.allrules = allRules; var userOptions = $.extend(true,{},$.validationEngine.defaults,options); form.data('jqv', userOptions); return userOptions; }, /** * Removes forbidden characters from class name * @param {String} className */ _getClassName: function(className) { if(className) return className.replace(/:/g, "_").replace(/\./g, "_"); }, /** * Conditionally required field * * @param {jqObject} field * @param {Array[String]} rules * @param {int} i rules index * @param {Map} * user options * @return an error string if validation failed */ _condRequired: function(field, rules, i, options) { var idx, dependingField; for(idx = (i + 1); idx < rules.length; idx++) { dependingField = jQuery("#" + rules[idx]).first(); /* Use _required for determining wether dependingField has a value. * There is logic there for handling all field types, and default value; so we won't replicate that here */ if (dependingField.length && methods._required(dependingField, ["required"], 0, options) == undefined) { /* We now know any of the depending fields has a value, * so we can validate this field as per normal required code */ return methods._required(field, ["required"], 0, options); } } } }; /** * Plugin entry point. * You may pass an action as a parameter or a list of options. * if none, the init and attach methods are being called. * Remember: if you pass options, the attached method is NOT called automatically * * @param {String} * method (optional) action */ $.fn.validationEngine = function(method) { var form = $(this); if(!form[0]) return form; // stop here if the form does not exist if (typeof(method) == 'string' && method.charAt(0) != '_' && methods[method]) { // make sure init is called once if(method != "showPrompt" && method != "hide" && method != "hideAll") methods.init.apply(form); return methods[method].apply(form, Array.prototype.slice.call(arguments, 1)); } else if (typeof method == 'object' || !method) { // default constructor with or without arguments methods.init.apply(form, arguments); return methods.attach.apply(form); } else { $.error('Method ' + method + ' does not exist in jQuery.validationEngine'); } }; // LEAK GLOBAL OPTIONS $.validationEngine= {fieldIdCounter: 0,defaults:{ // Name of the event triggering field validation validationEventTrigger: "blur", // Automatically scroll viewport to the first error scroll: true, // Focus on the first input focusFirstField:true, // Opening box position, possible locations are: topLeft, // topRight, bottomLeft, centerRight, bottomRight promptPosition: "topRight", bindMethod:"bind", // internal, automatically set to true when it parse a _ajax rule inlineAjax: false, // if set to true, the form data is sent asynchronously via ajax to the form.action url (get) ajaxFormValidation: false, // The url to send the submit ajax validation (default to action) ajaxFormValidationURL: false, // HTTP method used for ajax validation ajaxFormValidationMethod: 'get', // Ajax form validation callback method: boolean onComplete(form, status, errors, options) // retuns false if the form.submit event needs to be canceled. onAjaxFormComplete: $.noop, // called right before the ajax call, may return false to cancel onBeforeAjaxFormValidation: $.noop, // Stops form from submitting and execute function assiciated with it onValidationComplete: false, // Used when you have a form fields too close and the errors messages are on top of other disturbing viewing messages doNotShowAllErrosOnSubmit: false, // Object where you store custom messages to override the default error messages custom_error_messages:{}, // true if you want to vind the input fields binded: true, // set to true, when the prompt arrow needs to be displayed showArrow: true, // did one of the validation fail ? kept global to stop further ajax validations isError: false, // Caches field validation status, typically only bad status are created. // the array is used during ajax form validation to detect issues early and prevent an expensive submit ajaxValidCache: {}, // Auto update prompt position after window resize autoPositionUpdate: false, InvalidFields: [], onSuccess: false, onFailure: false, // Auto-hide prompt autoHidePrompt: false, // Delay before auto-hide autoHideDelay: 10000, // Fade out duration while hiding the validations fadeDuration: 0.3, // Use Prettify select library prettySelect: false, // Custom ID uses prefix usePrefix: "", // Custom ID uses suffix useSuffix: "", // Only show one message per error prompt showOneMessage: false }}; $(function(){$.validationEngine.defaults.promptPosition = methods.isRTL()?'topLeft':"topRight"}); })(jQuery); /*************************************************************** * Copyright notice * * (c) 2012 Alexander Kellner , in2code * * All rights reserved * * This script is part of the TYPO3 project. The TYPO3 project is * free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * The GNU General Public License can be found at * http://www.gnu.org/copyleft/gpl.html. * * This script is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * This copyright notice MUST APPEAR in all copies of the script! ***************************************************************/ jQuery.fn.powermailTabs = function(options) { 'use strict'; var $this = jQuery(this); options = jQuery.extend({ container: 'fieldset', header: 'legend' },options); // generate menu var $ul = jQuery('
    ', { 'id': 'tabmenu', 'class': 'tabmenu' }).insertBefore($this.children(options.container).filter(':first')); //all containers $this.children(options.container).each(function(i, $fieldset){ //tab_menu $ul.append( jQuery('
  • ') .html($(this).children(options.header).html()) .addClass((i==0) ? 'active' : '') .click({ container: $this.children(options.container), fieldset: $($fieldset) }, function(e){ jQuery('.tabmenu li', $this).removeClass('active'); jQuery(this).addClass('active'); e.data.container.hide(); e.data.fieldset.show() }) ) }); // initial show first fieldset $this.children(options.container).hide(); $this.find(options.container).first().show(); // Stop submit $this.submit(function(e) { //e.preventDefault(); }); }