/**
 * Copyright (c) 2008 Kelvin Luck (http://www.kelvinluck.com/)
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) 
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 * .
 * $Id: jquery.datePicker.js 81 2009-07-15 15:26:07Z kelvin.luck@gmail.com $
 **/

(function($){
$.fn.extend({
renderCalendar : function(s){
var dc=function(a){
return document.createElement(a)}
s=$.extend({},$.fn.datePicker.defaults,s)
if(s.showHeader !=$.dpConst.SHOW_HEADER_NONE){
var headRow=$(dc('tr'))
for(var i=Date.firstDayOfWeek;i<Date.firstDayOfWeek+7;i++){
var weekday=i%7
var day=Date.dayNames[weekday]
headRow.append(
jQuery(dc('th')).attr({'scope':'col','abbr':day,'title':day,'class':(weekday==0 || weekday==6 ? 'weekend' : 'weekday')}).html(s.showHeader==$.dpConst.SHOW_HEADER_SHORT ? day.substr(0,1): day)
)}}
var calendarTable=$(dc('table'))
.attr({
'cellspacing':2}
)
.addClass('jCalendar')
.append(
(s.showHeader !=$.dpConst.SHOW_HEADER_NONE ?
$(dc('thead'))
.append(headRow)
:
dc('thead')
)
)
var tbody=$(dc('tbody'))
var today=(new Date()).zeroTime()
today.setHours(12)
var month=s.month==undefined ? today.getMonth(): s.month
var year=s.year || today.getFullYear()
var currentDate=(new Date(year,month,1,12,0,0))
var firstDayOffset=Date.firstDayOfWeek-currentDate.getDay()+1
if(firstDayOffset>1)firstDayOffset-=7
var weeksToDraw=Math.ceil(((-1*firstDayOffset+1)+currentDate.getDaysInMonth())/7)
currentDate.addDays(firstDayOffset-1)
var doHover=function(firstDayInBounds){
return function(){
if(s.hoverClass){
var $this=$(this)
if(!s.selectWeek){
$this.addClass(s.hoverClass)
}else if(firstDayInBounds&&!$this.is('.disabled')){
$this.parent().addClass('activeWeekHover')}}}}
var unHover=function(){
if(s.hoverClass){
var $this=$(this)
$this.removeClass(s.hoverClass)
$this.parent().removeClass('activeWeekHover')}}
var w=0
while(w++<weeksToDraw){
var r=jQuery(dc('tr'))
var firstDayInBounds=s.dpController ? currentDate>s.dpController.startDate : false
for(var i=0;i<7;i++){
var thisMonth=currentDate.getMonth()==month
var d=$(dc('td'))
.text(currentDate.getDate()+'')
.addClass((thisMonth ? 'current-month ' : 'other-month ')+
(currentDate.isWeekend()? 'weekend ' : 'weekday ')+
(thisMonth&&currentDate.getTime()==today.getTime()? 'today ' : '')
)
.data('datePickerDate',currentDate.asString())
.hover(doHover(firstDayInBounds),unHover)
r.append(d)
if(s.renderCallback){
s.renderCallback(d,currentDate,month,year)}
currentDate=new Date(currentDate.getFullYear(),currentDate.getMonth(),currentDate.getDate()+1,12,0,0)}
tbody.append(r)}
calendarTable.append(tbody)
return this.each(
function(){
$(this).empty().append(calendarTable)}
)
},
datePicker : function(s){
if(!$.event._dpCache)$.event._dpCache=[]
s=$.extend({},$.fn.datePicker.defaults,s)
return this.each(
function(){
var $this=$(this)
var alreadyExists=true
if(!this._dpId){
this._dpId=$.event.guid++
$.event._dpCache[this._dpId]=new DatePicker(this)
alreadyExists=false}
if(s.inline){
s.createButton=false
s.displayClose=false
s.closeOnSelect=false
$this.empty()}
var controller=$.event._dpCache[this._dpId]
controller.init(s)
if(!alreadyExists&&s.createButton){
controller.button=$('<a href="#" class="dp-choose-date" title="'+$.dpText.TEXT_CHOOSE_DATE+'">'+$.dpText.TEXT_CHOOSE_DATE+'</a>')
.bind(
'click',
function(){
$this.dpDisplay(this)
this.blur()
return false}
)
$this.after(controller.button)}
if(!alreadyExists&&$this.is(':text')){
$this
.bind(
'dateSelected',
function(e,selectedDate,$td){
this.value=selectedDate.asString()}
).bind(
'change',
function(){
if(this.value==''){
controller.clearSelected()
}else{
var d=Date.fromString(this.value)
if(d){
controller.setSelected(d,true,true)}}}
)
if(s.clickInput){
$this.bind(
'click',
function(){
$this.trigger('change')
$this.dpDisplay()}
)}
var d=Date.fromString(this.value)
if(this.value !=''&&d){
controller.setSelected(d,true,true)}}
$this.addClass('dp-applied')}
)
},
dpSetDisabled : function(s){
return _w.call(this,'setDisabled',s)
},
dpSetStartDate : function(d){
return _w.call(this,'setStartDate',d)
},
dpSetEndDate : function(d){
return _w.call(this,'setEndDate',d)
},
dpGetSelected : function(){
var c=_getController(this[0])
if(c){
return c.getSelected()}
return null
},
dpSetSelected : function(d,v,m,e){
if(v==undefined)v=true
if(m==undefined)m=true
if(e==undefined)e=true
return _w.call(this,'setSelected',Date.fromString(d),v,m,e)
},
dpSetDisplayedMonth : function(m,y){
return _w.call(this,'setDisplayedMonth',Number(m),Number(y),true)
},
dpDisplay : function(e){
return _w.call(this,'display',e)
},
dpSetRenderCallback : function(a){
return _w.call(this,'setRenderCallback',a)
},
dpSetPosition : function(v,h){
return _w.call(this,'setPosition',v,h)
},
dpSetOffset : function(v,h){
return _w.call(this,'setOffset',v,h)
},
dpClose : function(){
return _w.call(this,'_closeCalendar',false,this[0])
},
_dpDestroy : function(){}
})
var _w=function(f,a1,a2,a3,a4){
return this.each(
function(){
var c=_getController(this)
if(c){
c[f](a1,a2,a3,a4)}}
)}
function DatePicker(ele){
this.ele=ele
this.displayedMonth=null
this.displayedYear=null
this.startDate=null
this.endDate=null
this.showYearNavigation=null
this.closeOnSelect=null
this.displayClose=null
this.rememberViewedMonth=null
this.selectMultiple=null
this.numSelectable=null
this.numSelected=null
this.verticalPosition=null
this.horizontalPosition=null
this.verticalOffset=null
this.horizontalOffset=null
this.button=null
this.renderCallback=[]
this.selectedDates={}
this.inline=null
this.context='#dp-popup'
this.settings={}}
$.extend(
DatePicker.prototype,{
init : function(s){
this.setStartDate(s.startDate)
this.setEndDate(s.endDate)
this.setDisplayedMonth(Number(s.month),Number(s.year))
this.setRenderCallback(s.renderCallback)
this.showYearNavigation=s.showYearNavigation
this.closeOnSelect=s.closeOnSelect
this.displayClose=s.displayClose
this.rememberViewedMonth=s.rememberViewedMonth
this.selectMultiple=s.selectMultiple
this.numSelectable=s.selectMultiple ? s.numSelectable : 1
this.numSelected=0
this.verticalPosition=s.verticalPosition
this.horizontalPosition=s.horizontalPosition
this.hoverClass=s.hoverClass
this.setOffset(s.verticalOffset,s.horizontalOffset)
this.inline=s.inline
this.settings=s
if(this.inline){
this.context=this.ele
this.display()}
},
setStartDate : function(d){
if(d){
this.startDate=Date.fromString(d)}
if(!this.startDate){
this.startDate=(new Date()).zeroTime()}
this.setDisplayedMonth(this.displayedMonth,this.displayedYear)
},
setEndDate : function(d){
if(d){
this.endDate=Date.fromString(d)}
if(!this.endDate){
this.endDate=(new Date('12/31/2999'))}
if(this.endDate.getTime()<this.startDate.getTime()){
this.endDate=this.startDate}
this.setDisplayedMonth(this.displayedMonth,this.displayedYear)
},
setPosition : function(v,h){
this.verticalPosition=v
this.horizontalPosition=h
},
setOffset : function(v,h){
this.verticalOffset=parseInt(v)|| 0
this.horizontalOffset=parseInt(h)|| 0
},
setDisabled : function(s){
$e=$(this.ele)
$e[s ? 'addClass' : 'removeClass']('dp-disabled')
if(this.button){
$but=$(this.button)
$but[s ? 'addClass' : 'removeClass']('dp-disabled')
$but.attr('title',s ? '' : $.dpText.TEXT_CHOOSE_DATE)}
if($e.is(':text')){
$e.attr('disabled',s ? 'disabled' : '')}
},
setDisplayedMonth : function(m,y,rerender){
if(this.startDate==undefined || this.endDate==undefined){
return}
var s=new Date(this.startDate.getTime())
s.setDate(1)
var e=new Date(this.endDate.getTime())
e.setDate(1)
var t
if((!m&&!y)||(isNaN(m)&&isNaN(y))){
t=new Date().zeroTime()
t.setDate(1)
}else if(isNaN(m)){
t=new Date(y,this.displayedMonth,1)
}else if(isNaN(y)){
t=new Date(this.displayedYear,m,1)
}else{
t=new Date(y,m,1)}
if(t.getTime()<s.getTime()){
t=s
}else if(t.getTime()>e.getTime()){
t=e}
var oldMonth=this.displayedMonth
var oldYear=this.displayedYear
this.displayedMonth=t.getMonth()
this.displayedYear=t.getFullYear()
if(rerender&&(this.displayedMonth !=oldMonth || this.displayedYear !=oldYear)){
this._rerenderCalendar()
$(this.ele).trigger('dpMonthChanged',[this.displayedMonth,this.displayedYear])}
},
setSelected : function(d,v,moveToMonth,dispatchEvents){
if(d<this.startDate || d>this.endDate){
return}
var s=this.settings
if(s.selectWeek){
d=d.addDays(-(d.getDay()-Date.firstDayOfWeek+7)% 7)
if(d<this.startDate){
return}}
if(v==this.isSelected(d)){
return}
if(this.selectMultiple==false){
this.clearSelected()
}else if(v&&this.numSelected==this.numSelectable){
return}
if(moveToMonth&&(this.displayedMonth !=d.getMonth()|| this.displayedYear !=d.getFullYear())){
this.setDisplayedMonth(d.getMonth(),d.getFullYear(),true)}
this.selectedDates[d.toString()]=v
this.numSelected+=v ? 1 :-1
var selectorString='td.'+(d.getMonth()==this.displayedMonth ? 'current-month' : 'other-month')
var $td
$(selectorString,this.context).each(
function(){
if($(this).data('datePickerDate')==d.asString()){
$td=$(this)
if(s.selectWeek){
$td.parent()[v ? 'addClass' : 'removeClass']('selectedWeek')}
$td[v ? 'addClass' : 'removeClass']('selected')}}
)
$('td',this.context).not('.selected')[this.selectMultiple&&this.numSelected==this.numSelectable ? 'addClass' : 'removeClass']('unselectable')
if(dispatchEvents){
var s=this.isSelected(d)
$e=$(this.ele)
var dClone=Date.fromString(d.asString())
$e.trigger('dateSelected',[dClone,$td,s])
$e.trigger('change')}
},
isSelected : function(d){
return this.selectedDates[d.toString()]
},
getSelected : function(){
var r=[]
for(s in this.selectedDates){
if(this.selectedDates[s]==true){
r.push(Date.parse(s))}}
return r
},
clearSelected : function(){
this.selectedDates={}
this.numSelected=0
$('td.selected',this.context).removeClass('selected').parent().removeClass('selectedWeek')
},
display : function(eleAlignTo){
if($(this.ele).is('.dp-disabled'))return
eleAlignTo=eleAlignTo || this.ele
var c=this
var $ele=$(eleAlignTo)
var eleOffset=$ele.offset()
var $createIn
var attrs
var attrsCalendarHolder
var cssRules
if(c.inline){
$createIn=$(this.ele)
attrs={
'id'	:	'calendar-'+this.ele._dpId,
'class'	:	'dp-popup dp-popup-inline'}
$('.dp-popup',$createIn).remove()
cssRules={}
}else{
$createIn=$('body')
attrs={
'id'	:	'dp-popup',
'class'	:	'dp-popup'}
cssRules={
'top'	:	eleOffset.top+c.verticalOffset,
'left'	:	eleOffset.left+c.horizontalOffset}
var _checkMouse=function(e){
var el=e.target
var cal=$('#dp-popup')[0]
while(true){
if(el==cal){
return true
}else if(el==document){
c._closeCalendar()
return false
}else{
el=$(el).parent()[0]}}}
this._checkMouse=_checkMouse
c._closeCalendar(true)
$(document).bind(
'keydown.datepicker',
function(event){
if(event.keyCode==27){
c._closeCalendar()}}
)}
if(!c.rememberViewedMonth){
var selectedDate=this.getSelected()[0]
if(selectedDate){
selectedDate=new Date(selectedDate)
this.setDisplayedMonth(selectedDate.getMonth(),selectedDate.getFullYear(),false)}}
$createIn
.append(
$('<div></div>')
.attr(attrs)
.css(cssRules)
.append(
$('<h2></h2>'),
$('<div class="dp-nav-prev"></div>')
.append(
$('<a class="dp-nav-prev-year" href="#" title="'+$.dpText.TEXT_PREV_YEAR+'">&lt;&lt;</a>')
.bind(
'click',
function(){
return c._displayNewMonth.call(c,this,0,-1)}
),
$('<a class="dp-nav-prev-month" href="#" title="'+$.dpText.TEXT_PREV_MONTH+'">&lt;</a>')
.bind(
'click',
function(){
return c._displayNewMonth.call(c,this,-1,0)}
)
),
$('<div class="dp-nav-next"></div>')
.append(
$('<a class="dp-nav-next-year" href="#" title="'+$.dpText.TEXT_NEXT_YEAR+'">&gt;&gt;</a>')
.bind(
'click',
function(){
return c._displayNewMonth.call(c,this,0,1)}
),
$('<a class="dp-nav-next-month" href="#" title="'+$.dpText.TEXT_NEXT_MONTH+'">&gt;</a>')
.bind(
'click',
function(){
return c._displayNewMonth.call(c,this,1,0)}
)
),
$('<div class="dp-calendar"></div>')
)
.bgIframe()
)
var $pop=this.inline ? $('.dp-popup',this.context): $('#dp-popup')
if(this.showYearNavigation==false){
$('.dp-nav-prev-year, .dp-nav-next-year',c.context).css('display','none')}
if(this.displayClose){
$pop.append(
$('<a href="#" id="dp-close">'+$.dpText.TEXT_CLOSE+'</a>')
.bind(
'click',
function(){
c._closeCalendar()
return false}
)
)}
c._renderCalendar()
$(this.ele).trigger('dpDisplayed',$pop)
if(!c.inline){
if(this.verticalPosition==$.dpConst.POS_BOTTOM){
$pop.css('top',eleOffset.top+$ele.height()-$pop.height()+c.verticalOffset)}
if(this.horizontalPosition==$.dpConst.POS_RIGHT){
$pop.css('left',eleOffset.left+$ele.width()-$pop.width()+c.horizontalOffset)}
$(document).bind('mousedown.datepicker',this._checkMouse)}
},
setRenderCallback : function(a){
if(a==null)return
if(a&&typeof(a)=='function'){
a=[a]}
this.renderCallback=this.renderCallback.concat(a)
},
cellRender : function($td,thisDate,month,year){
var c=this.dpController
var d=new Date(thisDate.getTime())
$td.bind(
'click',
function(){
var $this=$(this)
if(!$this.is('.disabled')){
c.setSelected(d,!$this.is('.selected')|| !c.selectMultiple,false,true)
if(c.closeOnSelect){
c._closeCalendar()}
if(!$.browser.msie){
$(c.ele).trigger('focus',[$.dpConst.DP_INTERNAL_FOCUS])}}}
)
if(c.isSelected(d)){
$td.addClass('selected')
if(c.settings.selectWeek){
$td.parent().addClass('selectedWeek')}
}else if(c.selectMultiple&&c.numSelected==c.numSelectable){
$td.addClass('unselectable')}
},
_applyRenderCallbacks : function(){
var c=this
$('td',this.context).each(
function(){
for(var i=0;i<c.renderCallback.length;i++){
$td=$(this)
c.renderCallback[i].apply(this,[$td,Date.fromString($td.data('datePickerDate')),c.displayedMonth,c.displayedYear])}}
)
return
},
_displayNewMonth : function(ele,m,y){
if(!$(ele).is('.disabled')){
this.setDisplayedMonth(this.displayedMonth+m,this.displayedYear+y,true)}
ele.blur()
return false
},
_rerenderCalendar : function(){
this._clearCalendar()
this._renderCalendar()
},
_renderCalendar : function(){
$('h2',this.context).html((new Date(this.displayedYear,this.displayedMonth,1)).asString($.dpText.HEADER_FORMAT))
$('.dp-calendar',this.context).renderCalendar(
$.extend(
{},
this.settings,{
month	: this.displayedMonth,
year	: this.displayedYear,
renderCallback	: this.cellRender,
dpController	: this,
hoverClass	: this.hoverClass
})
)
if(this.displayedYear==this.startDate.getFullYear()&&this.displayedMonth==this.startDate.getMonth()){
$('.dp-nav-prev-year',this.context).addClass('disabled')
$('.dp-nav-prev-month',this.context).addClass('disabled')
$('.dp-calendar td.other-month',this.context).each(
function(){
var $this=$(this)
if(Number($this.text())>20){
$this.addClass('disabled')}}
)
var d=this.startDate.getDate()
$('.dp-calendar td.current-month',this.context).each(
function(){
var $this=$(this)
if(Number($this.text())<d){
$this.addClass('disabled')}}
)
}else{
$('.dp-nav-prev-year',this.context).removeClass('disabled')
$('.dp-nav-prev-month',this.context).removeClass('disabled')
var d=this.startDate.getDate()
if(d>20){
var st=this.startDate.getTime()
var sd=new Date(st)
sd.addMonths(1)
if(this.displayedYear==sd.getFullYear()&&this.displayedMonth==sd.getMonth()){
$('.dp-calendar td.other-month',this.context).each(
function(){
var $this=$(this)
if(Date.fromString($this.data('datePickerDate')).getTime()<st){
$this.addClass('disabled')}}
)}}}
if(this.displayedYear==this.endDate.getFullYear()&&this.displayedMonth==this.endDate.getMonth()){
$('.dp-nav-next-year',this.context).addClass('disabled')
$('.dp-nav-next-month',this.context).addClass('disabled')
$('.dp-calendar td.other-month',this.context).each(
function(){
var $this=$(this)
if(Number($this.text())<14){
$this.addClass('disabled')}}
)
var d=this.endDate.getDate()
$('.dp-calendar td.current-month',this.context).each(
function(){
var $this=$(this)
if(Number($this.text())>d){
$this.addClass('disabled')}}
)
}else{
$('.dp-nav-next-year',this.context).removeClass('disabled')
$('.dp-nav-next-month',this.context).removeClass('disabled')
var d=this.endDate.getDate()
if(d<13){
var ed=new Date(this.endDate.getTime())
ed.addMonths(-1)
if(this.displayedYear==ed.getFullYear()&&this.displayedMonth==ed.getMonth()){
$('.dp-calendar td.other-month',this.context).each(
function(){
var $this=$(this)
if(Number($this.text())>d){
$this.addClass('disabled')}}
)}}}
this._applyRenderCallbacks()
},
_closeCalendar : function(programatic,ele){
if(!ele || ele==this.ele){
$(document).unbind('mousedown.datepicker')
$(document).unbind('keydown.datepicker')
this._clearCalendar()
$('#dp-popup a').unbind()
$('#dp-popup').empty().remove()
if(!programatic){
$(this.ele).trigger('dpClosed',[this.getSelected()])}}
},
_clearCalendar : function(){
$('.dp-calendar td',this.context).unbind()
$('.dp-calendar',this.context).empty()}}
)
$.dpConst={
SHOW_HEADER_NONE	:	0,
SHOW_HEADER_SHORT	:	1,
SHOW_HEADER_LONG	:	2,
POS_TOP	:	0,
POS_BOTTOM	:	1,
POS_LEFT	:	0,
POS_RIGHT	:	1,
DP_INTERNAL_FOCUS	:	'dpInternalFocusTrigger'}
$.dpText={
TEXT_PREV_YEAR	:	'Previous year',
TEXT_PREV_MONTH	:	'Previous month',
TEXT_NEXT_YEAR	:	'Next year',
TEXT_NEXT_MONTH	:	'Next month',
TEXT_CLOSE	:	'Close',
TEXT_CHOOSE_DATE	:	'Choose date',
HEADER_FORMAT	:	'mmmm yyyy'}
$.dpVersion='$Id: jquery.datePicker.js 81 2009-07-15 15:26:07Z kelvin.luck@gmail.com $'
$.fn.datePicker.defaults={
month	: undefined,
year	: undefined,
showHeader	: $.dpConst.SHOW_HEADER_SHORT,
startDate	: undefined,
endDate	: undefined,
inline	: false,
renderCallback	: null,
createButton	: true,
showYearNavigation	: true,
closeOnSelect	: true,
displayClose	: false,
selectMultiple	: false,
numSelectable	: Number.MAX_VALUE,
clickInput	: false,
rememberViewedMonth	: true,
selectWeek	: false,
verticalPosition	: $.dpConst.POS_TOP,
horizontalPosition	: $.dpConst.POS_LEFT,
verticalOffset	: 0,
horizontalOffset	: 0,
hoverClass	: 'dp-hover'}
function _getController(ele){
if(ele._dpId)return $.event._dpCache[ele._dpId]
return false}
if($.fn.bgIframe==undefined){
$.fn.bgIframe=function(){return this;}}
$(window)
.bind('unload',function(){
var els=$.event._dpCache || []
for(var i in els){
$(els[i].ele)._dpDestroy()}
})
})(jQuery)
