DayTile.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. import DateComponent, { Seg } from '../component/DateComponent'
  2. import SimpleDayGridEventRenderer from './SimpleDayGridEventRenderer'
  3. import { htmlEscape } from '../util/html'
  4. import { createFormatter } from '../datelib/formatting'
  5. import { Hit } from '../interactions/HitDragging'
  6. import OffsetTracker from '../common/OffsetTracker'
  7. import { computeRect } from '../util/dom-geom'
  8. import { Rect, pointInsideRect } from '../util/geom'
  9. import { addDays, DateMarker } from '../datelib/marker'
  10. import { removeElement } from '../util/dom-manip'
  11. import { EventInteractionUiState } from '../interactions/event-interaction-state'
  12. import { ComponentContext } from '../component/Component'
  13. export interface DayTileProps {
  14. date: DateMarker
  15. segs: Seg[]
  16. eventSelection: string
  17. eventDrag: EventInteractionUiState
  18. eventResize: EventInteractionUiState
  19. }
  20. export default class DayTile extends DateComponent<DayTileProps> {
  21. segContainerEl: HTMLElement
  22. width: number
  23. height: number
  24. offsetTracker: OffsetTracker // TODO: abstraction for tracking dims of whole element rect
  25. constructor(context: ComponentContext, el: HTMLElement) {
  26. super(context, el)
  27. this.eventRenderer = new DayTileEventRenderer(this)
  28. }
  29. render(props: DayTileProps) {
  30. let dateId = this.subrender('renderFrame', [ props.date ])
  31. let evId = this.subrender('renderFgEventSegs', [ props.segs, dateId ], 'unrenderEvents')
  32. this.subrender('renderEventSelection', [ props.eventSelection, evId ], 'unrenderEventSelection')
  33. this.subrender('renderEventDragState', [ props.eventDrag, dateId ], 'unrenderEventDragState')
  34. this.subrender('renderEventResizeState', [ props.eventResize, dateId ], 'unrenderEventResizeState')
  35. }
  36. renderFrame(date: DateMarker) {
  37. let { theme, dateEnv } = this
  38. let title = dateEnv.format(
  39. date,
  40. createFormatter(this.opt('dayPopoverFormat')) // TODO: cache
  41. )
  42. this.el.innerHTML =
  43. '<div class="fc-header ' + theme.getClass('popoverHeader') + '">' +
  44. '<span class="fc-close ' + theme.getIconClass('close') + '"></span>' +
  45. '<span class="fc-title">' +
  46. htmlEscape(title) +
  47. '</span>' +
  48. '<div class="fc-clear"></div>' +
  49. '</div>' +
  50. '<div class="fc-body ' + theme.getClass('popoverContent') + '">' +
  51. '<div class="fc-event-container"></div>' +
  52. '</div>'
  53. this.segContainerEl = this.el.querySelector('.fc-event-container')
  54. }
  55. renderEventDragState(state: EventInteractionUiState) {
  56. if (state) {
  57. this.eventRenderer.hideByHash(state.affectedEvents.instances)
  58. }
  59. }
  60. unrenderEventDragState(state: EventInteractionUiState) {
  61. if (state) {
  62. this.eventRenderer.showByHash(state.affectedEvents.instances)
  63. }
  64. }
  65. renderEventResizeState(state: EventInteractionUiState) {
  66. if (state) {
  67. this.eventRenderer.hideByHash(state.affectedEvents.instances)
  68. }
  69. }
  70. unrenderEventResizeState(state: EventInteractionUiState) {
  71. if (state) {
  72. this.eventRenderer.showByHash(state.affectedEvents.instances)
  73. }
  74. }
  75. prepareHits() {
  76. let rect = computeRect(this.el)
  77. this.width = rect.right - rect.left
  78. this.height = rect.bottom - rect.top
  79. this.offsetTracker = new OffsetTracker(this.el)
  80. }
  81. releaseHits() {
  82. this.offsetTracker.destroy()
  83. }
  84. queryHit(leftOffset, topOffset): Hit | null {
  85. let rectLeft = this.offsetTracker.computeLeft()
  86. let rectTop = this.offsetTracker.computeTop()
  87. let rect: Rect = {
  88. left: rectLeft,
  89. right: rectLeft + this.width,
  90. top: rectTop,
  91. bottom: rectTop + this.height
  92. }
  93. if (pointInsideRect({ left: leftOffset, top: topOffset }, rect)) {
  94. let date = (this.props as any).date // HACK
  95. return {
  96. component: this,
  97. dateSpan: {
  98. allDay: true,
  99. range: { start: date, end: addDays(date, 1) }
  100. },
  101. dayEl: this.el,
  102. rect: rect,
  103. layer: 1
  104. }
  105. }
  106. return null
  107. }
  108. }
  109. export class DayTileEventRenderer extends SimpleDayGridEventRenderer {
  110. dayTile: DayTile
  111. constructor(dayTile) {
  112. super(dayTile.context)
  113. this.dayTile = dayTile
  114. }
  115. attachSegs(segs: Seg[]) {
  116. for (let seg of segs) {
  117. this.dayTile.segContainerEl.appendChild(seg.el)
  118. }
  119. }
  120. detachSegs(segs: Seg[]) {
  121. for (let seg of segs) {
  122. removeElement(seg.el)
  123. }
  124. }
  125. }
  126. DayTile.prototype.isInteractable = true
  127. DayTile.prototype.useEventCenter = false