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

+ 13 - 2
src/Calendar.ts

@@ -24,12 +24,13 @@ import { RenderForceFlags } from './component/Component'
 import browserContext from './common/browser-context'
 import { DateRangeInput, rangeContainsMarker } from './datelib/date-range'
 import { DateProfile } from './DateProfileGenerator'
-import { EventSourceInput, parseEventSource } from './structs/event-source'
-import { EventInput, EventDef } from './structs/event'
+import { EventSourceInput, parseEventSource, EventSourceHash } from './structs/event-source'
+import { EventInput, EventDef, EventDefHash } from './structs/event'
 import { CalendarState, Action } from './reducers/types'
 import EventSourceApi from './api/EventSourceApi'
 import EventApi from './api/EventApi'
 import { parseEventStore, createEmptyEventStore, EventStore } from './structs/event-store'
+import { computeEventDefUis, EventUiHash } from './component/event-rendering'
 
 
 export default class Calendar {
@@ -83,6 +84,7 @@ export default class Calendar {
   isDisplaying: boolean = false // installed in DOM? accepting renders?
   isRendering: boolean = false // currently in the _render function?
   isSkeletonRendered: boolean = false // fyi: set within the debounce delay
+  computeEventDefUis: (eventDefs: EventDefHash, eventSources: EventSourceHash, options: any) => EventUiHash
   renderingPauseDepth: number = 0
   rerenderFlags: RenderForceFlags
   renderableEventStore: EventStore
@@ -101,6 +103,7 @@ export default class Calendar {
     this.buildDateEnv = reselector(buildDateEnv)
     this.buildTheme = reselector(buildTheme)
     this.buildDelayedRerender = reselector(buildDelayedRerender)
+    this.computeEventDefUis = reselector(computeEventDefUis)
 
     this.handleOptions(this.optionsManager.computed)
     this.hydrate()
@@ -349,6 +352,7 @@ export default class Calendar {
         defs: {},
         instances: {}
       },
+      eventUis: {},
       businessHoursDef: false, // gets populated when we delegate rendering to View
       dateSelection: null,
       eventSelection: '',
@@ -569,9 +573,16 @@ export default class Calendar {
         this.renderableEventStore :
         state.eventStore
 
+    let eventUis = this.computeEventDefUis(
+      renderableEventStore.defs,
+      state.eventSources,
+      renderedView.options
+    )
+
     renderedView.render({
       dateProfile: state.dateProfile,
       eventStore: renderableEventStore,
+      eventUis: eventUis,
       businessHoursDef: renderedView.opt('businessHours'),
       dateSelection: state.dateSelection,
       eventSelection: state.eventSelection,

+ 2 - 0
src/agenda/AgendaView.ts

@@ -189,6 +189,7 @@ export default class AgendaView extends View {
     this.timeGrid.render({
       dateProfile: renderState.dateProfile,
       eventStore: eventStoreGroups.timed,
+      eventUis: renderState.eventUis,
       dateSelection: timedSelection,
       eventSelection: renderState.eventSelection,
       eventDrag: dragGroups.timed,
@@ -200,6 +201,7 @@ export default class AgendaView extends View {
       this.dayGrid.render({
         dateProfile: renderState.dateProfile,
         eventStore: eventStoreGroups.allDay,
+        eventUis: renderState.eventUis,
         dateSelection: allDaySeletion,
         eventSelection: renderState.eventSelection,
         eventDrag: dragGroups.allDay,

+ 4 - 1
src/agenda/TimeGrid.ts

@@ -639,7 +639,10 @@ export default class TimeGrid extends DateComponent {
 
   // Renders a visual indication of an event being resized
   renderEventResize(eventStore: EventStore, origSeg) {
-    let segs = this.eventStoreToSegs(eventStore)
+    let segs = this.eventStoreToSegs(
+      eventStore,
+      this.eventUis // bad to use this here
+    )
 
     this.helperRenderer.renderEventResizingSegs(segs, origSeg)
   }

+ 4 - 1
src/basic/DayGrid.ts

@@ -397,7 +397,10 @@ export default class DayGrid extends DateComponent {
 
   // Renders a visual indication of an event being resized
   renderEventResize(eventStore: EventStore, origSeg) {
-    let segs = this.eventStoreToSegs(eventStore)
+    let segs = this.eventStoreToSegs(
+      eventStore,
+      this.eventUis // bad to use this here
+    )
 
     this.renderHighlightSegs(segs)
 

+ 23 - 20
src/component/DateComponent.ts

@@ -7,7 +7,7 @@ import { DateProfile } from '../DateProfileGenerator'
 import { DateMarker, DAY_IDS, addDays, startOfDay, diffDays, diffWholeDays } from '../datelib/marker'
 import { Duration, createDuration } from '../datelib/duration'
 import { DateSpan } from '../structs/date-span'
-import { EventRenderRange, sliceEventStore, computeUiHash } from '../component/event-rendering'
+import { EventRenderRange, sliceEventStore, computeEventDefUi, EventUiHash, computeEventDefUis } from '../component/event-rendering'
 import { EventStore } from '../structs/event-store'
 import { BusinessHoursDef, buildBusinessHours } from '../structs/business-hours'
 import { DateEnv } from '../datelib/env'
@@ -26,6 +26,7 @@ export interface DateComponentRenderState {
   dateProfile: DateProfile | null
   businessHoursDef: BusinessHoursDef // BusinessHoursDef's `false` is the empty state
   eventStore: EventStore
+  eventUis: EventUiHash
   dateSelection: DateSpan | null
   eventSelection: string
   eventDrag: EventInteractionState | null
@@ -85,6 +86,7 @@ export default abstract class DateComponent extends Component {
   dateProfile: DateProfile = null
   businessHoursDef: BusinessHoursDef = false
   eventStore: EventStore = null
+  eventUis: EventUiHash = null
   dateSelection: DateSpan = null
   eventSelection: string = ''
   eventDrag: EventInteractionState = null
@@ -317,7 +319,7 @@ export default abstract class DateComponent extends Component {
     let dirtyFlags = {
       skeleton: false,
       dates: renderState.dateProfile !== this.dateProfile,
-      events: renderState.eventStore !== this.eventStore,
+      events: renderState.eventStore !== this.eventStore || renderState.eventUis !== this.eventUis,
       businessHours: renderState.businessHoursDef !== this.businessHoursDef,
       dateSelection: renderState.dateSelection !== this.dateSelection,
       eventSelection: renderState.eventSelection !== this.eventSelection,
@@ -386,7 +388,7 @@ export default abstract class DateComponent extends Component {
     }
 
     if (flags.events && renderState.eventStore) {
-      this.renderEvents(renderState.eventStore)
+      this.renderEvents(renderState.eventStore, renderState.eventUis)
       renderedFlags.events = true
       dirtySizeFlags.events = true
     }
@@ -527,15 +529,18 @@ export default abstract class DateComponent extends Component {
 
   renderBusinessHours(businessHoursDef: BusinessHoursDef) {
     if (this.fillRenderer) {
+      let eventStore = buildBusinessHours(
+        businessHoursDef,
+        this.hasAllDayBusinessHours,
+        this.dateProfile.activeRange,
+        this.getCalendar()
+      )
+
       this.fillRenderer.renderSegs(
         'businessHours',
         this.eventStoreToSegs(
-          buildBusinessHours(
-            businessHoursDef,
-            this.hasAllDayBusinessHours,
-            this.dateProfile.activeRange,
-            this.getCalendar()
-          )
+          eventStore,
+          computeEventDefUis(eventStore.defs, {}, {})
         ),
         {
           getClasses(seg) {
@@ -573,11 +578,11 @@ export default abstract class DateComponent extends Component {
   // -----------------------------------------------------------------------------------------------------------------
 
 
-  renderEvents(eventStore: EventStore) {
+  renderEvents(eventStore: EventStore, eventUis: EventUiHash) {
     if (this.eventRenderer) {
       this.eventRenderer.rangeUpdated() // poorly named now
       this.eventRenderer.renderSegs(
-        this.eventStoreToSegs(eventStore)
+        this.eventStoreToSegs(eventStore, eventUis)
       )
       this.triggerRenderedSegs(this.eventRenderer.getSegs())
     }
@@ -631,7 +636,10 @@ export default abstract class DateComponent extends Component {
   // Renders a visual indication of a event or external-element drag over the given drop zone.
   // If an external-element, seg will be `null`.
   renderEventDrag(eventStore: EventStore, isEvent: boolean, origSeg: Seg | null) {
-    let segs = this.eventStoreToSegs(eventStore)
+    let segs = this.eventStoreToSegs(
+      eventStore,
+      this.eventUis // bad to use this here
+    )
 
     // if the user is dragging something that is considered an event with real event data,
     // and this component likes to do drag mirrors OR the component where the seg came from
@@ -843,14 +851,9 @@ export default abstract class DateComponent extends Component {
   ------------------------------------------------------------------------------------------------------------------*/
 
 
-  eventStoreToSegs(eventStore: EventStore): Seg[] {
+  eventStoreToSegs(eventStore: EventStore, eventUis: EventUiHash): Seg[] {
     let activeRange = this.dateProfile.activeRange
-    let eventRenderRanges = sliceEventStore(
-      eventStore,
-      this.getCalendar().state.eventSources,
-      activeRange,
-      this.view.options
-    )
+    let eventRenderRanges = sliceEventStore(eventStore, eventUis, activeRange)
     let allSegs: Seg[] = []
 
     for (let eventRenderRange of eventRenderRanges) {
@@ -878,7 +881,7 @@ export default abstract class DateComponent extends Component {
         eventDef: def,
         eventInstance: createEventInstance(def.defId, selection.range),
         range: selection.range,
-        ui: computeUiHash(def, {}, {})
+        ui: computeEventDefUi(def, {}, {})
       }
 
       for (let seg of segs) {

+ 21 - 19
src/component/event-rendering.ts

@@ -5,7 +5,7 @@ import { EventSourceHash } from '../structs/event-source'
 import { mapHash } from '../util/object'
 import { parseClassName } from '../util/html'
 
-export interface EventUiProps {
+export interface EventUi {
   startEditable: boolean
   durationEditable: boolean
   backgroundColor: string
@@ -15,11 +15,13 @@ export interface EventUiProps {
   classNames: string[]
 }
 
+export type EventUiHash = { [defId: string]: EventUi }
+
 export interface EventRenderRange {
   eventDef: EventDef
   eventInstance?: EventInstance
   range: DateRange
-  ui: EventUiProps
+  ui: EventUi
 }
 
 
@@ -27,16 +29,15 @@ export interface EventRenderRange {
 Does not slice ranges via framingRange into new ranges, but instead,
 keeps fg event ranges intact but more importantly slices inverse-BG events.
 */
-export function sliceEventStore(eventStore: EventStore, eventSources: EventSourceHash, framingRange: DateRange, options) {
+export function sliceEventStore(eventStore: EventStore, eventUis: EventUiHash, framingRange: DateRange) {
   let inverseBgByGroupId: { [groupId: string]: DateRange[] } = {}
   let inverseBgByDefId: { [defId: string]: DateRange[] } = {}
   let defByGroupId: { [groupId: string]: EventDef } = {}
   let renderRanges: EventRenderRange[] = []
-  let uiHashes = computeUiHashes(eventStore.defs, eventSources, options)
 
   for (let defId in eventStore.defs) {
     let def = eventStore.defs[defId]
-    let ui = uiHashes[defId]
+    let ui = eventUis[defId]
 
     if (ui.rendering === 'inverse-background') {
       if (def.groupId) {
@@ -54,7 +55,7 @@ export function sliceEventStore(eventStore: EventStore, eventSources: EventSourc
   for (let instanceId in eventStore.instances) {
     let instance = eventStore.instances[instanceId]
     let def = eventStore.defs[instance.defId]
-    let ui = uiHashes[def.defId]
+    let ui = eventUis[def.defId]
 
     if (ui.rendering === 'inverse-background') {
       if (def.groupId) {
@@ -78,7 +79,7 @@ export function sliceEventStore(eventStore: EventStore, eventSources: EventSourc
 
     for (let invertedRange of invertedRanges) {
       let def = defByGroupId[groupId]
-      let ui = uiHashes[def.defId]
+      let ui = eventUis[def.defId]
 
       renderRanges.push({
         eventDef: def,
@@ -96,7 +97,7 @@ export function sliceEventStore(eventStore: EventStore, eventSources: EventSourc
       renderRanges.push({
         eventDef: eventStore.defs[defId],
         range: invertedRange,
-        ui: uiHashes[defId]
+        ui: eventUis[defId]
       })
     }
   }
@@ -108,25 +109,26 @@ export function sliceEventStore(eventStore: EventStore, eventSources: EventSourc
 // UI Props
 // ----------------------------------------------------------------------------------------------------
 
-function computeUiHashes(eventDefs: EventDefHash, eventSources: EventSourceHash, options) {
+export function computeEventDefUis(eventDefs: EventDefHash, eventSources: EventSourceHash, options) {
   return mapHash(eventDefs, function(eventDef) {
-    return computeUiHash(eventDef, eventSources, options)
+    return computeEventDefUi(eventDef, eventSources, options)
   })
 }
 
-export function computeUiHash(eventDef: EventDef, eventSources: EventSourceHash, options) {
+export function computeEventDefUi(eventDef: EventDef, eventSources: EventSourceHash, options) {
+
   // lowest to highest priority
-  // TODO: hook for resources, using refineScopedUiHash
+  // TODO: hook for resources, using refineScopedUi
   let refinedHashes = [
-    refineScopedUiHash(options),
-    refineUnscopedUiHash(eventSources[eventDef.sourceId] || {}),
-    refineUnscopedUiHash(eventDef)
+    refineScopedUi(options),
+    refineUnscopedUi(eventSources[eventDef.sourceId] || {}),
+    refineUnscopedUi(eventDef)
   ]
 
-  return refinedHashes.reduce(combineUiHashes)
+  return refinedHashes.reduce(combineUis)
 }
 
-function refineScopedUiHash(input) { // has word "event" in prop names
+function refineScopedUi(input) { // has word "event" in prop names
   return {
     startEditable: (input.startEditable != null) ? input.startEditable : input.editable,
     durationEditable: (input.durationEditable != null) ? input.durationEditable : input.editable,
@@ -138,7 +140,7 @@ function refineScopedUiHash(input) { // has word "event" in prop names
   }
 }
 
-function refineUnscopedUiHash(input) { // does NOT have the word "event' in prop names
+function refineUnscopedUi(input) { // does NOT have the word "event" in prop names
   return {
     startEditable: (input.startEditable != null) ? input.startEditable : input.editable,
     durationEditable: (input.durationEditable != null) ? input.durationEditable : input.editable,
@@ -150,7 +152,7 @@ function refineUnscopedUiHash(input) { // does NOT have the word "event' in prop
   }
 }
 
-function combineUiHashes(hash0, hash1) { // hash1 has higher precedence
+function combineUis(hash0, hash1) { // hash1 has higher precedence
   return {
     startEditable: (hash1.startEditable != null) ? hash1.startEditable : hash0.startEditable,
     durationEditable: (hash1.durationEditable != null) ? hash1.durationEditable : hash0.durationEditable,

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

@@ -3,7 +3,7 @@ import { DateMarker } from '../../datelib/marker'
 import { createFormatter, DateFormatter } from '../../datelib/formatting'
 import { htmlToElements } from '../../util/dom-manip'
 import { compareByFieldSpecs } from '../../util/misc'
-import { EventRenderRange, EventUiProps } from '../event-rendering'
+import { EventRenderRange, EventUi } from '../event-rendering'
 import { Seg } from '../DateComponent'
 import EventApi from '../../api/EventApi'
 
@@ -312,7 +312,7 @@ export default class EventRenderer {
 
 
   // Utility for generating event skin-related CSS properties
-  getSkinCss(ui: EventUiProps) {
+  getSkinCss(ui: EventUi) {
     return {
       'background-color': ui.backgroundColor,
       'border-color': ui.borderColor,

+ 1 - 0
src/reducers/main.ts

@@ -17,6 +17,7 @@ export default function(state: CalendarState, action: Action, calendar: Calendar
     dateProfile,
     eventSources,
     eventStore: reduceEventStore(state.eventStore, action, eventSources, calendar),
+    eventUis: state.eventUis, // TODO: should really be internal state
     businessHoursDef: state.businessHoursDef,
     dateSelection: reduceDateSelection(state.dateSelection, action),
     eventSelection: reduceSelectedEvent(state.eventSelection, action),