event-rendering.ts 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. import { EventDef, EventTuple, EventDefHash } from '../structs/event'
  2. import { EventStore } from '../structs/event-store'
  3. import { DateRange, invertRanges, intersectRanges } from '../datelib/date-range'
  4. import { Duration } from '../datelib/duration'
  5. import { computeVisibleDayRange } from '../util/misc'
  6. import { Seg } from './DateComponent'
  7. import View from '../View'
  8. import EventApi from '../api/EventApi'
  9. import { EventUi, EventUiHash, combineEventUis } from './event-ui'
  10. import { mapHash } from '../util/object'
  11. export interface EventRenderRange extends EventTuple {
  12. ui: EventUi
  13. range: DateRange
  14. isStart: boolean
  15. isEnd: boolean
  16. }
  17. /*
  18. Specifying nextDayThreshold signals that all-day ranges should be sliced.
  19. */
  20. export function sliceEventStore(eventStore: EventStore, eventUiBases: EventUiHash, framingRange: DateRange, nextDayThreshold?: Duration) {
  21. let inverseBgByGroupId: { [groupId: string]: DateRange[] } = {}
  22. let inverseBgByDefId: { [defId: string]: DateRange[] } = {}
  23. let defByGroupId: { [groupId: string]: EventDef } = {}
  24. let bgRanges: EventRenderRange[] = []
  25. let fgRanges: EventRenderRange[] = []
  26. let eventUis = compileEventUis(eventStore.defs, eventUiBases)
  27. for (let defId in eventStore.defs) {
  28. let def = eventStore.defs[defId]
  29. if (def.rendering === 'inverse-background') {
  30. if (def.groupId) {
  31. inverseBgByGroupId[def.groupId] = []
  32. if (!defByGroupId[def.groupId]) {
  33. defByGroupId[def.groupId] = def
  34. }
  35. } else {
  36. inverseBgByDefId[defId] = []
  37. }
  38. }
  39. }
  40. for (let instanceId in eventStore.instances) {
  41. let instance = eventStore.instances[instanceId]
  42. let def = eventStore.defs[instance.defId]
  43. let ui = eventUis[def.defId]
  44. let origRange = instance.range
  45. let slicedRange = intersectRanges(origRange, framingRange)
  46. let visibleRange
  47. if (slicedRange) {
  48. visibleRange = (!def.allDay && nextDayThreshold) ?
  49. computeVisibleDayRange(slicedRange, nextDayThreshold) :
  50. slicedRange
  51. if (def.rendering === 'inverse-background') {
  52. if (def.groupId) {
  53. inverseBgByGroupId[def.groupId].push(visibleRange)
  54. } else {
  55. inverseBgByDefId[instance.defId].push(visibleRange)
  56. }
  57. } else {
  58. (def.rendering === 'background' ? bgRanges : fgRanges).push({
  59. def,
  60. ui,
  61. instance,
  62. range: visibleRange,
  63. isStart: origRange.start && origRange.start.valueOf() === slicedRange.start.valueOf(),
  64. isEnd: origRange.end && origRange.end.valueOf() === slicedRange.end.valueOf()
  65. })
  66. }
  67. }
  68. }
  69. for (let groupId in inverseBgByGroupId) { // BY GROUP
  70. let ranges = inverseBgByGroupId[groupId]
  71. let invertedRanges = invertRanges(ranges, framingRange)
  72. for (let invertedRange of invertedRanges) {
  73. let def = defByGroupId[groupId]
  74. let ui = eventUis[def.defId]
  75. bgRanges.push({
  76. def,
  77. ui,
  78. instance: null,
  79. range: invertedRange,
  80. isStart: false,
  81. isEnd: false
  82. })
  83. }
  84. }
  85. for (let defId in inverseBgByDefId) {
  86. let ranges = inverseBgByDefId[defId]
  87. let invertedRanges = invertRanges(ranges, framingRange)
  88. for (let invertedRange of invertedRanges) {
  89. bgRanges.push({
  90. def: eventStore.defs[defId],
  91. ui: eventUis[defId],
  92. instance: null,
  93. range: invertedRange,
  94. isStart: false,
  95. isEnd: false
  96. })
  97. }
  98. }
  99. return { bg: bgRanges, fg: fgRanges }
  100. }
  101. export function hasBgRendering(def: EventDef) {
  102. return def.rendering === 'background' || def.rendering === 'inverse-background'
  103. }
  104. export function filterSegsViaEls(view: View, segs: Seg[], isMirror) {
  105. if (view.hasPublicHandlers('eventRender')) {
  106. segs = segs.filter(function(seg) {
  107. let custom = view.publiclyTrigger('eventRender', [
  108. {
  109. event: new EventApi(
  110. view.calendar,
  111. seg.eventRange.def,
  112. seg.eventRange.instance
  113. ),
  114. isMirror,
  115. isStart: seg.isStart,
  116. isEnd: seg.isEnd,
  117. // TODO: include seg.range once all components consistently generate it
  118. el: seg.el,
  119. view
  120. }
  121. ])
  122. if (custom === false) { // means don't render at all
  123. return false
  124. } else if (custom && custom !== true) {
  125. seg.el = custom
  126. }
  127. return true
  128. })
  129. }
  130. for (let seg of segs) {
  131. setElSeg(seg.el, seg)
  132. }
  133. return segs
  134. }
  135. function setElSeg(el: HTMLElement, seg: Seg) {
  136. (el as any).fcSeg = seg
  137. }
  138. export function getElSeg(el: HTMLElement): Seg | null {
  139. return (el as any).fcSeg || null
  140. }
  141. // event ui computation
  142. export function compileEventUis(eventDefs: EventDefHash, eventUiBases: EventUiHash) {
  143. return mapHash(eventDefs, function(eventDef: EventDef) {
  144. return compileEventUi(eventDef, eventUiBases)
  145. })
  146. }
  147. export function compileEventUi(eventDef: EventDef, eventUiBases: EventUiHash) {
  148. let uis = []
  149. if (eventUiBases['']) {
  150. uis.push(eventUiBases[''])
  151. }
  152. if (eventUiBases[eventDef.defId]) {
  153. uis.push(eventUiBases[eventDef.defId])
  154. }
  155. uis.push(eventDef.ui)
  156. return combineEventUis(uis)
  157. }