Explorar el Código

simplified validation

Adam Shaw hace 7 años
padre
commit
1c0aebec73

+ 7 - 7
src/component/DateComponent.ts

@@ -1,5 +1,4 @@
 import Component, { ComponentContext } from './Component'
-import { EventStore } from '../structs/event-store'
 import { EventRenderRange } from './event-rendering'
 import { DateSpan } from '../structs/date-span'
 import { EventInstanceHash } from '../structs/event'
@@ -7,10 +6,11 @@ import { rangeContainsRange } from '../datelib/date-range'
 import { Hit } from '../interactions/HitDragging'
 import browserContext from '../common/browser-context'
 import { elementClosest, removeElement } from '../util/dom-manip'
-import { isSelectionValid, isEventsValid } from '../validation'
+import { isDateSelectionValid, isInteractionValid } from '../validation'
 import EventApi from '../api/EventApi'
 import FgEventRenderer from './renderers/FgEventRenderer'
 import FillRenderer from './renderers/FillRenderer'
+import { EventInteractionState } from '../interactions/event-interaction-state'
 
 export type DateComponentHash = { [uid: string]: DateComponent<any> }
 
@@ -142,10 +142,10 @@ export default class DateComponent<PropsType> extends Component<PropsType> {
   // Validation
   // -----------------------------------------------------------------------------------------------------------------
 
-  isEventsValid(eventStore: EventStore) {
+  isInteractionValid(interaction: EventInteractionState) {
     let { calendar } = this
     let dateProfile = (this.props as any).dateProfile // HACK
-    let instances = eventStore.instances
+    let instances = interaction.mutatedEvents.instances
 
     if (dateProfile) { // HACK for DayTile
       for (let instanceId in instances) {
@@ -155,10 +155,10 @@ export default class DateComponent<PropsType> extends Component<PropsType> {
       }
     }
 
-    return isEventsValid(eventStore, calendar)
+    return isInteractionValid(interaction, calendar)
   }
 
-  isSelectionValid(selection: DateSpan): boolean {
+  isDateSelectionValid(selection: DateSpan): boolean {
     let dateProfile = (this.props as any).dateProfile // HACK
 
     if (
@@ -168,7 +168,7 @@ export default class DateComponent<PropsType> extends Component<PropsType> {
       return false
     }
 
-    return isSelectionValid(selection, this.calendar)
+    return isDateSelectionValid(selection, this.calendar)
   }
 
 

+ 1 - 1
src/component/event-splitting.ts

@@ -7,7 +7,7 @@ import { EventUiHash, EventUi, combineEventUis } from './event-ui'
 import { DateSpan } from '../structs/date-span'
 
 export interface SplittableProps {
-  businessHours: EventStore | null
+  businessHours: EventStore | null // is this really allowed to be null?
   dateSelection: DateSpan | null
   eventStore: EventStore
   eventUiBases: EventUiHash

+ 13 - 17
src/interactions-external/ExternalElementDragging.ts

@@ -12,7 +12,7 @@ import { DragMetaInput, DragMeta, parseDragMeta } from '../structs/drag-meta'
 import EventApi from '../api/EventApi'
 import { elementMatches } from '../util/dom-manip'
 import { enableCursor, disableCursor } from '../util/misc'
-import { isEventsValid } from '../validation'
+import { isInteractionValid } from '../validation'
 
 export type DragMetaGenerator = DragMetaInput | ((el: HTMLElement) => DragMetaInput)
 
@@ -59,40 +59,36 @@ export default class ExternalElementDragging {
     let receivingCalendar: Calendar | null = null
     let droppableEvent: EventTuple | null = null
     let isInvalid = false
+    let interaction: EventInteractionState = {
+      affectedEvents: createEmptyEventStore(),
+      mutatedEvents: createEmptyEventStore(),
+      isEvent: this.dragMeta!.create,
+      origSeg: null
+    }
 
     if (hit) {
       receivingCalendar = hit.component.calendar
 
       if (this.canDropElOnCalendar(ev.subjectEl as HTMLElement, receivingCalendar)) {
+
         droppableEvent = computeEventForDateSpan(
           hit.dateSpan,
           this.dragMeta!,
           receivingCalendar
         )
 
-        isInvalid = !isEventsValid(
-          eventTupleToStore(droppableEvent), // TODO: fix inefficiency of calling eventTupleToStore again
-          receivingCalendar,
-          !this.dragMeta.create
-        )
+        interaction.mutatedEvents = eventTupleToStore(droppableEvent)
+        isInvalid = !isInteractionValid(interaction, receivingCalendar)
 
         if (isInvalid) {
-          droppableEvent = null
+          interaction.mutatedEvents = createEmptyEventStore()
         }
       }
     }
 
-    // TODO: always store as event-store?
-    let droppableEventStore = droppableEvent ? eventTupleToStore(droppableEvent) : createEmptyEventStore()
-
-    this.displayDrag(receivingCalendar, {
-      affectedEvents: createEmptyEventStore(),
-      mutatedEvents: droppableEventStore,
-      isEvent: this.dragMeta!.create,
-      origSeg: null
-    })
+    this.displayDrag(receivingCalendar, interaction)
 
-    // show mirror if no already-rendered mirror element OR if we are shutting down the mirror
+    // show mirror if no already-rendered mirror element OR if we are shutting down the mirror (?)
     // TODO: wish we could somehow wait for dispatch to guarantee render
     dragging.setMirrorIsVisible(
       isFinal || !droppableEvent || !document.querySelector('.fc-mirror')

+ 1 - 1
src/interactions/DateSelecting.ts

@@ -63,7 +63,7 @@ export default class DateSelecting {
         calendar.pluginSystem.hooks.dateSelectionTransformers
       )
 
-      if (!dragSelection || !this.component.isSelectionValid(dragSelection)) {
+      if (!dragSelection || !this.component.isDateSelectionValid(dragSelection)) {
         isInvalid = true
         dragSelection = null
       }

+ 11 - 7
src/interactions/EventDragging.ts

@@ -130,6 +130,12 @@ export default class EventDragging { // TODO: rename to EventSelectingAndDraggin
     let mutation: EventMutation | null = null
     let mutatedRelevantEvents: EventStore | null = null
     let isInvalid = false
+    let interaction: EventInteractionState = {
+      affectedEvents: relevantEvents,
+      mutatedEvents: createEmptyEventStore(),
+      isEvent: true,
+      origSeg: this.subjectSeg
+    }
 
     if (hit) {
       let receivingComponent = hit.component
@@ -143,11 +149,14 @@ export default class EventDragging { // TODO: rename to EventSelectingAndDraggin
 
         if (mutation) {
           mutatedRelevantEvents = applyMutationToEventStore(relevantEvents, mutation, receivingCalendar)
+          interaction.mutatedEvents = mutatedRelevantEvents
 
-          if (!this.component.isEventsValid(mutatedRelevantEvents)) {
+          if (!this.component.isInteractionValid(interaction)) {
             isInvalid = true
             mutation = null
+
             mutatedRelevantEvents = null
+            interaction.mutatedEvents = createEmptyEventStore()
           }
         }
       } else {
@@ -155,12 +164,7 @@ export default class EventDragging { // TODO: rename to EventSelectingAndDraggin
       }
     }
 
-    this.displayDrag(receivingCalendar, {
-      affectedEvents: relevantEvents,
-      mutatedEvents: mutatedRelevantEvents || createEmptyEventStore(),
-      isEvent: true,
-      origSeg: this.subjectSeg
-    })
+    this.displayDrag(receivingCalendar, interaction)
 
     if (!isInvalid) {
       enableCursor()

+ 13 - 8
src/interactions/EventResizing.ts

@@ -4,12 +4,13 @@ import { EventMutation, applyMutationToEventStore } from '../structs/event-mutat
 import { elementClosest } from '../util/dom-manip'
 import FeaturefulElementDragging from '../dnd/FeaturefulElementDragging'
 import { PointerDragEvent } from '../dnd/PointerDragging'
-import { EventStore, getRelevantEvents } from '../structs/event-store'
+import { EventStore, getRelevantEvents, createEmptyEventStore } from '../structs/event-store'
 import { diffDates, enableCursor, disableCursor } from '../util/misc'
 import { DateRange } from '../datelib/date-range'
 import EventApi from '../api/EventApi'
 import { EventRenderRange, getElSeg } from '../component/event-rendering'
 import { createDuration } from '../datelib/duration'
+import { EventInteractionState } from './event-interaction-state'
 
 export default class EventDragging {
 
@@ -86,6 +87,12 @@ export default class EventDragging {
     let mutation: EventMutation | null = null
     let mutatedRelevantEvents: EventStore | null = null
     let isInvalid = false
+    let interaction: EventInteractionState = {
+      affectedEvents: relevantEvents,
+      mutatedEvents: createEmptyEventStore(),
+      isEvent: true,
+      origSeg: this.draggingSeg
+    }
 
     if (hit) {
       mutation = computeMutation(
@@ -98,23 +105,21 @@ export default class EventDragging {
 
     if (mutation) {
       mutatedRelevantEvents = applyMutationToEventStore(relevantEvents, mutation, calendar)
+      interaction.mutatedEvents = mutatedRelevantEvents
 
-      if (!this.component.isEventsValid(mutatedRelevantEvents)) {
+      if (!this.component.isInteractionValid(interaction)) {
         isInvalid = true
         mutation = null
+
         mutatedRelevantEvents = null
+        interaction.mutatedEvents = null
       }
     }
 
     if (mutatedRelevantEvents) {
       calendar.dispatch({
         type: 'SET_EVENT_RESIZE',
-        state: {
-          affectedEvents: relevantEvents,
-          mutatedEvents: mutatedRelevantEvents,
-          isEvent: true,
-          origSeg: this.draggingSeg
-        }
+        state: interaction
       })
     } else {
       calendar.dispatch({ type: 'UNSET_EVENT_RESIZE' })

+ 5 - 20
src/plugin-system.ts

@@ -1,16 +1,14 @@
 import { reducerFunc } from './reducers/types'
-import { eventDefParserFunc, EventDef } from './structs/event'
+import { eventDefParserFunc } from './structs/event'
 import { eventDragMutationMassager } from './interactions/EventDragging'
 import { eventDefMutationApplier } from './structs/event-mutation'
-import Calendar, { dateClickApiTransformer, dateSelectionApiTransformer } from './Calendar'
+import { dateClickApiTransformer, dateSelectionApiTransformer } from './Calendar'
 import { dateSelectionJoinTransformer } from './interactions/DateSelecting'
 import { ViewConfigInputHash } from './structs/view-config'
 import { assignTo } from './util/object'
 import { ViewSpecTransformer, ViewSpec } from './structs/view-spec'
 import { ViewProps } from './View'
 import { CalendarComponentProps } from './CalendarComponent'
-import Splitter from './component/event-splitting'
-import { Constraint } from './validation'
 
 // TODO: easier way to add new hooks? need to update a million things
 
@@ -26,7 +24,6 @@ export interface PluginDefInput {
   viewConfigs?: ViewConfigInputHash
   viewSpecTransformers?: ViewSpecTransformer[]
   viewPropsTransformers?: ViewPropsTransformerClass[]
-  validationSplitter?: ValidationSplitterMeta
 }
 
 export interface PluginHooks {
@@ -40,7 +37,6 @@ export interface PluginHooks {
   viewConfigs: ViewConfigInputHash // TODO: parse before gets to this step?
   viewSpecTransformers: ViewSpecTransformer[]
   viewPropsTransformers: ViewPropsTransformerClass[]
-  validationSplitter: ValidationSplitterMeta | null
 }
 
 export interface PluginDef extends PluginHooks {
@@ -48,14 +44,6 @@ export interface PluginDef extends PluginHooks {
   deps: PluginDef[]
 }
 
-
-export interface ValidationSplitterMeta {
-  splitterClass: new() => Splitter
-  getDateSpanPropsForKey: (key: string) => any
-  constraintAllowsKey: (constraint: Constraint, key: string) => boolean
-  eventAllowsKey: (subjectDef: EventDef, calendar: Calendar, currentSegmentKey: string) => boolean
-}
-
 export type ViewPropsTransformerClass = new() => ViewPropsTransformer
 
 export interface ViewPropsTransformer {
@@ -78,8 +66,7 @@ export function createPlugin(input: PluginDefInput): PluginDef {
     dateSelectionApiTransformers: input.dateSelectionApiTransformers || [],
     viewConfigs: input.viewConfigs || {},
     viewSpecTransformers: input.viewSpecTransformers || [],
-    viewPropsTransformers: input.viewPropsTransformers || [],
-    validationSplitter: input.validationSplitter || null
+    viewPropsTransformers: input.viewPropsTransformers || []
   }
 }
 
@@ -99,8 +86,7 @@ export class PluginSystem {
       dateSelectionApiTransformers: [],
       viewConfigs: {},
       viewSpecTransformers: [],
-      viewPropsTransformers: [],
-      validationSplitter: null
+      viewPropsTransformers: []
     }
     this.addedHash = {}
   }
@@ -130,7 +116,6 @@ function combineHooks(hooks0: PluginHooks, hooks1: PluginHooks): PluginHooks {
     dateSelectionApiTransformers: hooks0.dateSelectionApiTransformers.concat(hooks1.dateSelectionApiTransformers),
     viewConfigs: assignTo({}, hooks0.viewConfigs, hooks1.viewConfigs),
     viewSpecTransformers: hooks0.viewSpecTransformers.concat(hooks1.viewSpecTransformers),
-    viewPropsTransformers: hooks0.viewPropsTransformers.concat(hooks1.viewPropsTransformers),
-    validationSplitter: hooks1.validationSplitter || hooks0.validationSplitter
+    viewPropsTransformers: hooks0.viewPropsTransformers.concat(hooks1.viewPropsTransformers)
   }
 }

+ 67 - 154
src/validation.ts

@@ -1,13 +1,13 @@
-import { EventStore, expandRecurring, filterEventStoreDefs, createEmptyEventStore, parseEvents } from './structs/event-store'
+import { EventStore, expandRecurring, filterEventStoreDefs, parseEvents } from './structs/event-store'
 import Calendar from './Calendar'
 import { DateSpan, buildDateSpanApi, DateSpanApi } from './structs/date-span'
 import { rangeContainsRange, rangesIntersect, DateRange, OpenDateRange } from './datelib/date-range'
 import EventApi from './api/EventApi'
-import { EventUiHash } from './component/event-ui'
 import { compileEventUis } from './component/event-rendering'
-import { ValidationSplitterMeta } from './plugin-system'
 import { excludeInstances } from './reducers/eventStore'
 import { EventInput } from './structs/event'
+import { EventInteractionState } from './interactions/event-interaction-state'
+import { SplittableProps } from './component/event-splitting'
 
 // TODO: rename to "criteria" ?
 export type ConstraintInput = 'businessHours' | string | EventInput | EventInput[]
@@ -19,95 +19,57 @@ export type AllowFunc = (span: DateSpanApi, movingEvent: EventApi | null) => boo
 // high-level segmenting-aware tester functions
 // ------------------------------------------------------------------------------------------------------------------------
 
-export function isEventsValid(subjectEventStore: EventStore, calendar: Calendar, isntEvent?: boolean): boolean {
-  let splitterMeta = calendar.pluginSystem.hooks.validationSplitter
-  let relevantSegmentedProps = getRelevantSegmentedProps(calendar, splitterMeta)
-  let subjectSegmentedProps = splitMinimalProps({
-    eventStore: subjectEventStore,
-    eventUiBases: isntEvent ? { '': calendar.selectionConfig } : calendar.eventUiBases,
-  }, splitterMeta)
-
-  for (let key in subjectSegmentedProps) {
-    let subjectProps = subjectSegmentedProps[key]
-    let relevantProps = relevantSegmentedProps[key]
-
-    if (!isSegmentedEventsValid(
-      subjectProps.eventStore,
-      subjectProps.eventUiBases,
-      relevantProps.eventStore,
-      relevantProps.eventUiBases,
-      relevantProps.businessHours,
-      calendar,
-      splitterMeta,
-      key,
-      isntEvent
-    )) {
-      return false
-    }
-  }
+export function isInteractionValid(interaction: EventInteractionState, calendar: Calendar) {
+  return isNewPropsValid({ eventDrag: interaction }, calendar) // HACK: the eventDrag props is used for ALL interactions
+}
 
-  return true
+export function isDateSelectionValid(dateSelection: DateSpan, calendar: Calendar) {
+  return isNewPropsValid({ dateSelection }, calendar)
 }
 
-export function isSelectionValid(selection: DateSpan, calendar: Calendar): boolean {
-  let splitterMeta = calendar.pluginSystem.hooks.validationSplitter
-  let relevantSegmentedProps = getRelevantSegmentedProps(calendar, splitterMeta)
-  let subjectSegmentedProps = splitMinimalProps({
-    dateSelection: selection
-  }, splitterMeta)
-
-  for (let key in subjectSegmentedProps) {
-    let subjectProps = subjectSegmentedProps[key]
-    let relevantProps = relevantSegmentedProps[key]
-
-    if (!isSegmentedSelectionValid(
-      subjectProps.dateSelection,
-      relevantProps.eventStore,
-      relevantProps.businessHours,
-      calendar,
-      splitterMeta,
-      key,
-    )) {
-      return false
-    }
-  }
+function isNewPropsValid(newProps, calendar: Calendar) {
+  let props = Object.assign({}, {
+    businessHours: calendar.view.props.businessHours, // yuck
+    dateSelection: '',
+    eventStore: calendar.state.eventStore,
+    eventUiBases: calendar.eventUiBases,
+    eventSelection: '',
+    eventDrag: null,
+    eventResize: null
+  }, newProps)
 
-  return true
+  // TODO: hooks
+
+  return isPropsValid(props, calendar)
 }
 
-// we have a different meaning of "relevant" here than other places of codebase
-function getRelevantSegmentedProps(calendar: Calendar, splitterMeta: ValidationSplitterMeta) {
-  let view = calendar.view // yuck
+export function isPropsValid(state: SplittableProps, calendar: Calendar, dateSpanMeta = {}) {
 
-  return splitMinimalProps({
-    eventStore: calendar.state.eventStore,
-    eventUiBases: calendar.eventUiBases,
-    businessHours: view ? view.props.businessHours : createEmptyEventStore() // yuck
-  }, splitterMeta)
+  if (state.dateSelection && !isDateSelectionPropsValid(state, calendar, dateSpanMeta)) {
+    return false
+  }
+
+  if (state.eventDrag && !isInteractionPropsValid(state, calendar, dateSpanMeta)) {
+    return false
+  }
 }
 
 
-// insular tester functions
+// Moving Event Validation
 // ------------------------------------------------------------------------------------------------------------------------
 
-function isSegmentedEventsValid(
-  subjectEventStore: EventStore,
-  subjectConfigBase: EventUiHash,
-  relevantEventStore: EventStore, // include the original subject events
-  relevantEventConfigBase: EventUiHash,
-  businessHoursUnexpanded: EventStore,
-  calendar: Calendar,
-  splitterMeta: ValidationSplitterMeta | null,
-  currentSegmentKey: string,
-  isntEvent: boolean
-): boolean {
+function isInteractionPropsValid(state: SplittableProps, calendar: Calendar, dateSpanMeta: any): boolean {
+  let interaction = state.eventDrag // HACK: the eventDrag props is used for ALL interactions
+
+  let subjectEventStore = interaction.mutatedEvents
   let subjectDefs = subjectEventStore.defs
   let subjectInstances = subjectEventStore.instances
-  let subjectConfigs = compileEventUis(subjectDefs, subjectConfigBase)
-  let otherEventStore = excludeInstances(relevantEventStore, subjectInstances) // exclude the subject events. TODO: exclude defs too?
+  let subjectConfigs = compileEventUis(subjectDefs, state.eventUiBases)
+
+  let otherEventStore = excludeInstances(state.eventStore, interaction.affectedEvents.instances) // exclude the subject events. TODO: exclude defs too?
   let otherDefs = otherEventStore.defs
   let otherInstances = otherEventStore.instances
-  let otherConfigs = compileEventUis(otherDefs, relevantEventConfigBase)
+  let otherConfigs = compileEventUis(otherDefs, state.eventUiBases)
 
   for (let subjectInstanceId in subjectInstances) {
     let subjectInstance = subjectInstances[subjectInstanceId]
@@ -115,20 +77,9 @@ function isSegmentedEventsValid(
     let subjectConfig = subjectConfigs[subjectInstance.defId]
     let subjectDef = subjectDefs[subjectInstance.defId]
 
-    if (splitterMeta && !splitterMeta.eventAllowsKey(subjectDef, calendar, currentSegmentKey)) { // TODO: pass in EventUi
-      return false
-    }
-
     // constraint
-    for (let subjectConstraint of subjectConfig.constraints) {
-
-      if (!constraintPasses(subjectConstraint, subjectRange, otherEventStore, businessHoursUnexpanded, calendar)) {
-        return false
-      }
-
-      if (splitterMeta && !splitterMeta.constraintAllowsKey(subjectConstraint, currentSegmentKey)) {
-        return false
-      }
+    if (!allConstraintPasses(subjectConfig.constraints, subjectRange, otherEventStore, state.businessHours, calendar)) {
+      return false
     }
 
     // overlap
@@ -144,7 +95,7 @@ function isSegmentedEventsValid(
         let otherOverlap = otherConfigs[otherInstance.defId].overlap
 
         // consider the other event's overlap. only do this if the subject event is a "real" event
-        if (otherOverlap === false && !isntEvent) {
+        if (otherOverlap === false && state.eventDrag.isEvent) {
           return false
         }
 
@@ -163,12 +114,12 @@ function isSegmentedEventsValid(
 
     // allow (a function)
     for (let subjectAllow of subjectConfig.allows) {
-      let origDef = relevantEventStore.defs[subjectDef.defId]
-      let origInstance = relevantEventStore.instances[subjectInstanceId]
+      let origDef = state.eventStore.defs[subjectDef.defId]
+      let origInstance = state.eventStore.instances[subjectInstanceId]
 
       let subjectDateSpan: DateSpan = Object.assign(
         {},
-        splitterMeta ? splitterMeta.getDateSpanPropsForKey(currentSegmentKey) : {},
+        dateSpanMeta,
         { range: subjectInstance.range, allDay: subjectDef.allDay }
       )
 
@@ -185,29 +136,22 @@ function isSegmentedEventsValid(
   return true
 }
 
-function isSegmentedSelectionValid(
-  selection: DateSpan,
-  relevantEventStore: EventStore,
-  businessHoursUnexpanded: EventStore,
-  calendar: Calendar,
-  splitterMeta: ValidationSplitterMeta | null,
-  currentSegmentKey: string
-): boolean {
+
+// Date Selection Validation
+// ------------------------------------------------------------------------------------------------------------------------
+
+function isDateSelectionPropsValid(state: SplittableProps, calendar: Calendar, dateSpanMeta: any): boolean {
+  let relevantEventStore = state.eventStore
   let relevantDefs = relevantEventStore.defs
   let relevantInstances = relevantEventStore.instances
+
+  let selection = state.dateSelection
   let selectionRange = selection.range
   let { selectionConfig } = calendar
 
   // constraint
-  for (let selectionConstraint of selectionConfig.constraints) {
-
-    if (!constraintPasses(selectionConstraint, selectionRange, relevantEventStore, businessHoursUnexpanded, calendar)) {
-      return false
-    }
-
-    if (splitterMeta && !splitterMeta.constraintAllowsKey(selectionConstraint, currentSegmentKey)) {
-      return false
-    }
+  if (!allConstraintPasses(selectionConfig.constraints, selectionRange, relevantEventStore, state.businessHours, calendar)) {
+    return false
   }
 
   // overlap
@@ -236,11 +180,7 @@ function isSegmentedSelectionValid(
   // allow (a function)
   for (let selectionAllow of selectionConfig.allows) {
 
-    let fullDateSpan = Object.assign(
-      {},
-      splitterMeta ? splitterMeta.getDateSpanPropsForKey(currentSegmentKey) : {},
-      selection,
-    )
+    let fullDateSpan = Object.assign({}, dateSpanMeta, selection)
 
     if (!selectionAllow(
       buildDateSpanApi(fullDateSpan, calendar.dateEnv),
@@ -257,17 +197,23 @@ function isSegmentedSelectionValid(
 // Constraint Utils
 // ------------------------------------------------------------------------------------------------------------------------
 
-function constraintPasses(
-  constraint: Constraint,
+function allConstraintPasses(
+  constraints: Constraint[],
   subjectRange: DateRange,
   otherEventStore: EventStore,
   businessHoursUnexpanded: EventStore,
   calendar: Calendar
 ) {
-  return anyRangesContainRange(
-    constraintToRanges(constraint, subjectRange, otherEventStore, businessHoursUnexpanded, calendar),
-    subjectRange
-  )
+  for (let constraint of constraints) {
+    if (!anyRangesContainRange(
+      constraintToRanges(constraint, subjectRange, otherEventStore, businessHoursUnexpanded, calendar),
+      subjectRange
+    )) {
+      return false
+    }
+  }
+
+  return true
 }
 
 function constraintToRanges(
@@ -324,39 +270,6 @@ function anyRangesContainRange(outerRanges: DateRange[], innerRange: DateRange):
 }
 
 
-// Splitting Utils
-// ------------------------------------------------------------------------------------------------------------------------
-
-interface MinimalSplittableProps {
-  dateSelection?: DateSpan
-  businessHours?: EventStore
-  eventStore?: EventStore
-  eventUiBases?: EventUiHash
-}
-
-function splitMinimalProps(
-  inputProps: MinimalSplittableProps,
-  splitterMeta: ValidationSplitterMeta | null
-): { [key: string]: MinimalSplittableProps } {
-
-  if (splitterMeta) {
-    let splitter = new splitterMeta.splitterClass()
-
-    return splitter.splitProps({
-      businessHours: inputProps.businessHours || createEmptyEventStore(),
-      dateSelection: inputProps.dateSelection || null,
-      eventStore: inputProps.eventStore || createEmptyEventStore(),
-      eventUiBases: inputProps.eventUiBases || {},
-      eventSelection: '',
-      eventDrag: null,
-      eventResize: null
-    })
-  } else {
-    return { '': inputProps }
-  }
-}
-
-
 // Parsing
 // ------------------------------------------------------------------------------------------------------------------------