2015-08-10 12:50:38 +02:00
/ * !
* Pikaday
*
* Copyright © 2014 David Bushell | BSD & MIT license | https : //github.com/dbushell/Pikaday
* /
( function ( root , factory )
{
'use strict' ;
var moment ;
if ( typeof exports === 'object' ) {
// CommonJS module
// Load moment.js as an optional dependency
try { moment = require ( 'moment' ) ; } catch ( e ) { }
module . exports = factory ( moment ) ;
} else if ( typeof define === 'function' && define . amd ) {
// AMD. Register as an anonymous module.
define ( function ( req )
{
// Load moment.js as an optional dependency
var id = 'moment' ;
try { moment = req ( id ) ; } catch ( e ) { }
return factory ( moment ) ;
} ) ;
} else {
root . Pikaday = factory ( root . moment ) ;
}
} ( this , function ( moment )
{
'use strict' ;
/ * *
* feature detection and helper functions
* /
var hasMoment = typeof moment === 'function' ,
hasEventListeners = ! ! window . addEventListener ,
document = window . document ,
sto = window . setTimeout ,
addEvent = function ( el , e , callback , capture )
{
if ( hasEventListeners ) {
el . addEventListener ( e , callback , ! ! capture ) ;
} else {
el . attachEvent ( 'on' + e , callback ) ;
}
} ,
removeEvent = function ( el , e , callback , capture )
{
if ( hasEventListeners ) {
el . removeEventListener ( e , callback , ! ! capture ) ;
} else {
el . detachEvent ( 'on' + e , callback ) ;
}
} ,
fireEvent = function ( el , eventName , data )
{
var ev ;
if ( document . createEvent ) {
ev = document . createEvent ( 'HTMLEvents' ) ;
ev . initEvent ( eventName , true , false ) ;
ev = extend ( ev , data ) ;
el . dispatchEvent ( ev ) ;
} else if ( document . createEventObject ) {
ev = document . createEventObject ( ) ;
ev = extend ( ev , data ) ;
el . fireEvent ( 'on' + eventName , ev ) ;
}
} ,
trim = function ( str )
{
return str . trim ? str . trim ( ) : str . replace ( /^\s+|\s+$/g , '' ) ;
} ,
hasClass = function ( el , cn )
{
return ( ' ' + el . className + ' ' ) . indexOf ( ' ' + cn + ' ' ) !== - 1 ;
} ,
addClass = function ( el , cn )
{
if ( ! hasClass ( el , cn ) ) {
el . className = ( el . className === '' ) ? cn : el . className + ' ' + cn ;
}
} ,
removeClass = function ( el , cn )
{
el . className = trim ( ( ' ' + el . className + ' ' ) . replace ( ' ' + cn + ' ' , ' ' ) ) ;
} ,
isArray = function ( obj )
{
return ( /Array/ ) . test ( Object . prototype . toString . call ( obj ) ) ;
} ,
isDate = function ( obj )
{
return ( /Date/ ) . test ( Object . prototype . toString . call ( obj ) ) && ! isNaN ( obj . getTime ( ) ) ;
} ,
isWeekend = function ( date )
{
var day = date . getDay ( ) ;
return day === 0 || day === 6 ;
} ,
isLeapYear = function ( year )
{
// solution by Matti Virkkunen: http://stackoverflow.com/a/4881951
return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0 ;
} ,
getDaysInMonth = function ( year , month )
{
return [ 31 , isLeapYear ( year ) ? 29 : 28 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 ] [ month ] ;
} ,
setToStartOfDay = function ( date )
{
if ( isDate ( date ) ) date . setHours ( 0 , 0 , 0 , 0 ) ;
} ,
compareDates = function ( a , b )
{
// weak date comparison (use setToStartOfDay(date) to ensure correct result)
return a . getTime ( ) === b . getTime ( ) ;
} ,
extend = function ( to , from , overwrite )
{
var prop , hasProp ;
for ( prop in from ) {
hasProp = to [ prop ] !== undefined ;
if ( hasProp && typeof from [ prop ] === 'object' && from [ prop ] !== null && from [ prop ] . nodeName === undefined ) {
if ( isDate ( from [ prop ] ) ) {
if ( overwrite ) {
to [ prop ] = new Date ( from [ prop ] . getTime ( ) ) ;
}
}
else if ( isArray ( from [ prop ] ) ) {
if ( overwrite ) {
to [ prop ] = from [ prop ] . slice ( 0 ) ;
}
} else {
to [ prop ] = extend ( { } , from [ prop ] , overwrite ) ;
}
} else if ( overwrite || ! hasProp ) {
to [ prop ] = from [ prop ] ;
}
}
return to ;
} ,
adjustCalendar = function ( calendar ) {
if ( calendar . month < 0 ) {
calendar . year -= Math . ceil ( Math . abs ( calendar . month ) / 12 ) ;
calendar . month += 12 ;
}
if ( calendar . month > 11 ) {
calendar . year += Math . floor ( Math . abs ( calendar . month ) / 12 ) ;
calendar . month -= 12 ;
}
return calendar ;
} ,
/ * *
* defaults and localisation
* /
defaults = {
// bind the picker to a form field
field : null ,
// automatically show/hide the picker on `field` focus (default `true` if `field` is set)
bound : undefined ,
// position of the datepicker, relative to the field (default to bottom & left)
// ('bottom' & 'left' keywords are not used, 'top' & 'right' are modifier on the bottom/left position)
position : 'bottom left' ,
// automatically fit in the viewport even if it means repositioning from the position option
reposition : true ,
// the default output format for `.toString()` and `field` value
format : 'YYYY-MM-DD' ,
// the initial date to view when first opened
defaultDate : null ,
// make the `defaultDate` the initial selected value
setDefaultDate : false ,
// first day of week (0: Sunday, 1: Monday etc)
firstDay : 0 ,
2016-01-20 21:06:41 +01:00
// the default flag for moment's strict date parsing
formatStrict : false ,
2015-08-10 12:50:38 +02:00
// the minimum/earliest date that can be selected
minDate : null ,
// the maximum/latest date that can be selected
maxDate : null ,
// number of years either side, or array of upper/lower range
yearRange : 10 ,
// show week numbers at head of row
showWeekNumber : false ,
// used internally (don't config outside)
minYear : 0 ,
maxYear : 9999 ,
minMonth : undefined ,
maxMonth : undefined ,
startRange : null ,
endRange : null ,
isRTL : false ,
// Additional text to append to the year in the calendar title
yearSuffix : '' ,
// Render the month after year in the calendar title
showMonthAfterYear : false ,
2016-01-20 21:06:41 +01:00
// Render days of the calendar grid that fall in the next or previous month
showDaysInNextAndPreviousMonths : false ,
2015-08-10 12:50:38 +02:00
// how many months are visible
numberOfMonths : 1 ,
// when numberOfMonths is used, this will help you to choose where the main calendar will be (default `left`, can be set to `right`)
// only used for the first display or when a selected date is not visible
mainCalendar : 'left' ,
// Specify a DOM element to render the calendar in
container : undefined ,
// internationalization
i18n : {
previousMonth : 'Previous Month' ,
nextMonth : 'Next Month' ,
months : [ 'January' , 'February' , 'March' , 'April' , 'May' , 'June' , 'July' , 'August' , 'September' , 'October' , 'November' , 'December' ] ,
weekdays : [ 'Sunday' , 'Monday' , 'Tuesday' , 'Wednesday' , 'Thursday' , 'Friday' , 'Saturday' ] ,
weekdaysShort : [ 'Sun' , 'Mon' , 'Tue' , 'Wed' , 'Thu' , 'Fri' , 'Sat' ]
} ,
// Theme Classname
theme : null ,
// callback function
onSelect : null ,
onOpen : null ,
onClose : null ,
onDraw : null
} ,
/ * *
* templating functions to abstract HTML rendering
* /
renderDayName = function ( opts , day , abbr )
{
day += opts . firstDay ;
while ( day >= 7 ) {
day -= 7 ;
}
return abbr ? opts . i18n . weekdaysShort [ day ] : opts . i18n . weekdays [ day ] ;
} ,
renderDay = function ( opts )
{
2016-01-20 21:06:41 +01:00
var arr = [ ] ;
2015-08-10 12:50:38 +02:00
if ( opts . isEmpty ) {
2016-01-20 21:06:41 +01:00
if ( opts . showDaysInNextAndPreviousMonths ) {
arr . push ( 'is-outside-current-month' ) ;
} else {
return '<td class="is-empty"></td>' ;
}
2015-08-10 12:50:38 +02:00
}
if ( opts . isDisabled ) {
arr . push ( 'is-disabled' ) ;
}
if ( opts . isToday ) {
arr . push ( 'is-today' ) ;
}
if ( opts . isSelected ) {
arr . push ( 'is-selected' ) ;
}
if ( opts . isInRange ) {
arr . push ( 'is-inrange' ) ;
}
if ( opts . isStartRange ) {
arr . push ( 'is-startrange' ) ;
}
if ( opts . isEndRange ) {
arr . push ( 'is-endrange' ) ;
}
return '<td data-day="' + opts . day + '" class="' + arr . join ( ' ' ) + '">' +
'<button class="pika-button pika-day" type="button" ' +
'data-pika-year="' + opts . year + '" data-pika-month="' + opts . month + '" data-pika-day="' + opts . day + '">' +
opts . day +
'</button>' +
'</td>' ;
} ,
renderWeek = function ( d , m , y ) {
// Lifted from http://javascript.about.com/library/blweekyear.htm, lightly modified.
var onejan = new Date ( y , 0 , 1 ) ,
weekNum = Math . ceil ( ( ( ( new Date ( y , m , d ) - onejan ) / 86400000 ) + onejan . getDay ( ) + 1 ) / 7 ) ;
return '<td class="pika-week">' + weekNum + '</td>' ;
} ,
renderRow = function ( days , isRTL )
{
return '<tr>' + ( isRTL ? days . reverse ( ) : days ) . join ( '' ) + '</tr>' ;
} ,
renderBody = function ( rows )
{
return '<tbody>' + rows . join ( '' ) + '</tbody>' ;
} ,
renderHead = function ( opts )
{
var i , arr = [ ] ;
if ( opts . showWeekNumber ) {
arr . push ( '<th></th>' ) ;
}
for ( i = 0 ; i < 7 ; i ++ ) {
arr . push ( '<th scope="col"><abbr title="' + renderDayName ( opts , i ) + '">' + renderDayName ( opts , i , true ) + '</abbr></th>' ) ;
}
2016-04-15 17:58:32 +02:00
return '<thead><tr>' + ( opts . isRTL ? arr . reverse ( ) : arr ) . join ( '' ) + '</tr></thead>' ;
2015-08-10 12:50:38 +02:00
} ,
renderTitle = function ( instance , c , year , month , refYear )
{
var i , j , arr ,
opts = instance . _o ,
isMinYear = year === opts . minYear ,
isMaxYear = year === opts . maxYear ,
html = '<div class="pika-title">' ,
monthHtml ,
yearHtml ,
prev = true ,
next = true ;
for ( arr = [ ] , i = 0 ; i < 12 ; i ++ ) {
arr . push ( '<option value="' + ( year === refYear ? i - c : 12 + i - c ) + '"' +
2016-04-15 17:58:32 +02:00
( i === month ? ' selected="selected"' : '' ) +
( ( isMinYear && i < opts . minMonth ) || ( isMaxYear && i > opts . maxMonth ) ? 'disabled="disabled"' : '' ) + '>' +
2015-08-10 12:50:38 +02:00
opts . i18n . months [ i ] + '</option>' ) ;
}
monthHtml = '<div class="pika-label">' + opts . i18n . months [ month ] + '<select class="pika-select pika-select-month" tabindex="-1">' + arr . join ( '' ) + '</select></div>' ;
if ( isArray ( opts . yearRange ) ) {
i = opts . yearRange [ 0 ] ;
j = opts . yearRange [ 1 ] + 1 ;
} else {
i = year - opts . yearRange ;
j = 1 + year + opts . yearRange ;
}
for ( arr = [ ] ; i < j && i <= opts . maxYear ; i ++ ) {
if ( i >= opts . minYear ) {
2016-04-15 17:58:32 +02:00
arr . push ( '<option value="' + i + '"' + ( i === year ? ' selected="selected"' : '' ) + '>' + ( i ) + '</option>' ) ;
2015-08-10 12:50:38 +02:00
}
}
yearHtml = '<div class="pika-label">' + year + opts . yearSuffix + '<select class="pika-select pika-select-year" tabindex="-1">' + arr . join ( '' ) + '</select></div>' ;
if ( opts . showMonthAfterYear ) {
html += yearHtml + monthHtml ;
} else {
html += monthHtml + yearHtml ;
}
if ( isMinYear && ( month === 0 || opts . minMonth >= month ) ) {
prev = false ;
}
if ( isMaxYear && ( month === 11 || opts . maxMonth <= month ) ) {
next = false ;
}
if ( c === 0 ) {
html += '<button class="pika-prev' + ( prev ? '' : ' is-disabled' ) + '" type="button">' + opts . i18n . previousMonth + '</button>' ;
}
if ( c === ( instance . _o . numberOfMonths - 1 ) ) {
html += '<button class="pika-next' + ( next ? '' : ' is-disabled' ) + '" type="button">' + opts . i18n . nextMonth + '</button>' ;
}
return html += '</div>' ;
} ,
renderTable = function ( opts , data )
{
return '<table cellpadding="0" cellspacing="0" class="pika-table">' + renderHead ( opts ) + renderBody ( data ) + '</table>' ;
} ,
/ * *
* Pikaday constructor
* /
Pikaday = function ( options )
{
var self = this ,
opts = self . config ( options ) ;
self . _onMouseDown = function ( e )
{
if ( ! self . _v ) {
return ;
}
e = e || window . event ;
var target = e . target || e . srcElement ;
if ( ! target ) {
return ;
}
2016-01-20 21:06:41 +01:00
if ( ! hasClass ( target , 'is-disabled' ) ) {
2016-04-15 17:58:32 +02:00
if ( hasClass ( target , 'pika-button' ) && ! hasClass ( target , 'is-empty' ) && ! hasClass ( target . parentNode , 'is-disabled' ) ) {
2015-08-10 12:50:38 +02:00
self . setDate ( new Date ( target . getAttribute ( 'data-pika-year' ) , target . getAttribute ( 'data-pika-month' ) , target . getAttribute ( 'data-pika-day' ) ) ) ;
if ( opts . bound ) {
sto ( function ( ) {
self . hide ( ) ;
if ( opts . field ) {
opts . field . blur ( ) ;
}
} , 100 ) ;
}
}
else if ( hasClass ( target , 'pika-prev' ) ) {
self . prevMonth ( ) ;
}
else if ( hasClass ( target , 'pika-next' ) ) {
self . nextMonth ( ) ;
}
}
if ( ! hasClass ( target , 'pika-select' ) ) {
2015-09-23 15:35:22 +02:00
// if this is touch event prevent mouse events emulation
2015-08-10 12:50:38 +02:00
if ( e . preventDefault ) {
e . preventDefault ( ) ;
} else {
e . returnValue = false ;
return false ;
}
} else {
self . _c = true ;
}
} ;
self . _onChange = function ( e )
{
e = e || window . event ;
var target = e . target || e . srcElement ;
if ( ! target ) {
return ;
}
if ( hasClass ( target , 'pika-select-month' ) ) {
self . gotoMonth ( target . value ) ;
}
else if ( hasClass ( target , 'pika-select-year' ) ) {
self . gotoYear ( target . value ) ;
}
} ;
self . _onInputChange = function ( e )
{
var date ;
if ( e . firedBy === self ) {
return ;
}
if ( hasMoment ) {
2016-01-20 21:06:41 +01:00
date = moment ( opts . field . value , opts . format , opts . formatStrict ) ;
2015-08-10 12:50:38 +02:00
date = ( date && date . isValid ( ) ) ? date . toDate ( ) : null ;
}
else {
date = new Date ( Date . parse ( opts . field . value ) ) ;
}
if ( isDate ( date ) ) {
self . setDate ( date ) ;
}
if ( ! self . _v ) {
self . show ( ) ;
}
} ;
self . _onInputFocus = function ( )
{
self . show ( ) ;
} ;
self . _onInputClick = function ( )
{
self . show ( ) ;
} ;
self . _onInputBlur = function ( )
{
// IE allows pika div to gain focus; catch blur the input field
var pEl = document . activeElement ;
do {
if ( hasClass ( pEl , 'pika-single' ) ) {
return ;
}
}
while ( ( pEl = pEl . parentNode ) ) ;
if ( ! self . _c ) {
self . _b = sto ( function ( ) {
self . hide ( ) ;
} , 50 ) ;
}
self . _c = false ;
} ;
self . _onClick = function ( e )
{
e = e || window . event ;
var target = e . target || e . srcElement ,
pEl = target ;
if ( ! target ) {
return ;
}
if ( ! hasEventListeners && hasClass ( target , 'pika-select' ) ) {
if ( ! target . onchange ) {
target . setAttribute ( 'onchange' , 'return;' ) ;
addEvent ( target , 'change' , self . _onChange ) ;
}
}
do {
if ( hasClass ( pEl , 'pika-single' ) || pEl === opts . trigger ) {
return ;
}
}
while ( ( pEl = pEl . parentNode ) ) ;
if ( self . _v && target !== opts . trigger && pEl !== opts . trigger ) {
self . hide ( ) ;
}
} ;
self . el = document . createElement ( 'div' ) ;
self . el . className = 'pika-single' + ( opts . isRTL ? ' is-rtl' : '' ) + ( opts . theme ? ' ' + opts . theme : '' ) ;
2015-09-23 15:35:22 +02:00
addEvent ( self . el , 'mousedown' , self . _onMouseDown , true ) ;
addEvent ( self . el , 'touchend' , self . _onMouseDown , true ) ;
2015-08-10 12:50:38 +02:00
addEvent ( self . el , 'change' , self . _onChange ) ;
if ( opts . field ) {
if ( opts . container ) {
opts . container . appendChild ( self . el ) ;
} else if ( opts . bound ) {
document . body . appendChild ( self . el ) ;
} else {
opts . field . parentNode . insertBefore ( self . el , opts . field . nextSibling ) ;
}
addEvent ( opts . field , 'change' , self . _onInputChange ) ;
if ( ! opts . defaultDate ) {
if ( hasMoment && opts . field . value ) {
opts . defaultDate = moment ( opts . field . value , opts . format ) . toDate ( ) ;
} else {
opts . defaultDate = new Date ( Date . parse ( opts . field . value ) ) ;
}
opts . setDefaultDate = true ;
}
}
var defDate = opts . defaultDate ;
if ( isDate ( defDate ) ) {
if ( opts . setDefaultDate ) {
self . setDate ( defDate , true ) ;
} else {
self . gotoDate ( defDate ) ;
}
} else {
self . gotoDate ( new Date ( ) ) ;
}
if ( opts . bound ) {
this . hide ( ) ;
self . el . className += ' is-bound' ;
addEvent ( opts . trigger , 'click' , self . _onInputClick ) ;
addEvent ( opts . trigger , 'focus' , self . _onInputFocus ) ;
addEvent ( opts . trigger , 'blur' , self . _onInputBlur ) ;
} else {
this . show ( ) ;
}
} ;
/ * *
* public Pikaday API
* /
Pikaday . prototype = {
/ * *
* configure functionality
* /
config : function ( options )
{
if ( ! this . _o ) {
this . _o = extend ( { } , defaults , true ) ;
}
var opts = extend ( this . _o , options , true ) ;
opts . isRTL = ! ! opts . isRTL ;
opts . field = ( opts . field && opts . field . nodeName ) ? opts . field : null ;
opts . theme = ( typeof opts . theme ) === 'string' && opts . theme ? opts . theme : null ;
opts . bound = ! ! ( opts . bound !== undefined ? opts . field && opts . bound : opts . field ) ;
opts . trigger = ( opts . trigger && opts . trigger . nodeName ) ? opts . trigger : opts . field ;
opts . disableWeekends = ! ! opts . disableWeekends ;
opts . disableDayFn = ( typeof opts . disableDayFn ) === 'function' ? opts . disableDayFn : null ;
var nom = parseInt ( opts . numberOfMonths , 10 ) || 1 ;
opts . numberOfMonths = nom > 4 ? 4 : nom ;
if ( ! isDate ( opts . minDate ) ) {
opts . minDate = false ;
}
if ( ! isDate ( opts . maxDate ) ) {
opts . maxDate = false ;
}
if ( ( opts . minDate && opts . maxDate ) && opts . maxDate < opts . minDate ) {
opts . maxDate = opts . minDate = false ;
}
if ( opts . minDate ) {
this . setMinDate ( opts . minDate ) ;
}
if ( opts . maxDate ) {
2016-01-20 21:06:41 +01:00
this . setMaxDate ( opts . maxDate ) ;
2015-08-10 12:50:38 +02:00
}
if ( isArray ( opts . yearRange ) ) {
var fallback = new Date ( ) . getFullYear ( ) - 10 ;
opts . yearRange [ 0 ] = parseInt ( opts . yearRange [ 0 ] , 10 ) || fallback ;
opts . yearRange [ 1 ] = parseInt ( opts . yearRange [ 1 ] , 10 ) || fallback ;
} else {
opts . yearRange = Math . abs ( parseInt ( opts . yearRange , 10 ) ) || defaults . yearRange ;
if ( opts . yearRange > 100 ) {
opts . yearRange = 100 ;
}
}
return opts ;
} ,
/ * *
* return a formatted string of the current selection ( using Moment . js if available )
* /
toString : function ( format )
{
return ! isDate ( this . _d ) ? '' : hasMoment ? moment ( this . _d ) . format ( format || this . _o . format ) : this . _d . toDateString ( ) ;
} ,
/ * *
* return a Moment . js object of the current selection ( if available )
* /
getMoment : function ( )
{
return hasMoment ? moment ( this . _d ) : null ;
} ,
/ * *
* set the current selection from a Moment . js object ( if available )
* /
setMoment : function ( date , preventOnSelect )
{
if ( hasMoment && moment . isMoment ( date ) ) {
this . setDate ( date . toDate ( ) , preventOnSelect ) ;
}
} ,
/ * *
* return a Date object of the current selection
* /
getDate : function ( )
{
return isDate ( this . _d ) ? new Date ( this . _d . getTime ( ) ) : null ;
} ,
/ * *
* set the current selection
* /
setDate : function ( date , preventOnSelect )
{
if ( ! date ) {
this . _d = null ;
if ( this . _o . field ) {
this . _o . field . value = '' ;
fireEvent ( this . _o . field , 'change' , { firedBy : this } ) ;
}
return this . draw ( ) ;
}
if ( typeof date === 'string' ) {
date = new Date ( Date . parse ( date ) ) ;
}
if ( ! isDate ( date ) ) {
return ;
}
var min = this . _o . minDate ,
max = this . _o . maxDate ;
if ( isDate ( min ) && date < min ) {
date = min ;
} else if ( isDate ( max ) && date > max ) {
date = max ;
}
this . _d = new Date ( date . getTime ( ) ) ;
setToStartOfDay ( this . _d ) ;
this . gotoDate ( this . _d ) ;
if ( this . _o . field ) {
this . _o . field . value = this . toString ( ) ;
fireEvent ( this . _o . field , 'change' , { firedBy : this } ) ;
}
if ( ! preventOnSelect && typeof this . _o . onSelect === 'function' ) {
this . _o . onSelect . call ( this , this . getDate ( ) ) ;
}
} ,
/ * *
* change view to a specific date
* /
gotoDate : function ( date )
{
var newCalendar = true ;
if ( ! isDate ( date ) ) {
return ;
}
if ( this . calendars ) {
var firstVisibleDate = new Date ( this . calendars [ 0 ] . year , this . calendars [ 0 ] . month , 1 ) ,
lastVisibleDate = new Date ( this . calendars [ this . calendars . length - 1 ] . year , this . calendars [ this . calendars . length - 1 ] . month , 1 ) ,
visibleDate = date . getTime ( ) ;
// get the end of the month
lastVisibleDate . setMonth ( lastVisibleDate . getMonth ( ) + 1 ) ;
lastVisibleDate . setDate ( lastVisibleDate . getDate ( ) - 1 ) ;
newCalendar = ( visibleDate < firstVisibleDate . getTime ( ) || lastVisibleDate . getTime ( ) < visibleDate ) ;
}
if ( newCalendar ) {
this . calendars = [ {
month : date . getMonth ( ) ,
year : date . getFullYear ( )
} ] ;
if ( this . _o . mainCalendar === 'right' ) {
this . calendars [ 0 ] . month += 1 - this . _o . numberOfMonths ;
}
}
this . adjustCalendars ( ) ;
} ,
adjustCalendars : function ( ) {
this . calendars [ 0 ] = adjustCalendar ( this . calendars [ 0 ] ) ;
for ( var c = 1 ; c < this . _o . numberOfMonths ; c ++ ) {
this . calendars [ c ] = adjustCalendar ( {
month : this . calendars [ 0 ] . month + c ,
year : this . calendars [ 0 ] . year
} ) ;
}
this . draw ( ) ;
} ,
gotoToday : function ( )
{
this . gotoDate ( new Date ( ) ) ;
} ,
/ * *
* change view to a specific month ( zero - index , e . g . 0 : January )
* /
gotoMonth : function ( month )
{
if ( ! isNaN ( month ) ) {
this . calendars [ 0 ] . month = parseInt ( month , 10 ) ;
this . adjustCalendars ( ) ;
}
} ,
nextMonth : function ( )
{
this . calendars [ 0 ] . month ++ ;
this . adjustCalendars ( ) ;
} ,
prevMonth : function ( )
{
this . calendars [ 0 ] . month -- ;
this . adjustCalendars ( ) ;
} ,
/ * *
* change view to a specific full year ( e . g . "2012" )
* /
gotoYear : function ( year )
{
if ( ! isNaN ( year ) ) {
this . calendars [ 0 ] . year = parseInt ( year , 10 ) ;
this . adjustCalendars ( ) ;
}
} ,
/ * *
* change the minDate
* /
setMinDate : function ( value )
{
setToStartOfDay ( value ) ;
this . _o . minDate = value ;
this . _o . minYear = value . getFullYear ( ) ;
this . _o . minMonth = value . getMonth ( ) ;
2016-01-20 21:06:41 +01:00
this . draw ( ) ;
2015-08-10 12:50:38 +02:00
} ,
/ * *
* change the maxDate
* /
setMaxDate : function ( value )
{
2016-01-20 21:06:41 +01:00
setToStartOfDay ( value ) ;
2015-08-10 12:50:38 +02:00
this . _o . maxDate = value ;
2016-01-20 21:06:41 +01:00
this . _o . maxYear = value . getFullYear ( ) ;
this . _o . maxMonth = value . getMonth ( ) ;
this . draw ( ) ;
2015-08-10 12:50:38 +02:00
} ,
setStartRange : function ( value )
{
this . _o . startRange = value ;
} ,
setEndRange : function ( value )
{
this . _o . endRange = value ;
} ,
/ * *
* refresh the HTML
* /
draw : function ( force )
{
if ( ! this . _v && ! force ) {
return ;
}
var opts = this . _o ,
minYear = opts . minYear ,
maxYear = opts . maxYear ,
minMonth = opts . minMonth ,
maxMonth = opts . maxMonth ,
html = '' ;
if ( this . _y <= minYear ) {
this . _y = minYear ;
if ( ! isNaN ( minMonth ) && this . _m < minMonth ) {
this . _m = minMonth ;
}
}
if ( this . _y >= maxYear ) {
this . _y = maxYear ;
if ( ! isNaN ( maxMonth ) && this . _m > maxMonth ) {
this . _m = maxMonth ;
}
}
for ( var c = 0 ; c < opts . numberOfMonths ; c ++ ) {
html += '<div class="pika-lendar">' + renderTitle ( this , c , this . calendars [ c ] . year , this . calendars [ c ] . month , this . calendars [ 0 ] . year ) + this . render ( this . calendars [ c ] . year , this . calendars [ c ] . month ) + '</div>' ;
}
this . el . innerHTML = html ;
if ( opts . bound ) {
if ( opts . field . type !== 'hidden' ) {
sto ( function ( ) {
opts . trigger . focus ( ) ;
} , 1 ) ;
}
}
if ( typeof this . _o . onDraw === 'function' ) {
2016-04-15 17:58:32 +02:00
this . _o . onDraw ( this ) ;
2015-08-10 12:50:38 +02:00
}
} ,
adjustPosition : function ( )
{
var field , pEl , width , height , viewportWidth , viewportHeight , scrollTop , left , top , clientRect ;
if ( this . _o . container ) return ;
this . el . style . position = 'absolute' ;
field = this . _o . trigger ;
pEl = field ;
width = this . el . offsetWidth ;
height = this . el . offsetHeight ;
viewportWidth = window . innerWidth || document . documentElement . clientWidth ;
viewportHeight = window . innerHeight || document . documentElement . clientHeight ;
scrollTop = window . pageYOffset || document . body . scrollTop || document . documentElement . scrollTop ;
if ( typeof field . getBoundingClientRect === 'function' ) {
clientRect = field . getBoundingClientRect ( ) ;
left = clientRect . left + window . pageXOffset ;
top = clientRect . bottom + window . pageYOffset ;
} else {
left = pEl . offsetLeft ;
top = pEl . offsetTop + pEl . offsetHeight ;
while ( ( pEl = pEl . offsetParent ) ) {
left += pEl . offsetLeft ;
top += pEl . offsetTop ;
}
}
// default position is bottom & left
if ( ( this . _o . reposition && left + width > viewportWidth ) ||
(
this . _o . position . indexOf ( 'right' ) > - 1 &&
left - width + field . offsetWidth > 0
)
) {
left = left - width + field . offsetWidth ;
}
if ( ( this . _o . reposition && top + height > viewportHeight + scrollTop ) ||
(
this . _o . position . indexOf ( 'top' ) > - 1 &&
top - height - field . offsetHeight > 0
)
) {
top = top - height - field . offsetHeight ;
}
this . el . style . left = left + 'px' ;
this . el . style . top = top + 'px' ;
} ,
/ * *
* render HTML for a particular month
* /
render : function ( year , month )
{
var opts = this . _o ,
now = new Date ( ) ,
days = getDaysInMonth ( year , month ) ,
before = new Date ( year , month , 1 ) . getDay ( ) ,
data = [ ] ,
row = [ ] ;
setToStartOfDay ( now ) ;
if ( opts . firstDay > 0 ) {
before -= opts . firstDay ;
if ( before < 0 ) {
before += 7 ;
}
}
2016-01-20 21:06:41 +01:00
var previousMonth = month === 0 ? 11 : month - 1 ,
nextMonth = month === 11 ? 0 : month + 1 ,
yearOfPreviousMonth = month === 0 ? year - 1 : year ,
yearOfNextMonth = month === 11 ? year + 1 : year ,
daysInPreviousMonth = getDaysInMonth ( yearOfPreviousMonth , previousMonth ) ;
2015-08-10 12:50:38 +02:00
var cells = days + before ,
after = cells ;
while ( after > 7 ) {
after -= 7 ;
}
cells += 7 - after ;
for ( var i = 0 , r = 0 ; i < cells ; i ++ )
{
var day = new Date ( year , month , 1 + ( i - before ) ) ,
isSelected = isDate ( this . _d ) ? compareDates ( day , this . _d ) : false ,
isToday = compareDates ( day , now ) ,
isEmpty = i < before || i >= ( days + before ) ,
2016-01-20 21:06:41 +01:00
dayNumber = 1 + ( i - before ) ,
monthNumber = month ,
yearNumber = year ,
2015-08-10 12:50:38 +02:00
isStartRange = opts . startRange && compareDates ( opts . startRange , day ) ,
isEndRange = opts . endRange && compareDates ( opts . endRange , day ) ,
isInRange = opts . startRange && opts . endRange && opts . startRange < day && day < opts . endRange ,
isDisabled = ( opts . minDate && day < opts . minDate ) ||
( opts . maxDate && day > opts . maxDate ) ||
( opts . disableWeekends && isWeekend ( day ) ) ||
2016-01-20 21:06:41 +01:00
( opts . disableDayFn && opts . disableDayFn ( day ) ) ;
if ( isEmpty ) {
if ( i < before ) {
dayNumber = daysInPreviousMonth + dayNumber ;
monthNumber = previousMonth ;
yearNumber = yearOfPreviousMonth ;
} else {
dayNumber = dayNumber - days ;
monthNumber = nextMonth ;
yearNumber = yearOfNextMonth ;
}
}
var dayConfig = {
day : dayNumber ,
month : monthNumber ,
year : yearNumber ,
2015-08-10 12:50:38 +02:00
isSelected : isSelected ,
isToday : isToday ,
isDisabled : isDisabled ,
isEmpty : isEmpty ,
isStartRange : isStartRange ,
isEndRange : isEndRange ,
2016-01-20 21:06:41 +01:00
isInRange : isInRange ,
showDaysInNextAndPreviousMonths : opts . showDaysInNextAndPreviousMonths
2015-08-10 12:50:38 +02:00
} ;
row . push ( renderDay ( dayConfig ) ) ;
if ( ++ r === 7 ) {
if ( opts . showWeekNumber ) {
row . unshift ( renderWeek ( i - before , month , year ) ) ;
}
data . push ( renderRow ( row , opts . isRTL ) ) ;
row = [ ] ;
r = 0 ;
}
}
return renderTable ( opts , data ) ;
} ,
isVisible : function ( )
{
return this . _v ;
} ,
show : function ( )
{
if ( ! this . _v ) {
removeClass ( this . el , 'is-hidden' ) ;
this . _v = true ;
this . draw ( ) ;
if ( this . _o . bound ) {
addEvent ( document , 'click' , this . _onClick ) ;
this . adjustPosition ( ) ;
}
if ( typeof this . _o . onOpen === 'function' ) {
this . _o . onOpen . call ( this ) ;
}
}
} ,
hide : function ( )
{
var v = this . _v ;
if ( v !== false ) {
if ( this . _o . bound ) {
removeEvent ( document , 'click' , this . _onClick ) ;
}
this . el . style . position = 'static' ; // reset
this . el . style . left = 'auto' ;
this . el . style . top = 'auto' ;
addClass ( this . el , 'is-hidden' ) ;
this . _v = false ;
if ( v !== undefined && typeof this . _o . onClose === 'function' ) {
this . _o . onClose . call ( this ) ;
}
}
} ,
/ * *
* GAME OVER
* /
destroy : function ( )
{
this . hide ( ) ;
removeEvent ( this . el , 'mousedown' , this . _onMouseDown , true ) ;
2015-09-23 15:35:22 +02:00
removeEvent ( this . el , 'touchend' , this . _onMouseDown , true ) ;
2015-08-10 12:50:38 +02:00
removeEvent ( this . el , 'change' , this . _onChange ) ;
if ( this . _o . field ) {
removeEvent ( this . _o . field , 'change' , this . _onInputChange ) ;
if ( this . _o . bound ) {
removeEvent ( this . _o . trigger , 'click' , this . _onInputClick ) ;
removeEvent ( this . _o . trigger , 'focus' , this . _onInputFocus ) ;
removeEvent ( this . _o . trigger , 'blur' , this . _onInputBlur ) ;
}
}
if ( this . el . parentNode ) {
this . el . parentNode . removeChild ( this . el ) ;
}
}
} ;
return Pikaday ;
} ) ) ;