import { Component , Input , Output , EventEmitter , OnChanges , OnDestroy , SimpleChanges , ElementRef , Renderer , ViewChild , ChangeDetectorRef , ViewEncapsulation , forwardRef } from "@angular/core" ; import { ControlValueAccessor , NG_VALUE_ACCESSOR } from "@angular/forms" ; import { IMyDateRange , IMyDate , IMyMonth , IMyCalendarDay , IMyCalendarMonth , IMyCalendarYear , IMyWeek , IMyDayLabels , IMyMonthLabels , IMyOptions , IMyDateRangeModel , IMyInputFieldChanged , IMyCalendarViewChanged , IMyInputFocusBlur , IMyDateSelected } from "./interfaces/index" ; import { DateRangeUtilService } from "./services/my-date-range-picker.date.range.util.service" ; declare var require ; const myDrpStyles = require ( "./my-date-range-picker.component.css" ) ; const myDrpTemplate = require ( "./my-date-range-picker.component.html" ) ; export const MYDRP_VALUE_ACCESSOR = { provide : NG_VALUE_ACCESSOR , useExisting : forwardRef ( ( ) => MyDateRangePicker ) , multi : true } ; enum Year { min = 1100 , max = 9100 } enum InputFocusBlur { focus = 1 , blur = 2 } enum KeyCode { enter = 13 , esc = 27 , space = 32 } enum MonthId { prev = 1 , curr = 2 , next = 3 } @ Component ( { selector : "my-date-range-picker" , exportAs : "mydaterangepicker" , styles : [ myDrpStyles ] , template : myDrpTemplate , providers : [ DateRangeUtilService , MYDRP_VALUE_ACCESSOR ] , encapsulation : ViewEncapsulation . None } ) export class MyDateRangePicker implements OnChanges , OnDestroy , ControlValueAccessor { @ Input ( ) options : any ; @ Input ( ) defaultMonth : string ; @ Input ( ) selDateRange : string ; @ Input ( ) placeholder : string ; @ Output ( ) dateRangeChanged : EventEmitter < IMyDateRangeModel > = new EventEmitter < IMyDateRangeModel > ( ) ; @ Output ( ) inputFieldChanged : EventEmitter < IMyInputFieldChanged > = new EventEmitter < IMyInputFieldChanged > ( ) ; @ Output ( ) calendarViewChanged : EventEmitter < IMyCalendarViewChanged > = new EventEmitter < IMyCalendarViewChanged > ( ) ; @ Output ( ) inputFocusBlur : EventEmitter < IMyInputFocusBlur > = new EventEmitter < IMyInputFocusBlur > ( ) ; @ Output ( ) dateSelected : EventEmitter < IMyDateSelected > = new EventEmitter < IMyDateSelected > ( ) ; @ ViewChild ( "selectorEl" ) selectorEl : any ; onChangeCb : ( _ : any ) => void = ( ) => { } ; onTouchedCb : ( ) => void = ( ) => { } ; showSelector : boolean = false ; visibleMonth : IMyMonth = { monthTxt : "" , monthNbr : 0 , year : 0 } ; selectedMonth : IMyMonth = { monthTxt : "" , monthNbr : 0 , year : 0 } ; weekDays : Array < string > = [ ] ; dates : Array < IMyWeek > = [ ] ; months : Array < Array < IMyCalendarMonth > > = [ ] ; years : Array < Array < IMyCalendarYear > > = [ ] ; selectionDayTxt : string = "" ; invalidDateRange : boolean = false ; dateRangeFormat : string = "" ; dayIdx : number = 0 ; weekDayOpts : Array < string > = [ "su" , "mo" , "tu" , "we" , "th" , "fr" , "sa" ] ; selectMonth : boolean = false ; selectYear : boolean = false ; prevMonthDisabled : boolean = false ; nextMonthDisabled : boolean = false ; prevYearDisabled : boolean = false ; nextYearDisabled : boolean = false ; prevYearsDisabled : boolean = false ; nextYearsDisabled : boolean = false ; prevMonthId : number = MonthId . prev ; currMonthId : number = MonthId . curr ; nextMonthId : number = MonthId . next ; beginDate : IMyDate = { year : 0 , month : 0 , day : 0 } ; endDate : IMyDate = { year : 0 , month : 0 , day : 0 } ; titleAreaText : string = "" ; globalListener : Function ; opts : IMyOptions = { dayLabels : < IMyDayLabels > { su : "Sun" , mo : "Mon" , tu : "Tue" , we : "Wed" , th : "Thu" , fr : "Fri" , sa : "Sat" } , monthLabels : < IMyMonthLabels > { 1 : "Jan" , 2 : "Feb" , 3 : "Mar" , 4 : "Apr" , 5 : "May" , 6 : "Jun" , 7 : "Jul" , 8 : "Aug" , 9 : "Sep" , 10 : "Oct" , 11 : "Nov" , 12 : "Dec" } , dateFormat : < string > "yyyy-mm-dd" , showClearBtn : < boolean > true , showApplyBtn : < boolean > true , showSelectDateText : < boolean > true , selectBeginDateTxt : < string > "Select Begin Date" , selectEndDateTxt : < string > "Select End Date" , firstDayOfWeek : < string > "mo" , sunHighlight : < boolean > true , markCurrentDay : < boolean > true , markCurrentMonth : < boolean > true , markCurrentYear : < boolean > true , height : < string > "34px" , width : < string > "262px" , selectorHeight : < string > "232px" , selectorWidth : < string > "252px" , inline : < boolean > false , showClearDateRangeBtn : < boolean > true , selectionTxtFontSize : < string > "14px" , alignSelectorRight : < boolean > false , indicateInvalidDateRange : < boolean > true , editableDateRangeField : < boolean > true , monthSelector : < boolean > true , yearSelector : < boolean > true , disableHeaderButtons : < boolean > true , showWeekNumbers : < boolean > false , minYear : < number > Year . min , maxYear : < number > Year . max , disableUntil : < IMyDate > { year : 0 , month : 0 , day : 0 } , disableSince : < IMyDate > { year : 0 , month : 0 , day : 0 } , disableDates : < Array < IMyDate > > [ ] , enableDates : < Array < IMyDate > > [ ] , disableDateRanges : < Array < IMyDateRange > > [ ] , componentDisabled : < boolean > false , showSelectorArrow : < boolean > true , openSelectorOnInputClick : < boolean > false , ariaLabelInputField : < string > "Date range input field" , ariaLabelClearDateRange : < string > "Clear date range" , ariaLabelOpenCalendar : < string > "Open Calendar" , ariaLabelPrevMonth : < string > "Previous Month" , ariaLabelNextMonth : < string > "Next Month" , ariaLabelPrevYear : < string > "Previous Year" , ariaLabelNextYear : < string > "Next Year" } ; constructor ( public elem , private renderer , private cdr , private drus ) { this . globalListener = renderer . listenGlobal ( "document" , "click" , ( event ) => { if ( this . showSelector && event . target && this . elem . nativeElement !== event . target && ! this . elem . nativeElement . contains ( event . target ) ) { this . showSelector = false ; } if ( this . opts . monthSelector || this . opts . yearSelector ) { this . resetMonthYearSelect ( ) ; } } ) ; } resetMonthYearSelect ( ) { this . selectMonth = false ; this . selectYear = false ; } onSelectMonthClicked ( event ) { event . stopPropagation ( ) ; this . selectMonth = ! this . selectMonth ; this . selectYear = false ; this . cdr . detectChanges ( ) ; if ( this . selectMonth ) { let today = this . getToday ( ) ; this . months . length = 0 ; for ( let i = 1 ; i <= 12 ; i += 3 ) { let row = [ ] ; for ( let j = i ; j < i + 3 ; j ++ ) { let disabled = this . drus . isMonthDisabledByDisableUntil ( { year : this . visibleMonth . year , month : j , day : this . daysInMonth ( j , this . visibleMonth . year ) } , this . opts . disableUntil ) || this . drus . isMonthDisabledByDisableSince ( { year : this . visibleMonth . year , month : j , day : 1 } , this . opts . disableSince ) ; row . push ( { nbr : j , name : this . opts . monthLabels [ j ] , currMonth : j === today . month && this . visibleMonth . year === today . year , selected : j === this . visibleMonth . monthNbr , disabled : disabled } ) ; } this . months . push ( row ) ; } } } onMonthCellClicked ( cell ) { let mc = cell . nbr !== this . visibleMonth . monthNbr ; this . visibleMonth = { monthTxt : this . monthText ( cell . nbr ) , monthNbr : cell . nbr , year : this . visibleMonth . year } ; this . generateCalendar ( cell . nbr , this . visibleMonth . year , mc ) ; this . selectMonth = false ; this . selectorEl . nativeElement . focus ( ) ; } onMonthCellKeyDown ( event , cell ) { if ( ( event . keyCode === KeyCode . enter || event . keyCode === KeyCode . space ) && ! cell . disabled ) { event . preventDefault ( ) ; this . onMonthCellClicked ( cell ) ; } } onSelectYearClicked ( event ) { event . stopPropagation ( ) ; this . selectYear = ! this . selectYear ; this . selectMonth = false ; this . cdr . detectChanges ( ) ; if ( this . selectYear ) { this . generateYears ( this . visibleMonth . year ) ; } } onYearCellClicked ( cell ) { let yc = cell . year !== this . visibleMonth . year ; this . visibleMonth = { monthTxt : this . visibleMonth . monthTxt , monthNbr : this . visibleMonth . monthNbr , year : cell . year } ; this . generateCalendar ( this . visibleMonth . monthNbr , cell . year , yc ) ; this . selectYear = false ; this . selectorEl . nativeElement . focus ( ) ; } onYearCellKeyDown ( event , cell ) { if ( ( event . keyCode === KeyCode . enter || event . keyCode === KeyCode . space ) && ! cell . disabled ) { event . preventDefault ( ) ; this . onYearCellClicked ( cell ) ; } } onPrevYears ( event , year ) { event . stopPropagation ( ) ; this . generateYears ( year - 25 ) ; } onNextYears ( event , year ) { event . stopPropagation ( ) ; this . generateYears ( year + 25 ) ; } generateYears ( year ) { this . years . length = 0 ; let today = this . getToday ( ) ; for ( let i = year ; i <= 20 + year ; i += 5 ) { let row = [ ] ; for ( let j = i ; j < i + 5 ; j ++ ) { let disabled = this . drus . isMonthDisabledByDisableUntil ( { year : j , month : this . visibleMonth . monthNbr , day : this . daysInMonth ( this . visibleMonth . monthNbr , j ) } , this . opts . disableUntil ) || this . drus . isMonthDisabledByDisableSince ( { year : j , month : this . visibleMonth . monthNbr , day : 1 } , this . opts . disableSince ) ; let minMax = j < this . opts . minYear || j > this . opts . maxYear ; row . push ( { year : j , currYear : j === today . year , selected : j === this . visibleMonth . year , disabled : disabled || minMax } ) ; } this . years . push ( row ) ; } this . prevYearsDisabled = this . years [ 0 ] [ 0 ] . year <= this . opts . minYear || this . drus . isMonthDisabledByDisableUntil ( { year : this . years [ 0 ] [ 0 ] . year - 1 , month : this . visibleMonth . monthNbr , day : this . daysInMonth ( this . visibleMonth . monthNbr , this . years [ 0 ] [ 0 ] . year - 1 ) } , this . opts . disableUntil ) ; this . nextYearsDisabled = this . years [ 4 ] [ 4 ] . year >= this . opts . maxYear || this . drus . isMonthDisabledByDisableSince ( { year : this . years [ 4 ] [ 4 ] . year + 1 , month : this . visibleMonth . monthNbr , day : 1 } , this . opts . disableSince ) ; } onUserDateRangeInput ( value ) { this . invalidDateRange = false ; if ( value . length === 0 ) { if ( this . drus . isInitializedDate ( this . beginDate ) && this . drus . isInitializedDate ( this . endDate ) ) { this . clearDateRange ( ) ; } else { this . inputFieldChanged . emit ( { value : value , dateRangeFormat : this . dateRangeFormat , valid : false } ) ; } } else { let daterange = this . drus . isDateRangeValid ( value , this . opts . dateFormat , this . opts . minYear , this . opts . maxYear , this . opts . disableUntil , this . opts . disableSince , this . opts . disableDates , this . opts . disableDateRanges , this . opts . enableDates , this . opts . monthLabels ) ; if ( this . drus . isInitializedDate ( daterange . beginDate ) && this . drus . isInitializedDate ( daterange . endDate ) ) { this . beginDate = daterange . beginDate ; this . endDate = daterange . endDate ; this . rangeSelected ( ) ; } else { this . invalidDateRange = true ; this . onChangeCb ( null ) ; this . onTouchedCb ( ) ; this . inputFieldChanged . emit ( { value : value , dateRangeFormat : this . dateRangeFormat , valid : false } ) ; } } } onFocusInput ( event ) { this . inputFocusBlur . emit ( { reason : InputFocusBlur . focus , value : event . target . value } ) ; } onBlurInput ( event ) { this . selectionDayTxt = event . target . value ; this . onTouchedCb ( ) ; this . inputFocusBlur . emit ( { reason : InputFocusBlur . blur , value : event . target . value } ) ; } onCloseSelector ( event ) { if ( event . keyCode === KeyCode . esc && this . showSelector && ! this . opts . inline ) { this . showSelector = false ; } } parseOptions ( ) { if ( this . options !== undefined ) { Object . keys ( this . options ) . forEach ( ( k ) => { ( < IMyOptions > this . opts ) [ k ] = this . options [ k ] ; } ) ; } if ( this . opts . minYear < Year . min ) { this . opts . minYear = Year . min ; } if ( this . opts . maxYear > Year . max ) { this . opts . maxYear = Year . max ; } this . dateRangeFormat = this . opts . dateFormat + " - " + this . opts . dateFormat ; this . dayIdx = this . weekDayOpts . indexOf ( this . opts . firstDayOfWeek ) ; if ( this . dayIdx !== - 1 ) { let idx = this . dayIdx ; for ( let i = 0 ; i < this . weekDayOpts . length ; i ++ ) { this . weekDays . push ( this . opts . dayLabels [ this . weekDayOpts [ idx ] ] ) ; idx = this . weekDayOpts [ idx ] === "sa" ? 0 : idx + 1 ; } } } writeValue ( value ) { if ( value && value [ "beginDate" ] && value [ "endDate" ] ) { this . beginDate = this . parseSelectedDate ( value [ "beginDate" ] ) ; this . endDate = this . parseSelectedDate ( value [ "endDate" ] ) ; let begin = this . formatDate ( this . beginDate ) ; let end = this . formatDate ( this . endDate ) ; this . selectionDayTxt = begin + " - " + end ; this . titleAreaText = this . selectionDayTxt ; this . inputFieldChanged . emit ( { value : this . selectionDayTxt , dateRangeFormat : this . dateRangeFormat , valid : true } ) ; } else if ( value === null || value === "" ) { this . clearRangeValues ( ) ; this . inputFieldChanged . emit ( { value : "" , dateRangeFormat : this . dateRangeFormat , valid : false } ) ; } this . invalidDateRange = false ; } setDisabledState ( disabled ) { this . opts . componentDisabled = disabled ; } registerOnChange ( fn ) { this . onChangeCb = fn ; } registerOnTouched ( fn ) { this . onTouchedCb = fn ; } ngOnDestroy ( ) { this . globalListener ( ) ; } ngOnChanges ( changes ) { if ( changes . hasOwnProperty ( "placeholder" ) ) { this . placeholder = changes [ "placeholder" ] . currentValue ; } if ( changes . hasOwnProperty ( "options" ) ) { this . options = changes [ "options" ] . currentValue ; this . weekDays . length = 0 ; this . parseOptions ( ) ; } let dmChange = false ; if ( changes . hasOwnProperty ( "defaultMonth" ) ) { let dm = changes [ "defaultMonth" ] . currentValue ; if ( typeof dm === "object" ) { dm = dm . defMonth ; } if ( dm !== null && dm !== undefined && dm !== "" ) { this . selectedMonth = this . parseSelectedMonth ( dm ) ; } else { this . selectedMonth = { monthTxt : "" , monthNbr : 0 , year : 0 } ; } dmChange = true ; } if ( changes . hasOwnProperty ( "selDateRange" ) ) { let sdr = changes [ "selDateRange" ] ; if ( sdr . currentValue !== null && sdr . currentValue !== undefined && sdr . currentValue !== "" ) { if ( typeof sdr . currentValue === "string" ) { let split = sdr . currentValue . split ( " - " ) ; this . beginDate = this . parseSelectedDate ( split [ 0 ] ) ; this . endDate = this . parseSelectedDate ( split [ 1 ] ) ; this . selectionDayTxt = sdr . currentValue ; } else if ( typeof sdr . currentValue === "object" ) { this . beginDate = this . parseSelectedDate ( sdr . currentValue [ "beginDate" ] ) ; this . endDate = this . parseSelectedDate ( sdr . currentValue [ "endDate" ] ) ; this . selectionDayTxt = this . formatDate ( this . beginDate ) + " - " + this . formatDate ( this . endDate ) ; } this . titleAreaText = this . selectionDayTxt ; setTimeout ( ( ) => { this . onChangeCb ( this . getDateRangeModel ( this . beginDate , this . endDate ) ) ; } ) ; this . toBeginDate ( ) ; } else { if ( ! sdr . isFirstChange ( ) ) { this . clearDateRange ( ) ; } } } if ( this . visibleMonth . year === 0 && this . visibleMonth . monthNbr === 0 || dmChange ) { this . setVisibleMonth ( ) ; } else { this . visibleMonth . monthTxt = this . opts . monthLabels [ this . visibleMonth . monthNbr ] ; this . generateCalendar ( this . visibleMonth . monthNbr , this . visibleMonth . year , false ) ; } } removeBtnClicked ( ) { this . clearDateRange ( ) ; } openBtnClicked ( ) { this . showSelector = ! this . showSelector ; this . cdr . detectChanges ( ) ; if ( this . showSelector ) { this . setVisibleMonth ( ) ; } } setVisibleMonth ( ) { if ( this . drus . isInitializedDate ( this . beginDate ) ) { this . toBeginDate ( ) ; } else { let y = 0 , m = 0 ; if ( this . selectedMonth . year === 0 && this . selectedMonth . monthNbr === 0 ) { let today = this . getToday ( ) ; y = today . year ; m = today . month ; } else { y = this . selectedMonth . year ; m = this . selectedMonth . monthNbr ; } this . visibleMonth = { monthTxt : this . opts . monthLabels [ m ] , monthNbr : m , year : y } ; this . generateCalendar ( m , y , true ) ; } } onPrevMonth ( ) { let d = this . getDate ( { year : this . visibleMonth . year , month : this . visibleMonth . monthNbr , day : 1 } ) ; d . setMonth ( d . getMonth ( ) - 1 ) ; let y = d . getFullYear ( ) ; let m = d . getMonth ( ) + 1 ; this . visibleMonth = { monthTxt : this . monthText ( m ) , monthNbr : m , year : y } ; this . generateCalendar ( m , y , true ) ; } onNextMonth ( ) { let d = this . getDate ( { year : this . visibleMonth . year , month : this . visibleMonth . monthNbr , day : 1 } ) ; d . setMonth ( d . getMonth ( ) + 1 ) ; let y = d . getFullYear ( ) ; let m = d . getMonth ( ) + 1 ; this . visibleMonth = { monthTxt : this . monthText ( m ) , monthNbr : m , year : y } ; this . generateCalendar ( m , y , true ) ; } onPrevYear ( ) { if ( this . visibleMonth . year - 1 < this . opts . minYear ) { return ; } this . visibleMonth . year -- ; this . generateCalendar ( this . visibleMonth . monthNbr , this . visibleMonth . year , true ) ; } onNextYear ( ) { if ( this . visibleMonth . year + 1 > this . opts . maxYear ) { return ; } this . visibleMonth . year ++ ; this . generateCalendar ( this . visibleMonth . monthNbr , this . visibleMonth . year , true ) ; } clearRangeValues ( ) { this . invalidDateRange = false ; this . selectionDayTxt = "" ; this . beginDate = { year : 0 , month : 0 , day : 0 } ; this . endDate = { year : 0 , month : 0 , day : 0 } ; this . titleAreaText = this . opts . selectBeginDateTxt ; this . generateCalendar ( this . visibleMonth . monthNbr , this . visibleMonth . year , false ) ; } onCellClicked ( cell ) { let bi = this . drus . isInitializedDate ( this . beginDate ) ; let ei = this . drus . isInitializedDate ( this . endDate ) ; if ( ei ) { this . beginDate = { year : 0 , month : 0 , day : 0 } ; this . endDate = { year : 0 , month : 0 , day : 0 } ; this . titleAreaText = this . opts . selectBeginDateTxt ; bi = false ; ei = false ; } if ( ! ei ) { if ( ! bi || bi && this . drus . getTimeInMilliseconds ( cell . dateObj ) < this . drus . getTimeInMilliseconds ( this . beginDate ) ) { this . selectBeginDate ( cell . dateObj ) ; this . titleAreaText = this . formatDate ( cell . dateObj ) + " - " + this . opts . selectEndDateTxt ; } else if ( this . drus . getTimeInMilliseconds ( cell . dateObj ) >= this . drus . getTimeInMilliseconds ( this . beginDate ) ) { this . selectEndDate ( cell . dateObj ) ; this . rangeSelected ( ) ; this . titleAreaText = this . formatDate ( this . beginDate ) + " - " + this . formatDate ( cell . dateObj ) ; } } } selectBeginDate ( date ) { this . beginDate = date ; let formatted = this . formatDate ( date ) ; this . titleAreaText = formatted + " - " + this . opts . selectEndDateTxt ; this . dateSelected . emit ( { type : 1 , date : date , formatted : formatted , jsdate : this . getDate ( date ) } ) ; } selectEndDate ( date ) { this . endDate = date ; let formatted = this . formatDate ( date ) ; this . titleAreaText = this . formatDate ( this . beginDate ) + " - " + formatted ; this . dateSelected . emit ( { type : 2 , date : date , formatted : formatted , jsdate : this . getDate ( date ) } ) ; } onCellKeyDown ( event , cell ) { if ( ( event . keyCode === KeyCode . enter || event . keyCode === KeyCode . space ) && ! cell . disabled ) { event . preventDefault ( ) ; this . onCellClicked ( cell ) ; } } onCellMouseEnter ( cell ) { if ( this . drus . isInitializedDate ( this . beginDate ) && ! this . drus . isInitializedDate ( this . endDate ) ) { for ( let w of this . dates ) { for ( let day of w . week ) { day . range = this . drus . getTimeInMilliseconds ( day . dateObj ) >= this . drus . getTimeInMilliseconds ( this . beginDate ) && this . drus . getTimeInMilliseconds ( day . dateObj ) <= this . drus . getTimeInMilliseconds ( cell . dateObj ) ; } } } } onCellMouseLeave ( ) { for ( let w of this . dates ) { for ( let day of w . week ) { day . range = false ; } } } toBeginDate ( ) { let viewChange = this . beginDate . year !== this . visibleMonth . year || this . beginDate . month !== this . visibleMonth . monthNbr ; this . visibleMonth = { monthTxt : this . monthText ( this . beginDate . month ) , monthNbr : this . beginDate . month , year : this . beginDate . year } ; this . generateCalendar ( this . beginDate . month , this . beginDate . year , viewChange ) ; } clearDateRange ( ) { if ( this . drus . isInitializedDate ( this . endDate ) ) { this . dateRangeChanged . emit ( { beginDate : { year : 0 , month : 0 , day : 0 } , beginJsDate : null , endDate : { year : 0 , month : 0 , day : 0 } , endJsDate : null , formatted : "" , beginEpoc : 0 , endEpoc : 0 } ) ; if ( this . selectionDayTxt !== "" ) { this . inputFieldChanged . emit ( { value : "" , dateRangeFormat : this . dateRangeFormat , valid : false } ) ; } this . onChangeCb ( null ) ; this . onTouchedCb ( ) ; } this . clearRangeValues ( ) ; } rangeSelected ( ) { let dateRangeModel = this . getDateRangeModel ( this . beginDate , this . endDate ) ; this . selectionDayTxt = this . formatDate ( this . beginDate ) + " - " + this . formatDate ( this . endDate ) ; this . showSelector = false ; this . dateRangeChanged . emit ( dateRangeModel ) ; this . inputFieldChanged . emit ( { value : this . selectionDayTxt , dateRangeFormat : this . dateRangeFormat , valid : true } ) ; this . onChangeCb ( dateRangeModel ) ; this . onTouchedCb ( ) ; this . invalidDateRange = false ; if ( this . opts . monthSelector || this . opts . yearSelector ) { this . resetMonthYearSelect ( ) ; } } getDateRangeModel ( beginDate , endDate ) { let bEpoc = this . drus . getTimeInMilliseconds ( beginDate ) / 1000.0 ; let eEpoc = this . drus . getTimeInMilliseconds ( endDate ) / 1000.0 ; return { beginDate : beginDate , beginJsDate : this . getDate ( beginDate ) , endDate : endDate , endJsDate : this . getDate ( endDate ) , formatted : this . formatDate ( beginDate ) + " - " + this . formatDate ( endDate ) , beginEpoc : bEpoc , endEpoc : eEpoc } ; } isInRange ( val ) { if ( ! this . drus . isInitializedDate ( this . beginDate ) || ! this . drus . isInitializedDate ( this . endDate ) ) { return false ; } let input = this . drus . getTimeInMilliseconds ( val . dateObj ) ; if ( input >= this . drus . getTimeInMilliseconds ( this . beginDate ) && input <= this . drus . getTimeInMilliseconds ( this . endDate ) ) { return true ; } return false ; } isRangeSelected ( ) { if ( this . drus . isInitializedDate ( this . beginDate ) && this . drus . isInitializedDate ( this . endDate ) ) { return true ; } return false ; } preZero ( val ) { return parseInt ( val ) < 10 ? "0" + val : val ; } formatDate ( val ) { let formatted = this . opts . dateFormat . replace ( "yyyy" , val . year ) . replace ( "dd" , this . preZero ( val . day ) ) ; return this . opts . dateFormat . indexOf ( "mmm" ) !== - 1 ? formatted . replace ( "mmm" , this . monthText ( val . month ) ) : formatted . replace ( "mm" , this . preZero ( val . month ) ) ; } monthText ( m ) { return this . opts . monthLabels [ m ] ; } monthStartIdx ( y , m ) { let d = new Date ( ) ; d . setDate ( 1 ) ; d . setMonth ( m - 1 ) ; d . setFullYear ( y ) ; let idx = d . getDay ( ) + this . sundayIdx ( ) ; return idx >= 7 ? idx - 7 : idx ; } daysInMonth ( m , y ) { return new Date ( y , m , 0 ) . getDate ( ) ; } daysInPrevMonth ( m , y ) { let d = this . getDate ( { year : y , month : m , day : 1 } ) ; d . setMonth ( d . getMonth ( ) - 1 ) ; return this . daysInMonth ( d . getMonth ( ) + 1 , d . getFullYear ( ) ) ; } isCurrDay ( d , m , y , cmo , today ) { return d === today . day && m === today . month && y === today . year && cmo === this . currMonthId ; } getPreviousDate ( date ) { let d = this . getDate ( date ) ; d . setDate ( d . getDate ( ) - 1 ) ; return { year : d . getFullYear ( ) , month : d . getMonth ( ) + 1 , day : d . getDate ( ) } ; } getNextDate ( date ) { let d = this . getDate ( date ) ; d . setDate ( d . getDate ( ) + 1 ) ; return { year : d . getFullYear ( ) , month : d . getMonth ( ) + 1 , day : d . getDate ( ) } ; } getDayNumber ( date ) { let d = this . getDate ( date ) ; return d . getDay ( ) ; } getWeekday ( date ) { return this . weekDayOpts [ this . getDayNumber ( date ) ] ; } getDate ( date ) { return new Date ( date . year , date . month - 1 , date . day , 0 , 0 , 0 , 0 ) ; } getToday ( ) { let date = new Date ( ) ; return { year : date . getFullYear ( ) , month : date . getMonth ( ) + 1 , day : date . getDate ( ) } ; } sundayIdx ( ) { return this . dayIdx > 0 ? 7 - this . dayIdx : 0 ; } generateCalendar ( m , y , viewChange ) { this . dates . length = 0 ; let today = this . getToday ( ) ; let monthStart = this . monthStartIdx ( y , m ) ; let dInThisM = this . daysInMonth ( m , y ) ; let dInPrevM = this . daysInPrevMonth ( m , y ) ; let dayNbr = 1 ; let cmo = this . prevMonthId ; for ( let i = 1 ; i < 7 ; i ++ ) { let week = [ ] ; if ( i === 1 ) { let pm = dInPrevM - monthStart + 1 ; for ( let j = pm ; j <= dInPrevM ; j ++ ) { let date = { year : m === 1 ? y - 1 : y , month : m === 1 ? 12 : m - 1 , day : j } ; week . push ( { dateObj : date , cmo : cmo , currDay : this . isCurrDay ( j , m , y , cmo , today ) , dayNbr : this . getDayNumber ( date ) , disabled : this . drus . isDisabledDay ( date , this . opts . minYear , this . opts . maxYear , this . opts . disableUntil , this . opts . disableSince , this . opts . disableDates , this . opts . disableDateRanges , this . opts . enableDates ) , range : false } ) ; } cmo = this . currMonthId ; let daysLeft = 7 - week . length ; for ( let j = 0 ; j < daysLeft ; j ++ ) { let date = { year : y , month : m , day : dayNbr } ; week . push ( { dateObj : date , cmo : cmo , currDay : this . isCurrDay ( dayNbr , m , y , cmo , today ) , dayNbr : this . getDayNumber ( date ) , disabled : this . drus . isDisabledDay ( date , this . opts . minYear , this . opts . maxYear , this . opts . disableUntil , this . opts . disableSince , this . opts . disableDates , this . opts . disableDateRanges , this . opts . enableDates ) , range : false } ) ; dayNbr ++ ; } } else { for ( let j = 1 ; j < 8 ; j ++ ) { if ( dayNbr > dInThisM ) { dayNbr = 1 ; cmo = this . nextMonthId ; } let date = { year : cmo === this . nextMonthId && m === 12 ? y + 1 : y , month : cmo === this . currMonthId ? m : cmo === this . nextMonthId && m < 12 ? m + 1 : 1 , day : dayNbr } ; week . push ( { dateObj : date , cmo : cmo , currDay : this . isCurrDay ( dayNbr , m , y , cmo , today ) , dayNbr : this . getDayNumber ( date ) , disabled : this . drus . isDisabledDay ( date , this . opts . minYear , this . opts . maxYear , this . opts . disableUntil , this . opts . disableSince , this . opts . disableDates , this . opts . disableDateRanges , this . opts . enableDates ) , range : false } ) ; dayNbr ++ ; } } let weekNbr = this . opts . showWeekNumbers && this . opts . firstDayOfWeek === "mo" ? this . drus . getWeekNumber ( week [ 0 ] . dateObj ) : 0 ; this . dates . push ( { week : week , weekNbr : weekNbr } ) ; } this . setHeaderBtnDisabledState ( m , y ) ; if ( viewChange ) { this . calendarViewChanged . emit ( { year : y , month : m , first : { number : 1 , weekday : this . getWeekday ( { year : y , month : m , day : 1 } ) } , last : { number : dInThisM , weekday : this . getWeekday ( { year : y , month : m , day : dInThisM } ) } } ) ; } } setHeaderBtnDisabledState ( m , y ) { let dpm = false ; let dpy = false ; let dnm = false ; let dny = false ; if ( this . opts . disableHeaderButtons ) { dpm = this . drus . isMonthDisabledByDisableUntil ( { year : m === 1 ? y - 1 : y , month : m === 1 ? 12 : m - 1 , day : this . daysInMonth ( m === 1 ? 12 : m - 1 , m === 1 ? y - 1 : y ) } , this . opts . disableUntil ) ; dpy = this . drus . isMonthDisabledByDisableUntil ( { year : y - 1 , month : m , day : this . daysInMonth ( m , y - 1 ) } , this . opts . disableUntil ) ; dnm = this . drus . isMonthDisabledByDisableSince ( { year : m === 12 ? y + 1 : y , month : m === 12 ? 1 : m + 1 , day : 1 } , this . opts . disableSince ) ; dny = this . drus . isMonthDisabledByDisableSince ( { year : y + 1 , month : m , day : 1 } , this . opts . disableSince ) ; } this . prevMonthDisabled = m === 1 && y === this . opts . minYear || dpm ; this . prevYearDisabled = y - 1 < this . opts . minYear || dpy ; this . nextMonthDisabled = m === 12 && y === this . opts . maxYear || dnm ; this . nextYearDisabled = y + 1 > this . opts . maxYear || dny ; } parseSelectedDate ( selDate ) { let date = { day : 0 , month : 0 , year : 0 } ; if ( typeof selDate === "string" ) { let sd = < string > selDate ; date . day = this . drus . parseDatePartNumber ( this . opts . dateFormat , sd , "dd" ) ; date . month = this . opts . dateFormat . indexOf ( "mmm" ) !== - 1 ? this . drus . parseDatePartMonthName ( this . opts . dateFormat , sd , "mmm" , this . opts . monthLabels ) : this . drus . parseDatePartNumber ( this . opts . dateFormat , sd , "mm" ) ; date . year = this . drus . parseDatePartNumber ( this . opts . dateFormat , sd , "yyyy" ) ; } else if ( typeof selDate === "object" ) { date = selDate ; } return date ; } parseSelectedMonth ( ms ) { return this . drus . parseDefaultMonth ( ms ) ; } }