Adam Shaw 7 anni fa
parent
commit
df500fe5b7

+ 5 - 4
src/agenda/TimeGridEventRenderer.ts

@@ -91,12 +91,13 @@ export default class TimeGridEventRenderer extends EventRenderer {
     let view = this.view
     let eventRange = seg.eventRange
     let eventDef = eventRange.eventDef
+    let eventUi = eventRange.ui
     let isAllDay = eventDef.isAllDay
-    let isDraggable = this.isEventDefDraggable(eventDef)
-    let isResizableFromStart = seg.isStart && this.isEventDefResizableFromStart(eventDef)
-    let isResizableFromEnd = seg.isEnd && this.isEventDefResizableFromEnd(eventDef)
+    let isDraggable = eventUi.startEditable
+    let isResizableFromStart = seg.isStart && eventUi.durationEditable && this.opt('eventResizableFromStart')
+    let isResizableFromEnd = seg.isEnd && eventUi.durationEditable
     let classes = this.getSegClasses(seg, isDraggable, isResizableFromStart || isResizableFromEnd)
-    let skinCss = cssToStr(this.getSkinCss(eventDef))
+    let skinCss = cssToStr(this.getSkinCss(eventUi))
     let timeText
     let fullTimeText // more verbose time text. for the print stylesheet
     let startTimeText // just the start time text

+ 4 - 2
src/basic/DayGrid.ts

@@ -22,6 +22,7 @@ import DayTile from './DayTile'
 import { Hit } from '../interactions/HitDragging'
 import { DateRange, rangeContainsMarker, intersectRanges } from '../datelib/date-range'
 import OffsetTracker from '../common/OffsetTracker'
+import { EventRenderRange } from '../component/event-rendering'
 
 const DAY_NUM_FORMAT = createFormatter({ day: 'numeric' })
 const WEEK_NUM_FORMAT = createFormatter({ week: 'numeric' })
@@ -700,8 +701,9 @@ export default class DayGrid extends DateComponent {
             eventRange: {
               eventDef: eventRange.eventDef,
               eventInstance: eventRange.eventInstance,
-              range: slicedRange
-            },
+              range: slicedRange,
+              ui: assignTo({}, eventRange.ui, { durationEditable: false }) // hack to disable resizing
+            } as EventRenderRange,
             isStart: seg.isStart && slicedRange.start.valueOf() === origRange.start.valueOf(),
             isEnd: seg.isEnd && slicedRange.end.valueOf() === origRange.end.valueOf()
           })

+ 5 - 4
src/basic/DayGridEventRenderer.ts

@@ -239,12 +239,13 @@ export default class DayGridEventRenderer extends EventRenderer {
   fgSegHtml(seg: Seg) {
     let eventRange = seg.eventRange
     let eventDef = eventRange.eventDef
+    let eventUi = eventRange.ui
     let isAllDay = eventDef.isAllDay
-    let isDraggable = this.isEventDefDraggable(eventDef)
-    let isResizableFromStart = isAllDay && seg.isStart && this.isEventDefResizableFromStart(eventDef)
-    let isResizableFromEnd = isAllDay && seg.isEnd && this.isEventDefResizableFromEnd(eventDef)
+    let isDraggable = eventUi.startEditable
+    let isResizableFromStart = isAllDay && seg.isStart && eventUi.durationEditable && this.opt('eventResizableFromStart')
+    let isResizableFromEnd = isAllDay && seg.isEnd && eventUi.durationEditable
     let classes = this.getSegClasses(seg, isDraggable, isResizableFromStart || isResizableFromEnd)
-    let skinCss = cssToStr(this.getSkinCss(eventDef))
+    let skinCss = cssToStr(this.getSkinCss(eventUi))
     let timeHtml = ''
     let timeText
     let titleHtml

+ 0 - 8
src/basic/DayTile.ts

@@ -95,14 +95,6 @@ export class DayTileEventRenderer extends EventRenderer {
     }
   }
 
-  isEventDefResizableFromStart(eventDef) {
-    return false
-  }
-
-  isEventDefResizableFromEnd(eventDef) {
-    return false
-  }
-
 }
 
 // hack

+ 12 - 3
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 } from '../component/event-rendering'
+import { EventRenderRange, sliceEventStore, computeUiHash } from '../component/event-rendering'
 import { EventStore } from '../structs/event-store'
 import { BusinessHoursDef, buildBusinessHours } from '../structs/business-hours'
 import { DateEnv } from '../datelib/env'
@@ -845,7 +845,12 @@ export default abstract class DateComponent extends Component {
 
   eventStoreToSegs(eventStore: EventStore): Seg[] {
     let activeRange = this.dateProfile.activeRange
-    let eventRenderRanges = sliceEventStore(eventStore, activeRange)
+    let eventRenderRanges = sliceEventStore(
+      eventStore,
+      this.getCalendar().state.eventSources,
+      activeRange,
+      this.view.options
+    )
     let allSegs: Seg[] = []
 
     for (let eventRenderRange of eventRenderRanges) {
@@ -865,11 +870,15 @@ export default abstract class DateComponent extends Component {
     let segs = this.rangeToSegs(selection.range, selection.isAllDay)
 
     if (fabricateEvents) {
+
+      // fabricate an eventRange. important for helper
+      // TODO: make a separate utility for this?
       let def = parseEventDef({ editable: false }, '', selection.isAllDay, true)
       let eventRange = {
         eventDef: def,
         eventInstance: createEventInstance(def.defId, selection.range),
-        range: selection.range
+        range: selection.range,
+        ui: computeUiHash(def, {}, {})
       }
 
       for (let seg of segs) {

+ 86 - 7
src/component/event-rendering.ts

@@ -1,11 +1,25 @@
-import { EventDef, EventInstance } from '../structs/event'
+import { EventDef, EventInstance, EventDefHash } from '../structs/event'
 import { EventStore } from '../structs/event-store'
 import { DateRange, invertRanges } from '../datelib/date-range'
+import { EventSourceHash } from '../structs/event-source'
+import { mapHash } from '../util/object'
+import { parseClassName } from '../util/html'
+
+export interface EventUiProps {
+  startEditable: boolean
+  durationEditable: boolean
+  backgroundColor: string
+  borderColor: string
+  textColor: string,
+  rendering: string,
+  classNames: string[]
+}
 
 export interface EventRenderRange {
   eventDef: EventDef
   eventInstance?: EventInstance
   range: DateRange
+  ui: EventUiProps
 }
 
 
@@ -13,16 +27,18 @@ 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, framingRange: DateRange) {
+export function sliceEventStore(eventStore: EventStore, eventSources: EventSourceHash, framingRange: DateRange, options) {
   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]
 
-    if (def.rendering === 'inverse-background') {
+    if (ui.rendering === 'inverse-background') {
       if (def.groupId) {
         inverseBgByGroupId[def.groupId] = []
 
@@ -38,8 +54,9 @@ export function sliceEventStore(eventStore: EventStore, framingRange: DateRange)
   for (let instanceId in eventStore.instances) {
     let instance = eventStore.instances[instanceId]
     let def = eventStore.defs[instance.defId]
+    let ui = uiHashes[def.defId]
 
-    if (def.rendering === 'inverse-background') {
+    if (ui.rendering === 'inverse-background') {
       if (def.groupId) {
         inverseBgByGroupId[def.groupId].push(instance.range)
       } else {
@@ -49,7 +66,8 @@ export function sliceEventStore(eventStore: EventStore, framingRange: DateRange)
       renderRanges.push({
         eventDef: def,
         eventInstance: instance,
-        range: instance.range
+        range: instance.range,
+        ui
       })
     }
   }
@@ -60,10 +78,12 @@ export function sliceEventStore(eventStore: EventStore, framingRange: DateRange)
 
     for (let invertedRange of invertedRanges) {
       let def = defByGroupId[groupId]
+      let ui = uiHashes[def.defId]
 
       renderRanges.push({
         eventDef: def,
-        range: invertedRange
+        range: invertedRange,
+        ui
       })
     }
   }
@@ -75,10 +95,69 @@ export function sliceEventStore(eventStore: EventStore, framingRange: DateRange)
     for (let invertedRange of invertedRanges) {
       renderRanges.push({
         eventDef: eventStore.defs[defId],
-        range: invertedRange
+        range: invertedRange,
+        ui: uiHashes[defId]
       })
     }
   }
 
   return renderRanges
 }
+
+
+// UI Props
+// ----------------------------------------------------------------------------------------------------
+
+function computeUiHashes(eventDefs: EventDefHash, eventSources: EventSourceHash, options) {
+  return mapHash(eventDefs, function(eventDef) {
+    return computeUiHash(eventDef, eventSources, options)
+  })
+}
+
+export function computeUiHash(eventDef: EventDef, eventSources: EventSourceHash, options) {
+  // lowest to highest priority
+  // TODO: hook for resources, using refineScopedUiHash
+  let refinedHashes = [
+    refineScopedUiHash(options),
+    refineUnscopedUiHash(eventSources[eventDef.sourceId] || {}),
+    refineUnscopedUiHash(eventDef)
+  ]
+
+  return refinedHashes.reduce(combineUiHashes)
+}
+
+function refineScopedUiHash(input) { // has word "event" in prop names
+  return {
+    startEditable: (input.startEditable != null) ? input.startEditable : input.editable,
+    durationEditable: (input.durationEditable != null) ? input.durationEditable : input.editable,
+    backgroundColor: input.eventBackgroundColor || input.eventColor || '',
+    borderColor: input.eventBorderColor || input.eventColor || '',
+    textColor: input.eventTextColor || '',
+    rendering: input.eventRendering || '',
+    classNames: parseClassName(input.eventClassNames || input.eventClassName)
+  }
+}
+
+function refineUnscopedUiHash(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,
+    backgroundColor: input.backgroundColor || input.color || '',
+    borderColor: input.borderColor || input.color || '',
+    textColor: input.textColor || '',
+    rendering: input.rendering || '',
+    classNames: parseClassName(input.classNames || input.className)
+  }
+}
+
+function combineUiHashes(hash0, hash1) { // hash1 has higher precedence
+  return {
+    startEditable: (hash1.startEditable != null) ? hash1.startEditable : hash0.startEditable,
+    durationEditable: (hash1.durationEditable != null) ? hash1.durationEditable : hash0.durationEditable,
+    backgroundColor: hash1.backgroundColor || hash0.backgroundColor,
+    borderColor: hash1.borderColor || hash0.borderColor,
+    textColor: hash1.textColor || hash0.textColor,
+    rendering: hash1.rendering || hash0.rendering,
+    classNames: hash0.classNames.concat(hash1.classNames)
+  }
+}

+ 9 - 160
src/component/renderers/EventRenderer.ts

@@ -3,10 +3,9 @@ import { DateMarker } from '../../datelib/marker'
 import { createFormatter, DateFormatter } from '../../datelib/formatting'
 import { htmlToElements } from '../../util/dom-manip'
 import { compareByFieldSpecs } from '../../util/misc'
-import { EventRenderRange } from '../event-rendering'
+import { EventRenderRange, EventUiProps } from '../event-rendering'
 import { Seg } from '../DateComponent'
 import EventApi from '../../api/EventApi'
-import { EventDef } from '../../structs/event'
 
 
 export default class EventRenderer {
@@ -67,7 +66,7 @@ export default class EventRenderer {
     let fgSegs: Seg[] = []
 
     for (let seg of allSegs) {
-      let rendering = seg.eventRange.eventDef.rendering
+      let rendering = seg.eventRange.ui.rendering
 
       if (rendering === 'background' || rendering === 'inverse-background') {
         bgSegs.push(seg)
@@ -121,11 +120,11 @@ export default class EventRenderer {
     if (this.fillRenderer) {
       return this.fillRenderer.renderSegs('bgEvent', segs, {
         getClasses: (seg) => {
-          return this.getBgClasses(seg.eventRange.eventDef)
+          return seg.eventRange.ui.classNames.concat([ 'fc-bgevent' ])
         },
         getCss: (seg) => {
           return {
-            'background-color': this.getBgColor(seg.eventRange.eventDef)
+            'background-color': seg.eventRange.ui.backgroundColor
           }
         },
         filterEl: (seg, el) => {
@@ -193,7 +192,7 @@ export default class EventRenderer {
       'fc-event',
       seg.isStart ? 'fc-start' : 'fc-not-start',
       seg.isEnd ? 'fc-end' : 'fc-not-end'
-    ].concat(this.getClasses(seg.eventRange.eventDef))
+    ].concat(seg.eventRange.ui.classNames)
 
     if (isDraggable) {
       classes.push('fc-draggable')
@@ -312,108 +311,12 @@ export default class EventRenderer {
   }
 
 
-  getBgClasses(eventDef) {
-    let classNames = this.getClasses(eventDef)
-    classNames.push('fc-bgevent')
-    return classNames
-  }
-
-
-  getClasses(eventDef) {
-    let objs = this.getStylingObjs(eventDef)
-    let i
-    let classNames = []
-
-    for (i = 0; i < objs.length; i++) {
-      classNames.push.apply( // append
-        classNames,
-        objs[i].eventClassName || objs[i].className || []
-      )
-    }
-
-    return classNames
-  }
-
-
   // Utility for generating event skin-related CSS properties
-  getSkinCss(eventDef) {
+  getSkinCss(ui: EventUiProps) {
     return {
-      'background-color': this.getBgColor(eventDef),
-      'border-color': this.getBorderColor(eventDef),
-      color: this.getTextColor(eventDef)
-    }
-  }
-
-
-  // Queries for caller-specified color, then falls back to default
-  getBgColor(eventDef) {
-    let objs = this.getStylingObjs(eventDef)
-    let i
-    let val
-
-    for (i = 0; i < objs.length && !val; i++) {
-      val = objs[i].eventBackgroundColor || objs[i].eventColor ||
-        objs[i].backgroundColor || objs[i].color
-    }
-
-    if (!val) {
-      val = this.opt('eventBackgroundColor') || this.opt('eventColor')
-    }
-
-    return val
-  }
-
-
-  // Queries for caller-specified color, then falls back to default
-  getBorderColor(eventDef) {
-    let objs = this.getStylingObjs(eventDef)
-    let i
-    let val
-
-    for (i = 0; i < objs.length && !val; i++) {
-      val = objs[i].eventBorderColor || objs[i].eventColor ||
-        objs[i].borderColor || objs[i].color
-    }
-
-    if (!val) {
-      val = this.opt('eventBorderColor') || this.opt('eventColor')
-    }
-
-    return val
-  }
-
-
-  // Queries for caller-specified color, then falls back to default
-  getTextColor(eventDef) {
-    let objs = this.getStylingObjs(eventDef)
-    let i
-    let val
-
-    for (i = 0; i < objs.length && !val; i++) {
-      val = objs[i].eventTextColor ||
-        objs[i].textColor
-    }
-
-    if (!val) {
-      val = this.opt('eventTextColor')
-    }
-
-    return val
-  }
-
-
-  getStylingObjs(eventDef) {
-    let objs = this.getFallbackStylingObjs(eventDef)
-    objs.unshift(eventDef)
-    return objs
-  }
-
-
-  getFallbackStylingObjs(eventDef): any {
-    if (eventDef.sourceId) {
-      return [ this.view.calendar.state.eventSources[eventDef.sourceId] ]
-    } else {
-      return []
+      'background-color': ui.backgroundColor,
+      'border-color': ui.borderColor,
+      color: ui.textColor
     }
   }
 
@@ -445,60 +348,6 @@ export default class EventRenderer {
   }
 
 
-  // Computes if the given event is allowed to be dragged by the user
-  isEventDefDraggable(eventDef: EventDef): boolean {
-    let val = eventDef.startEditable
-
-    if (val == null) {
-      let source = this.view.calendar.state.eventSources[eventDef.sourceId]
-      val = source ? source.startEditable : null
-
-      if (val == null) {
-        val = this.opt('eventStartEditable')
-
-        if (val == null) {
-          val = this.opt('editable')
-        }
-      }
-    }
-
-    return val
-  }
-
-
-  // Computes if the given event is allowed to be resized AT ALL
-  isEventDefResizable(eventDef): boolean {
-    let val = eventDef.durationEditable
-
-    if (val == null) {
-      let source = this.view.calendar.state.eventSources[eventDef.sourceId]
-      val = source ? source.durationEditable : null
-
-      if (val == null) {
-        val = this.opt('eventDurationEditable')
-
-        if (val == null) {
-          val = this.opt('editable')
-        }
-      }
-    }
-
-    return val
-  }
-
-
-  // Computes if the given event is allowed to be resized from its starting edge
-  isEventDefResizableFromStart(eventDef): boolean {
-    return this.opt('eventResizableFromStart') && this.isEventDefResizable(eventDef)
-  }
-
-
-  // Computes if the given event is allowed to be resized from its ending edge
-  isEventDefResizableFromEnd(eventDef): boolean {
-    return this.isEventDefResizable(eventDef)
-  }
-
-
   computeFgSize() {
   }
 

+ 1 - 1
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'
 
-export interface EventRes { // TODO: relate this to EventRenderRange?
+export interface EventRes {
   def: EventDef
   instance: EventInstance
 }

+ 3 - 2
src/list/ListEventRenderer.ts

@@ -23,9 +23,10 @@ export default class ListEventRenderer extends EventRenderer {
     let theme = calendar.theme
     let eventRange = seg.eventRange
     let eventDef = eventRange.eventDef
+    let eventUi = eventRange.ui
     let url = eventDef.url
-    let classes = [ 'fc-list-item' ].concat(this.getClasses(eventDef))
-    let bgColor = this.getBgColor(eventDef)
+    let classes = [ 'fc-list-item' ].concat(eventUi.classNames)
+    let bgColor = eventUi.backgroundColor
     let timeHtml
 
     if (eventDef.isAllDay) {

+ 1 - 1
src/options.ts

@@ -23,7 +23,7 @@ export const globalDefaults = {
   weekNumbers: false,
   weekNumberCalculation: 'local',
 
-  // editable: false,
+  editable: false,
 
   // nowIndicator: false,
 

+ 11 - 0
src/util/object.ts

@@ -103,6 +103,17 @@ export function filterHash(hash, func) {
 }
 
 
+export function mapHash(hash, func) {
+  let newHash = {}
+
+  for (let key in hash) {
+    newHash[key] = func(hash[key], key)
+  }
+
+  return newHash
+}
+
+
 export function arrayToHash(a): { [key: string]: true } {
   let hash = {}