|
|
@@ -0,0 +1,312 @@
|
|
|
+
|
|
|
+/*
|
|
|
+Caller must:
|
|
|
+- call initSegChronoComponent
|
|
|
+- implement componentFootprintToSegs
|
|
|
+- implement renderFgSegs
|
|
|
+- implement unrenderFgSegs
|
|
|
+- implement renderFill (FillSystemMixin)
|
|
|
+
|
|
|
+This mixin can depend on ChronoComponent:
|
|
|
+- opt
|
|
|
+- _getView
|
|
|
+- filterEventRenderEl
|
|
|
+- eventRangesToEventFootprints
|
|
|
+- eventFootprintsToSegs
|
|
|
+*/
|
|
|
+var SegChronoComponentMixin = $.extend({}, EventRenderingUtilsMixin, FillSystemMixin, {
|
|
|
+
|
|
|
+ segs: null, // the *event* segments currently rendered in the grid. TODO: rename to `eventSegs`
|
|
|
+
|
|
|
+
|
|
|
+ //initSegChronoComponent: function() {
|
|
|
+ // this.initEventRenderingUtils();
|
|
|
+ // this.initFillSystem();
|
|
|
+ //},
|
|
|
+
|
|
|
+
|
|
|
+ renderEventsPayload: function(eventsPayload) {
|
|
|
+ var view = this._getView();
|
|
|
+ var id, eventInstanceGroup;
|
|
|
+ var eventRenderRanges;
|
|
|
+ var eventFootprints;
|
|
|
+ var eventSegs;
|
|
|
+ var bgSegs = [];
|
|
|
+ var fgSegs = [];
|
|
|
+
|
|
|
+ for (id in eventsPayload) {
|
|
|
+ eventInstanceGroup = eventsPayload[id];
|
|
|
+
|
|
|
+ eventRenderRanges = eventInstanceGroup.sliceRenderRanges(view.activeUnzonedRange);
|
|
|
+ eventFootprints = this.eventRangesToEventFootprints(eventRenderRanges);
|
|
|
+ eventSegs = this.eventFootprintsToSegs(eventFootprints);
|
|
|
+
|
|
|
+ if (eventInstanceGroup.getEventDef().hasBgRendering()) {
|
|
|
+ bgSegs.push.apply(bgSegs, // append
|
|
|
+ eventSegs
|
|
|
+ );
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ fgSegs.push.apply(fgSegs, // append
|
|
|
+ eventSegs
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ this.segs = [].concat( // record all segs
|
|
|
+ this.renderBgSegs(bgSegs) || bgSegs,
|
|
|
+ this.renderFgSegs(fgSegs) || fgSegs
|
|
|
+ );
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ // Unrenders all events currently rendered on the grid
|
|
|
+ unrenderEvents: function() {
|
|
|
+ this.handleSegMouseout(); // trigger an eventMouseout if user's mouse is over an event
|
|
|
+
|
|
|
+ this.unrenderFgSegs();
|
|
|
+ this.unrenderBgSegs();
|
|
|
+
|
|
|
+ this.segs = null;
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ // Retrieves all rendered segment objects currently rendered on the grid
|
|
|
+ getEventSegs: function() {
|
|
|
+ return this.segs || [];
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ // Foreground Segment Rendering
|
|
|
+ // ---------------------------------------------------------------------------------------------------------------
|
|
|
+
|
|
|
+
|
|
|
+ // Renders foreground event segments onto the grid. May return a subset of segs that were rendered.
|
|
|
+ renderFgSegs: function(segs) {
|
|
|
+ // subclasses must implement
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ // Unrenders all currently rendered foreground segments
|
|
|
+ unrenderFgSegs: function() {
|
|
|
+ // subclasses must implement
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ // Renders and assigns an `el` property for each foreground event segment.
|
|
|
+ // Only returns segments that successfully rendered.
|
|
|
+ // A utility that subclasses may use.
|
|
|
+ renderFgSegEls: function(segs, disableResizing) {
|
|
|
+ var _this = this;
|
|
|
+ var hasEventRenderHandlers = this.hasPublicHandlers('eventRender');
|
|
|
+ var html = '';
|
|
|
+ var renderedSegs = [];
|
|
|
+ var i;
|
|
|
+
|
|
|
+ if (segs.length) { // don't build an empty html string
|
|
|
+
|
|
|
+ // build a large concatenation of event segment HTML
|
|
|
+ for (i = 0; i < segs.length; i++) {
|
|
|
+ html += this.fgSegHtml(segs[i], disableResizing);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Grab individual elements from the combined HTML string. Use each as the default rendering.
|
|
|
+ // Then, compute the 'el' for each segment. An el might be null if the eventRender callback returned false.
|
|
|
+ $(html).each(function(i, node) {
|
|
|
+ var seg = segs[i];
|
|
|
+ var el = $(node);
|
|
|
+
|
|
|
+ if (hasEventRenderHandlers) { // optimization
|
|
|
+ el = _this.filterEventRenderEl(seg.footprint, el);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (el) {
|
|
|
+ el.data('fc-seg', seg); // used by handlers
|
|
|
+ seg.el = el;
|
|
|
+ renderedSegs.push(seg);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ return renderedSegs;
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ // Generates the HTML for the default rendering of a foreground event segment. Used by renderFgSegEls()
|
|
|
+ fgSegHtml: function(seg, disableResizing) {
|
|
|
+ // subclasses should implement
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ /* Background Segment Rendering
|
|
|
+ ------------------------------------------------------------------------------------------------------------------*/
|
|
|
+
|
|
|
+
|
|
|
+ // Renders the given background event segments onto the grid.
|
|
|
+ // Returns a subset of the segs that were actually rendered.
|
|
|
+ renderBgSegs: function(segs) {
|
|
|
+ return this.renderFill('bgEvent', segs);
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ // Unrenders all the currently rendered background event segments
|
|
|
+ unrenderBgSegs: function() {
|
|
|
+ this.unrenderFill('bgEvent');
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ // Renders a background event element, given the default rendering. Called by the fill system.
|
|
|
+ // NEEDED BY FILL SYSTEM, renderFillSegEls :(
|
|
|
+ bgEventSegEl: function(seg, el) {
|
|
|
+ return this.filterEventRenderEl(seg.footprint, el);
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ // Generates an array of classNames to be used for the default rendering of a background event.
|
|
|
+ // NEEDED BY FILL SYSTEM, fillSegHtml :(
|
|
|
+ bgEventSegClasses: function(seg) {
|
|
|
+ return this.getBgEventFootprintClasses(seg.footprint);
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ // Generates a semicolon-separated CSS string to be used for the default rendering of a background event.
|
|
|
+ // NEEDED BY FILL SYSTEM, fillSegHtml :(
|
|
|
+ bgEventSegCss: function(seg) {
|
|
|
+ return {
|
|
|
+ 'background-color': this.getEventFootprintSkinCss(seg.footprint)['background-color']
|
|
|
+ };
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ /* Implement Highlight
|
|
|
+ ------------------------------------------------------------------------------------------------------------------*/
|
|
|
+
|
|
|
+
|
|
|
+ // Renders an emphasis on the given date range. Given a span (unzoned start/end and other misc data)
|
|
|
+ renderHighlight: function(componentFootprint) {
|
|
|
+ this.renderFill('highlight', this.componentFootprintToSegs(componentFootprint));
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ // Unrenders the emphasis on a date range
|
|
|
+ unrenderHighlight: function() {
|
|
|
+ this.unrenderFill('highlight');
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ // Generates an array of classNames for rendering the highlight.
|
|
|
+ // USED BY THE FILL SYSTEM, fillSegHtml
|
|
|
+ highlightSegClasses: function() {
|
|
|
+ return [ 'fc-highlight' ];
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ /* Utils
|
|
|
+ ------------------------------------------------------------------------------------------------------------------*/
|
|
|
+
|
|
|
+
|
|
|
+ // Generic utility for generating the HTML classNames for an event segment's element
|
|
|
+ getSegClasses: function(seg, isDraggable, isResizable) {
|
|
|
+ var view = this._getView();
|
|
|
+ var classes = [
|
|
|
+ 'fc-event',
|
|
|
+ seg.isStart ? 'fc-start' : 'fc-not-start',
|
|
|
+ seg.isEnd ? 'fc-end' : 'fc-not-end'
|
|
|
+ ].concat(this.getEventFootprintClasses(seg.footprint));
|
|
|
+
|
|
|
+ if (isDraggable) {
|
|
|
+ classes.push('fc-draggable');
|
|
|
+ }
|
|
|
+ if (isResizable) {
|
|
|
+ classes.push('fc-resizable');
|
|
|
+ }
|
|
|
+
|
|
|
+ // event is currently selected? attach a className.
|
|
|
+ if (view.isEventDefSelected(seg.footprint.eventDef)) {
|
|
|
+ classes.push('fc-selected');
|
|
|
+ }
|
|
|
+
|
|
|
+ return classes;
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ sortEventSegs: function(segs) {
|
|
|
+ segs.sort(proxy(this, 'compareEventSegs'));
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ // A cmp function for determining which segments should take visual priority
|
|
|
+ compareEventSegs: function(seg1, seg2) {
|
|
|
+ var view = this._getView(); // TODO: not optimal!
|
|
|
+ var f1 = seg1.footprint.componentFootprint;
|
|
|
+ var r1 = f1.unzonedRange;
|
|
|
+ var f2 = seg2.footprint.componentFootprint;
|
|
|
+ var r2 = f2.unzonedRange;
|
|
|
+
|
|
|
+ return r1.startMs - r2.startMs || // earlier events go first
|
|
|
+ (r2.endMs - r2.startMs) - (r1.endMs - r1.startMs) || // tie? longer events go first
|
|
|
+ f2.isAllDay - f1.isAllDay || // tie? put all-day events first (booleans cast to 0/1)
|
|
|
+ compareByFieldSpecs(
|
|
|
+ seg1.footprint.eventDef,
|
|
|
+ seg2.footprint.eventDef,
|
|
|
+ view.eventOrderSpecs
|
|
|
+ );
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ /* Converting componentFootprint/eventFootprint -> segs
|
|
|
+ ------------------------------------------------------------------------------------------------------------------*/
|
|
|
+
|
|
|
+
|
|
|
+ eventFootprintsToSegs: function(eventFootprints) {
|
|
|
+ var segs = [];
|
|
|
+ var i;
|
|
|
+
|
|
|
+ for (i = 0; i < eventFootprints.length; i++) {
|
|
|
+ segs.push.apply(segs,
|
|
|
+ this.eventFootprintToSegs(eventFootprints[i])
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ return segs;
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ // Given an event's span (unzoned start/end and other misc data), and the event itself,
|
|
|
+ // slices into segments and attaches event-derived properties to them.
|
|
|
+ // eventSpan - { start, end, isStart, isEnd, otherthings... }
|
|
|
+ // constraintRange allow additional clipping. optional. eventually remove this.
|
|
|
+ eventFootprintToSegs: function(eventFootprint, constraintRange) {
|
|
|
+ var unzonedRange = eventFootprint.componentFootprint.unzonedRange;
|
|
|
+ var segs;
|
|
|
+ var i, seg;
|
|
|
+
|
|
|
+ if (constraintRange) {
|
|
|
+ unzonedRange = unzonedRange.intersect(constraintRange);
|
|
|
+ }
|
|
|
+
|
|
|
+ segs = this.componentFootprintToSegs(eventFootprint.componentFootprint);
|
|
|
+
|
|
|
+ for (i = 0; i < segs.length; i++) {
|
|
|
+ seg = segs[i];
|
|
|
+
|
|
|
+ if (!unzonedRange.isStart) {
|
|
|
+ seg.isStart = false;
|
|
|
+ }
|
|
|
+ if (!unzonedRange.isEnd) {
|
|
|
+ seg.isEnd = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ seg.footprint = eventFootprint;
|
|
|
+ // TODO: rename to seg.eventFootprint
|
|
|
+ }
|
|
|
+
|
|
|
+ return segs;
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ componentFootprintToSegs: function(componentFootprint) {
|
|
|
+ // subclasses must implement
|
|
|
+ }
|
|
|
+
|
|
|
+});
|