Procházet zdrojové kódy

Slicer class instead of functional programming madness

Adam Shaw před 7 roky
rodič
revize
20d2ab9acc
5 změnil soubory, kde provedl 108 přidání a 194 odebrání
  1. 12 15
      src/agenda/SimpleTimeGrid.ts
  2. 12 19
      src/basic/SimpleDayGrid.ts
  3. 80 143
      src/common/slicing-utils.ts
  4. 4 2
      src/exports.ts
  5. 0 15
      src/util/array.ts

+ 12 - 15
src/agenda/SimpleTimeGrid.ts

@@ -10,7 +10,7 @@ import { intersectRanges, DateRange } from '../datelib/date-range'
 import DayTable from '../common/DayTable'
 import DayTable from '../common/DayTable'
 import { DateEnv } from '../datelib/env'
 import { DateEnv } from '../datelib/env'
 import { DateMarker, addMs } from '../datelib/marker'
 import { DateMarker, addMs } from '../datelib/marker'
-import { buildBusinessHoursToSegs, buildEventStoreToSegs, buildDateSpanToSegs, buildMassageInteraction } from '../common/slicing-utils'
+import { Slicer } from '../common/slicing-utils'
 
 
 export interface SimpleTimeGridProps {
 export interface SimpleTimeGridProps {
   dateProfile: DateProfile | null
   dateProfile: DateProfile | null
@@ -29,34 +29,31 @@ export default class SimpleTimeGrid extends Component<SimpleTimeGridProps> {
   timeGrid: TimeGrid
   timeGrid: TimeGrid
   dayRanges: DateRange[]
   dayRanges: DateRange[]
 
 
-  buildDayRanges = reselector(buildDayRanges)
-  businessHoursToSegs = reselector(buildBusinessHoursToSegs(sliceSegs))
-  eventStoreToSegs = reselector(buildEventStoreToSegs(sliceSegs))
-  selectionToSegs = reselector(buildDateSpanToSegs(sliceSegs))
-  buildEventDrag = reselector(buildMassageInteraction(sliceSegs))
-  buildEventResize = reselector(buildMassageInteraction(sliceSegs))
+  private buildDayRanges = reselector(buildDayRanges)
+  private slicer = new Slicer(sliceSegs)
 
 
   constructor(context, timeGrid: TimeGrid) {
   constructor(context, timeGrid: TimeGrid) {
     super(context)
     super(context)
 
 
     this.timeGrid = timeGrid
     this.timeGrid = timeGrid
+    this.slicer.component = timeGrid
   }
   }
 
 
   render(props: SimpleTimeGridProps) {
   render(props: SimpleTimeGridProps) {
-    let { timeGrid } = this
+    let { slicer } = this
     let { dateProfile, dayTable } = props
     let { dateProfile, dayTable } = props
 
 
     let dayRanges = this.dayRanges = this.buildDayRanges(dayTable, dateProfile, this.dateEnv)
     let dayRanges = this.dayRanges = this.buildDayRanges(dayTable, dateProfile, this.dateEnv)
 
 
-    timeGrid.receiveProps({
+    this.timeGrid.receiveProps({
       dateProfile,
       dateProfile,
       cells: dayTable.cells[0],
       cells: dayTable.cells[0],
-      businessHourSegs: this.businessHoursToSegs(props.businessHours, dateProfile, null, timeGrid, dayRanges),
-      eventSegs: this.eventStoreToSegs(props.eventStore, props.eventUis, dateProfile, null, timeGrid, dayRanges),
-      dateSelectionSegs: this.selectionToSegs(props.dateSelection, timeGrid, dayRanges),
+      businessHourSegs: slicer.businessHoursToSegs(props.businessHours, dateProfile, null, dayRanges),
+      eventSegs: slicer.eventStoreToSegs(props.eventStore, props.eventUis, dateProfile, null, dayRanges),
+      dateSelectionSegs: slicer.selectionToSegs(props.dateSelection, dayRanges),
       eventSelection: props.eventSelection,
       eventSelection: props.eventSelection,
-      eventDrag: this.buildEventDrag(props.eventDrag, dateProfile, timeGrid, dayRanges),
-      eventResize: this.buildEventResize(props.eventResize, dateProfile, timeGrid, dayRanges)
+      eventDrag: slicer.buildEventDrag(props.eventDrag, dateProfile, dayRanges),
+      eventResize: slicer.buildEventResize(props.eventResize, dateProfile, dayRanges)
     })
     })
   }
   }
 
 
@@ -87,7 +84,7 @@ export function buildDayRanges(dayTable: DayTable, dateProfile: DateProfile, dat
   return ranges
   return ranges
 }
 }
 
 
-function sliceSegs(range: DateRange, dayRanges: DateRange[]): TimeGridSeg[] {
+export function sliceSegs(range: DateRange, dayRanges: DateRange[]): TimeGridSeg[] {
   let segs: TimeGridSeg[] = []
   let segs: TimeGridSeg[] = []
 
 
   for (let col = 0; col < dayRanges.length; col++) {
   for (let col = 0; col < dayRanges.length; col++) {

+ 12 - 19
src/basic/SimpleDayGrid.ts

@@ -6,10 +6,9 @@ import { DateSpan } from '../structs/date-span'
 import { EventInteractionUiState } from '../interactions/event-interaction-state'
 import { EventInteractionUiState } from '../interactions/event-interaction-state'
 import DayTable from '../common/DayTable'
 import DayTable from '../common/DayTable'
 import { Duration } from '../datelib/duration'
 import { Duration } from '../datelib/duration'
-import reselector from '../util/reselector'
 import Component from '../component/Component'
 import Component from '../component/Component'
 import { DateRange } from '../datelib/date-range'
 import { DateRange } from '../datelib/date-range'
-import { buildBusinessHoursToSegs, buildEventStoreToSegs, buildDateSpanToSegs, buildMassageInteraction } from '../common/slicing-utils'
+import { Slicer } from '../common/slicing-utils'
 
 
 export interface SimpleDayGridProps {
 export interface SimpleDayGridProps {
   dateProfile: DateProfile | null
   dateProfile: DateProfile | null
@@ -29,48 +28,42 @@ export default class SimpleDayGrid extends Component<SimpleDayGridProps> {
 
 
   dayGrid: DayGrid
   dayGrid: DayGrid
 
 
-  businessHoursToSegs = reselector(buildBusinessHoursToSegs(sliceSegs))
-  eventStoreToSegs = reselector(buildEventStoreToSegs(sliceSegs))
-  selectionToSegs = reselector(buildDateSpanToSegs(sliceSegs))
-  buildEventDrag = reselector(buildMassageInteraction(sliceSegs))
-  buildEventResize = reselector(buildMassageInteraction(sliceSegs))
+  private slicer = new Slicer(sliceSegs)
 
 
   constructor(context, dayGrid: DayGrid) {
   constructor(context, dayGrid: DayGrid) {
     super(context)
     super(context)
 
 
     this.dayGrid = dayGrid
     this.dayGrid = dayGrid
+    this.slicer.component = dayGrid
   }
   }
 
 
   render(props: SimpleDayGridProps) {
   render(props: SimpleDayGridProps) {
-    let { dayGrid } = this
+    let { dayGrid, slicer, isRtl } = this
     let { dateProfile, dayTable, nextDayThreshold } = props
     let { dateProfile, dayTable, nextDayThreshold } = props
 
 
     dayGrid.receiveProps({
     dayGrid.receiveProps({
       dateProfile,
       dateProfile,
       cells: dayTable.cells,
       cells: dayTable.cells,
-      businessHourSegs: this.businessHoursToSegs(props.businessHours, dateProfile, nextDayThreshold, dayGrid, dayTable, dayGrid),
-      eventSegs: this.eventStoreToSegs(props.eventStore, props.eventUis, dateProfile, nextDayThreshold, dayGrid, dayTable, dayGrid),
-      dateSelectionSegs: this.selectionToSegs(props.dateSelection, dayGrid, dayTable, dayGrid),
+      businessHourSegs: slicer.businessHoursToSegs(props.businessHours, dateProfile, nextDayThreshold, dayTable, isRtl),
+      eventSegs: slicer.eventStoreToSegs(props.eventStore, props.eventUis, dateProfile, nextDayThreshold, dayTable, isRtl),
+      dateSelectionSegs: slicer.selectionToSegs(props.dateSelection, dayTable, isRtl),
       eventSelection: props.eventSelection,
       eventSelection: props.eventSelection,
-      eventDrag: this.buildEventDrag(props.eventDrag, dateProfile, dayGrid, dayTable, dayGrid),
-      eventResize: this.buildEventResize(props.eventResize, dateProfile, dayGrid, dayTable, dayGrid),
+      eventDrag: slicer.buildEventDrag(props.eventDrag, dateProfile, dayTable, isRtl),
+      eventResize: slicer.buildEventResize(props.eventResize, dateProfile, dayTable, isRtl),
       isRigid: props.isRigid
       isRigid: props.isRigid
     })
     })
   }
   }
 
 
 }
 }
 
 
-/*
-TODO: kill the inconvenient-to-call dayGrid argument when RTL is done differently
-*/
-function sliceSegs(range: DateRange, dayTable: DayTable, dayGrid: DayGrid): DayGridSeg[] {
+function sliceSegs(range: DateRange, dayTable: DayTable, isRtl: boolean): DayGridSeg[] {
   return dayTable.sliceRange(range).map(function(seg) {
   return dayTable.sliceRange(range).map(function(seg) {
     return {
     return {
       isStart: seg.isStart,
       isStart: seg.isStart,
       isEnd: seg.isEnd,
       isEnd: seg.isEnd,
       row: seg.row,
       row: seg.row,
-      leftCol: dayGrid.isRtl ? (dayTable.colCnt - 1 - seg.lastCol) : seg.firstCol,
-      rightCol: dayGrid.isRtl ? (dayTable.colCnt - 1 - seg.firstCol) : seg.lastCol
+      leftCol: isRtl ? (dayTable.colCnt - 1 - seg.lastCol) : seg.firstCol,
+      rightCol: isRtl ? (dayTable.colCnt - 1 - seg.firstCol) : seg.lastCol
     }
     }
   })
   })
 }
 }

+ 80 - 143
src/common/slicing-utils.ts

@@ -5,172 +5,109 @@ import { DateProfile } from '../DateProfileGenerator'
 import { Seg } from '../component/DateComponent'
 import { Seg } from '../component/DateComponent'
 import { DateSpan, fabricateEventRange } from '../structs/date-span'
 import { DateSpan, fabricateEventRange } from '../structs/date-span'
 import { EventInteractionUiState } from '../interactions/event-interaction-state'
 import { EventInteractionUiState } from '../interactions/event-interaction-state'
-import { collectArrays } from '../util/array'
 import { sliceBusinessHours } from '../structs/business-hours'
 import { sliceBusinessHours } from '../structs/business-hours'
 import DateComponent from '../component/DateComponent'
 import DateComponent from '../component/DateComponent'
-import { EventInstanceHash } from '../structs/event'
 import { Duration } from '../datelib/duration'
 import { Duration } from '../datelib/duration'
+import reselector from '../util/reselector'
 
 
 
 
-export function buildEventStoreToSegs<OtherArgsType extends any[], SegType extends Seg>(
-  sliceSegs: (dateRange: DateRange, ...args: OtherArgsType) => SegType[]
-): (
-  // returns a function with these args...
-  eventStore: EventStore,
-  eventUis: EventUiHash,
-  dateProfile: DateProfile,
-  nextDayThreshold: Duration,
-  component: DateComponent<any>,
-  ...args: OtherArgsType
-) => SegType[] {
-  return eventStoreToSegs.bind(null, sliceSegs)
-}
-
-export function buildBusinessHoursToSegs<OtherArgsType extends any[], SegType extends Seg>(
-  sliceSegs: (dateRange: DateRange, ...args: OtherArgsType) => SegType[]
-): (
-  // returns a function with these args...
-  businessHours: EventStore,
-  dateProfile: DateProfile,
-  nextDayThreshold: Duration,
-  component: DateComponent<any>,
-  ...args: OtherArgsType
-) => SegType[] {
-  return businessHoursToSegs.bind(null, sliceSegs)
-}
-
-export function buildDateSpanToSegs<OtherArgsType extends any[], SegType extends Seg>(
-  sliceSegs: (dateRange: DateRange, ...args: OtherArgsType) => SegType[]
-): (
-  // returns a function with these args...
-  dateSpan: DateSpan,
-  component: DateComponent<any>,
-  ...args: OtherArgsType
-) => SegType[] {
-  return dateSpanToSegs.bind(null, sliceSegs)
-}
-
-export function buildMassageInteraction<OtherArgsType extends any[], SegType extends Seg>(
-  sliceSegs: (dateRange: DateRange, ...args: OtherArgsType) => SegType[]
-): (
-  // returns a function with these args...
-  interaction: EventInteractionUiState,
-  dateProfile: DateProfile,
-  component: DateComponent<any>,
-  ...args: OtherArgsType
-) => {
-  segs: SegType[],
-  affectedInstances: EventInstanceHash,
-  isEvent: boolean,
-  sourceSeg: Seg
-} {
-  return massageInteraction.bind(null, sliceSegs)
-}
+export class Slicer<OtherArgsType extends any[], SegType extends Seg> {
 
 
+  slice: (range: DateRange, ...otherArgs: OtherArgsType) => SegType[]
+  component: DateComponent<any> // must set after initialization. TODO: kill
 
 
-type SliceSegsFunc = (range: DateRange, ...otherArgs) => Seg[]
+  businessHoursToSegs = reselector(this._businessHoursToSegs)
+  eventStoreToSegs = reselector(this._eventStoreToSegs)
+  selectionToSegs = reselector(this.dateSpanToCompleteSegs)
+  buildEventDrag = reselector(this.massageInteraction)
+  buildEventResize = reselector(this.massageInteraction)
 
 
-function massageInteraction(
-  sliceSegs: SliceSegsFunc,
-  interaction: EventInteractionUiState,
-  dateProfile: DateProfile,
-  component: DateComponent<any>,
-  ...otherArgs
-) {
-  if (!interaction) {
-    return null
+  constructor(slice: (range: DateRange, ...otherArgs: OtherArgsType) => SegType[]) {
+    this.slice = slice
   }
   }
 
 
-  return {
-    segs: eventRangesToSegs(
-      sliceSegs,
-      sliceEventStore(interaction.mutatedEvents, interaction.eventUis, dateProfile.activeRange),
-      component,
+  private _eventStoreToSegs(eventStore: EventStore, eventUis: EventUiHash, dateProfile: DateProfile, nextDayThreshold: Duration, ...otherArgs: OtherArgsType): SegType[] {
+    return this.eventRangesToSegs(
+      sliceEventStore(eventStore, eventUis, dateProfile.activeRange, nextDayThreshold),
       otherArgs
       otherArgs
-    ),
-    affectedInstances: interaction.affectedEvents.instances,
-    isEvent: interaction.isEvent,
-    sourceSeg: interaction.origSeg
+    )
   }
   }
-}
 
 
-function dateSpanToSegs(
-  sliceSegs: SliceSegsFunc,
-  dateSpan: DateSpan,
-  component: DateComponent<any>,
-  ...otherArgs
-) {
-  if (!dateSpan) {
-    return []
+  private _businessHoursToSegs(businessHours: EventStore, dateProfile: DateProfile, nextDayThreshold: Duration, ...otherArgs: OtherArgsType): SegType[] {
+    return this.eventRangesToSegs(
+      sliceBusinessHours(
+        businessHours,
+        dateProfile.activeRange,
+        nextDayThreshold,
+        this.component.calendar
+      ),
+      otherArgs
+    )
   }
   }
 
 
-  let eventRange = fabricateEventRange(dateSpan)
-  let segs = sliceSegs(dateSpan.range, ...otherArgs)
+  private dateSpanToCompleteSegs(dateSpan: DateSpan, ...otherArgs: OtherArgsType): SegType[] {
+
+    if (!dateSpan) {
+      return []
+    }
+
+    let eventRange = fabricateEventRange(dateSpan)
+    let segs = this.dateSpanToSegs(dateSpan, ...otherArgs)
+
+    for (let seg of segs) {
+      seg.component = this.component
+      seg.eventRange = eventRange
+    }
 
 
-  for (let seg of segs) {
-    seg.eventRange = eventRange
-    seg.component = component
+    return segs
   }
   }
 
 
-  return segs
-}
+  private massageInteraction(interaction: EventInteractionUiState, dateProfile: DateProfile, ...otherArgs: OtherArgsType) {
+
+    if (!interaction) {
+      return null
+    }
+
+    return {
+      segs: this.eventRangesToSegs(
+        sliceEventStore(interaction.mutatedEvents, interaction.eventUis, dateProfile.activeRange),
+        otherArgs
+      ),
+      affectedInstances: interaction.affectedEvents.instances,
+      isEvent: interaction.isEvent,
+      sourceSeg: interaction.origSeg
+    }
+  }
 
 
-function businessHoursToSegs(
-  sliceSegs: SliceSegsFunc,
-  businessHours: EventStore,
-  dateProfile: DateProfile,
-  nextDayThreshold: Duration,
-  component: DateComponent<any>,
-  ...otherArgs
-) {
-  return eventRangesToSegs(
-    sliceSegs,
-    sliceBusinessHours(
-      businessHours,
-      dateProfile.activeRange,
-      nextDayThreshold,
-      component.calendar
-    ),
-    component,
-    otherArgs
-  )
-}
+  private eventRangesToSegs(eventRanges: EventRenderRange[], otherArgs: OtherArgsType): SegType[] {
+    let segs: SegType[] = []
 
 
-function eventStoreToSegs(
-  sliceSegs: SliceSegsFunc,
-  eventStore: EventStore,
-  eventUis: EventUiHash,
-  dateProfile: DateProfile,
-  nextDayThreshold: Duration,
-  component: DateComponent<any>,
-  ...otherArgs
-) {
-  return eventRangesToSegs(
-    sliceSegs,
-    sliceEventStore(eventStore, eventUis, dateProfile.activeRange, nextDayThreshold),
-    component,
-    otherArgs
-  )
-}
+    for (let eventRange of eventRanges) {
+      segs.push(...this.eventRangeToCompleteSegs(eventRange, otherArgs))
+    }
 
 
-function eventRangesToSegs(sliceSegs: SliceSegsFunc, eventRanges: EventRenderRange[], component: DateComponent<any>, otherArgs) {
-  return collectArrays(
-    eventRangeToSegs.bind(null, sliceSegs),
-    eventRanges,
-    component,
-    ...otherArgs
-  )
-}
+    return segs
+  }
 
 
-function eventRangeToSegs(sliceSegs: SliceSegsFunc, eventRange: EventRenderRange, component: DateComponent<any>, ...otherArgs) {
-  let segs = sliceSegs(eventRange.range, ...otherArgs)
+  private eventRangeToCompleteSegs(eventRange: EventRenderRange, otherArgs: OtherArgsType): SegType[] {
+    let segs = this.eventRangeToSegs(eventRange, otherArgs)
+
+    for (let seg of segs) {
+      seg.component = this.component
+      seg.eventRange = eventRange
+      seg.isStart = eventRange.isStart && seg.isStart
+      seg.isEnd = eventRange.isEnd && seg.isEnd
+    }
+
+    return segs
+  }
+
+  protected dateSpanToSegs(dateSpan: DateSpan, ...otherArgs: OtherArgsType): SegType[] {
+    return this.slice(dateSpan.range, ...otherArgs)
+  }
 
 
-  for (let seg of segs) {
-    seg.eventRange = eventRange
-    seg.component = component
-    seg.isStart = eventRange.isStart && seg.isStart
-    seg.isEnd = eventRange.isEnd && seg.isEnd
+  protected eventRangeToSegs(eventRange: EventRenderRange, otherArgs: OtherArgsType): SegType[] {
+    return this.slice(eventRange.range, ...otherArgs)
   }
   }
 
 
-  return segs
 }
 }

+ 4 - 2
src/exports.ts

@@ -8,7 +8,7 @@ export const internalApiVersion = 12
 
 
 // types
 // types
 export { OptionsInput } from './types/input-types'
 export { OptionsInput } from './types/input-types'
-export { EventInput, EventDef } from './structs/event'
+export { EventInput, EventDef, EventInstance, EventInstanceHash } from './structs/event'
 export { BusinessHoursInput, sliceBusinessHours } from './structs/business-hours'
 export { BusinessHoursInput, sliceBusinessHours } from './structs/business-hours'
 
 
 export {
 export {
@@ -97,7 +97,7 @@ export { default as FillRenderer } from './component/renderers/FillRenderer'
 export { default as AgendaView } from './agenda/AgendaView'
 export { default as AgendaView } from './agenda/AgendaView'
 export { default as AbstractAgendaView} from './agenda/AbstractAgendaView'
 export { default as AbstractAgendaView} from './agenda/AbstractAgendaView'
 export { default as TimeGrid, TimeGridSeg } from './agenda/TimeGrid'
 export { default as TimeGrid, TimeGridSeg } from './agenda/TimeGrid'
-export { buildDayRanges } from './agenda/SimpleTimeGrid'
+export { buildDayRanges, sliceSegs as sliceTimeGridSegs } from './agenda/SimpleTimeGrid'
 export { default as DayGrid, DayGridSeg } from './basic/DayGrid'
 export { default as DayGrid, DayGridSeg } from './basic/DayGrid'
 export { default as BasicView } from './basic/BasicView'
 export { default as BasicView } from './basic/BasicView'
 export { default as MonthView } from './basic/MonthView'
 export { default as MonthView } from './basic/MonthView'
@@ -150,3 +150,5 @@ export { EventInteractionUiState } from './interactions/event-interaction-state'
 export { EventRenderRange, sliceEventStore } from './component/event-rendering'
 export { EventRenderRange, sliceEventStore } from './component/event-rendering'
 
 
 export { default as DayTable, DayTableSeg, DayTableCell } from './common/DayTable'
 export { default as DayTable, DayTableSeg, DayTableCell } from './common/DayTable'
+
+export { Slicer } from './common/slicing-utils'

+ 0 - 15
src/util/array.ts

@@ -49,18 +49,3 @@ export function isArraysEqual(a0, a1) {
 
 
   return true
   return true
 }
 }
-
-// best place for this?
-export function collectArrays<InputItemType, OtherArgsType extends any[], OutputItemType>(
-  generator: (inputItem: InputItemType, ...otherArgs: OtherArgsType) => OutputItemType[],
-  inputItems: InputItemType[],
-  ...otherArgs: OtherArgsType
-): OutputItemType[] {
-  let outputItems: OutputItemType[] = []
-
-  for (let inputItem of inputItems) {
-    outputItems.push(...generator(inputItem, ...otherArgs))
-  }
-
-  return outputItems
-}