Skip to content

Commit

Permalink
pluginify change handling
Browse files Browse the repository at this point in the history
  • Loading branch information
arshaw committed Mar 27, 2019
1 parent a28f171 commit 637fda8
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 59 deletions.
63 changes: 9 additions & 54 deletions src/core/Calendar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ import { Duration, createDuration } from './datelib/duration'
import reduce from './reducers/main'
import { parseDateSpan, DateSpanInput, DateSpan, buildDateSpanApi, DateSpanApi, buildDatePointApi, DatePointApi } from './structs/date-span'
import { memoize, memoizeOutput } from './util/memoize'
import { mapHash, isPropsEqual, anyKeysRemoved, computeChangedProps, hashValuesToArray, isObjsSimilar } from './util/object'
import { mapHash, isPropsEqual, anyKeysRemoved, computeChangedProps } from './util/object'
import { DateRangeInput } from './datelib/date-range'
import DateProfileGenerator from './DateProfileGenerator'
import { EventSourceInput, parseEventSource, EventSourceHash, EventSource } from './structs/event-source'
import { EventSourceInput, parseEventSource, EventSourceHash } from './structs/event-source'
import { EventInput, parseEvent, EventDefHash } from './structs/event'
import { CalendarState, Action } from './reducers/types'
import EventSourceApi from './api/EventSourceApi'
Expand Down Expand Up @@ -54,6 +54,9 @@ export type DateSpanTransform = (dateSpan: DateSpan, calendar: Calendar) => any
export type CalendarInteraction = { destroy() }
export type CalendarInteractionClass = { new(calendar: Calendar): CalendarInteraction }

export type OptionChangeHandler = (propValue: any, calendar: Calendar) => void
export type OptionChangeHandlerMap = { [propName: string]: OptionChangeHandler }

export default class Calendar {

// global handler registry
Expand Down Expand Up @@ -492,19 +495,20 @@ export default class Calendar {

// not really for public use
resetOptions(options) {
let changeHandlers = this.pluginSystem.hooks.optionChangeHandlers
let oldOptions = this.optionsManager.overrides
let oldNormalOptions = {}
let normalOptions = {}
let specialOptions = {}

for (let name in oldOptions) {
if (!SPECIAL_OPTIONS[name]) {
if (!changeHandlers[name]) {
oldNormalOptions[name] = oldOptions[name]
}
}

for (let name in options) {
if (SPECIAL_OPTIONS[name]) {
if (changeHandlers[name]) {
specialOptions[name] = options[name]
} else {
normalOptions[name] = options[name]
Expand All @@ -521,7 +525,7 @@ export default class Calendar {

// handle special options last
for (let name in specialOptions) {
SPECIAL_OPTIONS[name](specialOptions[name], this)
changeHandlers[name](specialOptions[name], this)
}
})
}
Expand Down Expand Up @@ -1337,52 +1341,3 @@ function buildEventUiBases(eventDefs: EventDefHash, eventUiSingleBase: EventUi,

return eventUiBases
}



const SPECIAL_OPTIONS = {
events(events, calendar) {
handleEventSources([ events ], calendar)
},
eventSources: handleEventSources,
plugins: handlePlugins
}


function handleEventSources(inputs, calendar: Calendar) {
let unfoundSources: EventSource[] = hashValuesToArray(calendar.state.eventSources)
let newInputs = []

for (let input of inputs) {
let inputFound = false

for (let i = 0; i < unfoundSources.length; i++) {
if (isObjsSimilar(unfoundSources[i]._raw, input)) {
unfoundSources.splice(i, 1) // delete
inputFound = true
break
}
}

if (!inputFound) {
newInputs.push(input)
}
}

for (let unfoundSource of unfoundSources) {
calendar.dispatch({
type: 'REMOVE_EVENT_SOURCE',
sourceId: unfoundSource.sourceId
})
}

for (let newInput of newInputs) {
calendar.addEventSource(newInput)
}
}


// shortcoming: won't remove plugins
function handlePlugins(inputs, calendar: Calendar) {
calendar.addPluginInputs(inputs) // will gracefully handle duplicates
}
51 changes: 51 additions & 0 deletions src/core/option-change-handlers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { createPlugin } from './plugin-system'
import { Calendar } from './main'
import { hashValuesToArray, isObjsSimilar } from './util/object'
import { EventSource } from './structs/event-source'

export default createPlugin({
optionChangeHandlers: {
events(events, calendar) {
handleEventSources([ events ], calendar)
},
eventSources: handleEventSources,
plugins: handlePlugins
}
})

function handleEventSources(inputs, calendar: Calendar) {
let unfoundSources: EventSource[] = hashValuesToArray(calendar.state.eventSources)
let newInputs = []

for (let input of inputs) {
let inputFound = false

for (let i = 0; i < unfoundSources.length; i++) {
if (isObjsSimilar(unfoundSources[i]._raw, input)) {
unfoundSources.splice(i, 1) // delete
inputFound = true
break
}
}

if (!inputFound) {
newInputs.push(input)
}
}

for (let unfoundSource of unfoundSources) {
calendar.dispatch({
type: 'REMOVE_EVENT_SOURCE',
sourceId: unfoundSource.sourceId
})
}

for (let newInput of newInputs) {
calendar.addEventSource(newInput)
}
}

// shortcoming: won't remove plugins
function handlePlugins(inputs, calendar: Calendar) {
calendar.addPluginInputs(inputs) // will gracefully handle duplicates
}
4 changes: 3 additions & 1 deletion src/core/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import FuncEventSourcePlugin from './event-sources/func-event-source'
import JsonFeedEventSourcePlugin from './event-sources/json-feed-event-source'
import SimpleRecurrencePlugin from './structs/recurring-event-simple'
import { capitaliseFirstLetter } from './util/misc'
import DefaultOptionChangeHandlers from './option-change-handlers'

export const config = {} as any // TODO: make these options

Expand Down Expand Up @@ -128,7 +129,8 @@ const INTERNAL_PLUGINS: PluginDef[] = [
ArrayEventSourcePlugin,
FuncEventSourcePlugin,
JsonFeedEventSourcePlugin,
SimpleRecurrencePlugin
SimpleRecurrencePlugin,
DefaultOptionChangeHandlers
]

export function refinePluginDefs(pluginInputs: any[]): PluginDef[] {
Expand Down
13 changes: 9 additions & 4 deletions src/core/plugin-system.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { reducerFunc } from './reducers/types'
import { eventDefParserFunc } from './structs/event'
import { eventDefMutationApplier } from './structs/event-mutation'
import Calendar, { DatePointTransform, DateSpanTransform, CalendarInteractionClass } from './Calendar'
import Calendar, { DatePointTransform, DateSpanTransform, CalendarInteractionClass, OptionChangeHandlerMap } from './Calendar'
import { ViewConfigInputHash } from './structs/view-config'
import { ViewSpec } from './structs/view-spec'
import View, { ViewProps } from './View'
Expand Down Expand Up @@ -46,6 +46,7 @@ export interface PluginDefInput {
namedTimeZonedImpl?: NamedTimeZoneImplClass
defaultView?: string
elementDraggingImpl?: ElementDraggingClass
optionChangeHandlers?: OptionChangeHandlerMap
}

export interface PluginHooks {
Expand All @@ -72,6 +73,7 @@ export interface PluginHooks {
namedTimeZonedImpl?: NamedTimeZoneImplClass
defaultView: string
elementDraggingImpl?: ElementDraggingClass
optionChangeHandlers: OptionChangeHandlerMap
}

export interface PluginDef extends PluginHooks {
Expand Down Expand Up @@ -116,7 +118,8 @@ export function createPlugin(input: PluginDefInput): PluginDef {
recurringTypes: input.recurringTypes || [],
namedTimeZonedImpl: input.namedTimeZonedImpl,
defaultView: input.defaultView || '',
elementDraggingImpl: input.elementDraggingImpl
elementDraggingImpl: input.elementDraggingImpl,
optionChangeHandlers: input.optionChangeHandlers || {}
}
}

Expand Down Expand Up @@ -149,7 +152,8 @@ export class PluginSystem {
recurringTypes: [],
namedTimeZonedImpl: null,
defaultView: '',
elementDraggingImpl: null
elementDraggingImpl: null,
optionChangeHandlers: {}
}
this.addedHash = {}
}
Expand Down Expand Up @@ -192,6 +196,7 @@ function combineHooks(hooks0: PluginHooks, hooks1: PluginHooks): PluginHooks {
recurringTypes: hooks0.recurringTypes.concat(hooks1.recurringTypes),
namedTimeZonedImpl: hooks1.namedTimeZonedImpl || hooks0.namedTimeZonedImpl,
defaultView: hooks0.defaultView || hooks1.defaultView, // put earlier plugins FIRST
elementDraggingImpl: hooks0.elementDraggingImpl || hooks1.elementDraggingImpl // "
elementDraggingImpl: hooks0.elementDraggingImpl || hooks1.elementDraggingImpl, // "
optionChangeHandlers: { ...hooks0.optionChangeHandlers, ...hooks1.optionChangeHandlers }
}
}

0 comments on commit 637fda8

Please sign in to comment.