import { Component , ElementRef , ViewEncapsulation , ViewChild , Renderer2 , ChangeDetectorRef , AfterViewInit , OnDestroy , HostBinding } from "@angular/core" ; import { IMyDate } from "../../interfaces/my-date.interface" ; import { IMyDateRange } from "../../interfaces/my-date-range.interface" ; import { IMyMonth } from "../../interfaces/my-month.interface" ; import { IMyCalendarDay } from "../../interfaces/my-calendar-day.interface" ; import { IMyCalendarMonth } from "../../interfaces/my-calendar-month.interface" ; import { IMyCalendarYear } from "../../interfaces/my-calendar-year.interface" ; import { IMyWeek } from "../../interfaces/my-week.interface" ; import { IMyOptions } from "../../interfaces/my-options.interface" ; import { IMySelectorPosition } from "../../interfaces/my-selector-pos.interface" ; import { IMyCalendarViewChanged } from "../../interfaces/my-calendar-view-changed.interface" ; import { IMyDateModel } from "../../interfaces/my-date-model.interface" ; import { IMyRangeDateSelection } from "../../interfaces/my-range-date-selection.interface" ; import { IMyCalendarAnimation } from "../../interfaces/my-calendar-animation.interface" ; import { IMyValidateOptions } from "../../interfaces/my-validate-options.interface" ; import { IMyDefaultMonth } from "../../interfaces/my-default-month.interface" ; import { UtilService } from "../../services/angular-mydatepicker.util.service" ; import { KeyCode } from "../../enums/key-code.enum" ; import { MonthId } from "../../enums/month-id.enum" ; import { DefaultView } from "../../enums/default-view.enum" ; import { CalAnimation } from "../../enums/cal-animation.enum" ; import { HeaderAction } from "../../enums/header-action.enum" ; import { ActiveView } from "../../enums/active-view.enum" ; import { DOT , UNDER_LINE , D , M , Y , DATE_ROW_COUNT , DATE_COL_COUNT , MONTH_ROW_COUNT , MONTH_COL_COUNT , YEAR_ROW_COUNT , YEAR_COL_COUNT , SU , MO , TU , WE , TH , FR , SA , EMPTY_STR , CLICK , STYLE , MY_DP_ANIMATION , ANIMATION_NAMES , IN , OUT , TABINDEX , TD_SELECTOR , ZERO_STR , YEAR_SEPARATOR } from "../../constants/constants" ; @ Component ( { selector : "lib-angular-mydatepicker-calendar" , templateUrl : './calendar.component.html' , styleUrls : [ '../../css/angular-mydatepicker.style.css' ] , providers : [ UtilService ] , encapsulation : ViewEncapsulation . None } ) export class CalendarComponent implements AfterViewInit , OnDestroy { @ ViewChild ( "selectorEl" ) selectorEl : ElementRef ; @ ViewChild ( "styleEl" ) styleEl : ElementRef ; @ HostBinding ( "style.position" ) position = "static" ; opts : IMyOptions ; visibleMonth : IMyMonth = { monthTxt : EMPTY_STR , monthNbr : 0 , year : 0 } ; selectedMonth : IMyMonth = { monthNbr : 0 , year : 0 } ; selectedDate : IMyDate = { year : 0 , month : 0 , day : 0 } ; selectedDateRange : IMyDateRange = { begin : { year : 0 , month : 0 , day : 0 } , end : { year : 0 , month : 0 , day : 0 } } ; weekDays : Array < string > = [ ] ; dates : Array < IMyWeek > = [ ] ; months : Array < Array < IMyCalendarMonth > > = [ ] ; years : Array < Array < IMyCalendarYear > > = [ ] ; yearsDuration : string = "" ; dayIdx : number = 0 ; weekDayOpts : Array < string > = [ SU , MO , TU , WE , TH , FR , SA ] ; selectMonth : boolean = false ; selectYear : boolean = false ; viewChanged : boolean = false ; dateChanged : ( dm : IMyDateModel , close : boolean ) => void ; calendarViewChanged : ( cvc : IMyCalendarViewChanged ) => void ; rangeDateSelection : ( rds : IMyRangeDateSelection ) => void ; viewActivated : ( va : ActiveView ) => void ; closedByEsc : ( ) => void ; selectorPos : IMySelectorPosition = null ; prevViewDisabled : boolean = false ; nextViewDisabled : boolean = false ; clickListener : ( ) => void ; constructor ( private elem , private renderer , private cdr , private utilService ) { this . clickListener = renderer . listen ( elem . nativeElement , CLICK , ( event ) => { if ( ( this . opts . monthSelector || this . opts . yearSelector ) && event . target ) { this . resetMonthYearSelect ( ) ; } } ) ; } ngAfterViewInit ( ) { const { stylesData , calendarAnimation , inline } = this . opts ; if ( stylesData . styles . length ) { const styleElTemp = this . renderer . createElement ( STYLE ) ; this . renderer . appendChild ( styleElTemp , this . renderer . createText ( stylesData . styles ) ) ; this . renderer . appendChild ( this . styleEl . nativeElement , styleElTemp ) ; } if ( calendarAnimation . in !== CalAnimation . None ) { this . setCalendarAnimation ( calendarAnimation , true ) ; } if ( ! inline ) { this . focusToSelector ( ) ; } } ngOnDestroy ( ) { this . clickListener ( ) ; } initializeComponent ( opts , defaultMonth , selectedValue , inputValue , selectorPos , dc , cvc , rds , va , cbe ) { this . opts = opts ; this . selectorPos = selectorPos ; this . dateChanged = dc ; this . calendarViewChanged = cvc ; this . rangeDateSelection = rds ; this . viewActivated = va ; this . closedByEsc = cbe ; const { defaultView , firstDayOfWeek , dayLabels } = opts ; this . weekDays . length = 0 ; this . dayIdx = this . weekDayOpts . indexOf ( firstDayOfWeek ) ; if ( this . dayIdx !== - 1 ) { let idx = this . dayIdx ; for ( let i = 0 ; i < this . weekDayOpts . length ; i ++ ) { this . weekDays . push ( dayLabels [ this . weekDayOpts [ idx ] ] ) ; idx = this . weekDayOpts [ idx ] === SA ? 0 : idx + 1 ; } } this . initializeView ( defaultMonth , selectedValue , inputValue ) ; this . setCalendarVisibleMonth ( ) ; this . setDefaultView ( defaultView ) ; } initializeView ( defaultMonth , selectedValue , inputValue ) { const { dateRange } = this . opts ; const today = this . utilService . getToday ( ) ; this . selectedMonth = { monthNbr : today . month , year : today . year } ; const { defMonth , overrideSelection } = defaultMonth ; if ( defMonth && defMonth . length ) { this . selectedMonth = this . utilService . parseDefaultMonth ( defMonth ) ; } let validateOpts = null ; if ( ! dateRange ) { validateOpts = { validateDisabledDates : false , selectedValue : this . utilService . getSelectedValue ( selectedValue , dateRange ) } ; const date = this . utilService . isDateValid ( inputValue , this . opts , validateOpts ) ; if ( this . utilService . isInitializedDate ( date ) ) { this . selectedDate = date ; if ( ! overrideSelection ) { this . selectedMonth = { monthNbr : date . month , year : date . year } ; } } } else { validateOpts = { validateDisabledDates : false , selectedValue : this . utilService . getSelectedValue ( selectedValue , dateRange ) } ; const { begin , end } = this . utilService . isDateValidDateRange ( inputValue , this . opts , validateOpts ) ; if ( this . utilService . isInitializedDate ( begin ) && this . utilService . isInitializedDate ( end ) ) { this . selectedDateRange = { begin , end } ; if ( ! overrideSelection ) { this . selectedMonth = { monthNbr : begin . month , year : begin . year } ; } } } } refreshComponent ( opts , defaultMonth , selectedValue , inputValue ) { this . opts = opts ; const { defaultView } = opts ; this . initializeView ( defaultMonth , selectedValue , inputValue ) ; this . setCalendarVisibleMonth ( ) ; this . setDefaultView ( defaultView ) ; } headerAction ( headerAction ) { const { monthSelector , yearSelector } = this . opts ; if ( headerAction === HeaderAction . PrevBtnClick ) { if ( ! this . prevViewDisabled ) { this . onPrevNavigateBtnClicked ( ) ; } } else if ( headerAction === HeaderAction . NextBtnClick ) { if ( ! this . nextViewDisabled ) { this . onNextNavigateBtnClicked ( ) ; } } else if ( headerAction === HeaderAction . MonthBtnClick ) { if ( monthSelector ) { this . onMonthViewBtnClicked ( ) ; } } else if ( headerAction === HeaderAction . YearBtnClick ) { if ( yearSelector ) { this . onYearViewBtnClicked ( ) ; } } } setDefaultView ( defaultView ) { if ( defaultView === DefaultView . Month ) { this . monthViewBtnClicked ( ) ; } else if ( defaultView === DefaultView . Year ) { this . yearViewBtnClicked ( ) ; } } setCalendarAnimation ( calAnimation , isOpen ) { const { nativeElement } = this . selectorEl ; const { renderer } = this ; const classIn = MY_DP_ANIMATION + ANIMATION_NAMES [ calAnimation . in - 1 ] ; if ( isOpen ) { renderer . addClass ( nativeElement , classIn + IN ) ; } else { const classOut = MY_DP_ANIMATION + ANIMATION_NAMES [ calAnimation . out - 1 ] ; renderer . removeClass ( nativeElement , classIn + IN ) ; renderer . addClass ( nativeElement , classOut + OUT ) ; } } resetDateValue ( ) { if ( ! this . opts . dateRange ) { this . selectedDate = this . utilService . resetDate ( ) ; } else { this . selectedDateRange . begin = this . utilService . resetDate ( ) ; this . selectedDateRange . end = this . utilService . resetDate ( ) ; } } clearDate ( ) { const { month , year } = this . utilService . getToday ( ) ; this . selectedMonth = { monthNbr : month , year : year } ; this . resetDateValue ( ) ; this . setCalendarVisibleMonth ( ) ; this . resetMonthYearSelect ( ) ; } resetMonthYearSelect ( ) { this . selectMonth = false ; this . selectYear = false ; } onMonthViewBtnClicked ( ) { this . viewChanged = true ; this . monthViewBtnClicked ( ) ; } monthViewBtnClicked ( ) { this . selectMonth = ! this . selectMonth ; this . selectYear = false ; this . cdr . detectChanges ( ) ; if ( this . selectMonth ) { this . generateMonths ( ) ; } else { const { year , monthNbr } = this . selectedMonth ; this . visibleMonth = { monthTxt : this . opts . monthLabels [ monthNbr ] , monthNbr , year } ; this . generateCalendar ( monthNbr , year , true ) ; } } onMonthCellClicked ( cell ) { this . viewChanged = true ; const { year , monthNbr } = this . visibleMonth ; const monthChange = cell . nbr !== monthNbr ; this . visibleMonth = { monthTxt : this . opts . monthLabels [ cell . nbr ] , monthNbr : cell . nbr , year } ; this . selectedMonth . year = year ; this . generateCalendar ( cell . nbr , year , monthChange ) ; this . selectMonth = false ; this . focusToSelector ( ) ; } onMonthCellKeyDown ( event ) { const { sourceRow , sourceCol } = this . getSourceRowAndColumnFromEvent ( event ) ; const { moveFocus , targetRow , targetCol , direction } = this . getTargetFocusRowAndColumn ( event , sourceRow , sourceCol , MONTH_ROW_COUNT , MONTH_COL_COUNT ) ; if ( moveFocus ) { this . focusCellElement ( M , targetRow , targetCol , direction , MONTH_COL_COUNT ) ; } } onYearViewBtnClicked ( ) { this . viewChanged = true ; this . yearViewBtnClicked ( ) ; } yearViewBtnClicked ( ) { this . selectYear = ! this . selectYear ; this . selectMonth = false ; this . cdr . detectChanges ( ) ; if ( this . selectYear ) { this . generateYears ( this . visibleMonth . year ) ; } else { const { year , monthNbr } = this . selectedMonth ; this . visibleMonth = { monthTxt : this . opts . monthLabels [ monthNbr ] , monthNbr , year } ; this . generateCalendar ( monthNbr , year , true ) ; } } onYearCellClicked ( cell ) { this . viewChanged = true ; const { year , monthNbr , monthTxt } = this . visibleMonth ; const yc = cell . year !== year ; this . visibleMonth = { monthTxt , monthNbr , year : cell . year } ; this . selectedMonth . year = cell . year ; this . generateCalendar ( monthNbr , cell . year , yc ) ; this . selectYear = false ; this . focusToSelector ( ) ; } onYearCellKeyDown ( event ) { const { sourceRow , sourceCol } = this . getSourceRowAndColumnFromEvent ( event ) ; const { moveFocus , targetRow , targetCol , direction } = this . getTargetFocusRowAndColumn ( event , sourceRow , sourceCol , YEAR_ROW_COUNT , YEAR_COL_COUNT ) ; if ( moveFocus ) { this . focusCellElement ( Y , targetRow , targetCol , direction , YEAR_COL_COUNT ) ; } } generateMonths ( ) { const today = this . utilService . getToday ( ) ; this . months . length = 0 ; const { year , monthNbr } = this . visibleMonth ; const { rtl , monthLabels } = this . opts ; let row = 0 ; for ( let i = 1 ; i <= 12 ; i += 3 ) { const rowData = [ ] ; let col = rtl ? 2 : 0 ; for ( let j = i ; j < i + 3 ; j ++ ) { const disabled = this . utilService . isDisabledMonth ( year , j , this . opts ) ; rowData . push ( { nbr : j , year , name : monthLabels [ j ] , currMonth : j === today . month && year === today . year , selected : j === monthNbr && year === this . selectedMonth . year , disabled , row , col : rtl ? col -- : col ++ } ) ; } row ++ ; this . months . push ( rowData ) ; } this . setMonthViewHeaderBtnDisabledState ( year ) ; } generateYears ( inputYear ) { const { minYear , maxYear , rtl } = this . opts ; let y = inputYear - 12 ; if ( inputYear < minYear ) { y = minYear ; } if ( inputYear + 25 > maxYear ) { y = maxYear - 24 ; } const { year } = this . visibleMonth ; this . years . length = 0 ; const today = this . utilService . getToday ( ) ; let row = 0 ; for ( let i = y ; i < y + 25 ; i += 5 ) { const rowData = [ ] ; let col = rtl ? 4 : 0 ; for ( let j = i ; j < i + 5 ; j ++ ) { const disabled = this . utilService . isDisabledYear ( j , this . opts ) ; rowData . push ( { year : j , currYear : j === today . year , selected : j === year , disabled , row , col : rtl ? col -- : col ++ } ) ; } row ++ ; this . years . push ( rowData ) ; } const beginYear = this . getYearValueByRowAndCol ( 0 , 0 ) ; const endYear = beginYear + 24 ; this . yearsDuration = ( ! rtl ? beginYear : endYear ) + YEAR_SEPARATOR + ( ! rtl ? endYear : beginYear ) ; this . setYearViewHeaderBtnDisabledState ( beginYear , endYear ) ; } onTodayFooterClicked ( ) { const date = this . utilService . getToday ( ) ; this . selectDate ( date ) ; } getYearValueByRowAndCol ( row , col ) { const { years } = this ; if ( ! years || years . length === 0 ) { const { year } = this . utilService . getToday ( ) ; return year ; } return years [ row ] [ col ] . year ; } setCalendarVisibleMonth ( ) { const { year , monthNbr } = this . selectedMonth ; this . visibleMonth = { monthTxt : this . opts . monthLabels [ monthNbr ] , monthNbr , year } ; this . generateCalendar ( monthNbr , year , true ) ; } onViewActivated ( event ) { this . viewActivated ( event ) ; } onPrevNavigateBtnClicked ( ) { if ( ! this . selectMonth && ! this . selectYear ) { this . setDateViewMonth ( false ) ; } else if ( this . selectMonth ) { this . visibleMonth . year -- ; this . generateMonths ( ) ; } else if ( this . selectYear ) { this . generateYears ( this . getYearValueByRowAndCol ( 2 , 2 ) - 25 ) ; } } onNextNavigateBtnClicked ( ) { if ( ! this . selectMonth && ! this . selectYear ) { this . setDateViewMonth ( true ) ; } else if ( this . selectMonth ) { this . visibleMonth . year ++ ; this . generateMonths ( ) ; } else if ( this . selectYear ) { this . generateYears ( this . getYearValueByRowAndCol ( 2 , 2 ) + 25 ) ; } } setDateViewMonth ( isNext ) { let change = isNext ? 1 : - 1 ; const { year , monthNbr } = this . visibleMonth ; const d = this . utilService . getJsDate ( year , monthNbr , 1 ) ; d . setMonth ( d . getMonth ( ) + change ) ; const y = d . getFullYear ( ) ; const m = d . getMonth ( ) + 1 ; this . visibleMonth = { monthTxt : this . opts . monthLabels [ m ] , monthNbr : m , year : y } ; this . generateCalendar ( m , y , true ) ; } onCloseSelector ( event ) { const keyCode = this . utilService . getKeyCodeFromEvent ( event ) ; if ( keyCode === KeyCode . esc ) { this . closedByEsc ( ) ; } } onDayCellClicked ( cell ) { this . selectDate ( cell . dateObj ) ; this . resetMonthYearSelect ( ) ; } onDayCellKeyDown ( event ) { const { sourceRow , sourceCol } = this . getSourceRowAndColumnFromEvent ( event ) ; const { moveFocus , targetRow , targetCol , direction } = this . getTargetFocusRowAndColumn ( event , sourceRow , sourceCol , DATE_ROW_COUNT , DATE_COL_COUNT ) ; if ( moveFocus ) { this . focusCellElement ( D , targetRow , targetCol , direction , DATE_COL_COUNT ) ; } } getSourceRowAndColumnFromEvent ( event ) { let sourceRow = 0 ; let sourceCol = 0 ; if ( event . target && event . target . id ) { const arr = event . target . id . split ( UNDER_LINE ) ; sourceRow = Number ( arr [ 1 ] ) ; sourceCol = Number ( arr [ 2 ] ) ; } return { sourceRow , sourceCol } ; } getTargetFocusRowAndColumn ( event , row , col , rowCount , colCount ) { let moveFocus = true ; let targetRow = row ; let targetCol = col ; let direction = false ; const keyCode = this . utilService . getKeyCodeFromEvent ( event ) ; if ( keyCode === KeyCode . upArrow && row > 0 ) { targetRow -- ; } else if ( keyCode === KeyCode . downArrow && row < rowCount ) { targetRow ++ ; direction = true ; } else if ( keyCode === KeyCode . leftArrow && col > 0 ) { targetCol -- ; } else if ( keyCode === KeyCode . rightArrow && col < colCount ) { targetCol ++ ; direction = true ; } else { moveFocus = false ; } return { moveFocus , targetRow , targetCol , direction } ; } focusCellElement ( type , row , col , direction , colCount ) { const className = type + UNDER_LINE + row + UNDER_LINE + col ; let elem = this . selectorEl . nativeElement . querySelector ( DOT + className ) ; if ( elem . getAttribute ( TABINDEX ) !== ZERO_STR ) { let tdList = this . getCalendarElements ( ) ; const idx = row * ( colCount + 1 ) + col ; let enabledElem = null ; if ( direction ) { enabledElem = tdList . slice ( idx ) . find ( ( td ) => td . getAttribute ( TABINDEX ) === ZERO_STR ) ; } else { enabledElem = tdList . slice ( 0 , idx ) . reverse ( ) . find ( ( td ) => td . getAttribute ( TABINDEX ) === ZERO_STR ) ; } elem = enabledElem ? enabledElem : this . selectorEl . nativeElement ; } else { elem . focus ( ) ; } } focusToSelector ( ) { this . selectorEl . nativeElement . focus ( ) ; } getCalendarElements ( ) { return Array . from ( this . selectorEl . nativeElement . querySelectorAll ( TD_SELECTOR ) ) ; } selectDate ( date ) { const { dateRange , dateFormat , monthLabels , dateRangeDatesDelimiter , closeSelectorOnDateSelect } = this . opts ; if ( dateRange ) { const isBeginDateInitialized = this . utilService . isInitializedDate ( this . selectedDateRange . begin ) ; const isEndDateInitialized = this . utilService . isInitializedDate ( this . selectedDateRange . end ) ; if ( isBeginDateInitialized && isEndDateInitialized ) { this . selectedDateRange . begin = date ; this . selectedDateRange . end = this . utilService . resetDate ( ) ; this . rangeDateSelection ( { isBegin : true , date , jsDate : this . utilService . myDateToJsDate ( date ) , dateFormat : dateFormat , formatted : this . utilService . formatDate ( date , dateFormat , monthLabels ) , epoc : this . utilService . getEpocTime ( date ) } ) ; } else if ( ! isBeginDateInitialized ) { this . selectedDateRange . begin = date ; this . rangeDateSelection ( { isBegin : true , date , jsDate : this . utilService . myDateToJsDate ( date ) , dateFormat : dateFormat , formatted : this . utilService . formatDate ( date , dateFormat , monthLabels ) , epoc : this . utilService . getEpocTime ( date ) } ) ; } else { const firstDateEarlier = this . utilService . isDateEarlier ( date , this . selectedDateRange . begin ) ; if ( firstDateEarlier ) { this . selectedDateRange . begin = date ; this . rangeDateSelection ( { isBegin : true , date , jsDate : this . utilService . myDateToJsDate ( date ) , dateFormat : dateFormat , formatted : this . utilService . formatDate ( date , dateFormat , monthLabels ) , epoc : this . utilService . getEpocTime ( date ) } ) ; } else { this . selectedDateRange . end = date ; this . rangeDateSelection ( { isBegin : false , date , jsDate : this . utilService . myDateToJsDate ( date ) , dateFormat : dateFormat , formatted : this . utilService . formatDate ( date , dateFormat , monthLabels ) , epoc : this . utilService . getEpocTime ( date ) } ) ; this . dateChanged ( this . utilService . getDateModel ( null , this . selectedDateRange , dateFormat , monthLabels , dateRangeDatesDelimiter ) , closeSelectorOnDateSelect ) ; } } } else { this . selectedDate = date ; this . dateChanged ( this . utilService . getDateModel ( this . selectedDate , null , dateFormat , monthLabels , dateRangeDatesDelimiter ) , closeSelectorOnDateSelect ) ; } } monthStartIdx ( y , m ) { const d = new Date ( ) ; d . setDate ( 1 ) ; d . setMonth ( m - 1 ) ; d . setFullYear ( y ) ; const idx = d . getDay ( ) + this . sundayIdx ( ) ; return idx >= 7 ? idx - 7 : idx ; } isCurrDay ( d , m , y , today ) { return d === today . day && m === today . month && y === today . year ; } getDayNumber ( date ) { const { year , month , day } = date ; const d = this . utilService . getJsDate ( year , month , day ) ; return d . getDay ( ) ; } getWeekday ( date ) { return this . weekDayOpts [ this . getDayNumber ( date ) ] ; } sundayIdx ( ) { return this . dayIdx > 0 ? 7 - this . dayIdx : 0 ; } generateCalendar ( m , y , notifyChange ) { this . dates . length = 0 ; const today = this . utilService . getToday ( ) ; const monthStart = this . monthStartIdx ( y , m ) ; const dInThisM = this . utilService . datesInMonth ( m , y ) ; const dInPrevM = this . utilService . datesInPrevMonth ( m , y ) ; let dayNbr = 1 ; let month = m ; let cmo = MonthId . prev ; const { rtl , showWeekNumbers , firstDayOfWeek } = this . opts ; for ( let i = 1 ; i < 7 ; i ++ ) { let col = rtl ? 6 : 0 ; const week = [ ] ; if ( i === 1 ) { const pm = dInPrevM - monthStart + 1 ; for ( let j = pm ; j <= dInPrevM ; j ++ ) { const date = { year : m === 1 ? y - 1 : y , month : m === 1 ? 12 : m - 1 , day : j } ; week . push ( { dateObj : date , cmo , currDay : this . isCurrDay ( j , month - 1 , y , today ) , disabledDate : this . utilService . isDisabledDate ( date , this . opts ) , markedDate : this . utilService . isMarkedDate ( date , this . opts ) , highlight : this . utilService . isHighlightedDate ( date , this . opts ) , row : i - 1 , col : rtl ? col -- : col ++ } ) ; } cmo = MonthId . curr ; const daysLeft = 7 - week . length ; for ( let j = 0 ; j < daysLeft ; j ++ ) { const date = { year : y , month : m , day : dayNbr } ; week . push ( { dateObj : date , cmo , currDay : this . isCurrDay ( dayNbr , m , y , today ) , disabledDate : this . utilService . isDisabledDate ( date , this . opts ) , markedDate : this . utilService . isMarkedDate ( date , this . opts ) , highlight : this . utilService . isHighlightedDate ( date , this . opts ) , row : i - 1 , col : rtl ? col -- : col ++ } ) ; dayNbr ++ ; } } else { for ( let j = 1 ; j < 8 ; j ++ ) { if ( dayNbr > dInThisM ) { dayNbr = 1 ; cmo = MonthId . next ; month = m + 1 ; } const date = { year : cmo === MonthId . next && m === 12 ? y + 1 : y , month : cmo === MonthId . curr ? m : cmo === MonthId . next && m < 12 ? m + 1 : 1 , day : dayNbr } ; week . push ( { dateObj : date , cmo , currDay : this . isCurrDay ( dayNbr , month , y , today ) , disabledDate : this . utilService . isDisabledDate ( date , this . opts ) , markedDate : this . utilService . isMarkedDate ( date , this . opts ) , highlight : this . utilService . isHighlightedDate ( date , this . opts ) , row : i - 1 , col : rtl ? col -- : col ++ } ) ; dayNbr ++ ; } } const weekNbr = showWeekNumbers && firstDayOfWeek === MO ? this . utilService . getWeekNumber ( week [ 0 ] . dateObj ) : 0 ; this . dates . push ( { week , weekNbr } ) ; } this . setDateViewHeaderBtnDisabledState ( m , y ) ; if ( notifyChange ) { this . calendarViewChanged ( { 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 } ) } } ) ; } } setDateViewHeaderBtnDisabledState ( m , y ) { let dpm = false ; let dnm = false ; const { disableHeaderButtons , disableUntil , disableSince , enableDates , minYear , maxYear , rtl } = this . opts ; if ( disableHeaderButtons ) { const duDate = { year : m === 1 ? y - 1 : y , month : m === 1 ? 12 : m - 1 , day : this . utilService . datesInMonth ( m === 1 ? 12 : m - 1 , m === 1 ? y - 1 : y ) } ; const dsDate = { year : m === 12 ? y + 1 : y , month : m === 12 ? 1 : m + 1 , day : 1 } ; dpm = this . utilService . isDisabledByDisableUntil ( duDate , disableUntil ) && ! this . utilService . isPastDatesEnabled ( duDate , enableDates ) ; dnm = this . utilService . isDisabledByDisableSince ( dsDate , disableSince ) && ! this . utilService . isFutureDatesEnabled ( dsDate , enableDates ) ; } this . prevViewDisabled = m === 1 && y === minYear || dpm ; this . nextViewDisabled = m === 12 && y === maxYear || dnm ; if ( rtl ) { this . swapHeaderBtnDisabled ( ) ; } } setMonthViewHeaderBtnDisabledState ( y ) { let dpm = false ; let dnm = false ; const { disableHeaderButtons , disableUntil , disableSince , enableDates , minYear , maxYear , rtl } = this . opts ; if ( disableHeaderButtons ) { const duDate = { year : y - 1 , month : 12 , day : 31 } ; const dsDate = { year : y + 1 , month : 1 , day : 1 } ; dpm = this . utilService . isDisabledByDisableUntil ( duDate , disableUntil ) && ! this . utilService . isPastDatesEnabled ( duDate , enableDates ) ; dnm = this . utilService . isDisabledByDisableSince ( dsDate , disableSince ) && ! this . utilService . isFutureDatesEnabled ( dsDate , enableDates ) ; } this . prevViewDisabled = y === minYear || dpm ; this . nextViewDisabled = y === maxYear || dnm ; if ( rtl ) { this . swapHeaderBtnDisabled ( ) ; } } setYearViewHeaderBtnDisabledState ( yp , yn ) { let dpy = false ; let dny = false ; const { disableHeaderButtons , disableUntil , disableSince , enableDates , minYear , maxYear , rtl } = this . opts ; if ( disableHeaderButtons ) { const duDate = { year : yp - 1 , month : 12 , day : 31 } ; const dsDate = { year : yn + 1 , month : 1 , day : 1 } ; dpy = this . utilService . isDisabledByDisableUntil ( duDate , disableUntil ) && ! this . utilService . isPastDatesEnabled ( duDate , enableDates ) ; dny = this . utilService . isDisabledByDisableSince ( dsDate , disableSince ) && ! this . utilService . isFutureDatesEnabled ( dsDate , enableDates ) ; } this . prevViewDisabled = yp <= minYear || dpy ; this . nextViewDisabled = yn >= maxYear || dny ; if ( rtl ) { this . swapHeaderBtnDisabled ( ) ; } } swapHeaderBtnDisabled ( ) { [ this . prevViewDisabled , this . nextViewDisabled ] = [ this . nextViewDisabled , this . prevViewDisabled ] ; } }