aboutsummaryrefslogtreecommitdiffstats
path: root/library/fullcalendar/packages/timegrid/main.esm.js
diff options
context:
space:
mode:
Diffstat (limited to 'library/fullcalendar/packages/timegrid/main.esm.js')
-rw-r--r--library/fullcalendar/packages/timegrid/main.esm.js1391
1 files changed, 1391 insertions, 0 deletions
diff --git a/library/fullcalendar/packages/timegrid/main.esm.js b/library/fullcalendar/packages/timegrid/main.esm.js
new file mode 100644
index 000000000..7038488f4
--- /dev/null
+++ b/library/fullcalendar/packages/timegrid/main.esm.js
@@ -0,0 +1,1391 @@
+/*!
+FullCalendar Time Grid Plugin v4.4.2
+Docs & License: https://fullcalendar.io/
+(c) 2019 Adam Shaw
+*/
+
+import { createFormatter, removeElement, computeEventDraggable, computeEventStartResizable, computeEventEndResizable, cssToStr, isMultiDayRange, htmlEscape, compareByFieldSpecs, applyStyle, FgEventRenderer, buildSegCompareObj, FillRenderer, memoize, memoizeRendering, createDuration, wholeDivideDurations, findElements, PositionCache, startOfDay, asRoughMs, formatIsoTimeString, addDurations, htmlToElement, createElement, multiplyDuration, DateComponent, hasBgRendering, Splitter, diffDays, buildGotoAnchorHtml, getAllDayHtml, ScrollComponent, matchCellWidths, uncompensateScroll, compensateScroll, subtractInnerElHeight, View, intersectRanges, Slicer, DayHeader, DaySeries, DayTable, createPlugin } from '@fullcalendar/core';
+import { DayBgRow, DayGrid, SimpleDayGrid } from '@fullcalendar/daygrid';
+
+/*! *****************************************************************************
+Copyright (c) Microsoft Corporation.
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+***************************************************************************** */
+/* global Reflect, Promise */
+
+var extendStatics = function(d, b) {
+ extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return extendStatics(d, b);
+};
+
+function __extends(d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+}
+
+var __assign = function() {
+ __assign = Object.assign || function __assign(t) {
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
+ s = arguments[i];
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
+ }
+ return t;
+ };
+ return __assign.apply(this, arguments);
+};
+
+/*
+Only handles foreground segs.
+Does not own rendering. Use for low-level util methods by TimeGrid.
+*/
+var TimeGridEventRenderer = /** @class */ (function (_super) {
+ __extends(TimeGridEventRenderer, _super);
+ function TimeGridEventRenderer(timeGrid) {
+ var _this = _super.call(this) || this;
+ _this.timeGrid = timeGrid;
+ return _this;
+ }
+ TimeGridEventRenderer.prototype.renderSegs = function (context, segs, mirrorInfo) {
+ _super.prototype.renderSegs.call(this, context, segs, mirrorInfo);
+ // TODO: dont do every time. memoize
+ this.fullTimeFormat = createFormatter({
+ hour: 'numeric',
+ minute: '2-digit',
+ separator: this.context.options.defaultRangeSeparator
+ });
+ };
+ // Given an array of foreground segments, render a DOM element for each, computes position,
+ // and attaches to the column inner-container elements.
+ TimeGridEventRenderer.prototype.attachSegs = function (segs, mirrorInfo) {
+ var segsByCol = this.timeGrid.groupSegsByCol(segs);
+ // order the segs within each column
+ // TODO: have groupSegsByCol do this?
+ for (var col = 0; col < segsByCol.length; col++) {
+ segsByCol[col] = this.sortEventSegs(segsByCol[col]);
+ }
+ this.segsByCol = segsByCol;
+ this.timeGrid.attachSegsByCol(segsByCol, this.timeGrid.fgContainerEls);
+ };
+ TimeGridEventRenderer.prototype.detachSegs = function (segs) {
+ segs.forEach(function (seg) {
+ removeElement(seg.el);
+ });
+ this.segsByCol = null;
+ };
+ TimeGridEventRenderer.prototype.computeSegSizes = function (allSegs) {
+ var _a = this, timeGrid = _a.timeGrid, segsByCol = _a.segsByCol;
+ var colCnt = timeGrid.colCnt;
+ timeGrid.computeSegVerticals(allSegs); // horizontals relies on this
+ if (segsByCol) {
+ for (var col = 0; col < colCnt; col++) {
+ this.computeSegHorizontals(segsByCol[col]); // compute horizontal coordinates, z-index's, and reorder the array
+ }
+ }
+ };
+ TimeGridEventRenderer.prototype.assignSegSizes = function (allSegs) {
+ var _a = this, timeGrid = _a.timeGrid, segsByCol = _a.segsByCol;
+ var colCnt = timeGrid.colCnt;
+ timeGrid.assignSegVerticals(allSegs); // horizontals relies on this
+ if (segsByCol) {
+ for (var col = 0; col < colCnt; col++) {
+ this.assignSegCss(segsByCol[col]);
+ }
+ }
+ };
+ // Computes a default event time formatting string if `eventTimeFormat` is not explicitly defined
+ TimeGridEventRenderer.prototype.computeEventTimeFormat = function () {
+ return {
+ hour: 'numeric',
+ minute: '2-digit',
+ meridiem: false
+ };
+ };
+ // Computes a default `displayEventEnd` value if one is not expliclty defined
+ TimeGridEventRenderer.prototype.computeDisplayEventEnd = function () {
+ return true;
+ };
+ // Renders the HTML for a single event segment's default rendering
+ TimeGridEventRenderer.prototype.renderSegHtml = function (seg, mirrorInfo) {
+ var eventRange = seg.eventRange;
+ var eventDef = eventRange.def;
+ var eventUi = eventRange.ui;
+ var allDay = eventDef.allDay;
+ var isDraggable = computeEventDraggable(this.context, eventDef, eventUi);
+ var isResizableFromStart = seg.isStart && computeEventStartResizable(this.context, eventDef, eventUi);
+ var isResizableFromEnd = seg.isEnd && computeEventEndResizable(this.context, eventDef, eventUi);
+ var classes = this.getSegClasses(seg, isDraggable, isResizableFromStart || isResizableFromEnd, mirrorInfo);
+ var skinCss = cssToStr(this.getSkinCss(eventUi));
+ var timeText;
+ var fullTimeText; // more verbose time text. for the print stylesheet
+ var startTimeText; // just the start time text
+ classes.unshift('fc-time-grid-event');
+ // if the event appears to span more than one day...
+ if (isMultiDayRange(eventRange.range)) {
+ // Don't display time text on segments that run entirely through a day.
+ // That would appear as midnight-midnight and would look dumb.
+ // Otherwise, display the time text for the *segment's* times (like 6pm-midnight or midnight-10am)
+ if (seg.isStart || seg.isEnd) {
+ var unzonedStart = seg.start;
+ var unzonedEnd = seg.end;
+ timeText = this._getTimeText(unzonedStart, unzonedEnd, allDay); // TODO: give the timezones
+ fullTimeText = this._getTimeText(unzonedStart, unzonedEnd, allDay, this.fullTimeFormat);
+ startTimeText = this._getTimeText(unzonedStart, unzonedEnd, allDay, null, false); // displayEnd=false
+ }
+ }
+ else {
+ // Display the normal time text for the *event's* times
+ timeText = this.getTimeText(eventRange);
+ fullTimeText = this.getTimeText(eventRange, this.fullTimeFormat);
+ startTimeText = this.getTimeText(eventRange, null, false); // displayEnd=false
+ }
+ return '<a class="' + classes.join(' ') + '"' +
+ (eventDef.url ?
+ ' href="' + htmlEscape(eventDef.url) + '"' :
+ '') +
+ (skinCss ?
+ ' style="' + skinCss + '"' :
+ '') +
+ '>' +
+ '<div class="fc-content">' +
+ (timeText ?
+ '<div class="fc-time"' +
+ ' data-start="' + htmlEscape(startTimeText) + '"' +
+ ' data-full="' + htmlEscape(fullTimeText) + '"' +
+ '>' +
+ '<span>' + htmlEscape(timeText) + '</span>' +
+ '</div>' :
+ '') +
+ (eventDef.title ?
+ '<div class="fc-title">' +
+ htmlEscape(eventDef.title) +
+ '</div>' :
+ '') +
+ '</div>' +
+ /* TODO: write CSS for this
+ (isResizableFromStart ?
+ '<div class="fc-resizer fc-start-resizer"></div>' :
+ ''
+ ) +
+ */
+ (isResizableFromEnd ?
+ '<div class="fc-resizer fc-end-resizer"></div>' :
+ '') +
+ '</a>';
+ };
+ // Given an array of segments that are all in the same column, sets the backwardCoord and forwardCoord on each.
+ // Assumed the segs are already ordered.
+ // NOTE: Also reorders the given array by date!
+ TimeGridEventRenderer.prototype.computeSegHorizontals = function (segs) {
+ var levels;
+ var level0;
+ var i;
+ levels = buildSlotSegLevels(segs);
+ computeForwardSlotSegs(levels);
+ if ((level0 = levels[0])) {
+ for (i = 0; i < level0.length; i++) {
+ computeSlotSegPressures(level0[i]);
+ }
+ for (i = 0; i < level0.length; i++) {
+ this.computeSegForwardBack(level0[i], 0, 0);
+ }
+ }
+ };
+ // Calculate seg.forwardCoord and seg.backwardCoord for the segment, where both values range
+ // from 0 to 1. If the calendar is left-to-right, the seg.backwardCoord maps to "left" and
+ // seg.forwardCoord maps to "right" (via percentage). Vice-versa if the calendar is right-to-left.
+ //
+ // The segment might be part of a "series", which means consecutive segments with the same pressure
+ // who's width is unknown until an edge has been hit. `seriesBackwardPressure` is the number of
+ // segments behind this one in the current series, and `seriesBackwardCoord` is the starting
+ // coordinate of the first segment in the series.
+ TimeGridEventRenderer.prototype.computeSegForwardBack = function (seg, seriesBackwardPressure, seriesBackwardCoord) {
+ var forwardSegs = seg.forwardSegs;
+ var i;
+ if (seg.forwardCoord === undefined) { // not already computed
+ if (!forwardSegs.length) {
+ // if there are no forward segments, this segment should butt up against the edge
+ seg.forwardCoord = 1;
+ }
+ else {
+ // sort highest pressure first
+ this.sortForwardSegs(forwardSegs);
+ // this segment's forwardCoord will be calculated from the backwardCoord of the
+ // highest-pressure forward segment.
+ this.computeSegForwardBack(forwardSegs[0], seriesBackwardPressure + 1, seriesBackwardCoord);
+ seg.forwardCoord = forwardSegs[0].backwardCoord;
+ }
+ // calculate the backwardCoord from the forwardCoord. consider the series
+ seg.backwardCoord = seg.forwardCoord -
+ (seg.forwardCoord - seriesBackwardCoord) / // available width for series
+ (seriesBackwardPressure + 1); // # of segments in the series
+ // use this segment's coordinates to computed the coordinates of the less-pressurized
+ // forward segments
+ for (i = 0; i < forwardSegs.length; i++) {
+ this.computeSegForwardBack(forwardSegs[i], 0, seg.forwardCoord);
+ }
+ }
+ };
+ TimeGridEventRenderer.prototype.sortForwardSegs = function (forwardSegs) {
+ var objs = forwardSegs.map(buildTimeGridSegCompareObj);
+ var specs = [
+ // put higher-pressure first
+ { field: 'forwardPressure', order: -1 },
+ // put segments that are closer to initial edge first (and favor ones with no coords yet)
+ { field: 'backwardCoord', order: 1 }
+ ].concat(this.context.eventOrderSpecs);
+ objs.sort(function (obj0, obj1) {
+ return compareByFieldSpecs(obj0, obj1, specs);
+ });
+ return objs.map(function (c) {
+ return c._seg;
+ });
+ };
+ // Given foreground event segments that have already had their position coordinates computed,
+ // assigns position-related CSS values to their elements.
+ TimeGridEventRenderer.prototype.assignSegCss = function (segs) {
+ for (var _i = 0, segs_1 = segs; _i < segs_1.length; _i++) {
+ var seg = segs_1[_i];
+ applyStyle(seg.el, this.generateSegCss(seg));
+ if (seg.level > 0) {
+ seg.el.classList.add('fc-time-grid-event-inset');
+ }
+ // if the event is short that the title will be cut off,
+ // attach a className that condenses the title into the time area.
+ if (seg.eventRange.def.title && seg.bottom - seg.top < 30) {
+ seg.el.classList.add('fc-short'); // TODO: "condensed" is a better name
+ }
+ }
+ };
+ // Generates an object with CSS properties/values that should be applied to an event segment element.
+ // Contains important positioning-related properties that should be applied to any event element, customized or not.
+ TimeGridEventRenderer.prototype.generateSegCss = function (seg) {
+ var shouldOverlap = this.context.options.slotEventOverlap;
+ var backwardCoord = seg.backwardCoord; // the left side if LTR. the right side if RTL. floating-point
+ var forwardCoord = seg.forwardCoord; // the right side if LTR. the left side if RTL. floating-point
+ var props = this.timeGrid.generateSegVerticalCss(seg); // get top/bottom first
+ var isRtl = this.context.isRtl;
+ var left; // amount of space from left edge, a fraction of the total width
+ var right; // amount of space from right edge, a fraction of the total width
+ if (shouldOverlap) {
+ // double the width, but don't go beyond the maximum forward coordinate (1.0)
+ forwardCoord = Math.min(1, backwardCoord + (forwardCoord - backwardCoord) * 2);
+ }
+ if (isRtl) {
+ left = 1 - forwardCoord;
+ right = backwardCoord;
+ }
+ else {
+ left = backwardCoord;
+ right = 1 - forwardCoord;
+ }
+ props.zIndex = seg.level + 1; // convert from 0-base to 1-based
+ props.left = left * 100 + '%';
+ props.right = right * 100 + '%';
+ if (shouldOverlap && seg.forwardPressure) {
+ // add padding to the edge so that forward stacked events don't cover the resizer's icon
+ props[isRtl ? 'marginLeft' : 'marginRight'] = 10 * 2; // 10 is a guesstimate of the icon's width
+ }
+ return props;
+ };
+ return TimeGridEventRenderer;
+}(FgEventRenderer));
+// Builds an array of segments "levels". The first level will be the leftmost tier of segments if the calendar is
+// left-to-right, or the rightmost if the calendar is right-to-left. Assumes the segments are already ordered by date.
+function buildSlotSegLevels(segs) {
+ var levels = [];
+ var i;
+ var seg;
+ var j;
+ for (i = 0; i < segs.length; i++) {
+ seg = segs[i];
+ // go through all the levels and stop on the first level where there are no collisions
+ for (j = 0; j < levels.length; j++) {
+ if (!computeSlotSegCollisions(seg, levels[j]).length) {
+ break;
+ }
+ }
+ seg.level = j;
+ (levels[j] || (levels[j] = [])).push(seg);
+ }
+ return levels;
+}
+// For every segment, figure out the other segments that are in subsequent
+// levels that also occupy the same vertical space. Accumulate in seg.forwardSegs
+function computeForwardSlotSegs(levels) {
+ var i;
+ var level;
+ var j;
+ var seg;
+ var k;
+ for (i = 0; i < levels.length; i++) {
+ level = levels[i];
+ for (j = 0; j < level.length; j++) {
+ seg = level[j];
+ seg.forwardSegs = [];
+ for (k = i + 1; k < levels.length; k++) {
+ computeSlotSegCollisions(seg, levels[k], seg.forwardSegs);
+ }
+ }
+ }
+}
+// Figure out which path forward (via seg.forwardSegs) results in the longest path until
+// the furthest edge is reached. The number of segments in this path will be seg.forwardPressure
+function computeSlotSegPressures(seg) {
+ var forwardSegs = seg.forwardSegs;
+ var forwardPressure = 0;
+ var i;
+ var forwardSeg;
+ if (seg.forwardPressure === undefined) { // not already computed
+ for (i = 0; i < forwardSegs.length; i++) {
+ forwardSeg = forwardSegs[i];
+ // figure out the child's maximum forward path
+ computeSlotSegPressures(forwardSeg);
+ // either use the existing maximum, or use the child's forward pressure
+ // plus one (for the forwardSeg itself)
+ forwardPressure = Math.max(forwardPressure, 1 + forwardSeg.forwardPressure);
+ }
+ seg.forwardPressure = forwardPressure;
+ }
+}
+// Find all the segments in `otherSegs` that vertically collide with `seg`.
+// Append into an optionally-supplied `results` array and return.
+function computeSlotSegCollisions(seg, otherSegs, results) {
+ if (results === void 0) { results = []; }
+ for (var i = 0; i < otherSegs.length; i++) {
+ if (isSlotSegCollision(seg, otherSegs[i])) {
+ results.push(otherSegs[i]);
+ }
+ }
+ return results;
+}
+// Do these segments occupy the same vertical space?
+function isSlotSegCollision(seg1, seg2) {
+ return seg1.bottom > seg2.top && seg1.top < seg2.bottom;
+}
+function buildTimeGridSegCompareObj(seg) {
+ var obj = buildSegCompareObj(seg);
+ obj.forwardPressure = seg.forwardPressure;
+ obj.backwardCoord = seg.backwardCoord;
+ return obj;
+}
+
+var TimeGridMirrorRenderer = /** @class */ (function (_super) {
+ __extends(TimeGridMirrorRenderer, _super);
+ function TimeGridMirrorRenderer() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ TimeGridMirrorRenderer.prototype.attachSegs = function (segs, mirrorInfo) {
+ this.segsByCol = this.timeGrid.groupSegsByCol(segs);
+ this.timeGrid.attachSegsByCol(this.segsByCol, this.timeGrid.mirrorContainerEls);
+ this.sourceSeg = mirrorInfo.sourceSeg;
+ };
+ TimeGridMirrorRenderer.prototype.generateSegCss = function (seg) {
+ var props = _super.prototype.generateSegCss.call(this, seg);
+ var sourceSeg = this.sourceSeg;
+ if (sourceSeg && sourceSeg.col === seg.col) {
+ var sourceSegProps = _super.prototype.generateSegCss.call(this, sourceSeg);
+ props.left = sourceSegProps.left;
+ props.right = sourceSegProps.right;
+ props.marginLeft = sourceSegProps.marginLeft;
+ props.marginRight = sourceSegProps.marginRight;
+ }
+ return props;
+ };
+ return TimeGridMirrorRenderer;
+}(TimeGridEventRenderer));
+
+var TimeGridFillRenderer = /** @class */ (function (_super) {
+ __extends(TimeGridFillRenderer, _super);
+ function TimeGridFillRenderer(timeGrid) {
+ var _this = _super.call(this) || this;
+ _this.timeGrid = timeGrid;
+ return _this;
+ }
+ TimeGridFillRenderer.prototype.attachSegs = function (type, segs) {
+ var timeGrid = this.timeGrid;
+ var containerEls;
+ // TODO: more efficient lookup
+ if (type === 'bgEvent') {
+ containerEls = timeGrid.bgContainerEls;
+ }
+ else if (type === 'businessHours') {
+ containerEls = timeGrid.businessContainerEls;
+ }
+ else if (type === 'highlight') {
+ containerEls = timeGrid.highlightContainerEls;
+ }
+ timeGrid.attachSegsByCol(timeGrid.groupSegsByCol(segs), containerEls);
+ return segs.map(function (seg) {
+ return seg.el;
+ });
+ };
+ TimeGridFillRenderer.prototype.computeSegSizes = function (segs) {
+ this.timeGrid.computeSegVerticals(segs);
+ };
+ TimeGridFillRenderer.prototype.assignSegSizes = function (segs) {
+ this.timeGrid.assignSegVerticals(segs);
+ };
+ return TimeGridFillRenderer;
+}(FillRenderer));
+
+/* A component that renders one or more columns of vertical time slots
+----------------------------------------------------------------------------------------------------------------------*/
+// potential nice values for the slot-duration and interval-duration
+// from largest to smallest
+var AGENDA_STOCK_SUB_DURATIONS = [
+ { hours: 1 },
+ { minutes: 30 },
+ { minutes: 15 },
+ { seconds: 30 },
+ { seconds: 15 }
+];
+var TimeGrid = /** @class */ (function (_super) {
+ __extends(TimeGrid, _super);
+ function TimeGrid(el, renderProps) {
+ var _this = _super.call(this, el) || this;
+ _this.isSlatSizesDirty = false;
+ _this.isColSizesDirty = false;
+ _this.processOptions = memoize(_this._processOptions);
+ _this.renderSkeleton = memoizeRendering(_this._renderSkeleton);
+ _this.renderSlats = memoizeRendering(_this._renderSlats, null, [_this.renderSkeleton]);
+ _this.renderColumns = memoizeRendering(_this._renderColumns, _this._unrenderColumns, [_this.renderSkeleton]);
+ _this.renderProps = renderProps;
+ var renderColumns = _this.renderColumns;
+ var eventRenderer = _this.eventRenderer = new TimeGridEventRenderer(_this);
+ var fillRenderer = _this.fillRenderer = new TimeGridFillRenderer(_this);
+ _this.mirrorRenderer = new TimeGridMirrorRenderer(_this);
+ _this.renderBusinessHours = memoizeRendering(fillRenderer.renderSegs.bind(fillRenderer, 'businessHours'), fillRenderer.unrender.bind(fillRenderer, 'businessHours'), [renderColumns]);
+ _this.renderDateSelection = memoizeRendering(_this._renderDateSelection, _this._unrenderDateSelection, [renderColumns]);
+ _this.renderFgEvents = memoizeRendering(eventRenderer.renderSegs.bind(eventRenderer), eventRenderer.unrender.bind(eventRenderer), [renderColumns]);
+ _this.renderBgEvents = memoizeRendering(fillRenderer.renderSegs.bind(fillRenderer, 'bgEvent'), fillRenderer.unrender.bind(fillRenderer, 'bgEvent'), [renderColumns]);
+ _this.renderEventSelection = memoizeRendering(eventRenderer.selectByInstanceId.bind(eventRenderer), eventRenderer.unselectByInstanceId.bind(eventRenderer), [_this.renderFgEvents]);
+ _this.renderEventDrag = memoizeRendering(_this._renderEventDrag, _this._unrenderEventDrag, [renderColumns]);
+ _this.renderEventResize = memoizeRendering(_this._renderEventResize, _this._unrenderEventResize, [renderColumns]);
+ return _this;
+ }
+ /* Options
+ ------------------------------------------------------------------------------------------------------------------*/
+ // Parses various options into properties of this object
+ // MUST have context already set
+ TimeGrid.prototype._processOptions = function (options) {
+ var slotDuration = options.slotDuration, snapDuration = options.snapDuration;
+ var snapsPerSlot;
+ var input;
+ slotDuration = createDuration(slotDuration);
+ snapDuration = snapDuration ? createDuration(snapDuration) : slotDuration;
+ snapsPerSlot = wholeDivideDurations(slotDuration, snapDuration);
+ if (snapsPerSlot === null) {
+ snapDuration = slotDuration;
+ snapsPerSlot = 1;
+ // TODO: say warning?
+ }
+ this.slotDuration = slotDuration;
+ this.snapDuration = snapDuration;
+ this.snapsPerSlot = snapsPerSlot;
+ // might be an array value (for TimelineView).
+ // if so, getting the most granular entry (the last one probably).
+ input = options.slotLabelFormat;
+ if (Array.isArray(input)) {
+ input = input[input.length - 1];
+ }
+ this.labelFormat = createFormatter(input || {
+ hour: 'numeric',
+ minute: '2-digit',
+ omitZeroMinute: true,
+ meridiem: 'short'
+ });
+ input = options.slotLabelInterval;
+ this.labelInterval = input ?
+ createDuration(input) :
+ this.computeLabelInterval(slotDuration);
+ };
+ // Computes an automatic value for slotLabelInterval
+ TimeGrid.prototype.computeLabelInterval = function (slotDuration) {
+ var i;
+ var labelInterval;
+ var slotsPerLabel;
+ // find the smallest stock label interval that results in more than one slots-per-label
+ for (i = AGENDA_STOCK_SUB_DURATIONS.length - 1; i >= 0; i--) {
+ labelInterval = createDuration(AGENDA_STOCK_SUB_DURATIONS[i]);
+ slotsPerLabel = wholeDivideDurations(labelInterval, slotDuration);
+ if (slotsPerLabel !== null && slotsPerLabel > 1) {
+ return labelInterval;
+ }
+ }
+ return slotDuration; // fall back
+ };
+ /* Rendering
+ ------------------------------------------------------------------------------------------------------------------*/
+ TimeGrid.prototype.render = function (props, context) {
+ this.processOptions(context.options);
+ var cells = props.cells;
+ this.colCnt = cells.length;
+ this.renderSkeleton(context.theme);
+ this.renderSlats(props.dateProfile);
+ this.renderColumns(props.cells, props.dateProfile);
+ this.renderBusinessHours(context, props.businessHourSegs);
+ this.renderDateSelection(props.dateSelectionSegs);
+ this.renderFgEvents(context, props.fgEventSegs);
+ this.renderBgEvents(context, props.bgEventSegs);
+ this.renderEventSelection(props.eventSelection);
+ this.renderEventDrag(props.eventDrag);
+ this.renderEventResize(props.eventResize);
+ };
+ TimeGrid.prototype.destroy = function () {
+ _super.prototype.destroy.call(this);
+ // should unrender everything else too
+ this.renderSlats.unrender();
+ this.renderColumns.unrender();
+ this.renderSkeleton.unrender();
+ };
+ TimeGrid.prototype.updateSize = function (isResize) {
+ var _a = this, fillRenderer = _a.fillRenderer, eventRenderer = _a.eventRenderer, mirrorRenderer = _a.mirrorRenderer;
+ if (isResize || this.isSlatSizesDirty) {
+ this.buildSlatPositions();
+ this.isSlatSizesDirty = false;
+ }
+ if (isResize || this.isColSizesDirty) {
+ this.buildColPositions();
+ this.isColSizesDirty = false;
+ }
+ fillRenderer.computeSizes(isResize);
+ eventRenderer.computeSizes(isResize);
+ mirrorRenderer.computeSizes(isResize);
+ fillRenderer.assignSizes(isResize);
+ eventRenderer.assignSizes(isResize);
+ mirrorRenderer.assignSizes(isResize);
+ };
+ TimeGrid.prototype._renderSkeleton = function (theme) {
+ var el = this.el;
+ el.innerHTML =
+ '<div class="fc-bg"></div>' +
+ '<div class="fc-slats"></div>' +
+ '<hr class="fc-divider ' + theme.getClass('widgetHeader') + '" style="display:none" />';
+ this.rootBgContainerEl = el.querySelector('.fc-bg');
+ this.slatContainerEl = el.querySelector('.fc-slats');
+ this.bottomRuleEl = el.querySelector('.fc-divider');
+ };
+ TimeGrid.prototype._renderSlats = function (dateProfile) {
+ var theme = this.context.theme;
+ this.slatContainerEl.innerHTML =
+ '<table class="' + theme.getClass('tableGrid') + '">' +
+ this.renderSlatRowHtml(dateProfile) +
+ '</table>';
+ this.slatEls = findElements(this.slatContainerEl, 'tr');
+ this.slatPositions = new PositionCache(this.el, this.slatEls, false, true // vertical
+ );
+ this.isSlatSizesDirty = true;
+ };
+ // Generates the HTML for the horizontal "slats" that run width-wise. Has a time axis on a side. Depends on RTL.
+ TimeGrid.prototype.renderSlatRowHtml = function (dateProfile) {
+ var _a = this.context, dateEnv = _a.dateEnv, theme = _a.theme, isRtl = _a.isRtl;
+ var html = '';
+ var dayStart = startOfDay(dateProfile.renderRange.start);
+ var slotTime = dateProfile.minTime;
+ var slotIterator = createDuration(0);
+ var slotDate; // will be on the view's first day, but we only care about its time
+ var isLabeled;
+ var axisHtml;
+ // Calculate the time for each slot
+ while (asRoughMs(slotTime) < asRoughMs(dateProfile.maxTime)) {
+ slotDate = dateEnv.add(dayStart, slotTime);
+ isLabeled = wholeDivideDurations(slotIterator, this.labelInterval) !== null;
+ axisHtml =
+ '<td class="fc-axis fc-time ' + theme.getClass('widgetContent') + '">' +
+ (isLabeled ?
+ '<span>' + // for matchCellWidths
+ htmlEscape(dateEnv.format(slotDate, this.labelFormat)) +
+ '</span>' :
+ '') +
+ '</td>';
+ html +=
+ '<tr data-time="' + formatIsoTimeString(slotDate) + '"' +
+ (isLabeled ? '' : ' class="fc-minor"') +
+ '>' +
+ (!isRtl ? axisHtml : '') +
+ '<td class="' + theme.getClass('widgetContent') + '"></td>' +
+ (isRtl ? axisHtml : '') +
+ '</tr>';
+ slotTime = addDurations(slotTime, this.slotDuration);
+ slotIterator = addDurations(slotIterator, this.slotDuration);
+ }
+ return html;
+ };
+ TimeGrid.prototype._renderColumns = function (cells, dateProfile) {
+ var _a = this.context, calendar = _a.calendar, view = _a.view, isRtl = _a.isRtl, theme = _a.theme, dateEnv = _a.dateEnv;
+ var bgRow = new DayBgRow(this.context);
+ this.rootBgContainerEl.innerHTML =
+ '<table class="' + theme.getClass('tableGrid') + '">' +
+ bgRow.renderHtml({
+ cells: cells,
+ dateProfile: dateProfile,
+ renderIntroHtml: this.renderProps.renderBgIntroHtml
+ }) +
+ '</table>';
+ this.colEls = findElements(this.el, '.fc-day, .fc-disabled-day');
+ for (var col = 0; col < this.colCnt; col++) {
+ calendar.publiclyTrigger('dayRender', [
+ {
+ date: dateEnv.toDate(cells[col].date),
+ el: this.colEls[col],
+ view: view
+ }
+ ]);
+ }
+ if (isRtl) {
+ this.colEls.reverse();
+ }
+ this.colPositions = new PositionCache(this.el, this.colEls, true, // horizontal
+ false);
+ this.renderContentSkeleton();
+ this.isColSizesDirty = true;
+ };
+ TimeGrid.prototype._unrenderColumns = function () {
+ this.unrenderContentSkeleton();
+ };
+ /* Content Skeleton
+ ------------------------------------------------------------------------------------------------------------------*/
+ // Renders the DOM that the view's content will live in
+ TimeGrid.prototype.renderContentSkeleton = function () {
+ var isRtl = this.context.isRtl;
+ var parts = [];
+ var skeletonEl;
+ parts.push(this.renderProps.renderIntroHtml());
+ for (var i = 0; i < this.colCnt; i++) {
+ parts.push('<td>' +
+ '<div class="fc-content-col">' +
+ '<div class="fc-event-container fc-mirror-container"></div>' +
+ '<div class="fc-event-container"></div>' +
+ '<div class="fc-highlight-container"></div>' +
+ '<div class="fc-bgevent-container"></div>' +
+ '<div class="fc-business-container"></div>' +
+ '</div>' +
+ '</td>');
+ }
+ if (isRtl) {
+ parts.reverse();
+ }
+ skeletonEl = this.contentSkeletonEl = htmlToElement('<div class="fc-content-skeleton">' +
+ '<table>' +
+ '<tr>' + parts.join('') + '</tr>' +
+ '</table>' +
+ '</div>');
+ this.colContainerEls = findElements(skeletonEl, '.fc-content-col');
+ this.mirrorContainerEls = findElements(skeletonEl, '.fc-mirror-container');
+ this.fgContainerEls = findElements(skeletonEl, '.fc-event-container:not(.fc-mirror-container)');
+ this.bgContainerEls = findElements(skeletonEl, '.fc-bgevent-container');
+ this.highlightContainerEls = findElements(skeletonEl, '.fc-highlight-container');
+ this.businessContainerEls = findElements(skeletonEl, '.fc-business-container');
+ if (isRtl) {
+ this.colContainerEls.reverse();
+ this.mirrorContainerEls.reverse();
+ this.fgContainerEls.reverse();
+ this.bgContainerEls.reverse();
+ this.highlightContainerEls.reverse();
+ this.businessContainerEls.reverse();
+ }
+ this.el.appendChild(skeletonEl);
+ };
+ TimeGrid.prototype.unrenderContentSkeleton = function () {
+ removeElement(this.contentSkeletonEl);
+ };
+ // Given a flat array of segments, return an array of sub-arrays, grouped by each segment's col
+ TimeGrid.prototype.groupSegsByCol = function (segs) {
+ var segsByCol = [];
+ var i;
+ for (i = 0; i < this.colCnt; i++) {
+ segsByCol.push([]);
+ }
+ for (i = 0; i < segs.length; i++) {
+ segsByCol[segs[i].col].push(segs[i]);
+ }
+ return segsByCol;
+ };
+ // Given segments grouped by column, insert the segments' elements into a parallel array of container
+ // elements, each living within a column.
+ TimeGrid.prototype.attachSegsByCol = function (segsByCol, containerEls) {
+ var col;
+ var segs;
+ var i;
+ for (col = 0; col < this.colCnt; col++) { // iterate each column grouping
+ segs = segsByCol[col];
+ for (i = 0; i < segs.length; i++) {
+ containerEls[col].appendChild(segs[i].el);
+ }
+ }
+ };
+ /* Now Indicator
+ ------------------------------------------------------------------------------------------------------------------*/
+ TimeGrid.prototype.getNowIndicatorUnit = function () {
+ return 'minute'; // will refresh on the minute
+ };
+ TimeGrid.prototype.renderNowIndicator = function (segs, date) {
+ // HACK: if date columns not ready for some reason (scheduler)
+ if (!this.colContainerEls) {
+ return;
+ }
+ var top = this.computeDateTop(date);
+ var nodes = [];
+ var i;
+ // render lines within the columns
+ for (i = 0; i < segs.length; i++) {
+ var lineEl = createElement('div', { className: 'fc-now-indicator fc-now-indicator-line' });
+ lineEl.style.top = top + 'px';
+ this.colContainerEls[segs[i].col].appendChild(lineEl);
+ nodes.push(lineEl);
+ }
+ // render an arrow over the axis
+ if (segs.length > 0) { // is the current time in view?
+ var arrowEl = createElement('div', { className: 'fc-now-indicator fc-now-indicator-arrow' });
+ arrowEl.style.top = top + 'px';
+ this.contentSkeletonEl.appendChild(arrowEl);
+ nodes.push(arrowEl);
+ }
+ this.nowIndicatorEls = nodes;
+ };
+ TimeGrid.prototype.unrenderNowIndicator = function () {
+ if (this.nowIndicatorEls) {
+ this.nowIndicatorEls.forEach(removeElement);
+ this.nowIndicatorEls = null;
+ }
+ };
+ /* Coordinates
+ ------------------------------------------------------------------------------------------------------------------*/
+ TimeGrid.prototype.getTotalSlatHeight = function () {
+ return this.slatContainerEl.getBoundingClientRect().height;
+ };
+ // Computes the top coordinate, relative to the bounds of the grid, of the given date.
+ // A `startOfDayDate` must be given for avoiding ambiguity over how to treat midnight.
+ TimeGrid.prototype.computeDateTop = function (when, startOfDayDate) {
+ if (!startOfDayDate) {
+ startOfDayDate = startOfDay(when);
+ }
+ return this.computeTimeTop(createDuration(when.valueOf() - startOfDayDate.valueOf()));
+ };
+ // Computes the top coordinate, relative to the bounds of the grid, of the given time (a Duration).
+ TimeGrid.prototype.computeTimeTop = function (duration) {
+ var len = this.slatEls.length;
+ var dateProfile = this.props.dateProfile;
+ var slatCoverage = (duration.milliseconds - asRoughMs(dateProfile.minTime)) / asRoughMs(this.slotDuration); // floating-point value of # of slots covered
+ var slatIndex;
+ var slatRemainder;
+ // compute a floating-point number for how many slats should be progressed through.
+ // from 0 to number of slats (inclusive)
+ // constrained because minTime/maxTime might be customized.
+ slatCoverage = Math.max(0, slatCoverage);
+ slatCoverage = Math.min(len, slatCoverage);
+ // an integer index of the furthest whole slat
+ // from 0 to number slats (*exclusive*, so len-1)
+ slatIndex = Math.floor(slatCoverage);
+ slatIndex = Math.min(slatIndex, len - 1);
+ // how much further through the slatIndex slat (from 0.0-1.0) must be covered in addition.
+ // could be 1.0 if slatCoverage is covering *all* the slots
+ slatRemainder = slatCoverage - slatIndex;
+ return this.slatPositions.tops[slatIndex] +
+ this.slatPositions.getHeight(slatIndex) * slatRemainder;
+ };
+ // For each segment in an array, computes and assigns its top and bottom properties
+ TimeGrid.prototype.computeSegVerticals = function (segs) {
+ var options = this.context.options;
+ var eventMinHeight = options.timeGridEventMinHeight;
+ var i;
+ var seg;
+ var dayDate;
+ for (i = 0; i < segs.length; i++) {
+ seg = segs[i];
+ dayDate = this.props.cells[seg.col].date;
+ seg.top = this.computeDateTop(seg.start, dayDate);
+ seg.bottom = Math.max(seg.top + eventMinHeight, this.computeDateTop(seg.end, dayDate));
+ }
+ };
+ // Given segments that already have their top/bottom properties computed, applies those values to
+ // the segments' elements.
+ TimeGrid.prototype.assignSegVerticals = function (segs) {
+ var i;
+ var seg;
+ for (i = 0; i < segs.length; i++) {
+ seg = segs[i];
+ applyStyle(seg.el, this.generateSegVerticalCss(seg));
+ }
+ };
+ // Generates an object with CSS properties for the top/bottom coordinates of a segment element
+ TimeGrid.prototype.generateSegVerticalCss = function (seg) {
+ return {
+ top: seg.top,
+ bottom: -seg.bottom // flipped because needs to be space beyond bottom edge of event container
+ };
+ };
+ /* Sizing
+ ------------------------------------------------------------------------------------------------------------------*/
+ TimeGrid.prototype.buildPositionCaches = function () {
+ this.buildColPositions();
+ this.buildSlatPositions();
+ };
+ TimeGrid.prototype.buildColPositions = function () {
+ this.colPositions.build();
+ };
+ TimeGrid.prototype.buildSlatPositions = function () {
+ this.slatPositions.build();
+ };
+ /* Hit System
+ ------------------------------------------------------------------------------------------------------------------*/
+ TimeGrid.prototype.positionToHit = function (positionLeft, positionTop) {
+ var dateEnv = this.context.dateEnv;
+ var _a = this, snapsPerSlot = _a.snapsPerSlot, slatPositions = _a.slatPositions, colPositions = _a.colPositions;
+ var colIndex = colPositions.leftToIndex(positionLeft);
+ var slatIndex = slatPositions.topToIndex(positionTop);
+ if (colIndex != null && slatIndex != null) {
+ var slatTop = slatPositions.tops[slatIndex];
+ var slatHeight = slatPositions.getHeight(slatIndex);
+ var partial = (positionTop - slatTop) / slatHeight; // floating point number between 0 and 1
+ var localSnapIndex = Math.floor(partial * snapsPerSlot); // the snap # relative to start of slat
+ var snapIndex = slatIndex * snapsPerSlot + localSnapIndex;
+ var dayDate = this.props.cells[colIndex].date;
+ var time = addDurations(this.props.dateProfile.minTime, multiplyDuration(this.snapDuration, snapIndex));
+ var start = dateEnv.add(dayDate, time);
+ var end = dateEnv.add(start, this.snapDuration);
+ return {
+ col: colIndex,
+ dateSpan: {
+ range: { start: start, end: end },
+ allDay: false
+ },
+ dayEl: this.colEls[colIndex],
+ relativeRect: {
+ left: colPositions.lefts[colIndex],
+ right: colPositions.rights[colIndex],
+ top: slatTop,
+ bottom: slatTop + slatHeight
+ }
+ };
+ }
+ };
+ /* Event Drag Visualization
+ ------------------------------------------------------------------------------------------------------------------*/
+ TimeGrid.prototype._renderEventDrag = function (state) {
+ if (state) {
+ this.eventRenderer.hideByHash(state.affectedInstances);
+ if (state.isEvent) {
+ this.mirrorRenderer.renderSegs(this.context, state.segs, { isDragging: true, sourceSeg: state.sourceSeg });
+ }
+ else {
+ this.fillRenderer.renderSegs('highlight', this.context, state.segs);
+ }
+ }
+ };
+ TimeGrid.prototype._unrenderEventDrag = function (state) {
+ if (state) {
+ this.eventRenderer.showByHash(state.affectedInstances);
+ if (state.isEvent) {
+ this.mirrorRenderer.unrender(this.context, state.segs, { isDragging: true, sourceSeg: state.sourceSeg });
+ }
+ else {
+ this.fillRenderer.unrender('highlight', this.context);
+ }
+ }
+ };
+ /* Event Resize Visualization
+ ------------------------------------------------------------------------------------------------------------------*/
+ TimeGrid.prototype._renderEventResize = function (state) {
+ if (state) {
+ this.eventRenderer.hideByHash(state.affectedInstances);
+ this.mirrorRenderer.renderSegs(this.context, state.segs, { isResizing: true, sourceSeg: state.sourceSeg });
+ }
+ };
+ TimeGrid.prototype._unrenderEventResize = function (state) {
+ if (state) {
+ this.eventRenderer.showByHash(state.affectedInstances);
+ this.mirrorRenderer.unrender(this.context, state.segs, { isResizing: true, sourceSeg: state.sourceSeg });
+ }
+ };
+ /* Selection
+ ------------------------------------------------------------------------------------------------------------------*/
+ // Renders a visual indication of a selection. Overrides the default, which was to simply render a highlight.
+ TimeGrid.prototype._renderDateSelection = function (segs) {
+ if (segs) {
+ if (this.context.options.selectMirror) {
+ this.mirrorRenderer.renderSegs(this.context, segs, { isSelecting: true });
+ }
+ else {
+ this.fillRenderer.renderSegs('highlight', this.context, segs);
+ }
+ }
+ };
+ TimeGrid.prototype._unrenderDateSelection = function (segs) {
+ if (segs) {
+ if (this.context.options.selectMirror) {
+ this.mirrorRenderer.unrender(this.context, segs, { isSelecting: true });
+ }
+ else {
+ this.fillRenderer.unrender('highlight', this.context);
+ }
+ }
+ };
+ return TimeGrid;
+}(DateComponent));
+
+var AllDaySplitter = /** @class */ (function (_super) {
+ __extends(AllDaySplitter, _super);
+ function AllDaySplitter() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ AllDaySplitter.prototype.getKeyInfo = function () {
+ return {
+ allDay: {},
+ timed: {}
+ };
+ };
+ AllDaySplitter.prototype.getKeysForDateSpan = function (dateSpan) {
+ if (dateSpan.allDay) {
+ return ['allDay'];
+ }
+ else {
+ return ['timed'];
+ }
+ };
+ AllDaySplitter.prototype.getKeysForEventDef = function (eventDef) {
+ if (!eventDef.allDay) {
+ return ['timed'];
+ }
+ else if (hasBgRendering(eventDef)) {
+ return ['timed', 'allDay'];
+ }
+ else {
+ return ['allDay'];
+ }
+ };
+ return AllDaySplitter;
+}(Splitter));
+
+var TIMEGRID_ALL_DAY_EVENT_LIMIT = 5;
+var WEEK_HEADER_FORMAT = createFormatter({ week: 'short' });
+/* An abstract class for all timegrid-related views. Displays one more columns with time slots running vertically.
+----------------------------------------------------------------------------------------------------------------------*/
+// Is a manager for the TimeGrid subcomponent and possibly the DayGrid subcomponent (if allDaySlot is on).
+// Responsible for managing width/height.
+var AbstractTimeGridView = /** @class */ (function (_super) {
+ __extends(AbstractTimeGridView, _super);
+ function AbstractTimeGridView() {
+ var _this = _super !== null && _super.apply(this, arguments) || this;
+ _this.splitter = new AllDaySplitter();
+ _this.renderSkeleton = memoizeRendering(_this._renderSkeleton, _this._unrenderSkeleton);
+ /* Header Render Methods
+ ------------------------------------------------------------------------------------------------------------------*/
+ // Generates the HTML that will go before the day-of week header cells
+ _this.renderHeadIntroHtml = function () {
+ var _a = _this.context, theme = _a.theme, dateEnv = _a.dateEnv, options = _a.options;
+ var range = _this.props.dateProfile.renderRange;
+ var dayCnt = diffDays(range.start, range.end);
+ var weekText;
+ if (options.weekNumbers) {
+ weekText = dateEnv.format(range.start, WEEK_HEADER_FORMAT);
+ return '' +
+ '<th class="fc-axis fc-week-number ' + theme.getClass('widgetHeader') + '" ' + _this.axisStyleAttr() + '>' +
+ buildGotoAnchorHtml(// aside from link, important for matchCellWidths
+ options, dateEnv, { date: range.start, type: 'week', forceOff: dayCnt > 1 }, htmlEscape(weekText) // inner HTML
+ ) +
+ '</th>';
+ }
+ else {
+ return '<th class="fc-axis ' + theme.getClass('widgetHeader') + '" ' + _this.axisStyleAttr() + '></th>';
+ }
+ };
+ /* Time Grid Render Methods
+ ------------------------------------------------------------------------------------------------------------------*/
+ // Generates the HTML that goes before the bg of the TimeGrid slot area. Long vertical column.
+ _this.renderTimeGridBgIntroHtml = function () {
+ var theme = _this.context.theme;
+ return '<td class="fc-axis ' + theme.getClass('widgetContent') + '" ' + _this.axisStyleAttr() + '></td>';
+ };
+ // Generates the HTML that goes before all other types of cells.
+ // Affects content-skeleton, mirror-skeleton, highlight-skeleton for both the time-grid and day-grid.
+ _this.renderTimeGridIntroHtml = function () {
+ return '<td class="fc-axis" ' + _this.axisStyleAttr() + '></td>';
+ };
+ /* Day Grid Render Methods
+ ------------------------------------------------------------------------------------------------------------------*/
+ // Generates the HTML that goes before the all-day cells
+ _this.renderDayGridBgIntroHtml = function () {
+ var _a = _this.context, theme = _a.theme, options = _a.options;
+ return '' +
+ '<td class="fc-axis ' + theme.getClass('widgetContent') + '" ' + _this.axisStyleAttr() + '>' +
+ '<span>' + // needed for matchCellWidths
+ getAllDayHtml(options) +
+ '</span>' +
+ '</td>';
+ };
+ // Generates the HTML that goes before all other types of cells.
+ // Affects content-skeleton, mirror-skeleton, highlight-skeleton for both the time-grid and day-grid.
+ _this.renderDayGridIntroHtml = function () {
+ return '<td class="fc-axis" ' + _this.axisStyleAttr() + '></td>';
+ };
+ return _this;
+ }
+ AbstractTimeGridView.prototype.render = function (props, context) {
+ _super.prototype.render.call(this, props, context);
+ this.renderSkeleton(context);
+ };
+ AbstractTimeGridView.prototype.destroy = function () {
+ _super.prototype.destroy.call(this);
+ this.renderSkeleton.unrender();
+ };
+ AbstractTimeGridView.prototype._renderSkeleton = function (context) {
+ this.el.classList.add('fc-timeGrid-view');
+ this.el.innerHTML = this.renderSkeletonHtml();
+ this.scroller = new ScrollComponent('hidden', // overflow x
+ 'auto' // overflow y
+ );
+ var timeGridWrapEl = this.scroller.el;
+ this.el.querySelector('.fc-body > tr > td').appendChild(timeGridWrapEl);
+ timeGridWrapEl.classList.add('fc-time-grid-container');
+ var timeGridEl = createElement('div', { className: 'fc-time-grid' });
+ timeGridWrapEl.appendChild(timeGridEl);
+ this.timeGrid = new TimeGrid(timeGridEl, {
+ renderBgIntroHtml: this.renderTimeGridBgIntroHtml,
+ renderIntroHtml: this.renderTimeGridIntroHtml
+ });
+ if (context.options.allDaySlot) { // should we display the "all-day" area?
+ this.dayGrid = new DayGrid(// the all-day subcomponent of this view
+ this.el.querySelector('.fc-day-grid'), {
+ renderNumberIntroHtml: this.renderDayGridIntroHtml,
+ renderBgIntroHtml: this.renderDayGridBgIntroHtml,
+ renderIntroHtml: this.renderDayGridIntroHtml,
+ colWeekNumbersVisible: false,
+ cellWeekNumbersVisible: false
+ });
+ // have the day-grid extend it's coordinate area over the <hr> dividing the two grids
+ var dividerEl = this.el.querySelector('.fc-divider');
+ this.dayGrid.bottomCoordPadding = dividerEl.getBoundingClientRect().height;
+ }
+ };
+ AbstractTimeGridView.prototype._unrenderSkeleton = function () {
+ this.el.classList.remove('fc-timeGrid-view');
+ this.timeGrid.destroy();
+ if (this.dayGrid) {
+ this.dayGrid.destroy();
+ }
+ this.scroller.destroy();
+ };
+ /* Rendering
+ ------------------------------------------------------------------------------------------------------------------*/
+ // Builds the HTML skeleton for the view.
+ // The day-grid and time-grid components will render inside containers defined by this HTML.
+ AbstractTimeGridView.prototype.renderSkeletonHtml = function () {
+ var _a = this.context, theme = _a.theme, options = _a.options;
+ return '' +
+ '<table class="' + theme.getClass('tableGrid') + '">' +
+ (options.columnHeader ?
+ '<thead class="fc-head">' +
+ '<tr>' +
+ '<td class="fc-head-container ' + theme.getClass('widgetHeader') + '">&nbsp;</td>' +
+ '</tr>' +
+ '</thead>' :
+ '') +
+ '<tbody class="fc-body">' +
+ '<tr>' +
+ '<td class="' + theme.getClass('widgetContent') + '">' +
+ (options.allDaySlot ?
+ '<div class="fc-day-grid"></div>' +
+ '<hr class="fc-divider ' + theme.getClass('widgetHeader') + '" />' :
+ '') +
+ '</td>' +
+ '</tr>' +
+ '</tbody>' +
+ '</table>';
+ };
+ /* Now Indicator
+ ------------------------------------------------------------------------------------------------------------------*/
+ AbstractTimeGridView.prototype.getNowIndicatorUnit = function () {
+ return this.timeGrid.getNowIndicatorUnit();
+ };
+ // subclasses should implement
+ // renderNowIndicator(date: DateMarker) {
+ // }
+ AbstractTimeGridView.prototype.unrenderNowIndicator = function () {
+ this.timeGrid.unrenderNowIndicator();
+ };
+ /* Dimensions
+ ------------------------------------------------------------------------------------------------------------------*/
+ AbstractTimeGridView.prototype.updateSize = function (isResize, viewHeight, isAuto) {
+ _super.prototype.updateSize.call(this, isResize, viewHeight, isAuto); // will call updateBaseSize. important that executes first
+ this.timeGrid.updateSize(isResize);
+ if (this.dayGrid) {
+ this.dayGrid.updateSize(isResize);
+ }
+ };
+ // Adjusts the vertical dimensions of the view to the specified values
+ AbstractTimeGridView.prototype.updateBaseSize = function (isResize, viewHeight, isAuto) {
+ var _this = this;
+ var eventLimit;
+ var scrollerHeight;
+ var scrollbarWidths;
+ // make all axis cells line up
+ this.axisWidth = matchCellWidths(findElements(this.el, '.fc-axis'));
+ // hack to give the view some height prior to timeGrid's columns being rendered
+ // TODO: separate setting height from scroller VS timeGrid.
+ if (!this.timeGrid.colEls) {
+ if (!isAuto) {
+ scrollerHeight = this.computeScrollerHeight(viewHeight);
+ this.scroller.setHeight(scrollerHeight);
+ }
+ return;
+ }
+ // set of fake row elements that must compensate when scroller has scrollbars
+ var noScrollRowEls = findElements(this.el, '.fc-row').filter(function (node) {
+ return !_this.scroller.el.contains(node);
+ });
+ // reset all dimensions back to the original state
+ this.timeGrid.bottomRuleEl.style.display = 'none'; // will be shown later if this <hr> is necessary
+ this.scroller.clear(); // sets height to 'auto' and clears overflow
+ noScrollRowEls.forEach(uncompensateScroll);
+ // limit number of events in the all-day area
+ if (this.dayGrid) {
+ this.dayGrid.removeSegPopover(); // kill the "more" popover if displayed
+ eventLimit = this.context.options.eventLimit;
+ if (eventLimit && typeof eventLimit !== 'number') {
+ eventLimit = TIMEGRID_ALL_DAY_EVENT_LIMIT; // make sure "auto" goes to a real number
+ }
+ if (eventLimit) {
+ this.dayGrid.limitRows(eventLimit);
+ }
+ }
+ if (!isAuto) { // should we force dimensions of the scroll container?
+ scrollerHeight = this.computeScrollerHeight(viewHeight);
+ this.scroller.setHeight(scrollerHeight);
+ scrollbarWidths = this.scroller.getScrollbarWidths();
+ if (scrollbarWidths.left || scrollbarWidths.right) { // using scrollbars?
+ // make the all-day and header rows lines up
+ noScrollRowEls.forEach(function (rowEl) {
+ compensateScroll(rowEl, scrollbarWidths);
+ });
+ // the scrollbar compensation might have changed text flow, which might affect height, so recalculate
+ // and reapply the desired height to the scroller.
+ scrollerHeight = this.computeScrollerHeight(viewHeight);
+ this.scroller.setHeight(scrollerHeight);
+ }
+ // guarantees the same scrollbar widths
+ this.scroller.lockOverflow(scrollbarWidths);
+ // if there's any space below the slats, show the horizontal rule.
+ // this won't cause any new overflow, because lockOverflow already called.
+ if (this.timeGrid.getTotalSlatHeight() < scrollerHeight) {
+ this.timeGrid.bottomRuleEl.style.display = '';
+ }
+ }
+ };
+ // given a desired total height of the view, returns what the height of the scroller should be
+ AbstractTimeGridView.prototype.computeScrollerHeight = function (viewHeight) {
+ return viewHeight -
+ subtractInnerElHeight(this.el, this.scroller.el); // everything that's NOT the scroller
+ };
+ /* Scroll
+ ------------------------------------------------------------------------------------------------------------------*/
+ // Computes the initial pre-configured scroll state prior to allowing the user to change it
+ AbstractTimeGridView.prototype.computeDateScroll = function (duration) {
+ var top = this.timeGrid.computeTimeTop(duration);
+ // zoom can give weird floating-point values. rather scroll a little bit further
+ top = Math.ceil(top);
+ if (top) {
+ top++; // to overcome top border that slots beyond the first have. looks better
+ }
+ return { top: top };
+ };
+ AbstractTimeGridView.prototype.queryDateScroll = function () {
+ return { top: this.scroller.getScrollTop() };
+ };
+ AbstractTimeGridView.prototype.applyDateScroll = function (scroll) {
+ if (scroll.top !== undefined) {
+ this.scroller.setScrollTop(scroll.top);
+ }
+ };
+ // Generates an HTML attribute string for setting the width of the axis, if it is known
+ AbstractTimeGridView.prototype.axisStyleAttr = function () {
+ if (this.axisWidth != null) {
+ return 'style="width:' + this.axisWidth + 'px"';
+ }
+ return '';
+ };
+ return AbstractTimeGridView;
+}(View));
+AbstractTimeGridView.prototype.usesMinMaxTime = true; // indicates that minTime/maxTime affects rendering
+
+var SimpleTimeGrid = /** @class */ (function (_super) {
+ __extends(SimpleTimeGrid, _super);
+ function SimpleTimeGrid(timeGrid) {
+ var _this = _super.call(this, timeGrid.el) || this;
+ _this.buildDayRanges = memoize(buildDayRanges);
+ _this.slicer = new TimeGridSlicer();
+ _this.timeGrid = timeGrid;
+ return _this;
+ }
+ SimpleTimeGrid.prototype.firstContext = function (context) {
+ context.calendar.registerInteractiveComponent(this, {
+ el: this.timeGrid.el
+ });
+ };
+ SimpleTimeGrid.prototype.destroy = function () {
+ _super.prototype.destroy.call(this);
+ this.context.calendar.unregisterInteractiveComponent(this);
+ };
+ SimpleTimeGrid.prototype.render = function (props, context) {
+ var dateEnv = this.context.dateEnv;
+ var dateProfile = props.dateProfile, dayTable = props.dayTable;
+ var dayRanges = this.dayRanges = this.buildDayRanges(dayTable, dateProfile, dateEnv);
+ var timeGrid = this.timeGrid;
+ timeGrid.receiveContext(context); // hack because context is used in sliceProps
+ timeGrid.receiveProps(__assign({}, this.slicer.sliceProps(props, dateProfile, null, context.calendar, timeGrid, dayRanges), { dateProfile: dateProfile, cells: dayTable.cells[0] }), context);
+ };
+ SimpleTimeGrid.prototype.renderNowIndicator = function (date) {
+ this.timeGrid.renderNowIndicator(this.slicer.sliceNowDate(date, this.timeGrid, this.dayRanges), date);
+ };
+ SimpleTimeGrid.prototype.buildPositionCaches = function () {
+ this.timeGrid.buildPositionCaches();
+ };
+ SimpleTimeGrid.prototype.queryHit = function (positionLeft, positionTop) {
+ var rawHit = this.timeGrid.positionToHit(positionLeft, positionTop);
+ if (rawHit) {
+ return {
+ component: this.timeGrid,
+ dateSpan: rawHit.dateSpan,
+ dayEl: rawHit.dayEl,
+ rect: {
+ left: rawHit.relativeRect.left,
+ right: rawHit.relativeRect.right,
+ top: rawHit.relativeRect.top,
+ bottom: rawHit.relativeRect.bottom
+ },
+ layer: 0
+ };
+ }
+ };
+ return SimpleTimeGrid;
+}(DateComponent));
+function buildDayRanges(dayTable, dateProfile, dateEnv) {
+ var ranges = [];
+ for (var _i = 0, _a = dayTable.headerDates; _i < _a.length; _i++) {
+ var date = _a[_i];
+ ranges.push({
+ start: dateEnv.add(date, dateProfile.minTime),
+ end: dateEnv.add(date, dateProfile.maxTime)
+ });
+ }
+ return ranges;
+}
+var TimeGridSlicer = /** @class */ (function (_super) {
+ __extends(TimeGridSlicer, _super);
+ function TimeGridSlicer() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ TimeGridSlicer.prototype.sliceRange = function (range, dayRanges) {
+ var segs = [];
+ for (var col = 0; col < dayRanges.length; col++) {
+ var segRange = intersectRanges(range, dayRanges[col]);
+ if (segRange) {
+ segs.push({
+ start: segRange.start,
+ end: segRange.end,
+ isStart: segRange.start.valueOf() === range.start.valueOf(),
+ isEnd: segRange.end.valueOf() === range.end.valueOf(),
+ col: col
+ });
+ }
+ }
+ return segs;
+ };
+ return TimeGridSlicer;
+}(Slicer));
+
+var TimeGridView = /** @class */ (function (_super) {
+ __extends(TimeGridView, _super);
+ function TimeGridView() {
+ var _this = _super !== null && _super.apply(this, arguments) || this;
+ _this.buildDayTable = memoize(buildDayTable);
+ return _this;
+ }
+ TimeGridView.prototype.render = function (props, context) {
+ _super.prototype.render.call(this, props, context); // for flags for updateSize. also _renderSkeleton/_unrenderSkeleton
+ var _a = this.props, dateProfile = _a.dateProfile, dateProfileGenerator = _a.dateProfileGenerator;
+ var nextDayThreshold = context.nextDayThreshold;
+ var dayTable = this.buildDayTable(dateProfile, dateProfileGenerator);
+ var splitProps = this.splitter.splitProps(props);
+ if (this.header) {
+ this.header.receiveProps({
+ dateProfile: dateProfile,
+ dates: dayTable.headerDates,
+ datesRepDistinctDays: true,
+ renderIntroHtml: this.renderHeadIntroHtml
+ }, context);
+ }
+ this.simpleTimeGrid.receiveProps(__assign({}, splitProps['timed'], { dateProfile: dateProfile,
+ dayTable: dayTable }), context);
+ if (this.simpleDayGrid) {
+ this.simpleDayGrid.receiveProps(__assign({}, splitProps['allDay'], { dateProfile: dateProfile,
+ dayTable: dayTable,
+ nextDayThreshold: nextDayThreshold, isRigid: false }), context);
+ }
+ this.startNowIndicator(dateProfile, dateProfileGenerator);
+ };
+ TimeGridView.prototype._renderSkeleton = function (context) {
+ _super.prototype._renderSkeleton.call(this, context);
+ if (context.options.columnHeader) {
+ this.header = new DayHeader(this.el.querySelector('.fc-head-container'));
+ }
+ this.simpleTimeGrid = new SimpleTimeGrid(this.timeGrid);
+ if (this.dayGrid) {
+ this.simpleDayGrid = new SimpleDayGrid(this.dayGrid);
+ }
+ };
+ TimeGridView.prototype._unrenderSkeleton = function () {
+ _super.prototype._unrenderSkeleton.call(this);
+ if (this.header) {
+ this.header.destroy();
+ }
+ this.simpleTimeGrid.destroy();
+ if (this.simpleDayGrid) {
+ this.simpleDayGrid.destroy();
+ }
+ };
+ TimeGridView.prototype.renderNowIndicator = function (date) {
+ this.simpleTimeGrid.renderNowIndicator(date);
+ };
+ return TimeGridView;
+}(AbstractTimeGridView));
+function buildDayTable(dateProfile, dateProfileGenerator) {
+ var daySeries = new DaySeries(dateProfile.renderRange, dateProfileGenerator);
+ return new DayTable(daySeries, false);
+}
+
+var main = createPlugin({
+ defaultView: 'timeGridWeek',
+ views: {
+ timeGrid: {
+ class: TimeGridView,
+ allDaySlot: true,
+ slotDuration: '00:30:00',
+ slotEventOverlap: true // a bad name. confused with overlap/constraint system
+ },
+ timeGridDay: {
+ type: 'timeGrid',
+ duration: { days: 1 }
+ },
+ timeGridWeek: {
+ type: 'timeGrid',
+ duration: { weeks: 1 }
+ }
+ }
+});
+
+export default main;
+export { AbstractTimeGridView, TimeGrid, TimeGridSlicer, TimeGridView, buildDayRanges, buildDayTable };