Adam Shaw 7 лет назад
Родитель
Сommit
cd50b4c795

+ 1 - 1
src/Calendar.ts

@@ -18,7 +18,7 @@ import { DateMarker, startOfDay } from './datelib/marker'
 import { createFormatter } from './datelib/formatting'
 import { createFormatter } from './datelib/formatting'
 import { Duration, createDuration } from './datelib/duration'
 import { Duration, createDuration } from './datelib/duration'
 import { CalendarState, reduce } from './reducers/main'
 import { CalendarState, reduce } from './reducers/main'
-import { parseDateSpan, DateSpanInput, DateSpan } from './reducers/date-span'
+import { parseDateSpan, DateSpanInput, DateSpan } from './structs/date-span'
 import reselector from './util/reselector'
 import reselector from './util/reselector'
 import { assignTo } from './util/object'
 import { assignTo } from './util/object'
 import { RenderForceFlags } from './component/Component'
 import { RenderForceFlags } from './component/Component'

+ 2 - 2
src/agenda/AgendaView.ts

@@ -13,10 +13,10 @@ import TimeGrid from './TimeGrid'
 import DayGrid from '../basic/DayGrid'
 import DayGrid from '../basic/DayGrid'
 import { createDuration } from '../datelib/duration'
 import { createDuration } from '../datelib/duration'
 import { createFormatter } from '../datelib/formatting'
 import { createFormatter } from '../datelib/formatting'
-import { EventStore } from '../reducers/event-store'
+import { EventStore } from '../structs/event-store'
 import { RenderForceFlags } from '../component/Component'
 import { RenderForceFlags } from '../component/Component'
 import { DateComponentRenderState } from '../component/DateComponent'
 import { DateComponentRenderState } from '../component/DateComponent'
-import { EventInteractionState } from '../reducers/event-interaction'
+import { EventInteractionState } from '../interactions/event-interaction-state'
 import reselector from '../util/reselector'
 import reselector from '../util/reselector'
 
 
 const AGENDA_ALL_DAY_EVENT_LIMIT = 5
 const AGENDA_ALL_DAY_EVENT_LIMIT = 5

+ 2 - 2
src/agenda/TimeGrid.ts

@@ -10,8 +10,8 @@ import { Duration, createDuration, addDurations, multiplyDuration, wholeDivideDu
 import { startOfDay, DateMarker, addMs } from '../datelib/marker'
 import { startOfDay, DateMarker, addMs } from '../datelib/marker'
 import { DateFormatter, createFormatter, formatIsoTimeString } from '../datelib/formatting'
 import { DateFormatter, createFormatter, formatIsoTimeString } from '../datelib/formatting'
 import DateComponent, { Seg } from '../component/DateComponent'
 import DateComponent, { Seg } from '../component/DateComponent'
-import { DateSpan } from '../reducers/date-span'
-import { EventStore } from '../reducers/event-store'
+import { DateSpan } from '../structs/date-span'
+import { EventStore } from '../structs/event-store'
 import { Hit } from '../interactions/HitDragging'
 import { Hit } from '../interactions/HitDragging'
 
 
 /* A component that renders one or more columns of vertical time slots
 /* A component that renders one or more columns of vertical time slots

+ 1 - 1
src/basic/DayGrid.ts

@@ -18,7 +18,7 @@ import DayGridFillRenderer from './DayGridFillRenderer'
 import { addDays } from '../datelib/marker'
 import { addDays } from '../datelib/marker'
 import { createFormatter } from '../datelib/formatting'
 import { createFormatter } from '../datelib/formatting'
 import DateComponent, { Seg } from '../component/DateComponent'
 import DateComponent, { Seg } from '../component/DateComponent'
-import { EventStore } from '../reducers/event-store'
+import { EventStore } from '../structs/event-store'
 import DayTile from './DayTile'
 import DayTile from './DayTile'
 import { Hit } from '../interactions/HitDragging'
 import { Hit } from '../interactions/HitDragging'
 
 

+ 1 - 1
src/common/browser-context.ts

@@ -6,7 +6,7 @@ import EventClicking from '../interactions/EventClicking'
 import EventHovering from '../interactions/EventHovering'
 import EventHovering from '../interactions/EventHovering'
 import EventDragging from '../interactions/EventDragging'
 import EventDragging from '../interactions/EventDragging'
 import EventResizing from '../interactions/EventResizing'
 import EventResizing from '../interactions/EventResizing'
-import { DateSpan } from '../reducers/date-span'
+import { DateSpan } from '../structs/date-span'
 import Calendar from '../Calendar'
 import Calendar from '../Calendar'
 
 
 export class BrowserContext {
 export class BrowserContext {

+ 5 - 5
src/component/DateComponent.ts

@@ -6,14 +6,14 @@ import View from '../View'
 import { DateProfile } from '../DateProfileGenerator'
 import { DateProfile } from '../DateProfileGenerator'
 import { DateMarker, DAY_IDS, addDays, startOfDay, diffDays, diffWholeDays } from '../datelib/marker'
 import { DateMarker, DAY_IDS, addDays, startOfDay, diffDays, diffWholeDays } from '../datelib/marker'
 import { Duration, createDuration, asRoughMs } from '../datelib/duration'
 import { Duration, createDuration, asRoughMs } from '../datelib/duration'
-import { DateSpan } from '../reducers/date-span'
+import { DateSpan } from '../structs/date-span'
 import UnzonedRange from '../models/UnzonedRange'
 import UnzonedRange from '../models/UnzonedRange'
-import { EventRenderRange, sliceEventStore } from '../reducers/event-rendering'
-import { EventStore } from '../reducers/event-store'
-import { BusinessHourDef, buildBusinessHourEventStore } from '../reducers/business-hours'
+import { EventRenderRange, sliceEventStore } from '../component/event-rendering'
+import { EventStore } from '../structs/event-store'
+import { BusinessHourDef, buildBusinessHourEventStore } from '../structs/business-hours'
 import { DateEnv } from '../datelib/env'
 import { DateEnv } from '../datelib/env'
 import Theme from '../theme/Theme'
 import Theme from '../theme/Theme'
-import { EventInteractionState } from '../reducers/event-interaction'
+import { EventInteractionState } from '../interactions/event-interaction-state'
 import { assignTo } from '../util/object'
 import { assignTo } from '../util/object'
 import browserContext from '../common/browser-context'
 import browserContext from '../common/browser-context'
 import { Hit } from '../interactions/HitDragging'
 import { Hit } from '../interactions/HitDragging'

+ 2 - 1
src/reducers/event-rendering.ts → src/component/event-rendering.ts

@@ -1,5 +1,6 @@
 import UnzonedRange from '../models/UnzonedRange'
 import UnzonedRange from '../models/UnzonedRange'
-import { EventStore, EventDef, EventInstance } from './event-store'
+import { EventDef, EventInstance } from '../structs/event'
+import { EventStore } from '../structs/event-store'
 
 
 export interface EventRenderRange {
 export interface EventRenderRange {
   eventDef: EventDef
   eventDef: EventDef

+ 1 - 1
src/component/renderers/EventRenderer.ts

@@ -3,7 +3,7 @@ import { DateMarker } from '../../datelib/marker'
 import { createFormatter, DateFormatter } from '../../datelib/formatting'
 import { createFormatter, DateFormatter } from '../../datelib/formatting'
 import { htmlToElements } from '../../util/dom-manip'
 import { htmlToElements } from '../../util/dom-manip'
 import { compareByFieldSpecs } from '../../util/misc'
 import { compareByFieldSpecs } from '../../util/misc'
-import { EventRenderRange } from '../../reducers/event-rendering'
+import { EventRenderRange } from '../event-rendering'
 import { Seg } from '../DateComponent'
 import { Seg } from '../DateComponent'
 
 
 
 

+ 2 - 2
src/reducers/array-event-source.ts → src/event-sources/array-event-source.ts

@@ -1,5 +1,5 @@
-import { registerSourceType } from './event-sources'
-import { EventInput } from './event-store'
+import { registerSourceType } from '../structs/event-source'
+import { EventInput } from '../structs/event'
 
 
 registerSourceType('array', {
 registerSourceType('array', {
 
 

+ 2 - 2
src/reducers/func-event-source.ts → src/event-sources/func-event-source.ts

@@ -1,6 +1,6 @@
 import { unpromisify } from '../util/promise'
 import { unpromisify } from '../util/promise'
-import { registerSourceType } from './event-sources'
-import { EventInput } from './event-store'
+import { registerSourceType } from '../structs/event-source'
+import { EventInput } from '../structs/event'
 
 
 registerSourceType('function', {
 registerSourceType('function', {
 
 

+ 1 - 1
src/reducers/json-feed-event-source.ts → src/event-sources/json-feed-event-source.ts

@@ -2,7 +2,7 @@ import UnzonedRange from '../models/UnzonedRange'
 import * as request from 'superagent'
 import * as request from 'superagent'
 import { assignTo } from '../util/object'
 import { assignTo } from '../util/object'
 import Calendar from '../Calendar'
 import Calendar from '../Calendar'
-import { registerSourceType } from './event-sources'
+import { registerSourceType } from '../structs/event-source'
 
 
 interface JsonFeedMeta {
 interface JsonFeedMeta {
   url: string
   url: string

+ 2 - 2
src/exports.ts

@@ -106,8 +106,8 @@ export { defineLocale, getLocale, getLocaleCodes } from './datelib/locale'
 export { DateFormatter, createFormatter } from './datelib/formatting'
 export { DateFormatter, createFormatter } from './datelib/formatting'
 export { parse as parseMarker } from './datelib/parsing'
 export { parse as parseMarker } from './datelib/parsing'
 
 
-export { registerSourceType } from './reducers/event-sources'
-export { refineProps } from './reducers/utils'
+export { registerSourceType } from './structs/event-source'
+export { refineProps } from './util/misc'
 
 
 export { default as PointerDragging, PointerDragEvent } from './dnd/PointerDragging'
 export { default as PointerDragging, PointerDragEvent } from './dnd/PointerDragging'
 export { default as ElementDragging } from './dnd/ElementDragging'
 export { default as ElementDragging } from './dnd/ElementDragging'

+ 4 - 3
src/interactions-external/ExternalElementDragging.ts

@@ -2,12 +2,13 @@ import ElementDragging from '../dnd/ElementDragging'
 import HitDragging, { Hit } from '../interactions/HitDragging'
 import HitDragging, { Hit } from '../interactions/HitDragging'
 import browserContext from '../common/browser-context'
 import browserContext from '../common/browser-context'
 import { PointerDragEvent } from '../dnd/PointerDragging'
 import { PointerDragEvent } from '../dnd/PointerDragging'
-import { EventStore, parseDef, createInstance, EventDef, createEmptyEventStore, EventInstance } from '../reducers/event-store'
+import { parseDef, createInstance, EventDef, EventInstance } from '../structs/event'
+import { EventStore, createEmptyEventStore } from '../structs/event-store'
 import UnzonedRange from '../models/UnzonedRange'
 import UnzonedRange from '../models/UnzonedRange'
 import * as externalHooks from '../exports'
 import * as externalHooks from '../exports'
-import { DateSpan } from '../reducers/date-span'
+import { DateSpan } from '../structs/date-span'
 import Calendar from '../Calendar'
 import Calendar from '../Calendar'
-import { EventInteractionState } from '../reducers/event-interaction'
+import { EventInteractionState } from '../interactions/event-interaction-state'
 import { DragMetaInput, DragMeta, parseDragMeta } from '../structs/drag-meta'
 import { DragMetaInput, DragMeta, parseDragMeta } from '../structs/drag-meta'
 
 
 export interface EventRes { // TODO: relate this to EventRenderRange?
 export interface EventRes { // TODO: relate this to EventRenderRange?

+ 1 - 1
src/interactions/DateSelecting.ts

@@ -2,7 +2,7 @@ import { compareNumbers } from '../util/misc'
 import { elementClosest } from '../util/dom-manip'
 import { elementClosest } from '../util/dom-manip'
 import DateComponent from '../component/DateComponent'
 import DateComponent from '../component/DateComponent'
 import HitDragging, { Hit } from './HitDragging'
 import HitDragging, { Hit } from './HitDragging'
-import { DateSpan } from '../reducers/date-span'
+import { DateSpan } from '../structs/date-span'
 import UnzonedRange from '../models/UnzonedRange'
 import UnzonedRange from '../models/UnzonedRange'
 import { PointerDragEvent } from '../dnd/PointerDragging'
 import { PointerDragEvent } from '../dnd/PointerDragging'
 import FeaturefulElementDragging from '../dnd/FeaturefulElementDragging'
 import FeaturefulElementDragging from '../dnd/FeaturefulElementDragging'

+ 3 - 3
src/interactions/EventDragging.ts

@@ -2,14 +2,14 @@ import { default as DateComponent, Seg } from '../component/DateComponent'
 import { getElSeg } from '../component/renderers/EventRenderer'
 import { getElSeg } from '../component/renderers/EventRenderer'
 import { PointerDragEvent } from '../dnd/PointerDragging'
 import { PointerDragEvent } from '../dnd/PointerDragging'
 import HitDragging, { isHitsEqual, Hit } from './HitDragging'
 import HitDragging, { isHitsEqual, Hit } from './HitDragging'
-import { EventMutation, diffDates, getRelatedEvents, applyMutationToAll } from '../reducers/event-mutation'
+import { EventMutation, diffDates, getRelatedEvents, applyMutationToAll } from '../structs/event-mutation'
 import browserContext from '../common/browser-context'
 import browserContext from '../common/browser-context'
 import { startOfDay } from '../datelib/marker'
 import { startOfDay } from '../datelib/marker'
 import { elementClosest } from '../util/dom-manip'
 import { elementClosest } from '../util/dom-manip'
 import FeaturefulElementDragging from '../dnd/FeaturefulElementDragging'
 import FeaturefulElementDragging from '../dnd/FeaturefulElementDragging'
-import { EventStore, createEmptyEventStore } from '../reducers/event-store'
+import { EventStore, createEmptyEventStore } from '../structs/event-store'
 import Calendar from '../Calendar'
 import Calendar from '../Calendar'
-import { EventInteractionState } from '../reducers/event-interaction'
+import { EventInteractionState } from '../interactions/event-interaction-state'
 
 
 export default class EventDragging {
 export default class EventDragging {
 
 

+ 3 - 2
src/interactions/EventResizing.ts

@@ -1,12 +1,13 @@
 import { default as DateComponent, Seg } from '../component/DateComponent'
 import { default as DateComponent, Seg } from '../component/DateComponent'
 import HitDragging, { isHitsEqual, Hit } from './HitDragging'
 import HitDragging, { isHitsEqual, Hit } from './HitDragging'
-import { EventMutation, diffDates, getRelatedEvents, applyMutationToAll } from '../reducers/event-mutation'
+import { EventMutation, diffDates, getRelatedEvents, applyMutationToAll } from '../structs/event-mutation'
 import { elementClosest } from '../util/dom-manip'
 import { elementClosest } from '../util/dom-manip'
 import UnzonedRange from '../models/UnzonedRange'
 import UnzonedRange from '../models/UnzonedRange'
 import FeaturefulElementDragging from '../dnd/FeaturefulElementDragging'
 import FeaturefulElementDragging from '../dnd/FeaturefulElementDragging'
 import { PointerDragEvent } from '../dnd/PointerDragging'
 import { PointerDragEvent } from '../dnd/PointerDragging'
 import { getElSeg } from '../component/renderers/EventRenderer'
 import { getElSeg } from '../component/renderers/EventRenderer'
-import { EventStore, EventInstance } from '../reducers/event-store'
+import { EventInstance } from '../structs/event'
+import { EventStore } from '../structs/event-store'
 
 
 export default class EventDragging {
 export default class EventDragging {
 
 

+ 1 - 1
src/interactions/HitDragging.ts

@@ -2,7 +2,7 @@ import EmitterMixin from '../common/EmitterMixin'
 import { PointerDragEvent } from '../dnd/PointerDragging'
 import { PointerDragEvent } from '../dnd/PointerDragging'
 import ElementDragging from '../dnd/ElementDragging'
 import ElementDragging from '../dnd/ElementDragging'
 import DateComponent, { DateComponentHash } from '../component/DateComponent'
 import DateComponent, { DateComponentHash } from '../component/DateComponent'
-import { DateSpan, isDateSpansEqual } from '../reducers/date-span'
+import { DateSpan, isDateSpansEqual } from '../structs/date-span'
 import { computeRect } from '../util/dom-geom'
 import { computeRect } from '../util/dom-geom'
 import { constrainPoint, intersectRects, getRectCenter, diffPoints, Rect, Point } from '../util/geom'
 import { constrainPoint, intersectRects, getRectCenter, diffPoints, Rect, Point } from '../util/geom'
 
 

+ 1 - 1
src/reducers/event-interaction.ts → src/interactions/event-interaction-state.ts

@@ -1,4 +1,4 @@
-import { EventStore } from './event-store'
+import { EventStore } from '../structs/event-store'
 import { Seg } from '../component/DateComponent'
 import { Seg } from '../component/DateComponent'
 
 
 export interface EventInteractionState {
 export interface EventInteractionState {

+ 2 - 2
src/main.ts

@@ -6,7 +6,7 @@ import './basic/config'
 import './agenda/config'
 import './agenda/config'
 import './list/config'
 import './list/config'
 
 
-import './reducers/json-feed-event-source'
-import './reducers/array-event-source'
+import './event-sources/json-feed-event-source'
+import './event-sources/array-event-source'
 
 
 export = exportHooks
 export = exportHooks

+ 2 - 115
src/reducers/event-sources.ts

@@ -1,99 +1,14 @@
 import { assignTo } from '../util/object'
 import { assignTo } from '../util/object'
-import UnzonedRange from '../models/UnzonedRange'
 import Calendar from '../Calendar'
 import Calendar from '../Calendar'
-import { EventInput } from './event-store'
-import { ClassNameInput, parseClassName, refineProps } from './utils'
 import { warn } from '../util/misc'
 import { warn } from '../util/misc'
+import { EventSource, EventSourceHash, parseSource, sourceTypes } from '../structs/event-source'
 
 
-// types
-
-export interface EventSourceInput {
-  id?: string | number
-  allDayDefault?: boolean
-  eventDataTransform?: any
-  editable?: boolean
-  startEditable?: boolean
-  durationEditable?: boolean
-  overlap?: any
-  constraint?: any
-  rendering?: string
-  className?: ClassNameInput
-  color?: string
-  backgroundColor?: string
-  borderColor?: string
-  textColor?: string
-  success?: (eventInputs: EventInput[]) => void
-  failure?: (errorObj: any) => void
-  [otherProp: string]: any
-}
-
-export interface EventSource {
-  sourceId: string
-  sourceType: string
-  sourceTypeMeta: any
-  publicId: string
-  isFetching: boolean
-  latestFetchId: string | null
-  fetchRange: UnzonedRange
-  allDayDefault: boolean | null
-  eventDataTransform: any
-  editable: boolean | null
-  startEditable: boolean | null
-  durationEditable: boolean | null
-  overlap: any
-  constraint: any
-  rendering: string | null
-  className: string[]
-  color: string | null
-  backgroundColor: string | null
-  borderColor: string | null
-  textColor: string | null
-  success?: (eventInputs: EventInput[]) => void
-  failure?: (errorObj: any) => void
-}
-
-export type EventSourceHash = { [sourceId: string]: EventSource }
-
-export interface EventSourceTypeSettings {
-  parseMeta: (raw: any) => any
-  fetch: (
-    arg: {
-      eventSource: EventSource
-      calendar: Calendar
-      range: UnzonedRange
-    },
-    success: (rawEvents: EventInput) => void,
-    failure: (errorObj: any) => void
-  ) => void
-}
-
-// vars
-
-const SIMPLE_SOURCE_PROPS = {
-  allDayDefault: Boolean,
-  eventDataTransform: null,
-  editable: Boolean,
-  startEditable: Boolean,
-  durationEditable: Boolean,
-  overlap: null,
-  constraint: null,
-  rendering: String,
-  className: parseClassName,
-  color: String,
-  backgroundColor: String,
-  borderColor: String,
-  textColor: String,
-  success: null,
-  failure: null
-}
-
-let sourceTypes: { [sourceTypeName: string]: EventSourceTypeSettings } = {}
 let guid = 0
 let guid = 0
 
 
 // reducers
 // reducers
 
 
 export function reduceEventSourceHash(sourceHash: EventSourceHash, action: any, calendar: Calendar): EventSourceHash {
 export function reduceEventSourceHash(sourceHash: EventSourceHash, action: any, calendar: Calendar): EventSourceHash {
-  let eventSource
+  let eventSource: EventSource
 
 
   switch (action.type) {
   switch (action.type) {
 
 
@@ -224,31 +139,3 @@ export function reduceEventSourceHash(sourceHash: EventSourceHash, action: any,
       return sourceHash
       return sourceHash
   }
   }
 }
 }
-
-// parsing
-
-export function registerSourceType(type: string, settings: EventSourceTypeSettings) {
-  sourceTypes[type] = settings
-}
-
-function parseSource(raw: EventSourceInput): EventSource {
-  for (let sourceTypeName in sourceTypes) {
-    let sourceTypeSettings = sourceTypes[sourceTypeName]
-    let sourceTypeMeta = sourceTypeSettings.parseMeta(raw)
-
-    if (sourceTypeMeta) {
-      let source: EventSource = refineProps(raw, SIMPLE_SOURCE_PROPS)
-      source.sourceId = String(guid++)
-      source.sourceType = sourceTypeName
-      source.sourceTypeMeta = sourceTypeMeta
-
-      if (raw.id != null) {
-        source.publicId = String(raw.id)
-      }
-
-      return source
-    }
-  }
-
-  return null
-}

+ 3 - 237
src/reducers/event-store.ts

@@ -1,112 +1,8 @@
-import UnzonedRange from '../models/UnzonedRange'
-import { DateInput } from '../datelib/env'
 import Calendar from '../Calendar'
 import Calendar from '../Calendar'
 import { filterHash } from '../util/object'
 import { filterHash } from '../util/object'
-import { parseClassName, refineProps, ClassNameInput } from './utils'
-import { expandRecurring } from './recurring-events'
-import { applyMutationToRelated, mergeStores } from './event-mutation' // TODO: move mergeStores here
-
-// types
-
-export type RenderingChoices = '' | 'background' | 'inverse-background' | 'none'
-
-export interface EventInput {
-  id?: string | number
-  groupId?: string | number
-  start?: DateInput
-  end?: DateInput
-  date?: DateInput
-  isAllDay?: boolean
-  title?: string
-  url?: string
-  editable?: boolean
-  startEditable?: boolean
-  durationEditable?: boolean
-  constraint?: any
-  overlap?: any
-  rendering?: RenderingChoices
-  className?: ClassNameInput
-  color?: string
-  backgroundColor?: string
-  borderColor?: string
-  textColor?: string
-  [extendedPropName: string]: any
-}
-
-export interface EventDef {
-  defId: string
-  sourceId: string
-  publicId: string | null
-  groupId: string | null
-  hasEnd: boolean
-  isAllDay: boolean
-  title: string | null
-  url: string | null
-  editable: boolean | null
-  startEditable: boolean | null
-  durationEditable: boolean | null
-  constraint: any
-  overlap: any
-  rendering: RenderingChoices
-  className: string[]
-  color: string | null
-  backgroundColor: string | null
-  borderColor: string | null
-  textColor: string | null
-  extendedProps: any
-}
-
-export interface EventInstance {
-  instanceId: string
-  defId: string
-  range: UnzonedRange
-  forcedStartTzo: number | null
-  forcedEndTzo: number | null
-}
-
-export type EventInstanceHash = { [instanceId: string]: EventInstance }
-export type EventDefHash = { [defId: string]: EventDef }
-
-export interface EventStore {
-  defs: EventDefHash
-  instances: EventInstanceHash
-}
-
-interface EventDateInfo {
-  isAllDay: boolean
-  hasEnd: boolean
-  range: UnzonedRange
-  forcedStartTzo: number | null
-  forcedEndTzo: number | null
-}
-
-// vars
-
-const DATE_PROPS = {
-  start: null,
-  date: null,
-  end: null,
-  isAllDay: null
-}
-
-const SIMPLE_DEF_PROPS = {
-  groupId: String,
-  title: String,
-  url: String,
-  editable: Boolean,
-  startEditable: Boolean,
-  durationEditable: Boolean,
-  constraint: null,
-  overlap: null,
-  rendering: String,
-  className: parseClassName,
-  color: String,
-  backgroundColor: String,
-  borderColor: String,
-  textColor: String
-}
-
-let guid = 0
+import { applyMutationToRelated, mergeStores } from '../structs/event-mutation'
+import { EventDef, EventInstance } from '../structs/event'
+import { EventStore, addRawEvents } from '../structs/event-store'
 
 
 // reducing
 // reducing
 
 
@@ -162,133 +58,3 @@ function excludeSource(eventStore: EventStore, sourceId: string): EventStore {
   }
   }
 }
 }
 
 
-function addRawEvents(eventStore: EventStore, sourceId: string, fetchRange: UnzonedRange, rawEvents: any, calendar: Calendar) {
-  rawEvents.forEach(function(rawEvent: EventInput) {
-    let leftoverProps = {}
-    let recurringDateInfo = expandRecurring(rawEvent, fetchRange, calendar, leftoverProps)
-
-    if (recurringDateInfo) {
-      let def = parseDef(leftoverProps, sourceId, recurringDateInfo.isAllDay, recurringDateInfo.hasEnd)
-      eventStore.defs[def.defId] = def
-
-      for (let range of recurringDateInfo.ranges) {
-        let instance = createInstance(def.defId, range)
-        eventStore.instances[instance.instanceId] = instance
-      }
-
-    } else {
-      let dateInfo = parseDateInfo(rawEvent, sourceId, calendar, leftoverProps)
-
-      if (dateInfo) {
-        let def = parseDef(leftoverProps, sourceId, dateInfo.isAllDay, dateInfo.hasEnd)
-        let instance = createInstance(def.defId, dateInfo.range, dateInfo.forcedStartTzo, dateInfo.forcedEndTzo)
-
-        eventStore.defs[def.defId] = def
-        eventStore.instances[instance.instanceId] = instance
-      }
-    }
-  })
-}
-
-// parsing + creating
-
-export function parseDef(raw: EventInput, sourceId: string, isAllDay: boolean, hasEnd: boolean): EventDef {
-  let leftovers = {} as any
-  let def = refineProps(raw, SIMPLE_DEF_PROPS, leftovers)
-
-  // TODO: allow explicit extendedProps hash
-
-  if (leftovers.id != null) {
-    def.publicId = String(leftovers.id)
-    delete leftovers.id
-  } else {
-    def.publicId = null
-  }
-
-  def.defId = String(guid++)
-  def.sourceId = sourceId
-  def.isAllDay = isAllDay
-  def.hasEnd = hasEnd
-  def.extendedProps = leftovers
-
-  return def
-}
-
-export function createInstance(
-  defId: string,
-  range: UnzonedRange,
-  forcedStartTzo: number = null,
-  forcedEndTzo: number = null
-): EventInstance {
-  let instanceId = String(guid++)
-  return { instanceId, defId, range, forcedStartTzo, forcedEndTzo }
-}
-
-function parseDateInfo(rawEvent: EventInput, sourceId: string, calendar: Calendar, leftoverProps: any): EventDateInfo {
-  let dateProps = refineProps(rawEvent, DATE_PROPS, leftoverProps)
-  let rawStart = dateProps.start
-  let startMeta
-  let hasEnd = false
-  let endMeta = null
-  let endMarker = null
-
-  if (rawStart == null) {
-    rawStart = dateProps.date
-  }
-
-  if (rawStart != null) {
-    startMeta = calendar.dateEnv.createMarkerMeta(rawStart)
-  }
-  if (!startMeta) {
-    return null
-  }
-
-  if (dateProps.end != null) {
-    endMeta = calendar.dateEnv.createMarkerMeta(dateProps.end)
-  }
-
-  let isAllDay = dateProps.isAllDay
-  if (isAllDay == null && sourceId) {
-    let source = calendar.state.eventSources[sourceId]
-    isAllDay = source.allDayDefault
-  }
-  if (isAllDay == null) {
-    isAllDay = calendar.opt('allDayDefault')
-  }
-  if (isAllDay == null) {
-    isAllDay = startMeta.isTimeUnspecified && (!endMeta || endMeta.isTimeUnspecified)
-  }
-
-  if (endMeta) {
-    endMarker = endMeta.marker
-
-    if (endMarker <= startMeta.marker) {
-      endMarker = null
-    }
-  }
-
-  if (endMarker) {
-    hasEnd = true
-  } else {
-    hasEnd = calendar.opt('forceEventDuration') || false
-
-    endMarker = calendar.dateEnv.add(
-      startMeta.marker,
-      isAllDay ?
-        calendar.defaultAllDayEventDuration :
-        calendar.defaultTimedEventDuration
-    )
-  }
-
-  return {
-    isAllDay,
-    hasEnd,
-    range: new UnzonedRange(startMeta.marker, endMarker),
-    forcedStartTzo: startMeta.forcedTimeZoneOffset, // TODO: rename to 'tzo' elsewhere
-    forcedEndTzo: endMeta ? endMeta.forcedTimeZoneOffset : null
-  }
-}
-
-export function createEmptyEventStore(): EventStore {
-  return { defs: {}, instances: {} }
-}

+ 2 - 1
src/reducers/main.ts

@@ -1,6 +1,7 @@
 import Calendar from '../Calendar'
 import Calendar from '../Calendar'
 import { DateComponentRenderState } from '../component/DateComponent'
 import { DateComponentRenderState } from '../component/DateComponent'
-import { EventSourceHash, reduceEventSourceHash } from './event-sources'
+import { EventSourceHash } from '../structs/event-source'
+import { reduceEventSourceHash } from './event-sources'
 import { reduceEventStore } from './event-store'
 import { reduceEventStore } from './event-store'
 import { DateMarker } from '../datelib/marker'
 import { DateMarker } from '../datelib/marker'
 import { assignTo } from '../util/object'
 import { assignTo } from '../util/object'

+ 0 - 117
src/reducers/options.ts

@@ -1,117 +0,0 @@
-
-const OPTIONS = {
-  allDaySlot
-  columnHeader
-  eventLimit
-  scrollTime
-  weekNumbers
-  slotDuration
-  snapDuration
-  slotLabelFormat
-  slotLabelInterval
-  agendaEventMinHeight
-  selectHelper
-  slotEventOverlap
-  weekNumbers
-  weekNumbersWithinDays
-  columnHeader
-  eventLimit
-  weekLabel
-  eventLimitClick
-  popoverViewportConstrain
-  dayPopoverFormat
-  eventLimitText
-  nextDayThreshold
-  isRTL
-  navLinks
-  allDayHtml
-  allDayText
-  columnHeaderFormat
-  columnFormat
-  columnHeaderHtml
-  columnHeaderText
-  eventResizableFromStart
-  eventTimeFormat
-  timeFormat
-  displayEventTime
-  displayEventEnd
-  eventBackgroundColor
-  eventColor
-  eventBorderColor
-  eventColor
-  eventTextColor
-  dragOpacity
-  noEventsMessage
-  listDayFormat
-  listDayAltFormat // how will work with plugins???
-  eventOrder
-  eventRenderWait
-  titleFormat
-  titleRangeSeparator
-  businessHours // ???
-  nowIndicator
-  unselectAuto
-  unselectCancel
-  hiddenDays
-  weekends
-
-  theme
-  themeSystem
-  isRTL
-  locale
-  timezone
-  firstDay
-  weekNumberCalculation
-  weekLabel
-
-
-  // dateprofile
-  fixedWeekCount
-  defaultDate
-  minTime
-  maxTime
-  dayCount
-  dateAlignment
-  dateIncrement
-
-  // event source
-  eventSources
-  events
-  lazyFetching
-  allDayDefault
-  forceEventDuration
-  defaultAllDayEventDuration
-  defaultTimedEventDuration // for other things too?
-  startParam
-  endParam
-  timezoneParam
-
-  navLink*
-  defaultView
-  handleWindowResize
-  windowResizeDelay
-  header
-  footer
-
-  now
-
-  // height
-  contentHeight
-  height
-  aspectRatio
-
-  // publiclyTrigger
-  dayRender
-  eventLimitClick
-  loading
-  windowResize
-  eventAfterAllRender
-  eventAfterRender
-  eventDestroy
-  eventRender
-  viewRender
-  viewDestroy
-  select
-  unselect
-
-}

+ 10 - 0
src/reducers/tsconfig.json

@@ -0,0 +1,10 @@
+{
+  "extends": "../../tsconfig",
+  "compilerOptions": {
+    "noImplicitAny": true,
+    "noImplicitThis": true,
+    "strictNullChecks": true,
+    "strictFunctionTypes": true,
+    "strictPropertyInitialization": true
+  }
+}

+ 0 - 36
src/reducers/utils.ts

@@ -1,36 +0,0 @@
-
-export function refineProps(rawProps, processorFuncs, leftoverProps?): any {
-  let refined = {}
-
-  for (let key in processorFuncs) {
-    if (rawProps[key] == null) {
-      refined[key] = null
-    } else if (processorFuncs[key]) {
-      refined[key] = processorFuncs[key](rawProps[key])
-    } else {
-      refined[key] = rawProps[key]
-    }
-  }
-
-  if (leftoverProps) {
-    for (let key in rawProps) {
-      if (processorFuncs[key] === undefined) {
-        leftoverProps[key] = rawProps[key]
-      }
-    }
-  }
-
-  return refined
-}
-
-export type ClassNameInput = string | string[]
-
-export function parseClassName(raw: ClassNameInput) {
-  if (Array.isArray(raw)) {
-    return raw
-  } else if (typeof raw === 'string') {
-    return raw.split(/\s+/)
-  } else {
-    return []
-  }
-}

+ 5 - 4
src/reducers/business-hours.ts → src/structs/business-hours.ts

@@ -1,9 +1,9 @@
 import Calendar from '../Calendar'
 import Calendar from '../Calendar'
 import UnzonedRange from '../models/UnzonedRange'
 import UnzonedRange from '../models/UnzonedRange'
-import { EventInput } from './event-store'
 import { assignTo } from '../util/object'
 import { assignTo } from '../util/object'
-import { expandRecurring } from './recurring-events'
-import { EventStore, parseDef, createInstance } from './event-store'
+import { expandRecurring } from './recurring-event'
+import { EventInput, parseDef, createInstance } from './event'
+import { EventStore } from './event-store'
 
 
 export type BusinessHourDef = boolean | EventInput | EventInput[] // TODO: rename to plural?
 export type BusinessHourDef = boolean | EventInput | EventInput[] // TODO: rename to plural?
 
 
@@ -28,8 +28,9 @@ export function buildBusinessHourEventStore(
     instances: {}
     instances: {}
   }
   }
 
 
+  // TODO: join with event-store
   for (let eventInput of eventInputs) {
   for (let eventInput of eventInputs) {
-    let def = parseDef(eventInput, null, isAllDay, true)
+    let def = parseDef(eventInput, '', isAllDay, true) // nooo, do this second, with lefotvers
     let ranges = expandRecurring(eventInput, framingRange, calendar).ranges
     let ranges = expandRecurring(eventInput, framingRange, calendar).ranges
 
 
     eventStore.defs[def.defId] = def
     eventStore.defs[def.defId] = def

+ 1 - 1
src/reducers/date-span.ts → src/structs/date-span.ts

@@ -1,6 +1,6 @@
 import UnzonedRange from '../models/UnzonedRange'
 import UnzonedRange from '../models/UnzonedRange'
 import { DateInput, DateEnv } from '../datelib/env'
 import { DateInput, DateEnv } from '../datelib/env'
-import { refineProps } from '../reducers/utils'
+import { refineProps } from '../util/misc'
 
 
 export interface DateSpanInput {
 export interface DateSpanInput {
   start: DateInput
   start: DateInput

+ 1 - 1
src/structs/drag-meta.ts

@@ -1,5 +1,5 @@
 import { createDuration, Duration, DurationInput } from '../datelib/duration'
 import { createDuration, Duration, DurationInput } from '../datelib/duration'
-import { refineProps } from '../reducers/utils'
+import { refineProps } from '../util/misc'
 
 
 export interface DragMetaInput {
 export interface DragMetaInput {
   time?: DurationInput
   time?: DurationInput

+ 4 - 1
src/reducers/event-mutation.ts → src/structs/event-mutation.ts

@@ -1,7 +1,8 @@
 import UnzonedRange from '../models/UnzonedRange'
 import UnzonedRange from '../models/UnzonedRange'
 import { diffDayAndTime, diffDays, startOfDay, addDays } from '../datelib/marker'
 import { diffDayAndTime, diffDays, startOfDay, addDays } from '../datelib/marker'
 import { Duration, createDuration } from '../datelib/duration'
 import { Duration, createDuration } from '../datelib/duration'
-import { EventStore, EventDef, EventInstance } from './event-store'
+import { EventStore } from './event-store'
+import { EventDef, EventInstance } from './event'
 import { assignTo } from '../util/object'
 import { assignTo } from '../util/object'
 import Calendar from '../Calendar'
 import Calendar from '../Calendar'
 
 
@@ -68,6 +69,7 @@ export function getRelatedEvents(eventStore: EventStore, instanceId: string): Ev
   return newStore
   return newStore
 }
 }
 
 
+// TODO: move to event-store
 export function mergeStores(store0: EventStore, store1: EventStore): EventStore {
 export function mergeStores(store0: EventStore, store1: EventStore): EventStore {
   return {
   return {
     defs: assignTo({}, store0.defs, store1.defs),
     defs: assignTo({}, store0.defs, store1.defs),
@@ -130,6 +132,7 @@ function applyMutationToInstance(
   return copy
   return copy
 }
 }
 
 
+// best place?
 export function diffDates(date0, date1, dateEnv, largeUnit) {
 export function diffDates(date0, date1, dateEnv, largeUnit) {
   if (largeUnit === 'year') {
   if (largeUnit === 'year') {
     return createDuration(dateEnv.diffWholeYears(date0, date1), 'year')!
     return createDuration(dateEnv.diffWholeYears(date0, date1), 'year')!

+ 114 - 0
src/structs/event-source.ts

@@ -0,0 +1,114 @@
+import UnzonedRange from '../models/UnzonedRange'
+import { ClassNameInput, parseClassName } from '../util/html'
+import { refineProps } from '../util/misc'
+import { EventInput } from './event'
+import Calendar from '../Calendar'
+
+export interface EventSourceInput {
+  id?: string | number
+  allDayDefault?: boolean
+  eventDataTransform?: any
+  editable?: boolean
+  startEditable?: boolean
+  durationEditable?: boolean
+  overlap?: any
+  constraint?: any
+  rendering?: string
+  className?: ClassNameInput
+  color?: string
+  backgroundColor?: string
+  borderColor?: string
+  textColor?: string
+  success?: (eventInputs: EventInput[]) => void
+  failure?: (errorObj: any) => void
+  [otherProp: string]: any
+}
+
+export interface EventSource {
+  sourceId: string
+  sourceType: string
+  sourceTypeMeta: any
+  publicId: string
+  isFetching: boolean
+  latestFetchId: string | null
+  fetchRange: UnzonedRange
+  allDayDefault: boolean | null
+  eventDataTransform: any
+  editable: boolean | null
+  startEditable: boolean | null
+  durationEditable: boolean | null
+  overlap: any
+  constraint: any
+  rendering: string | null
+  className: string[]
+  color: string | null
+  backgroundColor: string | null
+  borderColor: string | null
+  textColor: string | null
+  success?: (eventInputs: EventInput[]) => void
+  failure?: (errorObj: any) => void
+}
+
+// need this?
+export type EventSourceHash = { [sourceId: string]: EventSource }
+
+export interface EventSourceTypeSettings {
+  parseMeta: (raw: any) => any
+  fetch: (
+    arg: {
+      eventSource: EventSource
+      calendar: Calendar
+      range: UnzonedRange
+    },
+    success: (rawEvents: EventInput) => void,
+    failure: (errorObj: any) => void
+  ) => void
+}
+
+
+const SIMPLE_SOURCE_PROPS = {
+  allDayDefault: Boolean,
+  eventDataTransform: null,
+  editable: Boolean,
+  startEditable: Boolean,
+  durationEditable: Boolean,
+  overlap: null,
+  constraint: null,
+  rendering: String,
+  className: parseClassName,
+  color: String,
+  backgroundColor: String,
+  borderColor: String,
+  textColor: String,
+  success: null,
+  failure: null
+}
+
+export let sourceTypes: { [sourceTypeName: string]: EventSourceTypeSettings } = {}
+let guid = 0
+
+export function registerSourceType(type: string, settings: EventSourceTypeSettings) {
+  sourceTypes[type] = settings
+}
+
+export function parseSource(raw: EventSourceInput): EventSource {
+  for (let sourceTypeName in sourceTypes) {
+    let sourceTypeSettings = sourceTypes[sourceTypeName]
+    let sourceTypeMeta = sourceTypeSettings.parseMeta(raw)
+
+    if (sourceTypeMeta) {
+      let source: EventSource = refineProps(raw, SIMPLE_SOURCE_PROPS)
+      source.sourceId = String(guid++)
+      source.sourceType = sourceTypeName
+      source.sourceTypeMeta = sourceTypeMeta
+
+      if (raw.id != null) {
+        source.publicId = String(raw.id)
+      }
+
+      return source
+    }
+  }
+
+  return null
+}

+ 45 - 0
src/structs/event-store.ts

@@ -0,0 +1,45 @@
+import UnzonedRange from '../models/UnzonedRange'
+import { EventInput, EventDef, EventInstance, parseDef, parseDateInfo, createInstance } from './event'
+import { expandRecurring } from './recurring-event'
+import Calendar from '../Calendar'
+
+// need these?
+export type EventInstanceHash = { [instanceId: string]: EventInstance }
+export type EventDefHash = { [defId: string]: EventDef }
+
+export interface EventStore {
+  defs: EventDefHash
+  instances: EventInstanceHash
+}
+
+export function addRawEvents(eventStore: EventStore, sourceId: string, fetchRange: UnzonedRange, rawEvents: any, calendar: Calendar) {
+  rawEvents.forEach(function(rawEvent: EventInput) {
+    let leftoverProps = {}
+    let recurringDateInfo = expandRecurring(rawEvent, fetchRange, calendar, leftoverProps)
+
+    if (recurringDateInfo) {
+      let def = parseDef(leftoverProps, sourceId, recurringDateInfo.isAllDay, recurringDateInfo.hasEnd)
+      eventStore.defs[def.defId] = def
+
+      for (let range of recurringDateInfo.ranges) {
+        let instance = createInstance(def.defId, range)
+        eventStore.instances[instance.instanceId] = instance
+      }
+
+    } else {
+      let dateInfo = parseDateInfo(rawEvent, sourceId, calendar, leftoverProps)
+
+      if (dateInfo) {
+        let def = parseDef(leftoverProps, sourceId, dateInfo.isAllDay, dateInfo.hasEnd)
+        let instance = createInstance(def.defId, dateInfo.range, dateInfo.forcedStartTzo, dateInfo.forcedEndTzo)
+
+        eventStore.defs[def.defId] = def
+        eventStore.instances[instance.instanceId] = instance
+      }
+    }
+  })
+}
+
+export function createEmptyEventStore(): EventStore {
+  return { defs: {}, instances: {} }
+}

+ 197 - 0
src/structs/event.ts

@@ -0,0 +1,197 @@
+import { refineProps } from '../util/misc'
+import { parseClassName, ClassNameInput } from '../util/html'
+import { DateInput } from '../datelib/env'
+import UnzonedRange from '../models/UnzonedRange'
+import Calendar from '../Calendar'
+
+export type RenderingChoices = '' | 'background' | 'inverse-background' | 'none'
+
+export interface EventInput {
+  id?: string | number
+  groupId?: string | number
+  start?: DateInput
+  end?: DateInput
+  date?: DateInput
+  isAllDay?: boolean
+  title?: string
+  url?: string
+  editable?: boolean
+  startEditable?: boolean
+  durationEditable?: boolean
+  constraint?: any
+  overlap?: any
+  rendering?: RenderingChoices
+  className?: ClassNameInput
+  color?: string
+  backgroundColor?: string
+  borderColor?: string
+  textColor?: string
+  [extendedPropName: string]: any
+}
+
+export interface EventDef {
+  defId: string
+  sourceId: string
+  publicId: string | null
+  groupId: string | null
+  hasEnd: boolean
+  isAllDay: boolean
+  title: string | null
+  url: string | null
+  editable: boolean | null
+  startEditable: boolean | null
+  durationEditable: boolean | null
+  constraint: any
+  overlap: any
+  rendering: RenderingChoices
+  className: string[]
+  color: string | null
+  backgroundColor: string | null
+  borderColor: string | null
+  textColor: string | null
+  extendedProps: any
+}
+
+export interface EventInstance {
+  instanceId: string
+  defId: string
+  range: UnzonedRange
+  forcedStartTzo: number | null
+  forcedEndTzo: number | null
+}
+
+export interface EventDateInfo {
+  isAllDay: boolean
+  hasEnd: boolean
+  range: UnzonedRange
+  forcedStartTzo: number | null
+  forcedEndTzo: number | null
+}
+
+
+// vars
+
+const DATE_PROPS = {
+  start: null,
+  date: null,
+  end: null,
+  isAllDay: null
+}
+
+const SIMPLE_DEF_PROPS = {
+  groupId: String,
+  title: String,
+  url: String,
+  editable: Boolean,
+  startEditable: Boolean,
+  durationEditable: Boolean,
+  constraint: null,
+  overlap: null,
+  rendering: String,
+  className: parseClassName,
+  color: String,
+  backgroundColor: String,
+  borderColor: String,
+  textColor: String
+}
+
+let guid = 0
+
+
+
+export function parseDef(raw: EventInput, sourceId: string, isAllDay: boolean, hasEnd: boolean): EventDef {
+  let leftovers = {} as any
+  let def = refineProps(raw, SIMPLE_DEF_PROPS, leftovers)
+
+  // TODO: allow explicit extendedProps hash
+
+  if (leftovers.id != null) {
+    def.publicId = String(leftovers.id)
+    delete leftovers.id
+  } else {
+    def.publicId = null
+  }
+
+  def.defId = String(guid++)
+  def.sourceId = sourceId
+  def.isAllDay = isAllDay
+  def.hasEnd = hasEnd
+  def.extendedProps = leftovers
+
+  return def
+}
+
+export function createInstance(
+  defId: string,
+  range: UnzonedRange,
+  forcedStartTzo: number | null = null,
+  forcedEndTzo: number | null = null
+): EventInstance {
+  let instanceId = String(guid++)
+  return { instanceId, defId, range, forcedStartTzo, forcedEndTzo }
+}
+
+export function parseDateInfo(rawEvent: EventInput, sourceId: string, calendar: Calendar, leftoverProps: any): EventDateInfo | null {
+  let dateProps = refineProps(rawEvent, DATE_PROPS, leftoverProps)
+  let rawStart = dateProps.start
+  let startMeta
+  let hasEnd = false
+  let endMeta = null
+  let endMarker = null
+
+  if (rawStart == null) {
+    rawStart = dateProps.date
+  }
+
+  if (rawStart != null) {
+    startMeta = calendar.dateEnv.createMarkerMeta(rawStart)
+  }
+  if (!startMeta) {
+    return null
+  }
+
+  if (dateProps.end != null) {
+    endMeta = calendar.dateEnv.createMarkerMeta(dateProps.end)
+  }
+
+  let isAllDay = dateProps.isAllDay
+  if (isAllDay == null && sourceId) {
+    let source = calendar.state.eventSources[sourceId]
+    isAllDay = source.allDayDefault
+  }
+  if (isAllDay == null) {
+    isAllDay = calendar.opt('allDayDefault')
+  }
+  if (isAllDay == null) {
+    isAllDay = startMeta.isTimeUnspecified && (!endMeta || endMeta.isTimeUnspecified)
+  }
+
+  if (endMeta) {
+    endMarker = endMeta.marker
+
+    if (endMarker <= startMeta.marker) {
+      endMarker = null
+    }
+  }
+
+  if (endMarker) {
+    hasEnd = true
+  } else {
+    hasEnd = calendar.opt('forceEventDuration') || false
+
+    endMarker = calendar.dateEnv.add(
+      startMeta.marker,
+      isAllDay ?
+        calendar.defaultAllDayEventDuration :
+        calendar.defaultTimedEventDuration
+    )
+  }
+
+  return {
+    isAllDay,
+    hasEnd,
+    range: new UnzonedRange(startMeta.marker, endMarker),
+    forcedStartTzo: startMeta.forcedTimeZoneOffset, // TODO: rename to 'tzo' elsewhere
+    forcedEndTzo: endMeta ? endMeta.forcedTimeZoneOffset : null
+  }
+}

+ 2 - 2
src/reducers/recurring-events.ts → src/structs/recurring-event.ts

@@ -3,8 +3,8 @@ import { Duration, createDuration } from '../datelib/duration'
 import UnzonedRange from '../models/UnzonedRange'
 import UnzonedRange from '../models/UnzonedRange'
 import Calendar from '../Calendar'
 import Calendar from '../Calendar'
 import { arrayToHash } from '../util/object'
 import { arrayToHash } from '../util/object'
-import { refineProps } from './utils'
-import { EventInput } from './event-store'
+import { refineProps } from '../util/misc'
+import { EventInput } from './event'
 
 
 // types
 // types
 
 

+ 1 - 1
src/types/input-types.ts

@@ -4,7 +4,7 @@ https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/fullcalenda
 */
 */
 
 
 import View from '../View'
 import View from '../View'
-import { EventSourceInput } from '../reducers/event-sources'
+import { EventSourceInput } from '../structs/event-source'
 import { Duration } from '../datelib/duration'
 import { Duration } from '../datelib/duration'
 import { DateInput } from '../datelib/env'
 import { DateInput } from '../datelib/env'
 import { FormatterInput } from '../datelib/formatting'
 import { FormatterInput } from '../datelib/formatting'

+ 13 - 0
src/util/html.ts

@@ -39,3 +39,16 @@ export function attrsToStr(attrs) {
 
 
   return parts.join(' ')
   return parts.join(' ')
 }
 }
+
+
+export type ClassNameInput = string | string[]
+
+export function parseClassName(raw: ClassNameInput) {
+  if (Array.isArray(raw)) {
+    return raw
+  } else if (typeof raw === 'string') {
+    return raw.split(/\s+/)
+  } else {
+    return []
+  }
+}

+ 25 - 0
src/util/misc.ts

@@ -390,3 +390,28 @@ export function debounce(func, wait) {
     return result
     return result
   }
   }
 }
 }
+
+
+export function refineProps(rawProps, processorFuncs, leftoverProps?): any {
+  let refined = {}
+
+  for (let key in processorFuncs) {
+    if (rawProps[key] == null) {
+      refined[key] = null
+    } else if (processorFuncs[key]) {
+      refined[key] = processorFuncs[key](rawProps[key])
+    } else {
+      refined[key] = rawProps[key]
+    }
+  }
+
+  if (leftoverProps) {
+    for (let key in rawProps) {
+      if (processorFuncs[key] === undefined) {
+        leftoverProps[key] = rawProps[key]
+      }
+    }
+  }
+
+  return refined
+}