event-source.ts 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. import { ClassNameInput, parseClassName } from '../util/html'
  2. import { refineProps } from '../util/misc'
  3. import { EventInput } from './event'
  4. import Calendar from '../Calendar'
  5. import { DateRange } from '../datelib/date-range'
  6. import { EventSourceFunc } from '../event-sources/func-event-source'
  7. /*
  8. Parsing and normalization of the EventSource data type, which defines how event data is fetched.
  9. Contains the plugin system for defining new types if event sources.
  10. TODO: "EventSource" is the same name as a built-in type in TypeScript. Rethink.
  11. */
  12. export type EventInputTransformer = (eventInput: EventInput) => EventInput | null
  13. export type EventSourceSuccessHandler = (eventInputs: EventInput[]) => void
  14. export type EventSourceFailureHandler = (errorObj: any) => void
  15. export interface ExtendedEventSourceInput {
  16. id?: string | number
  17. allDayDefault?: boolean
  18. eventDataTransform?: EventInputTransformer
  19. editable?: boolean
  20. startEditable?: boolean
  21. durationEditable?: boolean
  22. overlap?: any
  23. constraint?: any
  24. rendering?: string
  25. className?: ClassNameInput
  26. color?: string
  27. backgroundColor?: string
  28. borderColor?: string
  29. textColor?: string
  30. success?: EventSourceSuccessHandler
  31. failure?: EventSourceFailureHandler
  32. // array (TODO: how to move this to array-event-source?)
  33. events?: EventInput[]
  34. // json feed (TODO: how to move this to json-feed-event-source?)
  35. url?: string
  36. method?: string
  37. data?: object | (() => object)
  38. startParam?: string
  39. endParam?: string
  40. timezoneParam?: string
  41. [otherProp: string]: any // in case plugins want more props
  42. }
  43. export type EventSourceInput =
  44. ExtendedEventSourceInput | // object in extended form
  45. EventSourceFunc | // just a function
  46. string // a URL for a JSON feed
  47. export interface EventSource {
  48. sourceId: string
  49. sourceDefId: number // one of the few IDs that's a NUMBER not a string
  50. meta: any
  51. publicId: string
  52. isFetching: boolean
  53. latestFetchId: string
  54. fetchRange: DateRange | null
  55. allDayDefault: boolean | null
  56. eventDataTransform: EventInputTransformer
  57. startEditable: boolean | null
  58. durationEditable: boolean | null
  59. overlap: any
  60. constraint: any
  61. rendering: string
  62. className: string[]
  63. backgroundColor: string
  64. borderColor: string
  65. textColor: string
  66. success: EventSourceSuccessHandler
  67. failure: EventSourceFailureHandler
  68. }
  69. export type EventSourceHash = { [sourceId: string]: EventSource }
  70. export type EventSourceFetcher = (
  71. arg: {
  72. eventSource: EventSource
  73. calendar: Calendar
  74. range: DateRange
  75. },
  76. success: EventSourceSuccessHandler,
  77. failure: EventSourceFailureHandler
  78. ) => void
  79. export interface EventSourceDef {
  80. parseMeta: (raw: EventSourceInput) => object | null
  81. fetch: EventSourceFetcher
  82. }
  83. const SIMPLE_SOURCE_PROPS = {
  84. allDayDefault: Boolean,
  85. eventDataTransform: Function,
  86. startEditable: Boolean,
  87. durationEditable: Boolean,
  88. overlap: null,
  89. constraint: null,
  90. rendering: String,
  91. className: parseClassName,
  92. backgroundColor: String,
  93. borderColor: String,
  94. textColor: String,
  95. success: Function,
  96. failure: Function
  97. }
  98. let defs: EventSourceDef[] = []
  99. let uid = 0
  100. // NOTE: if we ever want to remove defs,
  101. // we need to null out the entry in the array, not delete it,
  102. // because our event source IDs rely on the index.
  103. export function registerEventSourceDef(def: EventSourceDef) {
  104. defs.push(def)
  105. }
  106. export function getEventSourceDef(id: number): EventSourceDef {
  107. return defs[id]
  108. }
  109. export function parseEventSource(raw: EventSourceInput): EventSource | null {
  110. for (let i = defs.length - 1; i >= 0; i--) { // later-added plugins take precedence
  111. let def = defs[i]
  112. let meta = def.parseMeta(raw)
  113. if (meta) {
  114. return parseEventSourceProps(
  115. typeof raw === 'object' ? raw : {},
  116. meta,
  117. i
  118. )
  119. }
  120. }
  121. return null
  122. }
  123. function parseEventSourceProps(raw: ExtendedEventSourceInput, meta: object, sourceDefId: number): EventSource {
  124. let props = refineProps(raw, SIMPLE_SOURCE_PROPS) as EventSource
  125. props.isFetching = false
  126. props.latestFetchId = ''
  127. props.fetchRange = null
  128. props.publicId = String(raw.id || '')
  129. props.sourceId = String(uid++)
  130. props.sourceDefId = sourceDefId
  131. props.meta = meta
  132. // TODO: consolidate with event struct
  133. if ('editable' in raw) {
  134. if (props.startEditable === null) {
  135. props.startEditable = raw.editable
  136. }
  137. if (props.durationEditable === null) {
  138. props.durationEditable = raw.editable
  139. }
  140. }
  141. // TODO: consolidate with event struct
  142. if ('color' in raw) {
  143. if (props.backgroundColor === null) {
  144. props.backgroundColor = raw.color
  145. }
  146. if (props.borderColor === null) {
  147. props.borderColor = raw.color
  148. }
  149. }
  150. return props
  151. }