import { EventSource , EventSourceHash } from '../structs/event-source' ; import { parseEventSource , buildEventSourceRefiners } from '../structs/event-source-parse' ; import { arrayToHash , filterHash } from '../util/object' ; import { DateRange } from '../datelib/date-range' ; import { DateProfile } from '../DateProfileGenerator' ; import { Action } from './Action' ; import { guid } from '../util/misc' ; import { CalendarContext } from '../CalendarContext' ; import { CalendarOptions } from '../options' ; export function initEventSources ( calendarOptions , dateProfile , context ) { let activeRange = dateProfile ? dateProfile . activeRange : null ; return addSources ( { } , parseInitialSources ( calendarOptions , context ) , activeRange , context ) ; } export function reduceEventSources ( eventSources , action , dateProfile , context ) { let activeRange = dateProfile ? dateProfile . activeRange : null ; switch ( action . type ) { case 'ADD_EVENT_SOURCES' : return addSources ( eventSources , action . sources , activeRange , context ) ; case 'REMOVE_EVENT_SOURCE' : return removeSource ( eventSources , action . sourceId ) ; case 'PREV' : case 'NEXT' : case 'CHANGE_DATE' : case 'CHANGE_VIEW_TYPE' : if ( dateProfile ) { return fetchDirtySources ( eventSources , activeRange , context ) ; } return eventSources ; case 'FETCH_EVENT_SOURCES' : return fetchSourcesByIds ( eventSources , ( action as any ) . sourceIds ? arrayToHash ( ( action as any ) . sourceIds ) : excludeStaticSources ( eventSources , context ) , activeRange , action . isRefetch || false , context ) ; case 'RECEIVE_EVENTS' : case 'RECEIVE_EVENT_ERROR' : return receiveResponse ( eventSources , action . sourceId , action . fetchId , action . fetchRange ) ; case 'REMOVE_ALL_EVENT_SOURCES' : return { } ; default : return eventSources ; } } export function reduceEventSourcesNewTimeZone ( eventSources , dateProfile , context ) { let activeRange = dateProfile ? dateProfile . activeRange : null ; return fetchSourcesByIds ( eventSources , excludeStaticSources ( eventSources , context ) , activeRange , true , context ) ; } export function computeEventSourcesLoading ( eventSources ) { for ( let sourceId in eventSources ) { if ( eventSources [ sourceId ] . isFetching ) { return true ; } } return false ; } function addSources ( eventSourceHash , sources , fetchRange , context ) { let hash = { } ; for ( let source of sources ) { hash [ source . sourceId ] = source ; } if ( fetchRange ) { hash = fetchDirtySources ( hash , fetchRange , context ) ; } return { ... eventSourceHash , ... hash } ; } function removeSource ( eventSourceHash , sourceId ) { return filterHash ( eventSourceHash , ( eventSource ) => eventSource . sourceId !== sourceId ) ; } function fetchDirtySources ( sourceHash , fetchRange , context ) { return fetchSourcesByIds ( sourceHash , filterHash ( sourceHash , ( eventSource ) => isSourceDirty ( eventSource , fetchRange , context ) ) , fetchRange , false , context ) ; } function isSourceDirty ( eventSource , fetchRange , context ) { if ( ! doesSourceNeedRange ( eventSource , context ) ) { return ! eventSource . latestFetchId ; } return ! context . options . lazyFetching || ! eventSource . fetchRange || eventSource . isFetching || fetchRange . start < eventSource . fetchRange . start || fetchRange . end > eventSource . fetchRange . end ; } function fetchSourcesByIds ( prevSources , sourceIdHash , fetchRange , isRefetch , context ) { let nextSources = { } ; for ( let sourceId in prevSources ) { let source = prevSources [ sourceId ] ; if ( sourceIdHash [ sourceId ] ) { nextSources [ sourceId ] = fetchSource ( source , fetchRange , isRefetch , context ) ; } else { nextSources [ sourceId ] = source ; } } return nextSources ; } function fetchSource ( eventSource , fetchRange , isRefetch , context ) { let { options , calendarApi } = context ; let sourceDef = context . pluginHooks . eventSourceDefs [ eventSource . sourceDefId ] ; let fetchId = guid ( ) ; sourceDef . fetch ( { eventSource , range : fetchRange , isRefetch , context , } , ( res ) => { let { rawEvents } = res ; if ( options . eventSourceSuccess ) { rawEvents = options . eventSourceSuccess . call ( calendarApi , rawEvents , res . xhr ) || rawEvents ; } if ( eventSource . success ) { rawEvents = eventSource . success . call ( calendarApi , rawEvents , res . xhr ) || rawEvents ; } context . dispatch ( { type : 'RECEIVE_EVENTS' , sourceId : eventSource . sourceId , fetchId , fetchRange , rawEvents , } ) ; } , ( error ) => { console . warn ( error . message , error ) ; if ( options . eventSourceFailure ) { options . eventSourceFailure . call ( calendarApi , error ) ; } if ( eventSource . failure ) { eventSource . failure ( error ) ; } context . dispatch ( { type : 'RECEIVE_EVENT_ERROR' , sourceId : eventSource . sourceId , fetchId , fetchRange , error , } ) ; } ) ; return { ... eventSource , isFetching : true , latestFetchId : fetchId , } ; } function receiveResponse ( sourceHash , sourceId , fetchId , fetchRange ) { let eventSource = sourceHash [ sourceId ] ; if ( eventSource && fetchId === eventSource . latestFetchId ) { return { ... sourceHash , [ sourceId ] : { ... eventSource , isFetching : false , fetchRange , } , } ; } return sourceHash ; } function excludeStaticSources ( eventSources , context ) { return filterHash ( eventSources , ( eventSource ) => doesSourceNeedRange ( eventSource , context ) ) ; } function parseInitialSources ( rawOptions , context ) { let refiners = buildEventSourceRefiners ( context ) ; let rawSources = [ ] . concat ( rawOptions . eventSources || [ ] ) ; let sources = [ ] ; if ( rawOptions . initialEvents ) { rawSources . unshift ( rawOptions . initialEvents ) ; } if ( rawOptions . events ) { rawSources . unshift ( rawOptions . events ) ; } for ( let rawSource of rawSources ) { let source = parseEventSource ( rawSource , context , refiners ) ; if ( source ) { sources . push ( source ) ; } } return sources ; } function doesSourceNeedRange ( eventSource , context ) { let defs = context . pluginHooks . eventSourceDefs ; return ! defs [ eventSource . sourceDefId ] . ignoreRange ; }