import { DateMarker } from './datelib/marker' ; import { createFormatter } from './datelib/formatting' ; import { createDuration } from './datelib/duration' ; import { parseDateSpan } from './structs/date-span' ; import { parseEventSource } from './structs/event-source-parse' ; import { parseEvent } from './structs/event-parse' ; import { eventTupleToStore } from './structs/event-store' ; import { ViewSpec } from './structs/view-spec' ; import { PointerDragEvent } from './interactions/pointer' ; import { getNow } from './reducers/current-date' ; import { triggerDateSelect , triggerDateUnselect } from './calendar-utils' ; import { hashValuesToArray } from './util/object' ; import { CalendarDataManager } from './reducers/CalendarDataManager' ; import { Action } from './reducers/Action' ; import { EventSource } from './structs/event-source' ; import { eventApiToStore , buildEventApis } from './api/EventApi' ; import { CalendarOptions , CalendarListeners , DateInput , DurationInput , DateSpanInput , DateRangeInput , EventSourceInput , EventInput , EventSourceApi , EventApi , ViewApi , } from './api-type-deps' ; export class CalendarApi { currentDataManager ? : CalendarDataManager ; getCurrentData ( ) { return this . currentDataManager ! . getCurrentData ( ) ; } dispatch ( action ) { return this . currentDataManager ! . dispatch ( action ) ; } get view ( ) : ViewApi { return this . getCurrentData ( ) . viewApi ; } batchRendering ( callback ) { callback ( ) ; } updateSize ( ) { this . trigger ( '_resize' , true ) ; } setOption < OptionName extends keyof CalendarOptions > ( name , val ) { this . dispatch ( { type : 'SET_OPTION' , optionName : name , rawOptionValue : val , } ) ; } getOption < OptionName extends keyof CalendarOptions > ( name ) { return this . currentDataManager ! . currentCalendarOptionsInput [ name ] ; } getAvailableLocaleCodes ( ) { return Object . keys ( this . getCurrentData ( ) . availableRawLocales ) ; } on < ListenerName extends keyof CalendarListeners > ( handlerName , handler ) { let { currentDataManager } = this ; if ( currentDataManager . currentCalendarOptionsRefiners [ handlerName ] ) { currentDataManager . emitter . on ( handlerName , handler ) ; } else { console . warn ( `Unknown listener name '${ handlerName }'` ) ; } } off < ListenerName extends keyof CalendarListeners > ( handlerName , handler ) { this . currentDataManager ! . emitter . off ( handlerName , handler ) ; } trigger < ListenerName extends keyof CalendarListeners > ( handlerName , ... args ) { this . currentDataManager ! . emitter . trigger ( handlerName , ... args ) ; } changeView ( viewType , dateOrRange ? ) { this . batchRendering ( ( ) => { this . unselect ( ) ; if ( dateOrRange ) { if ( ( dateOrRange as DateRangeInput ) . start && ( dateOrRange as DateRangeInput ) . end ) { this . dispatch ( { type : 'CHANGE_VIEW_TYPE' , viewType , } ) ; this . dispatch ( { type : 'SET_OPTION' , optionName : 'visibleRange' , rawOptionValue : dateOrRange , } ) ; } else { let { dateEnv } = this . getCurrentData ( ) ; this . dispatch ( { type : 'CHANGE_VIEW_TYPE' , viewType , dateMarker : dateEnv . createMarker ( dateOrRange as DateInput ) , } ) ; } } else { this . dispatch ( { type : 'CHANGE_VIEW_TYPE' , viewType , } ) ; } } ) ; } zoomTo ( dateMarker , viewType ? ) { let state = this . getCurrentData ( ) ; let spec ; viewType = viewType || 'day' ; spec = state . viewSpecs [ viewType ] || this . getUnitViewSpec ( viewType ) ; this . unselect ( ) ; if ( spec ) { this . dispatch ( { type : 'CHANGE_VIEW_TYPE' , viewType : spec . type , dateMarker , } ) ; } else { this . dispatch ( { type : 'CHANGE_DATE' , dateMarker , } ) ; } } private getUnitViewSpec ( unit ) { let { viewSpecs , toolbarConfig } = this . getCurrentData ( ) ; let viewTypes = [ ] . concat ( toolbarConfig . header ? toolbarConfig . header . viewsWithButtons : [ ] , toolbarConfig . footer ? toolbarConfig . footer . viewsWithButtons : [ ] ) ; let i ; let spec ; for ( let viewType in viewSpecs ) { viewTypes . push ( viewType ) ; } for ( i = 0 ; i < viewTypes . length ; i += 1 ) { spec = viewSpecs [ viewTypes [ i ] ] ; if ( spec ) { if ( spec . singleUnit === unit ) { return spec ; } } } return null ; } prev ( ) { this . unselect ( ) ; this . dispatch ( { type : 'PREV' } ) ; } next ( ) { this . unselect ( ) ; this . dispatch ( { type : 'NEXT' } ) ; } prevYear ( ) { let state = this . getCurrentData ( ) ; this . unselect ( ) ; this . dispatch ( { type : 'CHANGE_DATE' , dateMarker : state . dateEnv . addYears ( state . currentDate , - 1 ) , } ) ; } nextYear ( ) { let state = this . getCurrentData ( ) ; this . unselect ( ) ; this . dispatch ( { type : 'CHANGE_DATE' , dateMarker : state . dateEnv . addYears ( state . currentDate , 1 ) , } ) ; } today ( ) { let state = this . getCurrentData ( ) ; this . unselect ( ) ; this . dispatch ( { type : 'CHANGE_DATE' , dateMarker : getNow ( state . calendarOptions . now , state . dateEnv ) , } ) ; } gotoDate ( zonedDateInput ) { let state = this . getCurrentData ( ) ; this . unselect ( ) ; this . dispatch ( { type : 'CHANGE_DATE' , dateMarker : state . dateEnv . createMarker ( zonedDateInput ) , } ) ; } incrementDate ( deltaInput ) { let state = this . getCurrentData ( ) ; let delta = createDuration ( deltaInput ) ; if ( delta ) { this . unselect ( ) ; this . dispatch ( { type : 'CHANGE_DATE' , dateMarker : state . dateEnv . add ( state . currentDate , delta ) , } ) ; } } getDate ( ) { let state = this . getCurrentData ( ) ; return state . dateEnv . toDate ( state . currentDate ) ; } formatDate ( d , formatter ) { let { dateEnv } = this . getCurrentData ( ) ; return dateEnv . format ( dateEnv . createMarker ( d ) , createFormatter ( formatter ) ) ; } formatRange ( d0 , d1 , settings ) { let { dateEnv } = this . getCurrentData ( ) ; return dateEnv . formatRange ( dateEnv . createMarker ( d0 ) , dateEnv . createMarker ( d1 ) , createFormatter ( settings ) , settings ) ; } formatIso ( d , omitTime ? ) { let { dateEnv } = this . getCurrentData ( ) ; return dateEnv . formatIso ( dateEnv . createMarker ( d ) , { omitTime } ) ; } select ( dateOrObj , endDate ? ) { let selectionInput ; if ( endDate == null ) { if ( dateOrObj . start != null ) { selectionInput = dateOrObj as DateSpanInput ; } else { selectionInput = { start : dateOrObj , end : null , } ; } } else { selectionInput = { start : dateOrObj , end : endDate , } as DateSpanInput ; } let state = this . getCurrentData ( ) ; let selection = parseDateSpan ( selectionInput , state . dateEnv , createDuration ( { days : 1 } ) ) ; if ( selection ) { this . dispatch ( { type : 'SELECT_DATES' , selection } ) ; triggerDateSelect ( selection , null , state ) ; } } unselect ( pev ? ) { let state = this . getCurrentData ( ) ; if ( state . dateSelection ) { this . dispatch ( { type : 'UNSELECT_DATES' } ) ; triggerDateUnselect ( pev , state ) ; } } addEvent ( eventInput , sourceInput ? ) { if ( eventInput instanceof EventApi ) { let def = eventInput . _def ; let instance = eventInput . _instance ; let currentData = this . getCurrentData ( ) ; if ( ! currentData . eventStore . defs [ def . defId ] ) { this . dispatch ( { type : 'ADD_EVENTS' , eventStore : eventTupleToStore ( { def , instance } ) , } ) ; this . triggerEventAdd ( eventInput ) ; } return eventInput ; } let state = this . getCurrentData ( ) ; let eventSource ; if ( sourceInput instanceof EventSourceApi ) { eventSource = sourceInput . internalEventSource ; } else if ( typeof sourceInput === 'boolean' ) { if ( sourceInput ) { [ eventSource ] = hashValuesToArray ( state . eventSources ) ; } } else if ( sourceInput != null ) { let sourceApi = this . getEventSourceById ( sourceInput ) ; if ( ! sourceApi ) { console . warn ( `Could not find an event source with ID "${ sourceInput }"` ) ; return null ; } eventSource = sourceApi . internalEventSource ; } let tuple = parseEvent ( eventInput , eventSource , state , false ) ; if ( tuple ) { let newEventApi = new EventApi ( state , tuple . def , tuple . def . recurringDef ? null : tuple . instance ) ; this . dispatch ( { type : 'ADD_EVENTS' , eventStore : eventTupleToStore ( tuple ) , } ) ; this . triggerEventAdd ( newEventApi ) ; return newEventApi ; } return null ; } private triggerEventAdd ( eventApi ) { let { emitter } = this . getCurrentData ( ) ; emitter . trigger ( 'eventAdd' , { event : eventApi , relatedEvents : [ ] , revert : ( ) => { this . dispatch ( { type : 'REMOVE_EVENTS' , eventStore : eventApiToStore ( eventApi ) , } ) ; } , } ) ; } getEventById ( id ) { let state = this . getCurrentData ( ) ; let { defs , instances } = state . eventStore ; id = String ( id ) ; for ( let defId in defs ) { let def = defs [ defId ] ; if ( def . publicId === id ) { if ( def . recurringDef ) { return new EventApi ( state , def , null ) ; } for ( let instanceId in instances ) { let instance = instances [ instanceId ] ; if ( instance . defId === def . defId ) { return new EventApi ( state , def , instance ) ; } } } } return null ; } getEvents ( ) { let currentData = this . getCurrentData ( ) ; return buildEventApis ( currentData . eventStore , currentData ) ; } removeAllEvents ( ) { this . dispatch ( { type : 'REMOVE_ALL_EVENTS' } ) ; } getEventSources ( ) { let state = this . getCurrentData ( ) ; let sourceHash = state . eventSources ; let sourceApis = [ ] ; for ( let internalId in sourceHash ) { sourceApis . push ( new EventSourceApi ( state , sourceHash [ internalId ] ) ) ; } return sourceApis ; } getEventSourceById ( id ) { let state = this . getCurrentData ( ) ; let sourceHash = state . eventSources ; id = String ( id ) ; for ( let sourceId in sourceHash ) { if ( sourceHash [ sourceId ] . publicId === id ) { return new EventSourceApi ( state , sourceHash [ sourceId ] ) ; } } return null ; } addEventSource ( sourceInput ) { let state = this . getCurrentData ( ) ; if ( sourceInput instanceof EventSourceApi ) { if ( ! state . eventSources [ sourceInput . internalEventSource . sourceId ] ) { this . dispatch ( { type : 'ADD_EVENT_SOURCES' , sources : [ sourceInput . internalEventSource ] , } ) ; } return sourceInput ; } let eventSource = parseEventSource ( sourceInput , state ) ; if ( eventSource ) { this . dispatch ( { type : 'ADD_EVENT_SOURCES' , sources : [ eventSource ] } ) ; return new EventSourceApi ( state , eventSource ) ; } return null ; } removeAllEventSources ( ) { this . dispatch ( { type : 'REMOVE_ALL_EVENT_SOURCES' } ) ; } refetchEvents ( ) { this . dispatch ( { type : 'FETCH_EVENT_SOURCES' , isRefetch : true } ) ; } scrollToTime ( timeInput ) { let time = createDuration ( timeInput ) ; if ( time ) { this . trigger ( '_scrollRequest' , { time } ) ; } } }